From 6be28745c75c3542058fc7833c773e3b44ad3b92 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Sat, 15 May 2021 11:38:09 -0700 Subject: [PATCH 0001/2325] Add information for apache mod_userdir Resolution of issue #4471 --- .../source/installation/running.rst | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index 4d00260ffcea..deb9bea50693 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -129,6 +129,72 @@ e.g., ``apache2/conf/extra/httpd-vhost.conf``:: If your project folder is not a subfolder of the Apache document root, then your element may need a nested element to grant the web server access to the files. +With mod_userdir (shared hosts) +-------------------------------- + +A common practice in shared hosting environments is to use the Apache module "mod_userdir" to enable per-user Virtual Hosts automatically. Additional configuration is required to allow CodeIgniter4 to be run from these per-user directories. + +The following assumes that the server is already configured for mod_userdir. A guide to enabling this module is available `in the Apache documentation `_. + +Because CodeIgniter4 requires the server to find the framework front controller at ``/public/index.php``, you must specify this location as an alternative to search for the request, even if CodeIgniter4 is installed within the per-user web directory. + +The default user web directory ``~/public_html`` is specified by the default ``UserDir`` directive, typically in ``/apache2/mods-available/userdir.conf`` or ``/apache2/conf/extra/httpd-userdir.conf``:: + + UserDir public_html + +So you will need to configure Apache to look for CodeIgniter's public directory first before trying to serve the default:: + + UserDir "public_html/public" "public_html" + +Be sure to specify options and permissions for the CodeIgniter public directory as well. A ``userdir.conf`` might look like:: + + + UserDir "public_html/public" "public_html" + UserDir disabled root + + + AllowOverride All + Options MultiViews Indexes FollowSymLinks + + # Apache <= 2.2: + #Order allow,deny + # Allow from all + + # Apache >= 2.4: + Require all granted + + + # Apache <= 2.2: + #Order deny,allow + # Deny from all + + # Apache >= 2.4: + Require all denied + + + + + AllowOverride All + Options MultiViews Indexes FollowSymLinks + + # Apache <= 2.2: + #Order allow,deny + #Allow from all + + # Apache >= 2.4: + Require all granted + + + # Apache <= 2.2: + #Order deny,allow + #Deny from all + + # Apache >= 2.4: + Require all denied + + + + Testing ------- From 4206bcc41ec182d181d6c6ecd7cc9f73069455d8 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Mon, 17 May 2021 06:52:34 -0700 Subject: [PATCH 0002/2325] Update user_guide_src/source/installation/running.rst Co-authored-by: MGatner --- user_guide_src/source/installation/running.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index deb9bea50693..9b5ed53b2c14 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -136,7 +136,7 @@ A common practice in shared hosting environments is to use the Apache module "mo The following assumes that the server is already configured for mod_userdir. A guide to enabling this module is available `in the Apache documentation `_. -Because CodeIgniter4 requires the server to find the framework front controller at ``/public/index.php``, you must specify this location as an alternative to search for the request, even if CodeIgniter4 is installed within the per-user web directory. +Because CodeIgniter4 expects the server to find the framework front controller at ``/public/index.php`` by default, you must specify this location as an alternative to search for the request (even if CodeIgniter4 is installed within the per-user web directory). The default user web directory ``~/public_html`` is specified by the default ``UserDir`` directive, typically in ``/apache2/mods-available/userdir.conf`` or ``/apache2/conf/extra/httpd-userdir.conf``:: From 032e8fdc7373dc5f4f05f79ee6c183eb4cbeda2a Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Mon, 17 May 2021 06:52:41 -0700 Subject: [PATCH 0003/2325] Update user_guide_src/source/installation/running.rst Co-authored-by: MGatner --- user_guide_src/source/installation/running.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index 9b5ed53b2c14..3c0abeeae114 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -138,7 +138,7 @@ The following assumes that the server is already configured for mod_userdir. A g Because CodeIgniter4 expects the server to find the framework front controller at ``/public/index.php`` by default, you must specify this location as an alternative to search for the request (even if CodeIgniter4 is installed within the per-user web directory). -The default user web directory ``~/public_html`` is specified by the default ``UserDir`` directive, typically in ``/apache2/mods-available/userdir.conf`` or ``/apache2/conf/extra/httpd-userdir.conf``:: +The default user web directory ``~/public_html`` is specified by the ``UserDir`` directive, typically in ``/apache2/mods-available/userdir.conf`` or ``/apache2/conf/extra/httpd-userdir.conf``:: UserDir public_html From ff77f3b7e909519e23170095be64a164deb76b59 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Mon, 17 May 2021 06:52:46 -0700 Subject: [PATCH 0004/2325] Update user_guide_src/source/installation/running.rst Co-authored-by: MGatner --- user_guide_src/source/installation/running.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index 3c0abeeae114..0e7e666ec963 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -165,7 +165,7 @@ Be sure to specify options and permissions for the CodeIgniter public directory # Apache <= 2.2: - #Order deny,allow + # Order deny,allow # Deny from all # Apache >= 2.4: From fbb4cb735753716136de030dd7efb6fdca5ff37e Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Mon, 17 May 2021 06:52:58 -0700 Subject: [PATCH 0005/2325] Update user_guide_src/source/installation/running.rst Co-authored-by: MGatner --- user_guide_src/source/installation/running.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index 0e7e666ec963..c1b5017748f6 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -186,8 +186,8 @@ Be sure to specify options and permissions for the CodeIgniter public directory # Apache <= 2.2: - #Order deny,allow - #Deny from all + # Order deny,allow + # Deny from all # Apache >= 2.4: Require all denied From 2b3798cf0f016446a0e103f009c22777ce3ff656 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Mon, 17 May 2021 06:53:02 -0700 Subject: [PATCH 0006/2325] Update user_guide_src/source/installation/running.rst Co-authored-by: MGatner --- user_guide_src/source/installation/running.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index c1b5017748f6..a7b1bb034a41 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -178,8 +178,8 @@ Be sure to specify options and permissions for the CodeIgniter public directory Options MultiViews Indexes FollowSymLinks # Apache <= 2.2: - #Order allow,deny - #Allow from all + # Order allow,deny + # Allow from all # Apache >= 2.4: Require all granted From 5fa4159d90afd3fe2d9e51128633d1eaaf52f6ee Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Mon, 17 May 2021 06:53:10 -0700 Subject: [PATCH 0007/2325] Update user_guide_src/source/installation/running.rst Co-authored-by: MGatner --- user_guide_src/source/installation/running.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index a7b1bb034a41..45e92387dee1 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -157,7 +157,7 @@ Be sure to specify options and permissions for the CodeIgniter public directory Options MultiViews Indexes FollowSymLinks # Apache <= 2.2: - #Order allow,deny + # Order allow,deny # Allow from all # Apache >= 2.4: From 1476c8417a489502ee0dbd69439d974c471160f9 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 15 Jun 2021 23:16:02 +0800 Subject: [PATCH 0008/2325] Define switch-related rules --- utils/PhpCsFixer/CodeIgniter4.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index f2515e6bf34c..3b10fe2ceb5f 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -176,11 +176,14 @@ public function __construct() 'null_adjustment' => 'always_last', 'sort_algorithm' => 'alpha', ], - 'set_type_to_cast' => true, - 'short_scalar_cast' => true, - 'static_lambda' => true, - 'ternary_to_null_coalescing' => true, - 'trailing_comma_in_multiline' => [ + 'set_type_to_cast' => true, + 'short_scalar_cast' => true, + 'static_lambda' => true, + 'switch_case_semicolon_to_colon' => true, + 'switch_case_space' => true, + 'switch_continue_to_break' => true, + 'ternary_to_null_coalescing' => true, + 'trailing_comma_in_multiline' => [ 'after_heredoc' => true, 'elements' => ['arrays'], ], From 44a9fe24d136f2e08600bd49bb3dfb756cb594bd Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 16 Jun 2021 00:08:12 +0800 Subject: [PATCH 0009/2325] Define rules starting with "L" --- tests/system/ControllerTest.php | 4 ++-- utils/PhpCsFixer/CodeIgniter4.php | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index 37e9596f58c8..2a89cb1f9350 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -79,7 +79,7 @@ public function testConstructorHTTPS() $original = $_SERVER; $_SERVER = ['HTTPS' => 'on']; // make sure we can instantiate one - $this->controller = new Class() extends Controller { + $this->controller = new class() extends Controller { protected $forceHTTPS = 1; }; $this->controller->initController($this->request, $this->response, $this->logger); @@ -165,7 +165,7 @@ public function testValidateWithStringRulesFoundUseMessagesParameter() //-------------------------------------------------------------------- public function testHelpers() { - $this->controller = new Class() extends Controller { + $this->controller = new class() extends Controller { protected $helpers = [ 'cookie', 'text', diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index f2515e6bf34c..0dbc17ce5d54 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -96,9 +96,14 @@ public function __construct() 'heredoc_indentation' => ['indentation' => 'start_plus_one'], 'heredoc_to_nowdoc' => true, 'indentation_type' => true, + 'lambda_not_used_import' => true, 'line_ending' => true, + 'linebreak_after_opening_tag' => true, 'list_syntax' => ['syntax' => 'short'], + 'logical_operators' => true, 'lowercase_cast' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, 'modernize_types_casting' => true, 'no_alias_functions' => ['sets' => ['@all']], 'no_short_bool_cast' => true, From 4c5d8e34c4472e04064db3313a0f9daf5ecc0dbb Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 15 Jun 2021 23:19:25 +0800 Subject: [PATCH 0010/2325] Define rules for ternary operators --- utils/PhpCsFixer/CodeIgniter4.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index f8461e3e6aab..98bb380de04c 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -187,6 +187,8 @@ public function __construct() 'switch_case_semicolon_to_colon' => true, 'switch_case_space' => true, 'switch_continue_to_break' => true, + 'ternary_operator_spaces' => true, + 'ternary_to_elvis_operator' => true, 'ternary_to_null_coalescing' => true, 'trailing_comma_in_multiline' => [ 'after_heredoc' => true, From fb24304d234c802e3c1c228cae8ea04757cab6c7 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 15 Jun 2021 23:32:42 +0800 Subject: [PATCH 0011/2325] Define rules on unary operators --- system/CLI/CLI.php | 14 +++++++------- system/Database/BaseBuilder.php | 6 +++--- system/Database/BaseConnection.php | 8 ++++---- system/Database/BaseResult.php | 6 +++--- system/Database/BaseUtils.php | 4 ++-- system/Database/MySQLi/Forge.php | 4 ++-- system/Database/Postgre/Connection.php | 2 +- system/Database/Postgre/PreparedQuery.php | 2 +- system/Database/Postgre/Result.php | 4 ++-- system/Database/SQLSRV/Builder.php | 3 ++- system/Database/SQLite3/Result.php | 4 ++-- system/Debug/Iterator.php | 5 ++--- system/Email/Email.php | 12 ++++++------ system/Files/File.php | 6 +++--- system/HTTP/RequestTrait.php | 2 +- system/HTTP/URI.php | 4 ++-- system/Helpers/number_helper.php | 2 +- system/Helpers/text_helper.php | 12 ++++++------ system/Helpers/url_helper.php | 8 ++++---- system/Pager/PagerRenderer.php | 2 +- system/Router/RouteCollection.php | 2 +- system/Session/Handlers/MemcachedHandler.php | 2 +- system/Session/Handlers/RedisHandler.php | 2 +- system/Typography/Typography.php | 6 +++--- system/Validation/CreditCardRules.php | 4 ++-- tests/system/Helpers/TextHelperTest.php | 4 ++-- tests/system/Validation/CreditCardRulesTest.php | 4 ++-- tests/system/View/ParserTest.php | 2 +- utils/PhpCsFixer/CodeIgniter4.php | 5 +++++ 29 files changed, 73 insertions(+), 68 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index b7249022497a..4d5ad1ec8ab5 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -403,7 +403,7 @@ public static function wait(int $seconds, bool $countdown = false) while ($time > 0) { static::fwrite(STDOUT, $time . '... '); sleep(1); - $time --; + $time--; } static::write(); @@ -442,7 +442,7 @@ public static function isWindows(): bool public static function newLine(int $num = 1) { // Do it once or more, write with empty string gives us a new line - for ($i = 0; $i < $num; $i ++) { + for ($i = 0; $i < $num; $i++) { static::write(); } } @@ -998,7 +998,7 @@ public static function table(array $tbody, array $thead = []) $maxColsLengths = []; // Read row by row and define the longest columns - for ($row = 0; $row < $totalRows; $row ++) { + for ($row = 0; $row < $totalRows; $row++) { $column = 0; // Current column index foreach ($tableRows[$row] as $col) { @@ -1013,13 +1013,13 @@ public static function table(array $tbody, array $thead = []) } // We can go check the size of the next column... - $column ++; + $column++; } } // Read row by row and add spaces at the end of the columns // to match the exact column length - for ($row = 0; $row < $totalRows; $row ++) { + for ($row = 0; $row < $totalRows; $row++) { $column = 0; foreach ($tableRows[$row] as $col) { @@ -1029,14 +1029,14 @@ public static function table(array $tbody, array $thead = []) $tableRows[$row][$column] = $tableRows[$row][$column] . str_repeat(' ', $diff); } - $column ++; + $column++; } } $table = ''; // Joins columns and append the well formatted rows to the table - for ($row = 0; $row < $totalRows; $row ++) { + for ($row = 0; $row < $totalRows; $row++) { // Set the table border-top if ($row === 0) { $cols = '+'; diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 2657586262dc..ce22b79b5901 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -653,7 +653,7 @@ public function join(string $table, string $cond, string $type = '', bool $escap $joints = $joints[0]; array_unshift($joints, ['', 0]); - for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i --) { + for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--) { $joints[$i][1] += strlen($joints[$i][0]); // offset $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]); $pos = $joints[$i][1] - strlen($joints[$i][0]); @@ -1419,7 +1419,7 @@ protected function groupStartPrepare(string $not = '', string $type = 'AND ', st $this->QBWhereGroupStarted = true; $prefix = empty($this->$clause) ? '' : $type; $where = [ - 'condition' => $prefix . $not . str_repeat(' ', ++ $this->QBWhereGroupCount) . ' (', + 'condition' => $prefix . $not . str_repeat(' ', ++$this->QBWhereGroupCount) . ' (', 'escape' => false, ]; @@ -1999,7 +1999,7 @@ public function insertBatch(array $set = null, bool $escape = null, int $batchSi $sql = $this->_insertBatch($this->db->protectIdentifiers($table, true, $escape, false), $this->QBKeys, array_slice($this->QBSet, $i, $batchSize)); if ($this->testMode) { - ++$affectedRows; + $affectedRows++; } else { $this->db->query($sql, $this->binds, false); $affectedRows += $this->db->affectedRows(); diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 7186036f32e5..b1d92c154c10 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -821,7 +821,7 @@ public function transBegin(bool $testMode = false): bool // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->transDepth > 0) { - $this->transDepth ++; + $this->transDepth++; return true; } @@ -836,7 +836,7 @@ public function transBegin(bool $testMode = false): bool $this->transFailure = ($testMode === true); if ($this->_transBegin()) { - $this->transDepth ++; + $this->transDepth++; return true; } @@ -859,7 +859,7 @@ public function transCommit(): bool // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->transDepth > 1 || $this->_transCommit()) { - $this->transDepth --; + $this->transDepth--; return true; } @@ -882,7 +882,7 @@ public function transRollback(): bool // When transactions are nested we only begin/commit/rollback the outermost ones if ($this->transDepth > 1 || $this->_transRollback()) { - $this->transDepth --; + $this->transDepth--; return true; } diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index ba190bda7b93..9c22e34ca74a 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -140,7 +140,7 @@ public function getCustomResultObject(string $className) } if ($_data !== null) { - for ($i = 0; $i < $c; $i ++) { + for ($i = 0; $i < $c; $i++) { $this->customResultObject[$className][$i] = new $className(); foreach ($this->{$_data}[$i] as $key => $value) { @@ -444,7 +444,7 @@ public function getNextRow(string $type = 'object') return null; } - return isset($result[$this->currentRow + 1]) ? $result[++ $this->currentRow] : null; + return isset($result[$this->currentRow + 1]) ? $result[++$this->currentRow] : null; } //-------------------------------------------------------------------- @@ -464,7 +464,7 @@ public function getPreviousRow(string $type = 'object') } if (isset($result[$this->currentRow - 1])) { - -- $this->currentRow; + $this->currentRow--; } return $result[$this->currentRow]; diff --git a/system/Database/BaseUtils.php b/system/Database/BaseUtils.php index 48d54f7f1a89..2fcfd2142949 100644 --- a/system/Database/BaseUtils.php +++ b/system/Database/BaseUtils.php @@ -57,7 +57,7 @@ abstract class BaseUtils */ public function __construct(ConnectionInterface &$db) { - $this->db = & $db; + $this->db = &$db; } //-------------------------------------------------------------------- @@ -91,7 +91,7 @@ public function listDatabases() return $this->db->dataCache['db_names']; } - for ($i = 0, $query = $query->getResultArray(), $c = count($query); $i < $c; $i ++) { + for ($i = 0, $query = $query->getResultArray(), $c = count($query); $i < $c; $i++) { $this->db->dataCache['db_names'][] = current($query[$i]); } diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index c3202a2e3008..390ee2e1e58b 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -207,9 +207,9 @@ protected function _processIndexes(string $table): string { $sql = ''; - for ($i = 0, $c = count($this->keys); $i < $c; $i ++) { + for ($i = 0, $c = count($this->keys); $i < $c; $i++) { if (is_array($this->keys[$i])) { - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2 ++) { + for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) { if (! isset($this->fields[$this->keys[$i][$i2]])) { unset($this->keys[$i][$i2]); diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index 334ac39df46b..3012a769491b 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -294,7 +294,7 @@ public function _fieldData(string $table): array $retVal = []; - for ($i = 0, $c = count($query); $i < $c; $i ++) { + for ($i = 0, $c = count($query); $i < $c; $i++) { $retVal[$i] = new stdClass(); $retVal[$i]->name = $query[$i]->column_name; diff --git a/system/Database/Postgre/PreparedQuery.php b/system/Database/Postgre/PreparedQuery.php index dd9c3699c746..9c94b5c304dd 100644 --- a/system/Database/Postgre/PreparedQuery.php +++ b/system/Database/Postgre/PreparedQuery.php @@ -112,7 +112,7 @@ public function parameterize(string $sql): string $count = 0; return preg_replace_callback('/\?/', static function () use (&$count) { - $count ++; + $count++; return "\${$count}"; }, $sql); diff --git a/system/Database/Postgre/Result.php b/system/Database/Postgre/Result.php index bd1d2342d08f..936adf339226 100644 --- a/system/Database/Postgre/Result.php +++ b/system/Database/Postgre/Result.php @@ -41,7 +41,7 @@ public function getFieldNames(): array { $fieldNames = []; - for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i ++) { + for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { $fieldNames[] = pg_field_name($this->resultID, $i); } @@ -59,7 +59,7 @@ public function getFieldData(): array { $retVal = []; - for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i ++) { + for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { $retVal[$i] = new stdClass(); $retVal[$i]->name = pg_field_name($this->resultID, $i); $retVal[$i]->type = pg_field_type_oid($this->resultID, $i); diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index f461c03477b4..656854093ba0 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -141,12 +141,13 @@ public function join(string $table, string $cond, string $type = '', bool $escap $joints = $joints[0]; array_unshift($joints, ['', 0]); - for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i --) { + for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--) { $joints[$i][1] += strlen($joints[$i][0]); // offset $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]); $pos = $joints[$i][1] - strlen($joints[$i][0]); $joints[$i] = $joints[$i][0]; } + ksort($conditions); } else { $conditions = [$cond]; diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 04109fb498f4..4bddc63fe854 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -43,7 +43,7 @@ public function getFieldNames(): array { $fieldNames = []; - for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i ++) { + for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { $fieldNames[] = $this->resultID->columnName($i); // @phpstan-ignore-line } @@ -70,7 +70,7 @@ public function getFieldData(): array $retVal = []; $this->resultID->fetchArray(SQLITE3_NUM); // @phpstan-ignore-line - for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i ++) { + for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { $retVal[$i] = new stdClass(); $retVal[$i]->name = $this->resultID->columnName($i); // @phpstan-ignore-line $type = $this->resultID->columnType($i); // @phpstan-ignore-line diff --git a/system/Debug/Iterator.php b/system/Debug/Iterator.php index 7f924b66a8eb..ca5233010d2f 100644 --- a/system/Debug/Iterator.php +++ b/system/Debug/Iterator.php @@ -75,9 +75,8 @@ public function run(int $iterations = 1000, bool $output = true) $start = microtime(true); $startMem = $maxMemory = memory_get_usage(true); - for ($i = 0; $i < $iterations; $i ++) { - $result = $test(); - + for ($i = 0; $i < $iterations; $i++) { + $result = $test(); $maxMemory = max($maxMemory, memory_get_usage(true)); unset($result); diff --git a/system/Email/Email.php b/system/Email/Email.php index 62742e7d8ebb..406a8c5ee7c9 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -691,7 +691,7 @@ public function attach($file, $disposition = '', $newname = null, $mime = '') fclose($fp); } else { - $fileContent = & $file; // buffered file + $fileContent = &$file; // buffered file } // declare names on their own, to make phpcbf happy @@ -1042,7 +1042,7 @@ protected function getAltMessage() $body = preg_match('/\(.*)\<\/body\>/si', $this->body, $match) ? $match[1] : $this->body; $body = str_replace("\t", '', preg_replace('#'; - $this->assertEquals('foo ', sanitize_filename($filename)); + $this->assertSame('foo ', sanitize_filename($filename)); } public function testStripImageTags() { - $this->assertEquals('http://example.com/spacer.gif', strip_image_tags('http://example.com/spacer.gif')); + $this->assertSame('http://example.com/spacer.gif', strip_image_tags('http://example.com/spacer.gif')); - $this->assertEquals('http://example.com/spacer.gif', strip_image_tags('Who needs CSS when you have a spacer.gif?')); + $this->assertSame('http://example.com/spacer.gif', strip_image_tags('Who needs CSS when you have a spacer.gif?')); } public function testEncodePhpTags() { - $this->assertEquals('<? echo $foo; ?>', encode_php_tags('')); + $this->assertSame('<? echo $foo; ?>', encode_php_tags('')); } } diff --git a/tests/system/Helpers/TextHelperTest.php b/tests/system/Helpers/TextHelperTest.php index f36c42ab0661..bdee7678e06e 100755 --- a/tests/system/Helpers/TextHelperTest.php +++ b/tests/system/Helpers/TextHelperTest.php @@ -30,7 +30,7 @@ public function testStripSlashes() "Is your name O\'reilly?", "No, my name is O\'connor.", ]; - $this->assertEquals($expected, strip_slashes($str)); + $this->assertSame($expected, strip_slashes($str)); } // -------------------------------------------------------------------- @@ -42,7 +42,7 @@ public function testStripQuotes() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, strip_quotes($str)); + $this->assertSame($expect, strip_quotes($str)); } } @@ -55,7 +55,7 @@ public function testQuotesToEntities() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, quotes_to_entities($str)); + $this->assertSame($expect, quotes_to_entities($str)); } } @@ -69,7 +69,7 @@ public function testReduceDoubleSlashes() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, reduce_double_slashes($str)); + $this->assertSame($expect, reduce_double_slashes($str)); } } @@ -82,7 +82,7 @@ public function testReduceMultiples() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, reduce_multiples($str)); + $this->assertSame($expect, reduce_multiples($str)); } $strs = [ 'Fred, Bill,, Joe, Jimmy' => 'Fred, Bill, Joe, Jimmy', @@ -90,37 +90,37 @@ public function testReduceMultiples() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, reduce_multiples($str, ',', true)); + $this->assertSame($expect, reduce_multiples($str, ',', true)); } } // -------------------------------------------------------------------- public function testRandomString() { - $this->assertEquals(16, strlen(random_string('alnum', 16))); - $this->assertEquals(16, strlen(random_string('alpha', 16))); - $this->assertEquals(16, strlen(random_string('nozero', 16))); - $this->assertEquals(16, strlen(random_string('numeric', 16))); - $this->assertEquals(8, strlen(random_string('numeric'))); + $this->assertSame(16, strlen(random_string('alnum', 16))); + $this->assertSame(16, strlen(random_string('alpha', 16))); + $this->assertSame(16, strlen(random_string('nozero', 16))); + $this->assertSame(16, strlen(random_string('numeric', 16))); + $this->assertSame(8, strlen(random_string('numeric'))); $this->assertIsString(random_string('basic')); - $this->assertEquals(16, strlen($random = random_string('crypto', 16))); + $this->assertSame(16, strlen($random = random_string('crypto', 16))); $this->assertIsString($random); - $this->assertEquals(32, strlen($random = random_string('md5'))); - $this->assertEquals(40, strlen($random = random_string('sha1'))); + $this->assertSame(32, strlen($random = random_string('md5'))); + $this->assertSame(40, strlen($random = random_string('sha1'))); } // -------------------------------------------------------------------- public function testIncrementString() { - $this->assertEquals('my-test_1', increment_string('my-test')); - $this->assertEquals('my-test-1', increment_string('my-test', '-')); - $this->assertEquals('file_5', increment_string('file_4')); - $this->assertEquals('file-5', increment_string('file-4', '-')); - $this->assertEquals('file-5', increment_string('file-4', '-')); - $this->assertEquals('file-1', increment_string('file', '-', '1')); - $this->assertEquals(124, increment_string('123', '')); + $this->assertSame('my-test_1', increment_string('my-test')); + $this->assertSame('my-test-1', increment_string('my-test', '-')); + $this->assertSame('file_5', increment_string('file_4')); + $this->assertSame('file-5', increment_string('file-4', '-')); + $this->assertSame('file-5', increment_string('file-4', '-')); + $this->assertSame('file-1', increment_string('file', '-', '1')); + $this->assertSame('124', increment_string('123', '')); } // ------------------------------------------------------------------- @@ -129,20 +129,20 @@ public function testIncrementString() public function testWordLimiter() { - $this->assertEquals('Once upon a time,…', word_limiter($this->_long_string, 4)); - $this->assertEquals('Once upon a time,…', word_limiter($this->_long_string, 4, '…')); - $this->assertEquals('', word_limiter('', 4)); - $this->assertEquals('Once upon a…', word_limiter($this->_long_string, 3, '…')); - $this->assertEquals('Once upon a time', word_limiter('Once upon a time', 4, '…')); + $this->assertSame('Once upon a time,…', word_limiter($this->_long_string, 4)); + $this->assertSame('Once upon a time,…', word_limiter($this->_long_string, 4, '…')); + $this->assertSame('', word_limiter('', 4)); + $this->assertSame('Once upon a…', word_limiter($this->_long_string, 3, '…')); + $this->assertSame('Once upon a time', word_limiter('Once upon a time', 4, '…')); } // ------------------------------------------------------------------------ public function testCharacterLimiter() { - $this->assertEquals('Once upon a time, a…', character_limiter($this->_long_string, 20)); - $this->assertEquals('Once upon a time, a…', character_limiter($this->_long_string, 20, '…')); - $this->assertEquals('Short', character_limiter('Short', 20)); - $this->assertEquals('Short', character_limiter('Short', 5)); + $this->assertSame('Once upon a time, a…', character_limiter($this->_long_string, 20)); + $this->assertSame('Once upon a time, a…', character_limiter($this->_long_string, 20, '…')); + $this->assertSame('Short', character_limiter('Short', 20)); + $this->assertSame('Short', character_limiter('Short', 5)); } // ------------------------------------------------------------------------ @@ -154,7 +154,7 @@ public function testAsciiToEntities() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, ascii_to_entities($str)); + $this->assertSame($expect, ascii_to_entities($str)); } } @@ -167,29 +167,29 @@ public function testEntitiesToAscii() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, entities_to_ascii($str)); + $this->assertSame($expect, entities_to_ascii($str)); } } public function testEntitiesToAsciiUnsafe() { $str = '<>'; - $this->assertEquals('<>', entities_to_ascii($str, true)); - $this->assertEquals('<>', entities_to_ascii($str, false)); + $this->assertSame('<>', entities_to_ascii($str, true)); + $this->assertSame('<>', entities_to_ascii($str, false)); } public function testEntitiesToAsciiSmallOrdinals() { $str = ''; - $this->assertEquals(pack('c', 7), entities_to_ascii($str)); + $this->assertSame(pack('c', 7), entities_to_ascii($str)); } // ------------------------------------------------------------------------ public function testConvertAccentedCharacters() { //$this->ci_vfs_clone('application/Config/ForeignChars.php'); - $this->assertEquals('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ')); - $this->assertEquals('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü')); + $this->assertSame('AAAeEEEIIOOEUUUeY', convert_accented_characters('ÀÂÄÈÊËÎÏÔŒÙÛÜŸ')); + $this->assertSame('a e i o u n ue', convert_accented_characters('á é í ó ú ñ ü')); } // ------------------------------------------------------------------------ @@ -211,7 +211,7 @@ public function testCensoredWords() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, word_censor($str, $censored, '$*#')); + $this->assertSame($expect, word_censor($str, $censored, '$*#')); } } @@ -219,7 +219,7 @@ public function testCensoredWords() public function testHighlightCode() { $expect = "\n<?php var_dump(\$this); ?> \n\n"; - $this->assertEquals($expect, highlight_code('')); + $this->assertSame($expect, highlight_code('')); } // ------------------------------------------------------------------------ @@ -234,10 +234,10 @@ public function testHighlightPhrase() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, highlight_phrase($str, 'this is')); + $this->assertSame($expect, highlight_phrase($str, 'this is')); } - $this->assertEquals('this is a strong test', highlight_phrase('this is a strong test', 'this is', '', '')); + $this->assertSame('this is a strong test', highlight_phrase('this is a strong test', 'this is', '', '')); } // ------------------------------------------------------------------------ @@ -266,7 +266,7 @@ public function testEllipsize() foreach ($strs as $pos => $s) { foreach ($s as $str => $expect) { - $this->assertEquals($expect, ellipsize($str, 10, $pos)); + $this->assertSame($expect, ellipsize($str, 10, $pos)); } } } @@ -276,26 +276,26 @@ public function testWordWrap() { $string = 'Here is a simple string of text that will help us demonstrate this function.'; $expected = "Here is a simple string\nof text that will help us\ndemonstrate this\nfunction."; - $this->assertEquals(substr_count(word_wrap($string, 25), "\n"), 3); - $this->assertEquals($expected, word_wrap($string, 25)); + $this->assertSame(substr_count(word_wrap($string, 25), "\n"), 3); + $this->assertSame($expected, word_wrap($string, 25)); $string2 = "Here is a\nbroken up sentence\rspanning lines\r\nwoohoo!"; $expected2 = "Here is a\nbroken up sentence\nspanning lines\nwoohoo!"; - $this->assertEquals(substr_count(word_wrap($string2, 25), "\n"), 3); - $this->assertEquals($expected2, word_wrap($string2, 25)); + $this->assertSame(substr_count(word_wrap($string2, 25), "\n"), 3); + $this->assertSame($expected2, word_wrap($string2, 25)); $string3 = "Here is another slightly longer\nbroken up sentence\rspanning lines\r\nwoohoo!"; $expected3 = "Here is another slightly\nlonger\nbroken up sentence\nspanning lines\nwoohoo!"; - $this->assertEquals(substr_count(word_wrap($string3, 25), "\n"), 4); - $this->assertEquals($expected3, word_wrap($string3, 25)); + $this->assertSame(substr_count(word_wrap($string3, 25), "\n"), 4); + $this->assertSame($expected3, word_wrap($string3, 25)); } public function testWordWrapUnwrap() { $string = 'Here is a {unwrap}simple string of text{/unwrap} that will help us demonstrate this function.'; $expected = "Here is a simple string of text\nthat will help us\ndemonstrate this\nfunction."; - $this->assertEquals(substr_count(word_wrap($string, 25), "\n"), 3); - $this->assertEquals($expected, word_wrap($string, 25)); + $this->assertSame(substr_count(word_wrap($string, 25), "\n"), 3); + $this->assertSame($expected, word_wrap($string, 25)); } public function testWordWrapLongWords() @@ -303,7 +303,7 @@ public function testWordWrapLongWords() // the really really long word will be split $string = 'Here is an unbelievable super-complicated and reallyreallyquiteextraordinarily sophisticated sentence.'; $expected = "Here is an unbelievable\nsuper-complicated and\nreallyreallyquiteextraor\ndinarily\nsophisticated sentence."; - $this->assertEquals($expected, word_wrap($string, 25)); + $this->assertSame($expected, word_wrap($string, 25)); } public function testWordWrapURL() @@ -311,14 +311,14 @@ public function testWordWrapURL() // the really really long word will be split $string = 'Here is an unbelievable super-complicated and http://www.reallyreallyquiteextraordinarily.com sophisticated sentence.'; $expected = "Here is an unbelievable\nsuper-complicated and\nhttp://www.reallyreallyquiteextraordinarily.com\nsophisticated sentence."; - $this->assertEquals($expected, word_wrap($string, 25)); + $this->assertSame($expected, word_wrap($string, 25)); } // ------------------------------------------------------------------------ public function testDefaultWordWrapCharlim() { $string = 'Here is a longer string of text that will help us demonstrate the default charlim of this function.'; - $this->assertEquals(strpos(word_wrap($string), "\n"), 73); + $this->assertSame(strpos(word_wrap($string), "\n"), 73); } // ----------------------------------------------------------------------- @@ -327,7 +327,7 @@ public function testExcerpt() { $string = $this->_long_string; $result = ' Once upon a time, a framework had no tests. It sad So some nice people began to write tests. The more time that went on, the happier it became. ...'; - $this->assertEquals(excerpt($string), $result); + $this->assertSame(excerpt($string), $result); } // ----------------------------------------------------------------------- @@ -337,7 +337,7 @@ public function testExcerptRadius() $string = $this->_long_string; $phrase = 'began'; $result = '... people began to ...'; - $this->assertEquals(excerpt($string, $phrase, 10), $result); + $this->assertSame(excerpt($string, $phrase, 10), $result); } // ----------------------------------------------------------------------- @@ -351,7 +351,7 @@ public function testAlternator() for ($i = 0; $i < 4; $i++) { $result .= alternator('I', 'you', 'we') . $phrase; } - $this->assertEquals('I scream! you scream! we scream! I scream! ', $result); + $this->assertSame('I scream! you scream! we scream! I scream! ', $result); } public function testEmptyAlternator() @@ -363,6 +363,6 @@ public function testEmptyAlternator() $result .= alternator() . $phrase; } - $this->assertEquals(' scream! scream! scream! scream! ', $result); + $this->assertSame(' scream! scream! scream! scream! ', $result); } } diff --git a/tests/system/Helpers/URLHelper/CurrentUrlTest.php b/tests/system/Helpers/URLHelper/CurrentUrlTest.php index 132427d1e301..30ed290c505b 100644 --- a/tests/system/Helpers/URLHelper/CurrentUrlTest.php +++ b/tests/system/Helpers/URLHelper/CurrentUrlTest.php @@ -65,7 +65,7 @@ public function testCurrentURLReturnsBasicURL() // Since we're on a CLI, we must provide our own URI $this->config->baseURL = 'http://example.com/public'; - $this->assertEquals('http://example.com/public/index.php/', current_url()); + $this->assertSame('http://example.com/public/index.php/', current_url()); } public function testCurrentURLReturnsObject() @@ -76,7 +76,7 @@ public function testCurrentURLReturnsObject() $url = current_url(true); $this->assertInstanceOf(URI::class, $url); - $this->assertEquals('http://example.com/public/index.php/', (string) $url); + $this->assertSame('http://example.com/public/index.php/', (string) $url); } public function testCurrentURLEquivalence() @@ -91,7 +91,7 @@ public function testCurrentURLEquivalence() $request = Services::request($this->config); Services::injectMock('request', $request); - $this->assertEquals(site_url(uri_string()), current_url()); + $this->assertSame(site_url(uri_string()), current_url()); } public function testCurrentURLInSubfolder() @@ -107,13 +107,13 @@ public function testCurrentURLInSubfolder() $request = Services::request($this->config); Services::injectMock('request', $request); - $this->assertEquals('http://example.com/foo/public/index.php/bar', current_url()); - $this->assertEquals('http://example.com/foo/public/index.php/bar?baz=quip', (string) current_url(true)); + $this->assertSame('http://example.com/foo/public/index.php/bar', current_url()); + $this->assertSame('http://example.com/foo/public/index.php/bar?baz=quip', (string) current_url(true)); $uri = current_url(true); - $this->assertEquals('foo', $uri->getSegment(1)); - $this->assertEquals('example.com', $uri->getHost()); - $this->assertEquals('http', $uri->getScheme()); + $this->assertSame('foo', $uri->getSegment(1)); + $this->assertSame('example.com', $uri->getHost()); + $this->assertSame('http', $uri->getScheme()); } public function testCurrentURLWithPortInSubfolder() @@ -130,15 +130,15 @@ public function testCurrentURLWithPortInSubfolder() $request = Services::request($this->config); Services::injectMock('request', $request); - $this->assertEquals('http://example.com:8080/foo/public/index.php/bar', current_url()); - $this->assertEquals('http://example.com:8080/foo/public/index.php/bar?baz=quip', (string) current_url(true)); + $this->assertSame('http://example.com:8080/foo/public/index.php/bar', current_url()); + $this->assertSame('http://example.com:8080/foo/public/index.php/bar?baz=quip', (string) current_url(true)); $uri = current_url(true); - $this->assertEquals(['foo', 'public', 'index.php', 'bar'], $uri->getSegments()); - $this->assertEquals('foo', $uri->getSegment(1)); - $this->assertEquals('example.com', $uri->getHost()); - $this->assertEquals('http', $uri->getScheme()); - $this->assertEquals('8080', $uri->getPort()); + $this->assertSame(['foo', 'public', 'index.php', 'bar'], $uri->getSegments()); + $this->assertSame('foo', $uri->getSegment(1)); + $this->assertSame('example.com', $uri->getHost()); + $this->assertSame('http', $uri->getScheme()); + $this->assertSame(8080, $uri->getPort()); } //-------------------------------------------------------------------- @@ -155,7 +155,7 @@ public function testUriStringAbsolute() Services::injectMock('request', $request); - $this->assertEquals('/assets/image.jpg', uri_string()); + $this->assertSame('/assets/image.jpg', uri_string()); } public function testUriStringRelative() @@ -168,7 +168,7 @@ public function testUriStringRelative() Services::injectMock('request', $request); - $this->assertEquals('assets/image.jpg', uri_string(true)); + $this->assertSame('assets/image.jpg', uri_string(true)); } public function testUriStringNoTrailingSlashAbsolute() @@ -182,7 +182,7 @@ public function testUriStringNoTrailingSlashAbsolute() Services::injectMock('request', $request); - $this->assertEquals('/assets/image.jpg', uri_string()); + $this->assertSame('/assets/image.jpg', uri_string()); } public function testUriStringNoTrailingSlashRelative() @@ -196,7 +196,7 @@ public function testUriStringNoTrailingSlashRelative() Services::injectMock('request', $request); - $this->assertEquals('assets/image.jpg', uri_string(true)); + $this->assertSame('assets/image.jpg', uri_string(true)); } public function testUriStringEmptyAbsolute() @@ -206,7 +206,7 @@ public function testUriStringEmptyAbsolute() Services::injectMock('request', $request); - $this->assertEquals('/', uri_string()); + $this->assertSame('/', uri_string()); } public function testUriStringEmptyRelative() @@ -216,7 +216,7 @@ public function testUriStringEmptyRelative() Services::injectMock('request', $request); - $this->assertEquals('', uri_string(true)); + $this->assertSame('', uri_string(true)); } public function testUriStringSubfolderAbsolute() @@ -230,7 +230,7 @@ public function testUriStringSubfolderAbsolute() Services::injectMock('request', $request); - $this->assertEquals('/subfolder/assets/image.jpg', uri_string()); + $this->assertSame('/subfolder/assets/image.jpg', uri_string()); } public function testUriStringSubfolderRelative() @@ -245,7 +245,7 @@ public function testUriStringSubfolderRelative() Services::injectMock('request', $request); - $this->assertEquals('assets/image.jpg', uri_string(true)); + $this->assertSame('assets/image.jpg', uri_string(true)); } //-------------------------------------------------------------------- @@ -305,7 +305,7 @@ public function testUrlIs(string $currentPath, string $testPath, bool $expected) $request->uri = new URI('http://example.com/' . $currentPath); Services::injectMock('request', $request); - $this->assertEquals($expected, url_is($testPath)); + $this->assertSame($expected, url_is($testPath)); } /** @@ -321,7 +321,7 @@ public function testUrlIsNoIndex(string $currentPath, string $testPath, bool $ex $request->uri = new URI('http://example.com/' . $currentPath); Services::injectMock('request', $request); - $this->assertEquals($expected, url_is($testPath)); + $this->assertSame($expected, url_is($testPath)); } /** @@ -338,6 +338,6 @@ public function testUrlIsWithSubfolder(string $currentPath, string $testPath, bo $request->uri = new URI('http://example.com/subfolder/' . $currentPath); Services::injectMock('request', $request); - $this->assertEquals($expected, url_is($testPath)); + $this->assertSame($expected, url_is($testPath)); } } diff --git a/tests/system/Helpers/URLHelper/MiscUrlTest.php b/tests/system/Helpers/URLHelper/MiscUrlTest.php index 7cd23ff4c911..acf533bc1fd0 100644 --- a/tests/system/Helpers/URLHelper/MiscUrlTest.php +++ b/tests/system/Helpers/URLHelper/MiscUrlTest.php @@ -66,7 +66,7 @@ public function testPreviousURLUsesSessionFirst() Services::injectMock('request', $request); - $this->assertEquals($uri2, previous_url()); + $this->assertSame($uri2, previous_url()); } //-------------------------------------------------------------------- @@ -84,7 +84,7 @@ public function testPreviousURLUsesRefererIfNeeded() Services::injectMock('request', $request); - $this->assertEquals($uri1, previous_url()); + $this->assertSame($uri1, previous_url()); } //-------------------------------------------------------------------- @@ -97,7 +97,7 @@ public function testIndexPage() Services::injectMock('request', $request); - $this->assertEquals('index.php', index_page()); + $this->assertSame('index.php', index_page()); } public function testIndexPageAlt() @@ -108,7 +108,7 @@ public function testIndexPageAlt() Services::injectMock('request', $request); - $this->assertEquals('banana.php', index_page($this->config)); + $this->assertSame('banana.php', index_page($this->config)); } //-------------------------------------------------------------------- @@ -166,7 +166,7 @@ public function testAnchor($expected = '', $uri = '', $title = '', $attributes = $request->uri = new URI('http://example.com/'); Services::injectMock('request', $request); - $this->assertEquals($expected, anchor($uri, $title, $attributes, $this->config)); + $this->assertSame($expected, anchor($uri, $title, $attributes, $this->config)); } public function anchorNoindexPatterns() @@ -228,7 +228,7 @@ public function testAnchorNoindex($expected = '', $uri = '', $title = '', $attri $request->uri = new URI('http://example.com/'); Services::injectMock('request', $request); - $this->assertEquals($expected, anchor($uri, $title, $attributes, $this->config)); + $this->assertSame($expected, anchor($uri, $title, $attributes, $this->config)); } public function anchorSubpagePatterns() @@ -280,7 +280,7 @@ public function testAnchorTargetted($expected = '', $uri = '', $title = '', $att $request->uri = new URI('http://example.com/'); Services::injectMock('request', $request); - $this->assertEquals($expected, anchor($uri, $title, $attributes, $this->config)); + $this->assertSame($expected, anchor($uri, $title, $attributes, $this->config)); } public function anchorExamplePatterns() @@ -320,7 +320,7 @@ public function testAnchorExamples($expected = '', $uri = '', $title = '', $attr $request->uri = new URI('http://example.com/'); Services::injectMock('request', $request); - $this->assertEquals($expected, anchor($uri, $title, $attributes, $this->config)); + $this->assertSame($expected, anchor($uri, $title, $attributes, $this->config)); } //-------------------------------------------------------------------- @@ -375,7 +375,7 @@ public function testAnchorPopup($expected = '', $uri = '', $title = '', $attribu $request->uri = new URI('http://example.com/'); Services::injectMock('request', $request); - $this->assertEquals($expected, anchor_popup($uri, $title, $attributes, $this->config)); + $this->assertSame($expected, anchor_popup($uri, $title, $attributes, $this->config)); } //-------------------------------------------------------------------- @@ -412,7 +412,7 @@ public function testMailto($expected = '', $email = '', $title = '', $attributes Services::injectMock('request', $request); - $this->assertEquals($expected, mailto($email, $title, $attributes)); + $this->assertSame($expected, mailto($email, $title, $attributes)); } //-------------------------------------------------------------------- @@ -449,7 +449,7 @@ public function testSafeMailto($expected = '', $email = '', $title = '', $attrib Services::injectMock('request', $request); - $this->assertEquals($expected, safe_mailto($email, $title, $attributes)); + $this->assertSame($expected, safe_mailto($email, $title, $attributes)); } //-------------------------------------------------------------------- @@ -498,7 +498,7 @@ public function autolinkUrls() */ public function testAutoLinkUrl($in, $out) { - $this->assertEquals($out, auto_link($in, 'url')); + $this->assertSame($out, auto_link($in, 'url')); } public function autolinkEmails() @@ -544,7 +544,7 @@ public function autolinkEmails() */ public function testAutoLinkEmail($in, $out) { - $this->assertEquals($out, auto_link($in, 'email')); + $this->assertSame($out, auto_link($in, 'email')); } public function autolinkBoth() @@ -590,7 +590,7 @@ public function autolinkBoth() */ public function testAutolinkBoth($in, $out) { - $this->assertEquals($out, auto_link($in)); + $this->assertSame($out, auto_link($in)); } public function autolinkPopup() @@ -636,7 +636,7 @@ public function autolinkPopup() */ public function testAutoLinkPopup($in, $out) { - $this->assertEquals($out, auto_link($in, 'url', true)); + $this->assertSame($out, auto_link($in, 'url', true)); } //-------------------------------------------------------------------- @@ -739,7 +739,7 @@ public function testUrlTitle() ]; foreach ($words as $in => $out) { - $this->assertEquals($out, url_title($in, '-', true)); + $this->assertSame($out, url_title($in, '-', true)); } } @@ -752,7 +752,7 @@ public function testUrlTitleExtraDashes() ]; foreach ($words as $in => $out) { - $this->assertEquals($out, url_title($in, '_')); + $this->assertSame($out, url_title($in, '_')); } } @@ -769,7 +769,7 @@ public function testMbUrlTitle() ]; foreach ($words as $in => $out) { - $this->assertEquals($out, mb_url_title($in, '-', true)); + $this->assertSame($out, mb_url_title($in, '-', true)); } } @@ -783,7 +783,7 @@ public function testMbUrlTitleExtraDashes() ]; foreach ($words as $in => $out) { - $this->assertEquals($out, mb_url_title($in, '_')); + $this->assertSame($out, mb_url_title($in, '_')); } } @@ -798,7 +798,7 @@ public function testUrlTo(string $expected, string $input, ...$args) $routes->add('path/(:any)/to/(:num)', 'myController::goto/$1/$2', ['as' => 'gotoPage']); $routes->add('route/(:any)/to/(:num)', 'myOtherController::goto/$1/$2'); - $this->assertEquals($expected, url_to($input, ...$args)); + $this->assertSame($expected, url_to($input, ...$args)); } /** diff --git a/tests/system/Helpers/URLHelper/SiteUrlTest.php b/tests/system/Helpers/URLHelper/SiteUrlTest.php index 49dc62cb53d1..5cf8613bafff 100644 --- a/tests/system/Helpers/URLHelper/SiteUrlTest.php +++ b/tests/system/Helpers/URLHelper/SiteUrlTest.php @@ -71,12 +71,12 @@ public function testUrls($baseURL, $indexPage, $scheme, $secure, $path, $expecte $this->config->indexPage = $indexPage; $this->config->forceGlobalSecureRequests = $secure; - $this->assertEquals($expectedSiteUrl, site_url($path, $scheme, $this->config)); + $this->assertSame($expectedSiteUrl, site_url($path, $scheme, $this->config)); // base_url is always the trimmed site_url without index page $expectedBaseUrl = $indexPage === '' ? $expectedSiteUrl : str_replace('/' . $indexPage, '', $expectedSiteUrl); $expectedBaseUrl = rtrim($expectedBaseUrl, '/'); - $this->assertEquals($expectedBaseUrl, base_url($path, $scheme)); + $this->assertSame($expectedBaseUrl, base_url($path, $scheme)); } public function configProvider() @@ -247,13 +247,13 @@ public function testBaseURLDiscovery() $_SERVER['HTTP_HOST'] = 'example.com'; $_SERVER['REQUEST_URI'] = '/test'; - $this->assertEquals('http://example.com', base_url()); + $this->assertSame('http://example.com', base_url()); $_SERVER['HTTP_HOST'] = 'example.com'; $_SERVER['REQUEST_URI'] = '/test/page'; - $this->assertEquals('http://example.com', base_url()); - $this->assertEquals('http://example.com/profile', base_url('profile')); + $this->assertSame('http://example.com', base_url()); + $this->assertSame('http://example.com/profile', base_url('profile')); } public function testBaseURLService() @@ -267,7 +267,7 @@ public function testBaseURLService() Services::injectMock('request', $request); - $this->assertEquals('http://example.com/ci/v4/index.php/controller/method', site_url('controller/method', null, $this->config)); - $this->assertEquals('http://example.com/ci/v4/controller/method', base_url('controller/method', null)); + $this->assertSame('http://example.com/ci/v4/index.php/controller/method', site_url('controller/method', null, $this->config)); + $this->assertSame('http://example.com/ci/v4/controller/method', base_url('controller/method', null)); } } diff --git a/tests/system/Helpers/XMLHelperTest.php b/tests/system/Helpers/XMLHelperTest.php index f84e557daae8..f3b422ff5fbc 100644 --- a/tests/system/Helpers/XMLHelperTest.php +++ b/tests/system/Helpers/XMLHelperTest.php @@ -22,7 +22,7 @@ public function testConvert() { $original = '

Here is a so-so paragraph & an entity ({).

'; $expected = '<p>Here is a so-so paragraph & an entity ({).</p>'; - $this->assertEquals($expected, xml_convert($original)); + $this->assertSame($expected, xml_convert($original)); } // -------------------------------------------------------------------- @@ -30,6 +30,6 @@ public function testConvertProtected() { $original = '

Here is a so&so; paragraph & an entity ({).

'; $expected = '<p>Here is a so&so; paragraph & an entity ({).</p>'; - $this->assertEquals($expected, xml_convert($original, true)); + $this->assertSame($expected, xml_convert($original, true)); } } diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 9dc7c8e77847..f9b255fec5ea 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -54,13 +54,13 @@ public function testAttachHoneypotAndContainer() $this->response->setBody('
'); $this->honeypot->attachHoneypot($this->response); $expected = '
'; - $this->assertEquals($expected, $this->response->getBody()); + $this->assertSame($expected, $this->response->getBody()); $this->config->container = ''; $this->response->setBody('
'); $this->honeypot->attachHoneypot($this->response); $expected = '
'; - $this->assertEquals($expected, $this->response->getBody()); + $this->assertSame($expected, $this->response->getBody()); } //-------------------------------------------------------------------- @@ -143,7 +143,7 @@ public function testEmptyConfigContainer() $config->container = ''; $honeypot = new Honeypot($config); - $this->assertEquals( + $this->assertSame( '
{template}
', $this->getPrivateProperty($honeypot, 'config')->container ); @@ -155,7 +155,7 @@ public function testNoTemplateConfigContainer() $config->container = '
'; $honeypot = new Honeypot($config); - $this->assertEquals( + $this->assertSame( '
{template}
', $this->getPrivateProperty($honeypot, 'config')->container ); diff --git a/tests/system/I18n/TimeDifferenceTest.php b/tests/system/I18n/TimeDifferenceTest.php index e64e4fcfe1d4..b2878f19bff4 100644 --- a/tests/system/I18n/TimeDifferenceTest.php +++ b/tests/system/I18n/TimeDifferenceTest.php @@ -27,29 +27,29 @@ public function testDifferenceBasics() $obj = $current->difference($test); - $this->assertEquals(-7, $obj->getYears()); - $this->assertEquals(-84, $obj->getMonths()); - $this->assertEquals(-365, $obj->getWeeks()); - $this->assertEquals(-2557, $obj->getDays()); - $this->assertEquals(-61368, $obj->getHours()); - $this->assertEquals(-3682080, $obj->getMinutes()); - $this->assertEquals(-220924800, $obj->getSeconds()); - - $this->assertEquals(-7, $obj->years); - $this->assertEquals(-84, $obj->months); - $this->assertEquals(-365, $obj->weeks); - $this->assertEquals(-2557, $obj->days); - $this->assertEquals(-61368, $obj->hours); - $this->assertEquals(-3682080, $obj->minutes); - $this->assertEquals(-220924800, $obj->seconds); - - $this->assertEquals($diff / YEAR, $obj->getYears(true)); - $this->assertEquals($diff / MONTH, $obj->getMonths(true)); - $this->assertEquals($diff / WEEK, $obj->getWeeks(true)); - $this->assertEquals($diff / DAY, $obj->getDays(true)); - $this->assertEquals($diff / HOUR, $obj->getHours(true)); - $this->assertEquals($diff / MINUTE, $obj->getMinutes(true)); - $this->assertEquals($diff / SECOND, $obj->getSeconds(true)); + $this->assertSame(-7, $obj->getYears()); + $this->assertSame(-84, $obj->getMonths()); + $this->assertSame(-365, $obj->getWeeks()); + $this->assertSame(-2557, $obj->getDays()); + $this->assertSame(-61368, $obj->getHours()); + $this->assertSame(-3682080, $obj->getMinutes()); + $this->assertSame(-220924800, $obj->getSeconds()); + + $this->assertSame(-7, $obj->years); + $this->assertSame(-84, $obj->months); + $this->assertSame(-365, $obj->weeks); + $this->assertSame(-2557, $obj->days); + $this->assertSame(-61368, $obj->hours); + $this->assertSame(-3682080, $obj->minutes); + $this->assertSame(-220924800, $obj->seconds); + + $this->assertSame($diff / YEAR, $obj->getYears(true)); + $this->assertSame($diff / MONTH, $obj->getMonths(true)); + $this->assertSame($diff / WEEK, $obj->getWeeks(true)); + $this->assertSame($diff / DAY, $obj->getDays(true)); + $this->assertSame($diff / HOUR, $obj->getHours(true)); + $this->assertSame($diff / MINUTE, $obj->getMinutes(true)); + $this->assertSame($diff / SECOND, $obj->getSeconds(true)); } public function testHumanizeYearsSingle() @@ -58,7 +58,7 @@ public function testHumanizeYearsSingle() $diff = $current->difference('March 9, 2016 12:00:00', 'America/Chicago'); - $this->assertEquals('1 year ago', $diff->humanize('en')); + $this->assertSame('1 year ago', $diff->humanize('en')); } public function testHumanizeYearsPlural() @@ -66,7 +66,7 @@ public function testHumanizeYearsPlural() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 9, 2014 12:00:00', 'America/Chicago'); - $this->assertEquals('3 years ago', $diff->humanize('en')); + $this->assertSame('3 years ago', $diff->humanize('en')); } public function testHumanizeYearsForward() @@ -74,7 +74,7 @@ public function testHumanizeYearsForward() $current = Time::parse('January 1, 2017', 'America/Chicago'); $diff = $current->difference('January 1, 2018 12:00:00', 'America/Chicago'); - $this->assertEquals('in 1 year', $diff->humanize('en')); + $this->assertSame('in 1 year', $diff->humanize('en')); } public function testHumanizeMonthsSingle() @@ -82,7 +82,7 @@ public function testHumanizeMonthsSingle() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('February 9, 2017', 'America/Chicago'); - $this->assertEquals('1 month ago', $diff->humanize('en')); + $this->assertSame('1 month ago', $diff->humanize('en')); } public function testHumanizeMonthsPlural() @@ -90,7 +90,7 @@ public function testHumanizeMonthsPlural() $current = Time::parse('March 1, 2017', 'America/Chicago'); $diff = $current->difference('January 1, 2017', 'America/Chicago'); - $this->assertEquals('2 months ago', $diff->humanize('en')); + $this->assertSame('2 months ago', $diff->humanize('en')); } public function testHumanizeMonthsForward() @@ -98,7 +98,7 @@ public function testHumanizeMonthsForward() $current = Time::parse('March 1, 2017', 'America/Chicago'); $diff = $current->difference('May 1, 2017', 'America/Chicago'); - $this->assertEquals('in 1 month', $diff->humanize('en')); + $this->assertSame('in 1 month', $diff->humanize('en')); } public function testHumanizeDaysSingle() @@ -106,7 +106,7 @@ public function testHumanizeDaysSingle() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 9, 2017', 'America/Chicago'); - $this->assertEquals('1 day ago', $diff->humanize('en')); + $this->assertSame('1 day ago', $diff->humanize('en')); } public function testHumanizeDaysPlural() @@ -114,7 +114,7 @@ public function testHumanizeDaysPlural() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 8, 2017', 'America/Chicago'); - $this->assertEquals('2 days ago', $diff->humanize('en')); + $this->assertSame('2 days ago', $diff->humanize('en')); } public function testHumanizeDaysForward() @@ -122,7 +122,7 @@ public function testHumanizeDaysForward() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 11, 2017', 'America/Chicago'); - $this->assertEquals('in 1 day', $diff->humanize('en')); + $this->assertSame('in 1 day', $diff->humanize('en')); } public function testHumanizeHoursSingle() @@ -130,7 +130,7 @@ public function testHumanizeHoursSingle() $current = Time::parse('March 10, 2017 12:00', 'America/Chicago'); $diff = $current->difference('March 10, 2017 11:00', 'America/Chicago'); - $this->assertEquals('1 hour ago', $diff->humanize('en')); + $this->assertSame('1 hour ago', $diff->humanize('en')); } public function testHumanizeHoursPlural() @@ -138,7 +138,7 @@ public function testHumanizeHoursPlural() $current = Time::parse('March 10, 2017 12:00', 'America/Chicago'); $diff = $current->difference('March 10, 2017 10:00', 'America/Chicago'); - $this->assertEquals('2 hours ago', $diff->humanize('en')); + $this->assertSame('2 hours ago', $diff->humanize('en')); } public function testHumanizeHoursForward() @@ -146,7 +146,7 @@ public function testHumanizeHoursForward() $current = Time::parse('March 10, 2017 12:00', 'America/Chicago'); $diff = $current->difference('March 10, 2017 13:00', 'America/Chicago'); - $this->assertEquals('in 1 hour', $diff->humanize('en')); + $this->assertSame('in 1 hour', $diff->humanize('en')); } public function testHumanizeMinutesSingle() @@ -154,7 +154,7 @@ public function testHumanizeMinutesSingle() $current = Time::parse('March 10, 2017 12:30', 'America/Chicago'); $diff = $current->difference('March 10, 2017 12:29', 'America/Chicago'); - $this->assertEquals('1 minute ago', $diff->humanize('en')); + $this->assertSame('1 minute ago', $diff->humanize('en')); } public function testHumanizeMinutesPlural() @@ -162,7 +162,7 @@ public function testHumanizeMinutesPlural() $current = Time::parse('March 10, 2017 12:30', 'America/Chicago'); $diff = $current->difference('March 10, 2017 12:28', 'America/Chicago'); - $this->assertEquals('2 minutes ago', $diff->humanize('en')); + $this->assertSame('2 minutes ago', $diff->humanize('en')); } public function testHumanizeMinutesForward() @@ -170,7 +170,7 @@ public function testHumanizeMinutesForward() $current = Time::parse('March 10, 2017 12:30', 'America/Chicago'); $diff = $current->difference('March 10, 2017 12:31', 'America/Chicago'); - $this->assertEquals('in 1 minute', $diff->humanize('en')); + $this->assertSame('in 1 minute', $diff->humanize('en')); } public function testHumanizeWeeksSingle() @@ -178,7 +178,7 @@ public function testHumanizeWeeksSingle() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 2, 2017', 'America/Chicago'); - $this->assertEquals('1 week ago', $diff->humanize('en')); + $this->assertSame('1 week ago', $diff->humanize('en')); } public function testHumanizeWeeksPlural() @@ -186,7 +186,7 @@ public function testHumanizeWeeksPlural() $current = Time::parse('March 30, 2017', 'America/Chicago'); $diff = $current->difference('March 15, 2017', 'America/Chicago'); - $this->assertEquals('2 weeks ago', $diff->humanize('en')); + $this->assertSame('2 weeks ago', $diff->humanize('en')); } public function testHumanizeWeeksForward() @@ -194,7 +194,7 @@ public function testHumanizeWeeksForward() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 18, 2017', 'America/Chicago'); - $this->assertEquals('in 1 week', $diff->humanize('en')); + $this->assertSame('in 1 week', $diff->humanize('en')); } public function testHumanizeNoDifference() @@ -202,7 +202,7 @@ public function testHumanizeNoDifference() $current = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $current->difference('March 10, 2017', 'America/Chicago'); - $this->assertEquals('Just now', $diff->humanize('en')); + $this->assertSame('Just now', $diff->humanize('en')); } public function testGetterUTC() @@ -210,9 +210,9 @@ public function testGetterUTC() $current = Time::parse('March 10, 2017', 'UTC'); $diff = $current->difference('March 18, 2017', 'UTC'); - $this->assertEquals(8, $diff->getDays()); - $this->assertEquals(8, $diff->days); - $this->assertEquals(-8, (int) round($diff->getDays(true))); + $this->assertSame(8, $diff->getDays()); + $this->assertSame(8, $diff->days); + $this->assertSame(-8, (int) round($diff->getDays(true))); $this->assertNull($diff->nonsense); } @@ -222,11 +222,11 @@ public function testGetterChicagoTime() $diff = $current->difference('March 18, 2017', 'America/Chicago'); // Daylight Saving Time had begun since Sun, 12 Mar, 02:00. - $this->assertEquals(7, $diff->getDays()); - $this->assertEquals(7, $diff->days); + $this->assertSame(7, $diff->getDays()); + $this->assertSame(7, $diff->days); // The raw value does not take Daylight Saving Time into account. - $this->assertEquals(-8, (int) round($diff->getDays(true))); + $this->assertSame(-8, (int) round($diff->getDays(true))); $this->assertNull($diff->nonsense); } diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index eb2a0036287e..141e0f7c9be8 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -35,7 +35,7 @@ public function testNewTimeNow() $time = new Time(null, 'America/Chicago'); - $this->assertEquals($formatter->format($time), (string) $time); + $this->assertSame($formatter->format($time), (string) $time); } public function testTimeWithTimezone() @@ -51,7 +51,7 @@ public function testTimeWithTimezone() $time = new Time('now', 'Europe/London'); - $this->assertEquals($formatter->format($time), (string) $time); + $this->assertSame($formatter->format($time), (string) $time); } public function testTimeWithTimezoneAndLocale() @@ -67,7 +67,7 @@ public function testTimeWithTimezoneAndLocale() $time = new Time('now', 'Europe/London', 'fr_FR'); - $this->assertEquals($formatter->format($time), (string) $time); + $this->assertSame($formatter->format($time), (string) $time); } public function testTimeWithDateTimeZone() @@ -83,7 +83,7 @@ public function testTimeWithDateTimeZone() $time = new Time('now', new \DateTimeZone('Europe/London'), 'fr_FR'); - $this->assertEquals($formatter->format($time), (string) $time); + $this->assertSame($formatter->format($time), (string) $time); } public function testToDateTime() @@ -101,7 +101,7 @@ public function testNow() $time1 = new \DateTime(); $this->assertInstanceOf(Time::class, $time); - $this->assertEquals($time->getTimestamp(), $time1->getTimestamp()); + $this->assertSame($time->getTimestamp(), $time1->getTimestamp()); } public function testParse() @@ -110,15 +110,15 @@ public function testParse() $time1 = new \DateTime('now', new \DateTimeZone('America/Chicago')); $time1->modify('next Tuesday'); - $this->assertEquals($time->getTimestamp(), $time1->getTimestamp()); + $this->assertSame($time->getTimestamp(), $time1->getTimestamp()); } public function testToDateTimeString() { $time = Time::parse('2017-01-12 00:00', 'America/Chicago'); - $this->assertEquals('2017-01-12 00:00:00', (string) $time); - $this->assertEquals('2017-01-12 00:00:00', $time->toDateTimeString()); + $this->assertSame('2017-01-12 00:00:00', (string) $time); + $this->assertSame('2017-01-12 00:00:00', $time->toDateTimeString()); } public function testToDateTimeStringWithTimeZone() @@ -127,63 +127,63 @@ public function testToDateTimeStringWithTimeZone() $expects = new \DateTime('2017-01-12', new \DateTimeZone('Europe/London')); - $this->assertEquals($expects->format('Y-m-d H:i:s'), $time->toDateTimeString()); + $this->assertSame($expects->format('Y-m-d H:i:s'), $time->toDateTimeString()); } public function testToday() { $time = Time::today(); - $this->assertEquals(date('Y-m-d 00:00:00'), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 00:00:00'), $time->toDateTimeString()); } public function testTodayLocalized() { $time = Time::today('Europe/London'); - $this->assertEquals(date('Y-m-d 00:00:00'), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 00:00:00'), $time->toDateTimeString()); } public function testYesterday() { $time = Time::yesterday(); - $this->assertEquals(date('Y-m-d 00:00:00', strtotime('-1 day')), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 00:00:00', strtotime('-1 day')), $time->toDateTimeString()); } public function testTomorrow() { $time = Time::tomorrow(); - $this->assertEquals(date('Y-m-d 00:00:00', strtotime('+1 day')), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 00:00:00', strtotime('+1 day')), $time->toDateTimeString()); } public function testCreateFromDate() { $time = Time::createFromDate(2017, 03, 05, 'America/Chicago'); - $this->assertEquals(date('Y-m-d 00:00:00', strtotime('2017-03-05 00:00:00')), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 00:00:00', strtotime('2017-03-05 00:00:00')), $time->toDateTimeString()); } public function testCreateFromDateLocalized() { $time = Time::createFromDate(2017, 03, 05, 'Europe/London'); - $this->assertEquals(date('Y-m-d 00:00:00', strtotime('2017-03-05 00:00:00')), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 00:00:00', strtotime('2017-03-05 00:00:00')), $time->toDateTimeString()); } public function testCreateFromTime() { $time = Time::createFromTime(10, 03, 05, 'America/Chicago'); - $this->assertEquals(date('Y-m-d 10:03:05'), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 10:03:05'), $time->toDateTimeString()); } public function testCreateFromTimeEvening() { $time = Time::createFromTime(20, 03, 05, 'America/Chicago'); - $this->assertEquals(date('Y-m-d 20:03:05'), $time->toDateTimeString()); + $this->assertSame(date('Y-m-d 20:03:05'), $time->toDateTimeString()); } public function testCreateFromTimeLocalized() @@ -242,7 +242,7 @@ public function testCreateFromTimestamp() $time = Time::createFromTimestamp($timestamp); - $this->assertEquals(date('2017-03-18 00:00:00'), $time->toDateTimeString()); + $this->assertSame(date('2017-03-18 00:00:00'), $time->toDateTimeString()); } public function testTestNow() @@ -254,7 +254,7 @@ public function testTestNow() Time::setTestNow($t); $this->assertTrue(Time::hasTestNow()); - $this->assertEquals('2000-01-02 00:00:00', Time::now()->toDateTimeString()); + $this->assertSame('2000-01-02 00:00:00', Time::now()->toDateTimeString()); Time::setTestNow(); $this->assertCloseEnoughString(date('Y-m-d H:i:s', time()), Time::now()->toDateTimeString()); @@ -283,71 +283,71 @@ public function testGetYear() $time = Time::parse('January 1, 2016'); $time2 = Time::parse('December 31, 2019'); - $this->assertEquals(2016, $time->year); - $this->assertEquals(2019, $time2->year); + $this->assertSame('2016', $time->year); + $this->assertSame('2019', $time2->year); } public function testGetMonth() { $time = Time::parse('August 1, 2016'); - $this->assertEquals(8, $time->month); + $this->assertSame('8', $time->month); } public function testGetDay() { $time = Time::parse('August 12, 2016'); - $this->assertEquals(12, $time->day); + $this->assertSame('12', $time->day); } public function testGetHour() { $time = Time::parse('August 12, 2016 4:15pm'); - $this->assertEquals(16, $time->hour); + $this->assertSame('16', $time->hour); } public function testGetMinute() { $time = Time::parse('August 12, 2016 4:15pm'); - $this->assertEquals(15, $time->minute); + $this->assertSame('15', $time->minute); } public function testGetSecond() { $time = Time::parse('August 12, 2016 4:15:23pm'); - $this->assertEquals(23, $time->second); + $this->assertSame('23', $time->second); } public function testGetDayOfWeek() { $time = Time::parse('August 12, 2016 4:15:23pm'); - $this->assertEquals(6, $time->dayOfWeek); + $this->assertSame('6', $time->dayOfWeek); } public function testGetDayOfYear() { $time = Time::parse('August 12, 2016 4:15:23pm'); - $this->assertEquals(225, $time->dayOfYear); + $this->assertSame('225', $time->dayOfYear); } public function testGetWeekOfMonth() { $time = Time::parse('August 12, 2016 4:15:23pm'); - $this->assertEquals(2, $time->weekOfMonth); + $this->assertSame('2', $time->weekOfMonth); } public function testGetWeekOfYear() { $time = Time::parse('August 12, 2016 4:15:23pm'); - $this->assertEquals(33, $time->weekOfYear); + $this->assertSame('33', $time->weekOfYear); } public function testGetTimestamp() @@ -355,32 +355,32 @@ public function testGetTimestamp() $time = Time::parse('August 12, 2016 4:15:23pm'); $expected = strtotime('August 12, 2016 4:15:23pm'); - $this->assertEquals($expected, $time->timestamp); + $this->assertSame($expected, $time->timestamp); } public function testGetAge() { $time = Time::parse('5 years ago'); - $this->assertEquals(5, $time->age); + $this->assertSame(5, $time->age); } public function testAgeNow() { $time = new Time(); - $this->assertEquals(0, $time->age); + $this->assertSame(0, $time->age); } public function testAgeFuture() { $time = Time::parse('August 12, 2116 4:15:23pm'); - $this->assertEquals(0, $time->age); + $this->assertSame(0, $time->age); } public function testGetQuarter() { $time = Time::parse('April 15, 2015'); - $this->assertEquals(2, $time->quarter); + $this->assertSame('2', $time->quarter); } public function testGetDST() @@ -422,8 +422,8 @@ public function testGetTimezone() public function testGetTimezonename() { - $this->assertEquals('America/Chicago', Time::now('America/Chicago')->getTimezoneName()); - $this->assertEquals('Europe/London', Time::now('Europe/London')->timezoneName); + $this->assertSame('America/Chicago', Time::now('America/Chicago')->getTimezoneName()); + $this->assertSame('Europe/London', Time::now('Europe/London')->timezoneName); } public function testSetYear() @@ -433,7 +433,7 @@ public function testSetYear() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2015-05-10 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2015-05-10 00:00:00', $time2->toDateTimeString()); } public function testSetMonthNumber() @@ -443,7 +443,7 @@ public function testSetMonthNumber() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-04-10 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-04-10 00:00:00', $time2->toDateTimeString()); } public function testSetMonthLongName() @@ -453,7 +453,7 @@ public function testSetMonthLongName() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-04-10 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-04-10 00:00:00', $time2->toDateTimeString()); } public function testSetMonthShortName() @@ -463,7 +463,7 @@ public function testSetMonthShortName() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-02-10 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-02-10 00:00:00', $time2->toDateTimeString()); } public function testSetDay() @@ -473,7 +473,7 @@ public function testSetDay() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-05-15 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-05-15 00:00:00', $time2->toDateTimeString()); } public function testSetDayOverMaxInCurrentMonth() @@ -491,7 +491,7 @@ public function testSetDayNotOverMaxInCurrentMonth() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2012-02-29 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2012-02-29 00:00:00', $time2->toDateTimeString()); } public function testSetHour() @@ -501,7 +501,7 @@ public function testSetHour() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-05-10 15:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-05-10 15:00:00', $time2->toDateTimeString()); } public function testSetMinute() @@ -511,7 +511,7 @@ public function testSetMinute() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-05-10 00:30:00', $time2->toDateTimeString()); + $this->assertSame('2017-05-10 00:30:00', $time2->toDateTimeString()); } public function testSetSecond() @@ -521,7 +521,7 @@ public function testSetSecond() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-05-10 00:00:20', $time2->toDateTimeString()); + $this->assertSame('2017-05-10 00:00:20', $time2->toDateTimeString()); } public function testSetMonthTooSmall() @@ -611,8 +611,8 @@ public function testSetTimezone() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('America/Chicago', $time->getTimezoneName()); - $this->assertEquals('Europe/London', $time2->getTimezoneName()); + $this->assertSame('America/Chicago', $time->getTimezoneName()); + $this->assertSame('Europe/London', $time2->getTimezoneName()); } public function testSetTimestamp() @@ -623,19 +623,19 @@ public function testSetTimestamp() $this->assertInstanceOf(Time::class, $time2); $this->assertNotSame($time, $time2); - $this->assertEquals('2017-04-01 00:00:00', $time2->toDateTimeString()); + $this->assertSame('2017-04-01 00:00:00', $time2->toDateTimeString()); } public function testToDateString() { $time = Time::parse('May 10, 2017', 'America/Chicago'); - $this->assertEquals('2017-05-10', $time->toDateString()); + $this->assertSame('2017-05-10', $time->toDateString()); } public function testToFormattedDateString() { $time = Time::parse('2017-05-10', 'America/Chicago'); - $this->assertEquals('May 10, 2017', $time->toFormattedDateString()); + $this->assertSame('May 10, 2017', $time->toFormattedDateString()); } /** @@ -654,7 +654,7 @@ public function testToFormattedDateString() public function testToTimeString() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); - $this->assertEquals('13:20:33', $time->toTimeString()); + $this->assertSame('13:20:33', $time->toTimeString()); } //-------------------------------------------------------------------- @@ -665,104 +665,104 @@ public function testCanAddSeconds() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addSeconds(10); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-10 13:20:43', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:43', $newTime->toDateTimeString()); } public function testCanAddMinutes() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addMinutes(10); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-10 13:30:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-10 13:30:33', $newTime->toDateTimeString()); } public function testCanAddHours() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addHours(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-10 16:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-10 16:20:33', $newTime->toDateTimeString()); } public function testCanAddDays() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addDays(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-13 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-13 13:20:33', $newTime->toDateTimeString()); } public function testCanAddMonths() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addMonths(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-04-10 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-04-10 13:20:33', $newTime->toDateTimeString()); } public function testCanAddMonthsOverYearBoundary() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addMonths(13); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2018-02-10 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2018-02-10 13:20:33', $newTime->toDateTimeString()); } public function testCanAddYears() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->addYears(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2020-01-10 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2020-01-10 13:20:33', $newTime->toDateTimeString()); } public function testCanSubtractSeconds() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->subSeconds(10); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-10 13:20:23', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:23', $newTime->toDateTimeString()); } public function testCanSubtractMinutes() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->subMinutes(10); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-10 13:10:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-10 13:10:33', $newTime->toDateTimeString()); } public function testCanSubtractHours() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->subHours(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-10 10:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-10 10:20:33', $newTime->toDateTimeString()); } public function testCanSubtractDays() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->subDays(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2017-01-07 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2017-01-07 13:20:33', $newTime->toDateTimeString()); } public function testCanSubtractMonths() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->subMonths(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2016-10-10 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2016-10-10 13:20:33', $newTime->toDateTimeString()); } public function testCanSubtractYears() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); $newTime = $time->subYears(3); - $this->assertEquals('2017-01-10 13:20:33', $time->toDateTimeString()); - $this->assertEquals('2014-01-10 13:20:33', $newTime->toDateTimeString()); + $this->assertSame('2017-01-10 13:20:33', $time->toDateTimeString()); + $this->assertSame('2014-01-10 13:20:33', $newTime->toDateTimeString()); } //-------------------------------------------------------------------- @@ -868,7 +868,7 @@ public function testHumanizeYearsSingle() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - $this->assertEquals('1 year ago', $time->humanize()); + $this->assertSame('1 year ago', $time->humanize()); } public function testHumanizeYearsPlural() @@ -876,7 +876,7 @@ public function testHumanizeYearsPlural() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 9, 2014 12:00:00', 'America/Chicago'); - $this->assertEquals('3 years ago', $time->humanize()); + $this->assertSame('3 years ago', $time->humanize()); } public function testHumanizeYearsForward() @@ -884,7 +884,7 @@ public function testHumanizeYearsForward() Time::setTestNow('January 1, 2017', 'America/Chicago'); $time = Time::parse('January 1, 2018 12:00:00', 'America/Chicago'); - $this->assertEquals('in 1 year', $time->humanize()); + $this->assertSame('in 1 year', $time->humanize()); } public function testHumanizeMonthsSingle() @@ -892,7 +892,7 @@ public function testHumanizeMonthsSingle() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('February 9, 2017', 'America/Chicago'); - $this->assertEquals('1 month ago', $time->humanize()); + $this->assertSame('1 month ago', $time->humanize()); } public function testHumanizeMonthsPlural() @@ -900,7 +900,7 @@ public function testHumanizeMonthsPlural() Time::setTestNow('March 1, 2017', 'America/Chicago'); $time = Time::parse('January 1, 2017', 'America/Chicago'); - $this->assertEquals('2 months ago', $time->humanize()); + $this->assertSame('2 months ago', $time->humanize()); } public function testHumanizeMonthsForward() @@ -908,7 +908,7 @@ public function testHumanizeMonthsForward() Time::setTestNow('March 1, 2017', 'America/Chicago'); $time = Time::parse('April 1, 2017', 'America/Chicago'); - $this->assertEquals('in 1 month', $time->humanize()); + $this->assertSame('in 1 month', $time->humanize()); } public function testHumanizeDaysSingle() @@ -916,7 +916,7 @@ public function testHumanizeDaysSingle() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 8, 2017', 'America/Chicago'); - $this->assertEquals('2 days ago', $time->humanize()); + $this->assertSame('2 days ago', $time->humanize()); } public function testHumanizeDaysPlural() @@ -924,7 +924,7 @@ public function testHumanizeDaysPlural() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 8, 2017', 'America/Chicago'); - $this->assertEquals('2 days ago', $time->humanize()); + $this->assertSame('2 days ago', $time->humanize()); } public function testHumanizeDaysForward() @@ -932,7 +932,7 @@ public function testHumanizeDaysForward() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 12, 2017', 'America/Chicago'); - $this->assertEquals('in 2 days', $time->humanize()); + $this->assertSame('in 2 days', $time->humanize()); } public function testHumanizeDaysTomorrow() @@ -940,7 +940,7 @@ public function testHumanizeDaysTomorrow() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 11, 2017', 'America/Chicago'); - $this->assertEquals('Tomorrow', $time->humanize()); + $this->assertSame('Tomorrow', $time->humanize()); } public function testHumanizeDaysYesterday() @@ -948,7 +948,7 @@ public function testHumanizeDaysYesterday() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 9, 2017', 'America/Chicago'); - $this->assertEquals('Yesterday', $time->humanize()); + $this->assertSame('Yesterday', $time->humanize()); } public function testHumanizeHoursAsTime() @@ -956,7 +956,7 @@ public function testHumanizeHoursAsTime() Time::setTestNow('March 10, 2017 12:00', 'America/Chicago'); $time = Time::parse('March 10, 2017 14:00', 'America/Chicago'); - $this->assertEquals('in 2 hours', $time->humanize()); + $this->assertSame('in 2 hours', $time->humanize()); } public function testHumanizeHoursAWhileAgo() @@ -964,7 +964,7 @@ public function testHumanizeHoursAWhileAgo() Time::setTestNow('March 10, 2017 12:00', 'America/Chicago'); $time = Time::parse('March 10, 2017 8:00', 'America/Chicago'); - $this->assertEquals('4 hours ago', $time->humanize()); + $this->assertSame('4 hours ago', $time->humanize()); } public function testHumanizeMinutesSingle() @@ -972,7 +972,7 @@ public function testHumanizeMinutesSingle() Time::setTestNow('March 10, 2017 12:30', 'America/Chicago'); $time = Time::parse('March 10, 2017 12:29', 'America/Chicago'); - $this->assertEquals('1 minute ago', $time->humanize()); + $this->assertSame('1 minute ago', $time->humanize()); } public function testHumanizeMinutesPlural() @@ -980,7 +980,7 @@ public function testHumanizeMinutesPlural() Time::setTestNow('March 10, 2017 12:30', 'America/Chicago'); $time = Time::parse('March 10, 2017 12:28', 'America/Chicago'); - $this->assertEquals('2 minutes ago', $time->humanize()); + $this->assertSame('2 minutes ago', $time->humanize()); } public function testHumanizeMinutesForward() @@ -988,7 +988,7 @@ public function testHumanizeMinutesForward() Time::setTestNow('March 10, 2017 12:30', 'America/Chicago'); $time = Time::parse('March 10, 2017 12:31', 'America/Chicago'); - $this->assertEquals('in 1 minute', $time->humanize()); + $this->assertSame('in 1 minute', $time->humanize()); } public function testHumanizeWeeksSingle() @@ -996,7 +996,7 @@ public function testHumanizeWeeksSingle() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 2, 2017', 'America/Chicago'); - $this->assertEquals('1 week ago', $time->humanize()); + $this->assertSame('1 week ago', $time->humanize()); } public function testHumanizeWeeksPlural() @@ -1004,7 +1004,7 @@ public function testHumanizeWeeksPlural() Time::setTestNow('March 30, 2017', 'America/Chicago'); $time = Time::parse('March 15, 2017', 'America/Chicago'); - $this->assertEquals('2 weeks ago', $time->humanize()); + $this->assertSame('2 weeks ago', $time->humanize()); } public function testHumanizeWeeksForward() @@ -1012,7 +1012,7 @@ public function testHumanizeWeeksForward() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 18, 2017', 'America/Chicago'); - $this->assertEquals('in 2 weeks', $time->humanize()); + $this->assertSame('in 2 weeks', $time->humanize()); } public function testHumanizeNow() @@ -1020,19 +1020,17 @@ public function testHumanizeNow() Time::setTestNow('March 10, 2017', 'America/Chicago'); $time = Time::parse('March 10, 2017', 'America/Chicago'); - $this->assertEquals('Just now', $time->humanize()); + $this->assertSame('Just now', $time->humanize()); } public function testSetTimezoneDate() { $time = Time::parse('13 May 2020 10:00', 'GMT'); $time2 = $time->setTimezone('GMT+8'); - $this->assertEquals('2020-05-13 10:00:00', $time->toDateTimeString()); - $this->assertEquals('2020-05-13 18:00:00', $time2->toDateTimeString()); + $this->assertSame('2020-05-13 10:00:00', $time->toDateTimeString()); + $this->assertSame('2020-05-13 18:00:00', $time2->toDateTimeString()); } - //-------------------------------------------------------------------- - public function testCreateFromInstance() { $datetime = new DateTime(); @@ -1056,6 +1054,6 @@ public function testUnserializeTimeObject() $this->assertInstanceOf(Time::class, $time2); $this->assertTrue($time2->equals($time1)); - $this->assertEquals($time1, $time2); + $this->assertNotSame($time1, $time2); } } diff --git a/tests/system/Images/BaseHandlerTest.php b/tests/system/Images/BaseHandlerTest.php index cd180c1d6586..324ab59bf286 100644 --- a/tests/system/Images/BaseHandlerTest.php +++ b/tests/system/Images/BaseHandlerTest.php @@ -64,8 +64,8 @@ public function testWithFile() $image = $handler->getFile(); $this->assertTrue($image instanceof Image); - $this->assertEquals(155, $image->origWidth); - $this->assertEquals($path, $image->getPathname()); + $this->assertSame(155, $image->origWidth); + $this->assertSame($path, $image->getPathname()); } public function testMissingFile() @@ -116,6 +116,6 @@ public function testImageHandled() { $handler = Services::image('gd', null, false); $handler->withFile($this->path); - $this->assertEquals($this->path, $handler->getPathname()); + $this->assertSame($this->path, $handler->getPathname()); } } diff --git a/tests/system/Images/GDHandlerTest.php b/tests/system/Images/GDHandlerTest.php index 214af7d6c1b3..cf60c5d674a0 100644 --- a/tests/system/Images/GDHandlerTest.php +++ b/tests/system/Images/GDHandlerTest.php @@ -63,15 +63,15 @@ public function testImageProperties() $file = $this->handler->getFile(); $props = $file->getProperties(true); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(155, $props['width']); - $this->assertEquals(155, $file->origWidth); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(155, $props['width']); + $this->assertSame(155, $file->origWidth); - $this->assertEquals(200, $this->handler->getHeight()); - $this->assertEquals(200, $props['height']); - $this->assertEquals(200, $file->origHeight); + $this->assertSame(200, $this->handler->getHeight()); + $this->assertSame(200, $props['height']); + $this->assertSame(200, $file->origHeight); - $this->assertEquals('width="155" height="200"', $props['size_str']); + $this->assertSame('width="155" height="200"', $props['size_str']); } public function testImageTypeProperties() @@ -80,8 +80,8 @@ public function testImageTypeProperties() $file = $this->handler->getFile(); $props = $file->getProperties(true); - $this->assertEquals(IMAGETYPE_PNG, $props['image_type']); - $this->assertEquals('image/png', $props['mime_type']); + $this->assertSame(IMAGETYPE_PNG, $props['image_type']); + $this->assertSame('image/png', $props['mime_type']); } //-------------------------------------------------------------------- @@ -90,40 +90,40 @@ public function testResizeIgnored() { $this->handler->withFile($this->path); $this->handler->resize(155, 200); // 155x200 result - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testResizeAbsolute() { $this->handler->withFile($this->path); $this->handler->resize(123, 456, false); // 123x456 result - $this->assertEquals(123, $this->handler->getWidth()); - $this->assertEquals(456, $this->handler->getHeight()); + $this->assertSame(123, $this->handler->getWidth()); + $this->assertSame(456, $this->handler->getHeight()); } public function testResizeAspect() { $this->handler->withFile($this->path); $this->handler->resize(123, 456, true); // 123x159 result - $this->assertEquals(123, $this->handler->getWidth()); - $this->assertEquals(159, $this->handler->getHeight()); + $this->assertSame(123, $this->handler->getWidth()); + $this->assertSame(159, $this->handler->getHeight()); } public function testResizeAspectWidth() { $this->handler->withFile($this->path); $this->handler->resize(123, 0, true); // 123x159 result - $this->assertEquals(123, $this->handler->getWidth()); - $this->assertEquals(159, $this->handler->getHeight()); + $this->assertSame(123, $this->handler->getWidth()); + $this->assertSame(159, $this->handler->getHeight()); } public function testResizeAspectHeight() { $this->handler->withFile($this->path); $this->handler->resize(0, 456, true); // 354x456 result - $this->assertEquals(354, $this->handler->getWidth()); - $this->assertEquals(456, $this->handler->getHeight()); + $this->assertSame(354, $this->handler->getWidth()); + $this->assertSame(456, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -132,48 +132,48 @@ public function testCropTopLeft() { $this->handler->withFile($this->path); $this->handler->crop(100, 100); // 100x100 result - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropMiddle() { $this->handler->withFile($this->path); $this->handler->crop(100, 100, 50, 50, false); // 100x100 result - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropMiddlePreserved() { $this->handler->withFile($this->path); $this->handler->crop(100, 100, 50, 50, true); // 78x100 result - $this->assertEquals(78, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(78, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropTopLeftPreserveAspect() { $this->handler->withFile($this->path); $this->handler->crop(100, 100); // 100x100 result - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropNothing() { $this->handler->withFile($this->path); $this->handler->crop(155, 200); // 155x200 result - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testCropOutOfBounds() { $this->handler->withFile($this->path); $this->handler->crop(100, 100, 100); // 55x100 result in 100x100 - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -181,16 +181,16 @@ public function testCropOutOfBounds() public function testRotate() { $this->handler->withFile($this->path); // 155x200 - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); // first rotation $this->handler->rotate(90); // 200x155 - $this->assertEquals(200, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getWidth()); // check image size again after another rotation $this->handler->rotate(180); // 200x155 - $this->assertEquals(200, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getWidth()); } public function testRotateBadAngle() @@ -206,8 +206,8 @@ public function testFlatten() { $this->handler->withFile($this->path); $this->handler->flatten(); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -216,24 +216,24 @@ public function testFlip() { $this->handler->withFile($this->path); $this->handler->flip(); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testHorizontal() { $this->handler->withFile($this->path); $this->handler->flip('horizontal'); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testFlipVertical() { $this->handler->withFile($this->path); $this->handler->flip('vertical'); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testFlipUnknown() @@ -248,24 +248,24 @@ public function testFit() { $this->handler->withFile($this->path); $this->handler->fit(100, 100); - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testFitTaller() { $this->handler->withFile($this->path); $this->handler->fit(100, 400); - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(400, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(400, $this->handler->getHeight()); } public function testFitAutoHeight() { $this->handler->withFile($this->path); $this->handler->fit(100); - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(129, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(129, $this->handler->getHeight()); } public function testFitPositions() @@ -285,8 +285,8 @@ public function testFitPositions() foreach ($choices as $position) { $this->handler->fit(100, 100, $position); - $this->assertEquals(100, $this->handler->getWidth(), 'Position ' . $position . ' failed'); - $this->assertEquals(100, $this->handler->getHeight(), 'Position ' . $position . ' failed'); + $this->assertSame(100, $this->handler->getWidth(), 'Position ' . $position . ' failed'); + $this->assertSame(100, $this->handler->getHeight(), 'Position ' . $position . ' failed'); } } @@ -296,8 +296,8 @@ public function testText() { $this->handler->withFile($this->path); $this->handler->text('vertical', ['hAlign' => 'right', 'vAlign' => 'bottom']); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -306,8 +306,8 @@ public function testMoreText() { $this->handler->withFile($this->path); $this->handler->text('vertical', ['vAlign' => 'middle', 'withShadow' => 'sure', 'shadowOffset' => 3]); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -322,8 +322,8 @@ public function testImageCreation() $this->handler->withFile($this->origin . 'ci-logo.' . $type); $this->handler->text('vertical'); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } } @@ -341,7 +341,7 @@ public function testImageCopy() $this->handler->save($this->start . 'work/ci-logo.' . $type); $this->assertTrue($this->root->hasChild('work/ci-logo.' . $type)); - $this->assertNotEquals( + $this->assertNotSame( file_get_contents($this->origin . 'ci-logo.' . $type), $this->root->getChild('work/ci-logo.' . $type)->getContent() ); @@ -355,7 +355,7 @@ public function testImageCopyWithNoTargetAndMaxQuality() $this->handler->save(null, 100); $this->assertFileExists($this->origin . 'ci-logo.' . $type); - $this->assertEquals( + $this->assertSame( file_get_contents($this->origin . 'ci-logo.' . $type), file_get_contents($this->origin . 'ci-logo.' . $type) ); @@ -375,7 +375,7 @@ public function testImageCompressionGetResource() $this->handler->save($this->start . 'work/ci-logo.' . $type); $this->assertTrue($this->root->hasChild('work/ci-logo.' . $type)); - $this->assertNotEquals( + $this->assertNotSame( file_get_contents($this->origin . 'ci-logo.' . $type), $this->root->getChild('work/ci-logo.' . $type)->getContent() ); @@ -396,7 +396,7 @@ public function testImageCompressionWithResource() $this->assertTrue($this->root->hasChild('work/ci-logo.' . $type)); - $this->assertNotEquals( + $this->assertNotSame( file_get_contents($this->origin . 'ci-logo.' . $type), $this->root->getChild('work/ci-logo.' . $type)->getContent() ); @@ -409,7 +409,7 @@ public function testImageConvert() $this->handler->getResource(); // make sure resource is loaded $this->handler->convert(IMAGETYPE_PNG); $this->handler->save($this->start . 'work/ci-logo.png'); - $this->assertEquals(exif_imagetype($this->start . 'work/ci-logo.png'), IMAGETYPE_PNG); + $this->assertSame(exif_imagetype($this->start . 'work/ci-logo.png'), IMAGETYPE_PNG); } public function testImageReorientLandscape() @@ -424,7 +424,7 @@ public function testImageReorientLandscape() $point = imagecolorat($resource, 0, 0); $rgb = imagecolorsforindex($resource, $point); - $this->assertEquals(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); + $this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); } } @@ -440,7 +440,7 @@ public function testImageReorientPortrait() $point = imagecolorat($resource, 0, 0); $rgb = imagecolorsforindex($resource, $point); - $this->assertEquals(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); + $this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); } } } diff --git a/tests/system/Images/ImageMagickHandlerTest.php b/tests/system/Images/ImageMagickHandlerTest.php index 997274f6ff19..c451ef936352 100644 --- a/tests/system/Images/ImageMagickHandlerTest.php +++ b/tests/system/Images/ImageMagickHandlerTest.php @@ -61,15 +61,15 @@ public function testImageProperties() $file = $this->handler->getFile(); $props = $file->getProperties(true); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(155, $props['width']); - $this->assertEquals(155, $file->origWidth); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(155, $props['width']); + $this->assertSame(155, $file->origWidth); - $this->assertEquals(200, $this->handler->getHeight()); - $this->assertEquals(200, $props['height']); - $this->assertEquals(200, $file->origHeight); + $this->assertSame(200, $this->handler->getHeight()); + $this->assertSame(200, $props['height']); + $this->assertSame(200, $file->origHeight); - $this->assertEquals('width="155" height="200"', $props['size_str']); + $this->assertSame('width="155" height="200"', $props['size_str']); } public function testImageTypeProperties() @@ -78,8 +78,8 @@ public function testImageTypeProperties() $file = $this->handler->getFile(); $props = $file->getProperties(true); - $this->assertEquals(IMAGETYPE_PNG, $props['image_type']); - $this->assertEquals('image/png', $props['mime_type']); + $this->assertSame(IMAGETYPE_PNG, $props['image_type']); + $this->assertSame('image/png', $props['mime_type']); } //-------------------------------------------------------------------- @@ -88,40 +88,40 @@ public function testResizeIgnored() { $this->handler->withFile($this->path); $this->handler->resize(155, 200); // 155x200 result - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testResizeAbsolute() { $this->handler->withFile($this->path); $this->handler->resize(123, 456, false); // 123x456 result - $this->assertEquals(123, $this->handler->getWidth()); - $this->assertEquals(456, $this->handler->getHeight()); + $this->assertSame(123, $this->handler->getWidth()); + $this->assertSame(456, $this->handler->getHeight()); } public function testResizeAspect() { $this->handler->withFile($this->path); $this->handler->resize(123, 456, true); // 123x159 result - $this->assertEquals(123, $this->handler->getWidth()); - $this->assertEquals(159, $this->handler->getHeight()); + $this->assertSame(123, $this->handler->getWidth()); + $this->assertSame(159, $this->handler->getHeight()); } public function testResizeAspectWidth() { $this->handler->withFile($this->path); $this->handler->resize(123, 0, true); // 123x159 result - $this->assertEquals(123, $this->handler->getWidth()); - $this->assertEquals(159, $this->handler->getHeight()); + $this->assertSame(123, $this->handler->getWidth()); + $this->assertSame(159, $this->handler->getHeight()); } public function testResizeAspectHeight() { $this->handler->withFile($this->path); $this->handler->resize(0, 456, true); // 353x456 result - $this->assertEquals(353, $this->handler->getWidth()); - $this->assertEquals(456, $this->handler->getHeight()); + $this->assertSame(353, $this->handler->getWidth()); + $this->assertSame(456, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -130,48 +130,48 @@ public function testCropTopLeft() { $this->handler->withFile($this->path); $this->handler->crop(100, 100); // 100x100 result - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropMiddle() { $this->handler->withFile($this->path); $this->handler->crop(100, 100, 50, 50, false); // 100x100 result - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropMiddlePreserved() { $this->handler->withFile($this->path); $this->handler->crop(100, 100, 50, 50, true); // 78x100 result - $this->assertEquals(78, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(78, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropTopLeftPreserveAspect() { $this->handler->withFile($this->path); $this->handler->crop(100, 100); // 100x100 result - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testCropNothing() { $this->handler->withFile($this->path); $this->handler->crop(155, 200); // 155x200 result - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testCropOutOfBounds() { $this->handler->withFile($this->path); $this->handler->crop(100, 100, 100); // 55x100 result in 100x100 - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -179,16 +179,16 @@ public function testCropOutOfBounds() public function testRotate() { $this->handler->withFile($this->path); // 155x200 - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); // first rotation $this->handler->rotate(90); // 200x155 - $this->assertEquals(200, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getWidth()); // check image size again after another rotation $this->handler->rotate(180); // 200x155 - $this->assertEquals(200, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getWidth()); } public function testRotateBadAngle() @@ -204,8 +204,8 @@ public function testFlatten() { $this->handler->withFile($this->path); $this->handler->flatten(); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -214,24 +214,24 @@ public function testFlip() { $this->handler->withFile($this->path); $this->handler->flip(); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testHorizontal() { $this->handler->withFile($this->path); $this->handler->flip('horizontal'); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testFlipVertical() { $this->handler->withFile($this->path); $this->handler->flip('vertical'); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } public function testFlipUnknown() @@ -246,24 +246,24 @@ public function testFit() { $this->handler->withFile($this->path); $this->handler->fit(100, 100); - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(100, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(100, $this->handler->getHeight()); } public function testFitTaller() { $this->handler->withFile($this->path); $this->handler->fit(100, 400); - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(400, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(400, $this->handler->getHeight()); } public function testFitAutoHeight() { $this->handler->withFile($this->path); $this->handler->fit(100); - $this->assertEquals(100, $this->handler->getWidth()); - $this->assertEquals(129, $this->handler->getHeight()); + $this->assertSame(100, $this->handler->getWidth()); + $this->assertSame(129, $this->handler->getHeight()); } public function testFitPositions() @@ -283,8 +283,8 @@ public function testFitPositions() foreach ($choices as $position) { $this->handler->fit(100, 100, $position); - $this->assertEquals(100, $this->handler->getWidth(), 'Position ' . $position . ' failed'); - $this->assertEquals(100, $this->handler->getHeight(), 'Position ' . $position . ' failed'); + $this->assertSame(100, $this->handler->getWidth(), 'Position ' . $position . ' failed'); + $this->assertSame(100, $this->handler->getHeight(), 'Position ' . $position . ' failed'); } } @@ -294,8 +294,8 @@ public function testText() { $this->handler->withFile($this->path); $this->handler->text('vertical', ['hAlign' => 'right', 'vAlign' => 'bottom']); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -304,8 +304,8 @@ public function testMoreText() { $this->handler->withFile($this->path); $this->handler->text('vertical', ['vAlign' => 'middle', 'withShadow' => 'sure', 'shadowOffset' => 3]); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } //-------------------------------------------------------------------- @@ -320,8 +320,8 @@ public function testImageCreation() $this->handler->withFile($this->origin . 'ci-logo.' . $type); $this->handler->text('vertical'); - $this->assertEquals(155, $this->handler->getWidth()); - $this->assertEquals(200, $this->handler->getHeight()); + $this->assertSame(155, $this->handler->getWidth()); + $this->assertSame(200, $this->handler->getHeight()); } } @@ -339,7 +339,7 @@ public function testImageCopy() $this->handler->save($this->root . 'ci-logo.' . $type); $this->assertFileExists($this->root . 'ci-logo.' . $type); - $this->assertNotEquals( + $this->assertNotSame( file_get_contents($this->origin . 'ci-logo.' . $type), file_get_contents($this->root . 'ci-logo.' . $type) ); @@ -353,7 +353,7 @@ public function testImageCopyWithNoTargetAndMaxQuality() $this->handler->save(null, 100); $this->assertFileExists($this->origin . 'ci-logo.' . $type); - $this->assertEquals( + $this->assertSame( file_get_contents($this->origin . 'ci-logo.' . $type), file_get_contents($this->origin . 'ci-logo.' . $type) ); @@ -373,7 +373,7 @@ public function testImageCompressionGetResource() $this->handler->save($this->root . 'ci-logo.' . $type); $this->assertFileExists($this->root . 'ci-logo.' . $type); - $this->assertNotEquals( + $this->assertNotSame( file_get_contents($this->origin . 'ci-logo.' . $type), file_get_contents($this->root . 'ci-logo.' . $type) ); @@ -394,7 +394,7 @@ public function testImageCompressionWithResource() $this->assertFileExists($this->root . 'ci-logo.' . $type); - $this->assertNotEquals( + $this->assertNotSame( file_get_contents($this->origin . 'ci-logo.' . $type), file_get_contents($this->root . 'ci-logo.' . $type) ); @@ -407,7 +407,7 @@ public function testImageConvert() $this->handler->getResource(); // make sure resource is loaded $this->handler->convert(IMAGETYPE_PNG); $this->handler->save($this->root . 'ci-logo.png'); - $this->assertEquals(exif_imagetype($this->root . 'ci-logo.png'), IMAGETYPE_PNG); + $this->assertSame(exif_imagetype($this->root . 'ci-logo.png'), IMAGETYPE_PNG); } public function testImageReorientLandscape() @@ -425,7 +425,7 @@ public function testImageReorientLandscape() $this->handler->save($result); - $this->assertEquals(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); + $this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); } } @@ -444,7 +444,7 @@ public function testImageReorientPortrait() $this->handler->save($result); - $this->assertEquals(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); + $this->assertSame(['red' => 62, 'green' => 62, 'blue' => 62, 'alpha' => 0], $rgb); } } } diff --git a/tests/system/Images/ImageTest.php b/tests/system/Images/ImageTest.php index 93cf2e1e2598..163addcf78f2 100644 --- a/tests/system/Images/ImageTest.php +++ b/tests/system/Images/ImageTest.php @@ -36,10 +36,10 @@ protected function setUp(): void public function testBasicPropertiesInherited() { - $this->assertEquals('ci-logo.png', $this->image->getFilename()); - $this->assertEquals($this->start . 'ci-logo.png', $this->image->getPathname()); - $this->assertEquals($this->root->url(), $this->image->getPath()); - $this->assertEquals('ci-logo.png', $this->image->getBasename()); + $this->assertSame('ci-logo.png', $this->image->getFilename()); + $this->assertSame($this->start . 'ci-logo.png', $this->image->getPathname()); + $this->assertSame($this->root->url(), $this->image->getPath()); + $this->assertSame('ci-logo.png', $this->image->getBasename()); } public function testGetProperties() @@ -52,7 +52,7 @@ public function testGetProperties() 'mime_type' => 'image/png', ]; - $this->assertEquals($expected, $this->image->getProperties(true)); + $this->assertSame($expected, $this->image->getProperties(true)); } public function testExtractProperties() @@ -60,11 +60,11 @@ public function testExtractProperties() // extract properties from the image $this->assertTrue($this->image->getProperties(false)); - $this->assertEquals(155, $this->image->origWidth); - $this->assertEquals(200, $this->image->origHeight); - $this->assertEquals(IMAGETYPE_PNG, $this->image->imageType); - $this->assertEquals('width="155" height="200"', $this->image->sizeStr); - $this->assertEquals('image/png', $this->image->mime); + $this->assertSame(155, $this->image->origWidth); + $this->assertSame(200, $this->image->origHeight); + $this->assertSame(IMAGETYPE_PNG, $this->image->imageType); + $this->assertSame('width="155" height="200"', $this->image->sizeStr); + $this->assertSame('image/png', $this->image->mime); } public function testCopyDefaultName() diff --git a/tests/system/Language/LanguageTest.php b/tests/system/Language/LanguageTest.php index 53a6d60b2d2b..2a9a3df7f69c 100644 --- a/tests/system/Language/LanguageTest.php +++ b/tests/system/Language/LanguageTest.php @@ -24,7 +24,7 @@ protected function setUp(): void public function testReturnsStringWithNoFileInMessage() { - $this->assertEquals('something', $this->lang->getLine('something')); + $this->assertSame('something', $this->lang->getLine('something')); } /** @@ -49,7 +49,7 @@ public function testGetLineReturnsLine() 'booksSaved' => 'We saved some more', ]); - $this->assertEquals('We saved some more', $this->lang->getLine('books.booksSaved')); + $this->assertSame('We saved some more', $this->lang->getLine('books.booksSaved')); } //-------------------------------------------------------------------- @@ -69,11 +69,11 @@ public function testGetLineReturnsFallbackLine() 'slowcoach' => 'slowpoke', ], 'en-US'); - $this->assertEquals('lay of the land', $this->lang->getLine('equivalent.lieOfLand')); - $this->assertEquals('slowpoke', $this->lang->getLine('equivalent.slowcoach')); - $this->assertEquals('a new lease of life', $this->lang->getLine('equivalent.leaseOfLife')); - $this->assertEquals('touch wood', $this->lang->getLine('equivalent.touchWood')); - $this->assertEquals('equivalent.unknown', $this->lang->getLine('equivalent.unknown')); + $this->assertSame('lay of the land', $this->lang->getLine('equivalent.lieOfLand')); + $this->assertSame('slowpoke', $this->lang->getLine('equivalent.slowcoach')); + $this->assertSame('a new lease of life', $this->lang->getLine('equivalent.leaseOfLife')); + $this->assertSame('touch wood', $this->lang->getLine('equivalent.touchWood')); + $this->assertSame('equivalent.unknown', $this->lang->getLine('equivalent.unknown')); } //-------------------------------------------------------------------- @@ -87,7 +87,7 @@ public function testGetLineArrayReturnsLineArray() ], ]); - $this->assertEquals([ + $this->assertSame([ 'The Boogeyman', 'We Saved', ], $this->lang->getLine('books.booksList')); @@ -106,7 +106,7 @@ public function testGetLineFormatsMessage() 'bookCount' => '{0, number, integer} books have been saved.', ]); - $this->assertEquals('45 books have been saved.', $this->lang->getLine('books.bookCount', [91 / 2])); + $this->assertSame('45 books have been saved.', $this->lang->getLine('books.bookCount', [91 / 2])); } //-------------------------------------------------------------------- @@ -124,7 +124,7 @@ public function testGetLineArrayFormatsMessages() ], ]); - $this->assertEquals(['45 related books.'], $this->lang->getLine('books.bookList', [91 / 2])); + $this->assertSame(['45 related books.'], $this->lang->getLine('books.bookList', [91 / 2])); } //-------------------------------------------------------------------- @@ -137,8 +137,8 @@ public function testLangAllowsOtherLocales() $str1 = lang('Language.languageGetLineInvalidArgumentException', [], 'en'); $str2 = lang('Language.languageGetLineInvalidArgumentException', [], 'ru'); - $this->assertEquals('Get line must be a string or array of strings.', $str1); - $this->assertEquals('Whatever this would be, translated', $str2); + $this->assertSame('Get line must be a string or array of strings.', $str1); + $this->assertSame('Whatever this would be, translated', $str2); } //-------------------------------------------------------------------- @@ -153,7 +153,7 @@ public function testLangDoesntFormat() ], ]); - $this->assertEquals(['{0, number, integer} related books.'], $this->lang->getLine('books.bookList', [15])); + $this->assertSame(['{0, number, integer} related books.'], $this->lang->getLine('books.bookList', [15])); } //-------------------------------------------------------------------- @@ -161,10 +161,10 @@ public function testLangDoesntFormat() public function testLanguageDuplicateKey() { $this->lang = new Language('en'); - $this->assertEquals('These are not the droids you are looking for', $this->lang->getLine('More.strongForce', [])); - $this->assertEquals('I have a very bad feeling about this', $this->lang->getLine('More.cannotMove', [])); - $this->assertEquals('Could not move file {0} to {1} ({2}).', $this->lang->getLine('Files.cannotMove', [])); - $this->assertEquals('I have a very bad feeling about this', $this->lang->getLine('More.cannotMove', [])); + $this->assertSame('These are not the droids you are looking for', $this->lang->getLine('More.strongForce', [])); + $this->assertSame('I have a very bad feeling about this', $this->lang->getLine('More.cannotMove', [])); + $this->assertSame('Could not move file {0} to {1} ({2}).', $this->lang->getLine('Files.cannotMove', [])); + $this->assertSame('I have a very bad feeling about this', $this->lang->getLine('More.cannotMove', [])); } //-------------------------------------------------------------------- @@ -203,12 +203,12 @@ public function testLanguageSameKeyAndFileName() $this->lang->setData('example', ['message' => 'This is an example message']); // force loading data into file Example - $this->assertEquals('This is an example message', $this->lang->getLine('example.message')); + $this->assertSame('This is an example message', $this->lang->getLine('example.message')); // second file data | another.example $this->lang->setData('another', ['example' => 'Another example']); - $this->assertEquals('Another example', $this->lang->getLine('another.example')); + $this->assertSame('Another example', $this->lang->getLine('another.example')); } //-------------------------------------------------------------------- @@ -216,7 +216,7 @@ public function testLanguageSameKeyAndFileName() public function testGetLocale() { $this->lang = Services::language('en', false); - $this->assertEquals('en', $this->lang->getLocale()); + $this->assertSame('en', $this->lang->getLocale()); } //-------------------------------------------------------------------- @@ -225,9 +225,9 @@ public function testPrioritizedLocator() { // this should load the replacement bundle of messages $message = lang('Core.missingExtension', [], 'en'); - $this->assertEquals('The framework needs the following extension(s) installed and loaded: {0}.', $message); + $this->assertSame('The framework needs the following extension(s) installed and loaded: {0}.', $message); // and we should have our new message too - $this->assertEquals('billions and billions', lang('Core.bazillion', [], 'en')); + $this->assertSame('billions and billions', lang('Core.bazillion', [], 'en')); } //-------------------------------------------------------------------- @@ -277,16 +277,16 @@ public function testBaseFallbacks() { $this->lang = Services::language('en-ZZ', false); // key is in both base and variant; should pick variant - $this->assertEquals("It's made of cheese", $this->lang->getLine('More.notaMoon')); + $this->assertSame("It's made of cheese", $this->lang->getLine('More.notaMoon')); // key is in base but not variant; should pick base - $this->assertEquals('I have a very bad feeling about this', $this->lang->getLine('More.cannotMove')); + $this->assertSame('I have a very bad feeling about this', $this->lang->getLine('More.cannotMove')); // key is in variant but not base; should pick variant - $this->assertEquals('There is no try', $this->lang->getLine('More.wisdom')); + $this->assertSame('There is no try', $this->lang->getLine('More.wisdom')); // key isn't in either base or variant; should return bad key - $this->assertEquals('More.shootMe', $this->lang->getLine('More.shootMe')); + $this->assertSame('More.shootMe', $this->lang->getLine('More.shootMe')); } //-------------------------------------------------------------------- @@ -307,14 +307,14 @@ public function testBaseFallbacks() public function testAllTheWayFallbacks() { $this->lang = Services::language('ab-CD', false); - $this->assertEquals('Allin.none', $this->lang->getLine('Allin.none')); - $this->assertEquals('Pyramid of Giza', $this->lang->getLine('Allin.one')); - $this->assertEquals('gluttony', $this->lang->getLine('Allin.two')); - $this->assertEquals('Colossus of Rhodes', $this->lang->getLine('Allin.tre')); - $this->assertEquals('four calling birds', $this->lang->getLine('Allin.for')); - $this->assertEquals('Temple of Artemis', $this->lang->getLine('Allin.fiv')); - $this->assertEquals('envy', $this->lang->getLine('Allin.six')); - $this->assertEquals('Hanging Gardens of Babylon', $this->lang->getLine('Allin.sev')); + $this->assertSame('Allin.none', $this->lang->getLine('Allin.none')); + $this->assertSame('Pyramid of Giza', $this->lang->getLine('Allin.one')); + $this->assertSame('gluttony', $this->lang->getLine('Allin.two')); + $this->assertSame('Colossus of Rhodes', $this->lang->getLine('Allin.tre')); + $this->assertSame('four calling birds', $this->lang->getLine('Allin.for')); + $this->assertSame('Temple of Artemis', $this->lang->getLine('Allin.fiv')); + $this->assertSame('envy', $this->lang->getLine('Allin.six')); + $this->assertSame('Hanging Gardens of Babylon', $this->lang->getLine('Allin.sev')); } public function testLanguageNestedArrayDefinition() @@ -322,7 +322,7 @@ public function testLanguageNestedArrayDefinition() $this->lang = new SecondMockLanguage('en'); $this->lang->loadem('Nested', 'en'); - $this->assertEquals('e', $this->lang->getLine('Nested.a.b.c.d')); + $this->assertSame('e', $this->lang->getLine('Nested.a.b.c.d')); } public function testLanguageKeySeparatedByDot() @@ -330,7 +330,7 @@ public function testLanguageKeySeparatedByDot() $this->lang = new SecondMockLanguage('en'); $this->lang->loadem('Foo', 'en'); - $this->assertEquals('The fieldname field is very short.', $this->lang->getLine('Foo.bar.min_length1', ['field' => 'fieldname'])); - $this->assertEquals('The fieldname field is very short.', $this->lang->getLine('Foo.baz.min_length3.short', ['field' => 'fieldname'])); + $this->assertSame('The fieldname field is very short.', $this->lang->getLine('Foo.bar.min_length1', ['field' => 'fieldname'])); + $this->assertSame('The fieldname field is very short.', $this->lang->getLine('Foo.baz.min_length3.short', ['field' => 'fieldname'])); } } diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 13d17f1733d3..0a178086c549 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -69,7 +69,7 @@ public function testLogActuallyLogs() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -103,7 +103,7 @@ public function testLogInterpolatesMessage() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -122,7 +122,7 @@ public function testLogInterpolatesPost() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -141,7 +141,7 @@ public function testLogInterpolatesGet() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -160,7 +160,7 @@ public function testLogInterpolatesSession() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -178,7 +178,7 @@ public function testLogInterpolatesCurrentEnvironment() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -198,7 +198,7 @@ public function testLogInterpolatesEnvironmentVars() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -255,7 +255,7 @@ public function testEmergencyLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -272,7 +272,7 @@ public function testAlertLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -289,7 +289,7 @@ public function testCriticalLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -306,7 +306,7 @@ public function testErrorLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -323,7 +323,7 @@ public function testWarningLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -340,7 +340,7 @@ public function testNoticeLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -357,7 +357,7 @@ public function testInfoLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -374,7 +374,7 @@ public function testDebugLogsCorrectly() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -391,7 +391,7 @@ public function testLogLevels() $logs = TestHandler::getLogs(); $this->assertCount(1, $logs); - $this->assertEquals($expected, $logs[0]); + $this->assertSame($expected, $logs[0]); } //-------------------------------------------------------------------- @@ -420,7 +420,7 @@ public function testFilenameCleaning() $ohoh = APPPATH . 'LoggerTest'; $expected = 'APPPATH/LoggerTest'; - $this->assertEquals($expected, $logger->cleanup($ohoh)); + $this->assertSame($expected, $logger->cleanup($ohoh)); } //-------------------------------------------------------------------- @@ -435,6 +435,6 @@ public function testDetermineFileNoStackTrace() 'unknown', ]; - $this->assertEquals($expected, $logger->determineFile()); + $this->assertSame($expected, $logger->determineFile()); } } diff --git a/tests/system/Models/ValidationModelTest.php b/tests/system/Models/ValidationModelTest.php index 544ff587c89a..06b0f3cd72f9 100644 --- a/tests/system/Models/ValidationModelTest.php +++ b/tests/system/Models/ValidationModelTest.php @@ -30,7 +30,7 @@ public function testValid(): void $this->assertIsInt($this->model->insert($data)); $errors = $this->model->errors(); - $this->assertEquals([], $errors); + $this->assertSame([], $errors); } public function testValidationBasics(): void diff --git a/tests/system/Pager/PagerRendererTest.php b/tests/system/Pager/PagerRendererTest.php index 291d1289ba70..558b435d1086 100644 --- a/tests/system/Pager/PagerRendererTest.php +++ b/tests/system/Pager/PagerRendererTest.php @@ -59,7 +59,7 @@ public function testHasPreviousReturnsTrueWhenFirstIsMoreThanOne() $pager->setSurroundCount(2); $this->assertTrue($pager->hasPrevious()); - $this->assertEquals('http://example.com/foo?foo=bar&page=2', $pager->getPrevious()); + $this->assertSame('http://example.com/foo?foo=bar&page=2', $pager->getPrevious()); } //-------------------------------------------------------------------- @@ -80,7 +80,7 @@ public function testGetPreviousWhenSurroundCountIsZero() $pager->setSurroundCount(0); $this->assertTrue($pager->hasPrevious()); - $this->assertEquals('http://example.com/foo?foo=bar&page=3', $pager->getPrevious()); + $this->assertSame('http://example.com/foo?foo=bar&page=3', $pager->getPrevious()); } //-------------------------------------------------------------------- @@ -121,7 +121,7 @@ public function testHasNextReturnsTrueWhenLastIsSmallerThanTotal() $pager->setSurroundCount(2); $this->assertTrue($pager->hasNext()); - $this->assertEquals('http://example.com/foo?foo=bar&page=7', $pager->getNext()); + $this->assertSame('http://example.com/foo?foo=bar&page=7', $pager->getNext()); } //-------------------------------------------------------------------- @@ -142,7 +142,7 @@ public function testGetNextWhenSurroundCountIsZero() $pager->setSurroundCount(0); $this->assertTrue($pager->hasNext()); - $this->assertEquals('http://example.com/foo?foo=bar&page=5', $pager->getNext()); + $this->assertSame('http://example.com/foo?foo=bar&page=5', $pager->getNext()); } //-------------------------------------------------------------------- @@ -177,7 +177,7 @@ public function testLinksBasics() ], ]; - $this->assertEquals($expected, $pager->links()); + $this->assertSame($expected, $pager->links()); } //-------------------------------------------------------------------- @@ -196,8 +196,8 @@ public function testGetFirstAndGetLast() $pager = new PagerRenderer($details); - $this->assertEquals('http://example.com/foo?foo=bar&page=1', $pager->getFirst()); - $this->assertEquals('http://example.com/foo?foo=bar&page=50', $pager->getLast()); + $this->assertSame('http://example.com/foo?foo=bar&page=1', $pager->getFirst()); + $this->assertSame('http://example.com/foo?foo=bar&page=50', $pager->getLast()); } //-------------------------------------------------------------------- @@ -216,7 +216,7 @@ public function testGetCurrent() $pager = new PagerRenderer($details); - $this->assertEquals('http://example.com/foo?foo=bar&page=10', $pager->getCurrent()); + $this->assertSame('http://example.com/foo?foo=bar&page=10', $pager->getCurrent()); } //-------------------------------------------------------------------- @@ -236,7 +236,7 @@ public function testGetCurrentWithSegment() $pager = new PagerRenderer($details); - $this->assertEquals('http://example.com/foo/10?foo=bar', $pager->getCurrent()); + $this->assertSame('http://example.com/foo/10?foo=bar', $pager->getCurrent()); } //-------------------------------------------------------------------- @@ -260,13 +260,13 @@ public function testSurroundCount() // with surropund count of 2 $pager->setSurroundCount(2); - $this->assertEquals($this->expect . '1', $pager->getPrevious()); - $this->assertEquals($this->expect . '7', $pager->getNext()); + $this->assertSame($this->expect . '1', $pager->getPrevious()); + $this->assertSame($this->expect . '7', $pager->getNext()); // with unchanged surround count $pager->setSurroundCount(); - $this->assertEquals($this->expect . '1', $pager->getPrevious()); - $this->assertEquals($this->expect . '7', $pager->getNext()); + $this->assertSame($this->expect . '1', $pager->getPrevious()); + $this->assertSame($this->expect . '7', $pager->getNext()); // and with huge surround count $pager->setSurroundCount(100); @@ -310,7 +310,7 @@ public function testHasPreviousReturnsTrueWhenFirstIsMoreThanOneSegment() $pager->setSurroundCount(2); $this->assertTrue($pager->hasPrevious()); - $this->assertEquals('http://example.com/foo/2?foo=bar', $pager->getPrevious()); + $this->assertSame('http://example.com/foo/2?foo=bar', $pager->getPrevious()); } //-------------------------------------------------------------------- @@ -332,7 +332,7 @@ public function testGetPreviousWhenSurroundCountIsZeroSegment() $pager->setSurroundCount(0); $this->assertTrue($pager->hasPrevious()); - $this->assertEquals('http://example.com/foo/3?foo=bar', $pager->getPrevious()); + $this->assertSame('http://example.com/foo/3?foo=bar', $pager->getPrevious()); } //-------------------------------------------------------------------- @@ -375,7 +375,7 @@ public function testHasNextReturnsTrueWhenLastIsSmallerThanTotalSegment() $pager->setSurroundCount(2); $this->assertTrue($pager->hasNext()); - $this->assertEquals('http://example.com/foo/7?foo=bar', $pager->getNext()); + $this->assertSame('http://example.com/foo/7?foo=bar', $pager->getNext()); } //-------------------------------------------------------------------- @@ -397,7 +397,7 @@ public function testGetNextWhenSurroundCountIsZeroSegment() $pager->setSurroundCount(0); $this->assertTrue($pager->hasNext()); - $this->assertEquals('http://example.com/foo/5?foo=bar', $pager->getNext()); + $this->assertSame('http://example.com/foo/5?foo=bar', $pager->getNext()); } //-------------------------------------------------------------------- @@ -433,7 +433,7 @@ public function testLinksBasicsSegment() ], ]; - $this->assertEquals($expected, $pager->links()); + $this->assertSame($expected, $pager->links()); } //-------------------------------------------------------------------- @@ -453,8 +453,8 @@ public function testGetFirstAndGetLastSegment() $pager = new PagerRenderer($details); - $this->assertEquals('http://example.com/foo/1?foo=bar', $pager->getFirst()); - $this->assertEquals('http://example.com/foo/50?foo=bar', $pager->getLast()); + $this->assertSame('http://example.com/foo/1?foo=bar', $pager->getFirst()); + $this->assertSame('http://example.com/foo/50?foo=bar', $pager->getLast()); } //-------------------------------------------------------------------- @@ -508,7 +508,7 @@ public function testHasPreviousPageReturnsTrueWhenFirstIsMoreThanCurrent() $this->assertNotNull($pager->getPreviousPage()); $this->assertTrue($pager->hasPreviousPage()); - $this->assertEquals('http://example.com/foo?page=2', $pager->getPreviousPage()); + $this->assertSame('http://example.com/foo?page=2', $pager->getPreviousPage()); } //-------------------------------------------------------------------- @@ -526,7 +526,7 @@ public function testGetPreviousPageWithSegmentHigherThanZero() ]; $pager = new PagerRenderer($details); - $this->assertEquals('http://example.com/foo/2', $pager->getPreviousPage()); + $this->assertSame('http://example.com/foo/2', $pager->getPreviousPage()); } //-------------------------------------------------------------------- @@ -546,7 +546,7 @@ public function testHasNextPageReturnsTrueWhenLastIsMoreThanCurrent() $this->assertNotNull($pager->getNextPage()); $this->assertTrue($pager->hasNextPage()); - $this->assertEquals('http://example.com/foo?page=4', $pager->getNextPage()); + $this->assertSame('http://example.com/foo?page=4', $pager->getNextPage()); } public function testGetNextPageWithSegmentHigherThanZero() @@ -562,7 +562,7 @@ public function testGetNextPageWithSegmentHigherThanZero() ]; $pager = new PagerRenderer($details); - $this->assertEquals('http://example.com/foo/4', $pager->getNextPage()); + $this->assertSame('http://example.com/foo/4', $pager->getNextPage()); } public function testGetPageNumber() @@ -576,10 +576,10 @@ public function testGetPageNumber() ]; $pager = new PagerRenderer($details); - $this->assertEquals(1, $pager->getFirstPageNumber()); - $this->assertEquals(3, $pager->getCurrentPageNumber()); - $this->assertEquals(10, $pager->getLastPageNumber()); - $this->assertEquals(10, $pager->getPageCount()); + $this->assertSame(1, $pager->getFirstPageNumber()); + $this->assertSame(3, $pager->getCurrentPageNumber()); + $this->assertSame(10, $pager->getLastPageNumber()); + $this->assertSame(10, $pager->getPageCount()); } public function testGetPageNumberSetSurroundCount() @@ -594,9 +594,9 @@ public function testGetPageNumberSetSurroundCount() $pager = new PagerRenderer($details); $pager->setSurroundCount(2); - $this->assertEquals(3, $pager->getFirstPageNumber()); - $this->assertEquals(5, $pager->getCurrentPageNumber()); - $this->assertEquals(7, $pager->getLastPageNumber()); + $this->assertSame(3, $pager->getFirstPageNumber()); + $this->assertSame(5, $pager->getCurrentPageNumber()); + $this->assertSame(7, $pager->getLastPageNumber()); } public function testGetPreviousPageNumber() @@ -611,7 +611,7 @@ public function testGetPreviousPageNumber() $pager = new PagerRenderer($details); $pager->setSurroundCount(2); - $this->assertEquals(4, $pager->getPreviousPageNumber()); + $this->assertSame(4, $pager->getPreviousPageNumber()); } public function testGetPreviousPageNumberNull() @@ -641,7 +641,7 @@ public function testGetNextPageNumber() $pager = new PagerRenderer($details); $pager->setSurroundCount(2); - $this->assertEquals(6, $pager->getNextPageNumber()); + $this->assertSame(6, $pager->getNextPageNumber()); } public function testGetNextPageNumberNull() diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 9bc355fdfb41..571df88afeb4 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -50,7 +50,7 @@ public function testSetPathRemembersPath() $details = $this->pager->getDetails(); - $this->assertEquals('foo/bar', $details['uri']->getPath()); + $this->assertSame('foo/bar', $details['uri']->getPath()); } public function testGetDetailsRecognizesPageQueryVar() @@ -62,7 +62,7 @@ public function testGetDetailsRecognizesPageQueryVar() $details = $this->pager->getDetails(); - $this->assertEquals(2, $details['currentPage']); + $this->assertSame(2, $details['currentPage']); } public function testGetDetailsRecognizesGroupedPageQueryVar() @@ -74,7 +74,7 @@ public function testGetDetailsRecognizesGroupedPageQueryVar() $details = $this->pager->getDetails('foo'); - $this->assertEquals(2, $details['currentPage']); + $this->assertSame(2, $details['currentPage']); } public function testGetDetailsThrowExceptionIfGroupNotFound() @@ -91,7 +91,7 @@ public function testDetailsHasConfiguredPerPageValue() $details = $this->pager->getDetails('foo'); - $this->assertEquals($this->config->perPage, $details['perPage']); + $this->assertSame($this->config->perPage, $details['perPage']); } public function testStoreDoesBasicCalcs() @@ -100,9 +100,9 @@ public function testStoreDoesBasicCalcs() $details = $this->pager->getDetails('foo'); - $this->assertEquals($details['total'], 100); - $this->assertEquals($details['perPage'], 25); - $this->assertEquals($details['currentPage'], 3); + $this->assertSame($details['total'], 100); + $this->assertSame($details['perPage'], 25); + $this->assertSame($details['currentPage'], 3); } public function testStoreDoesBasicCalcsOnPerPageReadFromPagerConfig() @@ -111,9 +111,9 @@ public function testStoreDoesBasicCalcsOnPerPageReadFromPagerConfig() $details = $this->pager->getDetails('foo'); - $this->assertEquals($details['total'], 100); - $this->assertEquals($details['perPage'], 20); - $this->assertEquals($details['currentPage'], 3); + $this->assertSame($details['total'], 100); + $this->assertSame($details['perPage'], 20); + $this->assertSame($details['currentPage'], 3); } public function testStoreAndHasMore() @@ -137,10 +137,10 @@ public function testStoreWithQueries() $this->pager->store('default', 3, 25, 100); - $this->assertEquals('http://example.com/index.php?page=2&foo=bar', $this->pager->getPreviousPageURI()); - $this->assertEquals('http://example.com/index.php?page=4&foo=bar', $this->pager->getNextPageURI()); - $this->assertEquals('http://example.com/index.php?page=5&foo=bar', $this->pager->getPageURI(5)); - $this->assertEquals( + $this->assertSame('http://example.com/index.php?page=2&foo=bar', $this->pager->getPreviousPageURI()); + $this->assertSame('http://example.com/index.php?page=4&foo=bar', $this->pager->getNextPageURI()); + $this->assertSame('http://example.com/index.php?page=5&foo=bar', $this->pager->getPageURI(5)); + $this->assertSame( 'http://example.com/index.php?foo=bar&page=5', $this->pager->only(['foo'])->getPageURI(5) ); @@ -153,10 +153,10 @@ public function testStoreWithSegments() $this->pager->store('default', 3, 25, 100, 1); - $this->assertEquals('http://example.com/2?page=3&foo=bar', $this->pager->getPreviousPageURI()); - $this->assertEquals('http://example.com/4?page=3&foo=bar', $this->pager->getNextPageURI()); - $this->assertEquals('http://example.com/5?page=3&foo=bar', $this->pager->getPageURI(5)); - $this->assertEquals( + $this->assertSame('http://example.com/2?page=3&foo=bar', $this->pager->getPreviousPageURI()); + $this->assertSame('http://example.com/4?page=3&foo=bar', $this->pager->getNextPageURI()); + $this->assertSame('http://example.com/5?page=3&foo=bar', $this->pager->getPageURI(5)); + $this->assertSame( 'http://example.com/5?foo=bar', $this->pager->only(['foo'])->getPageURI(5) ); @@ -169,59 +169,59 @@ public function testHasMoreDefaultsToFalse() public function testPerPageHasDefaultValue() { - $this->assertEquals($this->config->perPage, $this->pager->getPerPage()); + $this->assertSame($this->config->perPage, $this->pager->getPerPage()); } public function testPerPageKeepsStoredValue() { $this->pager->store('foo', 3, 13, 70); - $this->assertEquals(13, $this->pager->getPerPage('foo')); + $this->assertSame(13, $this->pager->getPerPage('foo')); } public function testGetCurrentPageDefaultsToOne() { - $this->assertEquals(1, $this->pager->getCurrentPage()); + $this->assertSame(1, $this->pager->getCurrentPage()); } public function testGetCurrentPageRemembersStoredPage() { $this->pager->store('foo', 3, 13, 70); - $this->assertEquals(3, $this->pager->getCurrentPage('foo')); + $this->assertSame(3, $this->pager->getCurrentPage('foo')); } public function testGetCurrentPageDetectsURI() { $_GET['page'] = 2; - $this->assertEquals(2, $this->pager->getCurrentPage()); + $this->assertSame(2, $this->pager->getCurrentPage()); } public function testGetCurrentPageDetectsGroupedURI() { $_GET['page_foo'] = 2; - $this->assertEquals(2, $this->pager->getCurrentPage('foo')); + $this->assertSame(2, $this->pager->getCurrentPage('foo')); } public function testGetTotalPagesDefaultsToOne() { - $this->assertEquals(1, $this->pager->getPageCount()); + $this->assertSame(1, $this->pager->getPageCount()); } public function testGetTotalCorrectValue() { $this->pager->store('foo', 3, 12, 70); - $this->assertEquals(70, $this->pager->getTotal('foo')); + $this->assertSame(70, $this->pager->getTotal('foo')); } public function testGetTotalPagesCalcsCorrectValue() { $this->pager->store('foo', 3, 12, 70); - $this->assertEquals(6, $this->pager->getPageCount('foo')); + $this->assertSame(6, $this->pager->getPageCount('foo')); } public function testGetNextURIUsesCurrentURI() @@ -233,7 +233,7 @@ public function testGetNextURIUsesCurrentURI() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=3'); - $this->assertEquals((string) $expected, $this->pager->getNextPageURI('foo')); + $this->assertSame((string) $expected, $this->pager->getNextPageURI('foo')); } public function testGetNextURIReturnsNullOnLastPage() @@ -250,7 +250,7 @@ public function testGetNextURICorrectOnFirstPage() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=2'); - $this->assertEquals($expected, $this->pager->getNextPageURI('foo')); + $this->assertSame($expected, $this->pager->getNextPageURI('foo')); } public function testGetPreviousURIUsesCurrentURI() @@ -262,7 +262,7 @@ public function testGetPreviousURIUsesCurrentURI() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=1'); - $this->assertEquals((string) $expected, $this->pager->getPreviousPageURI('foo')); + $this->assertSame((string) $expected, $this->pager->getPreviousPageURI('foo')); } public function testGetNextURIReturnsNullOnFirstPage() @@ -284,7 +284,7 @@ public function testGetNextURIWithQueryStringUsesCurrentURI() $this->pager->store('foo', $_GET['page_foo'] - 1, 12, 70); - $this->assertEquals((string) $expected, $this->pager->getNextPageURI('foo')); + $this->assertSame((string) $expected, $this->pager->getNextPageURI('foo')); } public function testGetPreviousURIWithQueryStringUsesCurrentURI() @@ -298,7 +298,7 @@ public function testGetPreviousURIWithQueryStringUsesCurrentURI() $this->pager->store('foo', $_GET['page_foo'] + 1, 12, 70); - $this->assertEquals((string) $expected, $this->pager->getPreviousPageURI('foo')); + $this->assertSame((string) $expected, $this->pager->getPreviousPageURI('foo')); } public function testGetOnlyQueries() @@ -319,15 +319,15 @@ public function testGetOnlyQueries() $uri = current_url(true); - $this->assertEquals( + $this->assertSame( $this->pager->only($onlyQueries)->getPreviousPageURI(), (string) $uri->setQuery('search=foo&order=asc&page=1') ); - $this->assertEquals( + $this->assertSame( $this->pager->only($onlyQueries)->getNextPageURI(), (string) $uri->setQuery('search=foo&order=asc&page=3') ); - $this->assertEquals( + $this->assertSame( $this->pager->only($onlyQueries)->getPageURI(4), (string) $uri->setQuery('search=foo&order=asc&page=4') ); @@ -445,18 +445,18 @@ public function testBasedURI() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=1'); - $this->assertEquals((string) $expected, $this->pager->getPreviousPageURI('foo')); + $this->assertSame((string) $expected, $this->pager->getPreviousPageURI('foo')); } public function testAccessPageMoreThanPageCountGetLastPage() { $this->pager->store('default', 11, 1, 10); - $this->assertEquals(10, $this->pager->getCurrentPage()); + $this->assertSame(10, $this->pager->getCurrentPage()); } public function testSegmentOutOfBound() { $this->pager->store('default', 10, 1, 10, 1000); - $this->assertEquals(1, $this->pager->getCurrentPage()); + $this->assertSame(1, $this->pager->getCurrentPage()); } } diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index 1ac6168e46a8..6a87d92363e6 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -236,7 +236,7 @@ public function testModelBogus() $resource->setModel('Something'); $this->assertEmpty($resource->getModel()); - $this->assertEquals('Something', $resource->getModelName()); + $this->assertSame('Something', $resource->getModelName()); } public function testModelByName() @@ -244,7 +244,7 @@ public function testModelByName() $resource = new MockResourceController(); $resource->setModel('\Tests\Support\Models\UserModel'); $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); - $this->assertEquals('\Tests\Support\Models\UserModel', $resource->getModelName()); + $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); } public function testModelByObject() @@ -255,20 +255,20 @@ public function testModelByObject() $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); // Note that the leading backslash is missing if we build it this way - $this->assertEquals('Tests\Support\Models\UserModel', $resource->getModelName()); + $this->assertSame('Tests\Support\Models\UserModel', $resource->getModelName()); } //-------------------------------------------------------------------- public function testFormat() { $resource = new MockResourceController(); - $this->assertEquals('json', $resource->getFormat()); + $this->assertSame('json', $resource->getFormat()); $resource->setFormat('Nonsense'); - $this->assertEquals('json', $resource->getFormat()); + $this->assertSame('json', $resource->getFormat()); $resource->setFormat('xml'); - $this->assertEquals('xml', $resource->getFormat()); + $this->assertSame('xml', $resource->getFormat()); } //-------------------------------------------------------------------- @@ -297,7 +297,7 @@ public function testJSONFormatOutput() $JSONFormatter = new JSONFormatter(); $expected = $JSONFormatter->format($data); - $this->assertEquals($expected, $result); + $this->assertSame($expected, $result); } //-------------------------------------------------------------------- @@ -326,6 +326,6 @@ public function testXMLFormatOutput() $XMLFormatter = new XMLFormatter(); $expected = $XMLFormatter->format($data); - $this->assertEquals($expected, $result); + $this->assertSame($expected, $result); } } diff --git a/tests/system/RESTful/ResourcePresenterTest.php b/tests/system/RESTful/ResourcePresenterTest.php index 2bbbf98dfaad..9910891f90c2 100644 --- a/tests/system/RESTful/ResourcePresenterTest.php +++ b/tests/system/RESTful/ResourcePresenterTest.php @@ -80,7 +80,7 @@ public function testResourceGet() $this->codeigniter->useSafeOutput(true)->run($this->routes); $output = ob_get_clean(); - $this->assertEquals(lang('RESTful.notImplemented', ['index']), $output); + $this->assertSame(lang('RESTful.notImplemented', ['index']), $output); } public function testResourceShow() @@ -237,7 +237,7 @@ public function testModelBogus() $resource->setModel('Something'); $this->assertEmpty($resource->getModel()); - $this->assertEquals('Something', $resource->getModelName()); + $this->assertSame('Something', $resource->getModelName()); } public function testModelByName() @@ -245,7 +245,7 @@ public function testModelByName() $resource = new MockResourcePresenter(); $resource->setModel('\Tests\Support\Models\UserModel'); $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); - $this->assertEquals('\Tests\Support\Models\UserModel', $resource->getModelName()); + $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); } public function testModelByObject() @@ -256,7 +256,7 @@ public function testModelByObject() $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); // Note that the leading backslash is missing if we build it this way - $this->assertEquals('Tests\Support\Models\UserModel', $resource->getModelName()); + $this->assertSame('Tests\Support\Models\UserModel', $resource->getModelName()); } public function testChangeSetModelByObject() @@ -264,12 +264,12 @@ public function testChangeSetModelByObject() $resource = new MockResourcePresenter(); $resource->setModel('\Tests\Support\Models\UserModel'); $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); - $this->assertEquals('\Tests\Support\Models\UserModel', $resource->getModelName()); + $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); $model = new EntityModel(); $resource->setModel($model); $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); - $this->assertEquals('Tests\Support\Models\EntityModel', $resource->getModelName()); + $this->assertSame('Tests\Support\Models\EntityModel', $resource->getModelName()); } public function testChangeSetModelByName() @@ -277,10 +277,10 @@ public function testChangeSetModelByName() $resource = new MockResourcePresenter(); $resource->setModel('\Tests\Support\Models\UserModel'); $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); - $this->assertEquals('\Tests\Support\Models\UserModel', $resource->getModelName()); + $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); $resource->setModel('\Tests\Support\Models\EntityModel'); $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); - $this->assertEquals('\Tests\Support\Models\EntityModel', $resource->getModelName()); + $this->assertSame('\Tests\Support\Models\EntityModel', $resource->getModelName()); } } diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 6222f28569c1..01b2e4d513bc 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -18,8 +18,6 @@ protected function tearDown(): void { } - //-------------------------------------------------------------------- - protected function getCollector(array $config = [], array $files = [], $moduleConfig = null) { $defaults = [ @@ -52,7 +50,7 @@ public function testBasicAdd() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -69,7 +67,7 @@ public function testAddPrefixesDefaultNamespaceWhenNoneExist() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -86,7 +84,7 @@ public function testAddIgnoresDefaultNamespaceWhenExists() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -105,7 +103,7 @@ public function testAddWorksWithCurrentHTTPMethods() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -122,7 +120,7 @@ public function testAddWithLeadingSlash() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -137,7 +135,7 @@ public function testMatchIgnoresInvalidHTTPMethods() $routes = $routes->getRoutes(); - $this->assertEquals([], $routes); + $this->assertSame([], $routes); } //-------------------------------------------------------------------- @@ -156,7 +154,7 @@ public function testAddWorksWithArrayOFHTTPMethods() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -173,7 +171,7 @@ public function testAddReplacesDefaultPlaceholders() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -191,7 +189,7 @@ public function testAddReplacesCustomPlaceholders() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -209,7 +207,7 @@ public function testAddRecognizesCustomNamespaces() $routes = $routes->getRoutes(); - $this->assertEquals($expects, $routes); + $this->assertSame($expects, $routes); } //-------------------------------------------------------------------- @@ -219,7 +217,7 @@ public function testSetDefaultControllerStoresIt() $routes = $this->getCollector(); $routes->setDefaultController('godzilla'); - $this->assertEquals('godzilla', $routes->getDefaultController()); + $this->assertSame('godzilla', $routes->getDefaultController()); } //-------------------------------------------------------------------- @@ -229,7 +227,7 @@ public function testSetDefaultMethodStoresIt() $routes = $this->getCollector(); $routes->setDefaultMethod('biggerBox'); - $this->assertEquals('biggerBox', $routes->getDefaultMethod()); + $this->assertSame('biggerBox', $routes->getDefaultMethod()); } //-------------------------------------------------------------------- @@ -269,7 +267,7 @@ static function ($routes) { 'admin/users/list' => '\Users::list', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -289,7 +287,7 @@ static function ($routes) { 'admin/users/list' => '\Users::list', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -310,7 +308,7 @@ static function ($routes) { 'admin/users/list' => '\Admin\Users::list', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -330,7 +328,7 @@ static function ($routes) { 'users/list' => '\Users::list', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -360,7 +358,7 @@ static function ($routes) { 'admin/delegate/foo' => '\Users::foo', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -378,7 +376,7 @@ public function testHostnameOption() 'from' => '\to', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -397,7 +395,7 @@ public function testResourceScaffoldsCorrectly() 'photos/(.*)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('post'); @@ -407,7 +405,7 @@ public function testResourceScaffoldsCorrectly() 'photos' => '\Photos::create', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('put'); @@ -417,7 +415,7 @@ public function testResourceScaffoldsCorrectly() 'photos/(.*)' => '\Photos::update/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('patch'); @@ -427,7 +425,7 @@ public function testResourceScaffoldsCorrectly() 'photos/(.*)' => '\Photos::update/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('delete'); @@ -437,7 +435,7 @@ public function testResourceScaffoldsCorrectly() 'photos/(.*)' => '\Photos::delete/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } // Similar to the above, but with a more typical endpoint @@ -456,7 +454,7 @@ public function testResourceAPIScaffoldsCorrectly() 'api/photos/(.*)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('post'); @@ -466,7 +464,7 @@ public function testResourceAPIScaffoldsCorrectly() 'api/photos' => '\Photos::create', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('put'); @@ -476,7 +474,7 @@ public function testResourceAPIScaffoldsCorrectly() 'api/photos/(.*)' => '\Photos::update/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('patch'); @@ -486,7 +484,7 @@ public function testResourceAPIScaffoldsCorrectly() 'api/photos/(.*)' => '\Photos::update/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('delete'); @@ -496,7 +494,7 @@ public function testResourceAPIScaffoldsCorrectly() 'api/photos/(.*)' => '\Photos::delete/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } public function testPresenterScaffoldsCorrectly() @@ -515,7 +513,7 @@ public function testPresenterScaffoldsCorrectly() 'photos/(.*)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $routes = $this->getCollector(); $routes->setHTTPVerb('post'); @@ -528,7 +526,7 @@ public function testPresenterScaffoldsCorrectly() 'photos' => '\Photos::create', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -547,7 +545,7 @@ public function testResourcesWithCustomController() 'photos/(.*)' => '\Gallery::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -566,7 +564,7 @@ public function testResourcesWithCustomPlaceholder() 'photos/([0-9]+)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } public function testResourcesWithDefaultPlaceholder() @@ -584,7 +582,7 @@ public function testResourcesWithDefaultPlaceholder() 'photos/([0-9]+)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } public function testResourcesWithBogusDefaultPlaceholder() @@ -602,7 +600,7 @@ public function testResourcesWithBogusDefaultPlaceholder() 'photos/(.*)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -618,7 +616,7 @@ public function testResourcesWithOnly() 'photos' => '\Photos::index', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -635,7 +633,7 @@ public function testResourcesWithExcept() 'photos/(.*)' => '\Photos::show/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -649,11 +647,11 @@ public function testResourcesWithWebsafe() $expected = [ 'photos' => '\Photos::create', - 'photos/(.*)' => '\Photos::update/$1', 'photos/(.*)/delete' => '\Photos::delete/$1', + 'photos/(.*)' => '\Photos::update/$1', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -666,12 +664,12 @@ public function testMatchSupportsMultipleMethods() $expected = ['here' => '\there']; $routes->match(['get', 'post'], 'here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); Services::request()->setMethod('post'); $routes = $this->getCollector(); $routes->match(['get', 'post'], 'here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -684,7 +682,7 @@ public function testGet() $expected = ['here' => '\there']; $routes->get('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -697,7 +695,7 @@ public function testPost() $expected = ['here' => '\there']; $routes->post('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -711,7 +709,7 @@ public function testGetDoesntAllowOtherMethods() $routes->get('here', 'there'); $routes->post('from', 'to'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -724,7 +722,7 @@ public function testPut() $expected = ['here' => '\there']; $routes->put('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -737,7 +735,7 @@ public function testDelete() $expected = ['here' => '\there']; $routes->delete('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -750,7 +748,7 @@ public function testHead() $expected = ['here' => '\there']; $routes->head('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -763,7 +761,7 @@ public function testPatch() $expected = ['here' => '\there']; $routes->patch('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -776,7 +774,7 @@ public function testOptions() $expected = ['here' => '\there']; $routes->options('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -788,7 +786,7 @@ public function testCLI() $expected = ['here' => '\there']; $routes->cli('here', 'there'); - $this->assertEquals($expected, $routes->getRoutes('cli')); + $this->assertSame($expected, $routes->getRoutes('cli')); } //-------------------------------------------------------------------- @@ -816,7 +814,7 @@ static function ($routes) { } ); - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -829,7 +827,7 @@ public function testReverseRoutingFindsSimpleMatch() $match = $routes->reverseRoute('myController::goto', 'string', 13); - $this->assertEquals('/path/string/to/13', $match); + $this->assertSame('/path/string/to/13', $match); } //-------------------------------------------------------------------- @@ -842,7 +840,7 @@ public function testReverseRoutingWithLocaleAndFindsSimpleMatch() $match = $routes->reverseRoute('myController::goto', 'string', 13); - $this->assertEquals('/en/path/string/to/13', $match); + $this->assertSame('/en/path/string/to/13', $match); } //-------------------------------------------------------------------- @@ -887,7 +885,7 @@ public function testReverseRoutingWithLocale() $routes->add('{locale}/contact', 'myController::goto'); - $this->assertEquals('/en/contact', $routes->reverseRoute('myController::goto')); + $this->assertSame('/en/contact', $routes->reverseRoute('myController::goto')); } //-------------------------------------------------------------------- @@ -898,7 +896,7 @@ public function testNamedRoutes() $routes->add('users', 'Users::index', ['as' => 'namedRoute']); - $this->assertEquals('/users', $routes->reverseRoute('namedRoute')); + $this->assertSame('/users', $routes->reverseRoute('namedRoute')); } //-------------------------------------------------------------------- @@ -909,7 +907,7 @@ public function testNamedRoutesWithLocale() $routes->add('{locale}/users', 'Users::index', ['as' => 'namedRoute']); - $this->assertEquals('/en/users', $routes->reverseRoute('namedRoute')); + $this->assertSame('/en/users', $routes->reverseRoute('namedRoute')); } //-------------------------------------------------------------------- @@ -922,7 +920,7 @@ public function testNamedRoutesFillInParams() $match = $routes->reverseRoute('namedRoute', 'string', 13); - $this->assertEquals('/path/string/to/13', $match); + $this->assertSame('/path/string/to/13', $match); } //-------------------------------------------------------------------- @@ -935,7 +933,7 @@ public function testNamedRoutesWithLocaleAndFillInParams() $match = $routes->reverseRoute('namedRoute', 'string', 13); - $this->assertEquals('/en/path/string/to/13', $match); + $this->assertSame('/en/path/string/to/13', $match); } //-------------------------------------------------------------------- @@ -963,9 +961,9 @@ static function () {}, $match2 = $routes->reverseRoute('namedRoute2'); $match3 = $routes->reverseRoute('namedRoute3'); - $this->assertEquals('/user/insert', $match1); - $this->assertEquals('/user/insert', $match2); - $this->assertEquals('/user/insert', $match3); + $this->assertSame('/user/insert', $match1); + $this->assertSame('/user/insert', $match2); + $this->assertSame('/user/insert', $match3); } //-------------------------------------------------------------------- @@ -995,9 +993,9 @@ static function () { $match2 = $routes->reverseRoute('namedRoute2'); $match3 = $routes->reverseRoute('namedRoute3'); - $this->assertEquals('/en/user/insert', $match1); - $this->assertEquals('/en/user/insert', $match2); - $this->assertEquals('/en/user/insert', $match3); + $this->assertSame('/en/user/insert', $match1); + $this->assertSame('/en/user/insert', $match2); + $this->assertSame('/en/user/insert', $match3); } //-------------------------------------------------------------------- @@ -1011,8 +1009,8 @@ public function testNamedRoutesWithPipesInRegex() $routes->get('/system/(this|that)', 'myController::system/$1', ['as' => 'pipedRoute']); - $this->assertEquals('/system/this', $routes->reverseRoute('pipedRoute', 'this')); - $this->assertEquals('/system/that', $routes->reverseRoute('pipedRoute', 'that')); + $this->assertSame('/system/this', $routes->reverseRoute('pipedRoute', 'this')); + $this->assertSame('/system/that', $routes->reverseRoute('pipedRoute', 'that')); } //-------------------------------------------------------------------- @@ -1025,7 +1023,7 @@ public function testReverseRouteMatching() $match = $routes->reverseRoute('testRouter', 1, 2); - $this->assertEquals('/test/1/2', $match); + $this->assertSame('/test/1/2', $match); } //-------------------------------------------------------------------- @@ -1038,7 +1036,7 @@ public function testReverseRouteMatchingWithLocale() $match = $routes->reverseRoute('testRouter', 1, 2); - $this->assertEquals('/en/test/1/2', $match); + $this->assertSame('/en/test/1/2', $match); } //-------------------------------------------------------------------- @@ -1054,10 +1052,10 @@ public function testAddRedirect() 'users' => 'users/index', ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $this->assertTrue($routes->isRedirect('users')); - $this->assertEquals(307, $routes->getRedirectCode('users')); - $this->assertEquals(0, $routes->getRedirectCode('bosses')); + $this->assertSame(307, $routes->getRedirectCode('users')); + $this->assertSame(0, $routes->getRedirectCode('bosses')); } public function testAddRedirectNamed() @@ -1068,15 +1066,13 @@ public function testAddRedirectNamed() $routes->addRedirect('users', 'namedRoute', 307); $expected = [ - 'users' => [ - 'zombies' => '\Zombies::index', - ], 'zombies' => '\Zombies::index', + 'users' => ['zombies' => '\Zombies::index'], ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $this->assertTrue($routes->isRedirect('users')); - $this->assertEquals(307, $routes->getRedirectCode('users')); + $this->assertSame(307, $routes->getRedirectCode('users')); } public function testAddRedirectGetMethod() @@ -1087,15 +1083,13 @@ public function testAddRedirectGetMethod() $routes->addRedirect('users', 'namedRoute', 307); $expected = [ - 'users' => [ - 'zombies' => '\Zombies::index', - ], 'zombies' => '\Zombies::index', + 'users' => ['zombies' => '\Zombies::index'], ]; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); $this->assertTrue($routes->isRedirect('users')); - $this->assertEquals(307, $routes->getRedirectCode('users')); + $this->assertSame(307, $routes->getRedirectCode('users')); } //-------------------------------------------------------------------- @@ -1116,7 +1110,7 @@ public function testWithSubdomain() 'objects/([a-zA-Z0-9]+)' => '\Admin::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } public function testWithSubdomainMissing() @@ -1132,7 +1126,7 @@ public function testWithSubdomainMissing() 'objects/([a-zA-Z0-9]+)' => '\App::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } public function testWithDifferentSubdomain() @@ -1148,7 +1142,7 @@ public function testWithDifferentSubdomain() 'objects/([a-zA-Z0-9]+)' => '\App::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } public function testWithWWWSubdomain() @@ -1164,7 +1158,7 @@ public function testWithWWWSubdomain() 'objects/([a-zA-Z0-9]+)' => '\App::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } public function testWithDotCoSubdomain() @@ -1180,7 +1174,7 @@ public function testWithDotCoSubdomain() 'objects/([a-zA-Z0-9]+)' => '\App::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } public function testWithDifferentSubdomainMissing() @@ -1196,7 +1190,7 @@ public function testWithDifferentSubdomainMissing() 'objects/([a-zA-Z0-9]+)' => '\App::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -1217,7 +1211,7 @@ public function testWithSubdomainOrdered() 'objects/([a-zA-Z0-9]+)' => '\Admin::objectsList/$1', ]; - $this->assertEquals($expects, $routes->getRoutes()); + $this->assertSame($expects, $routes->getRoutes()); } //-------------------------------------------------------------------- @@ -1234,7 +1228,7 @@ public function testReverseRoutingWithClosure() $match = $routes->reverseRoute('login'); - $this->assertEquals('/login', $match); + $this->assertSame('/login', $match); } public function testReverseRoutingWithClosureNoMatch() @@ -1251,9 +1245,7 @@ public function testReverseRoutingWithClosureNoMatch() public function testWillDiscoverLocal() { - $config = [ - 'SampleSpace' => TESTPATH . '_support', - ]; + $config = ['SampleSpace' => TESTPATH . '_support']; $moduleConfig = new Modules(); $moduleConfig->enabled = true; @@ -1263,7 +1255,7 @@ public function testWillDiscoverLocal() $match = $routes->getRoutes(); $this->assertArrayHasKey('testing', $match); - $this->assertEquals($match['testing'], '\TestController::index'); + $this->assertSame($match['testing'], '\TestController::index'); } //-------------------------------------------------------------------- @@ -1284,7 +1276,7 @@ public function testDiscoverLocalAllowsConfigToOverridePackages() $match = $routes->getRoutes(); $this->assertArrayHasKey('testing', $match); - $this->assertEquals($match['testing'], '\MainRoutes::index'); + $this->assertSame($match['testing'], '\MainRoutes::index'); } //-------------------------------------------------------------------- @@ -1306,7 +1298,7 @@ static function () {}, $options = $routes->getRoutesOptions('administrator'); - $this->assertEquals($options, ['as' => 'admin', 'foo' => 'baz']); + $this->assertSame($options, ['as' => 'admin', 'foo' => 'baz']); } public function testRoutesOptionsForDifferentVerbs() @@ -1343,15 +1335,15 @@ static function () {}, $options = $routes->getRoutesOptions('administrator'); - $this->assertEquals($options, ['as' => 'admin1', 'foo' => 'baz1', 'bar' => 'baz']); + $this->assertSame($options, ['as' => 'admin1', 'foo' => 'baz1', 'bar' => 'baz']); $options = $routes->setHTTPVerb('post')->getRoutesOptions('administrator'); - $this->assertEquals($options, ['as' => 'admin2', 'foo' => 'baz2', 'bar' => 'baz']); + $this->assertSame($options, ['as' => 'admin2', 'foo' => 'baz2', 'bar' => 'baz']); $options = $routes->setHTTPVerb('get')->getRoutesOptions('administrator', 'post'); - $this->assertEquals($options, ['as' => 'admin2', 'foo' => 'baz2', 'bar' => 'baz']); + $this->assertSame($options, ['as' => 'admin2', 'foo' => 'baz2', 'bar' => 'baz']); } public function testRouteGroupWithFilterSimple() @@ -1369,8 +1361,8 @@ static function ($routes) { $this->assertTrue($routes->isFiltered('admin/users')); $this->assertFalse($routes->isFiltered('admin/franky')); - $this->assertEquals('role', $routes->getFilterForRoute('admin/users')); - $this->assertEquals('', $routes->getFilterForRoute('admin/bosses')); + $this->assertSame('role', $routes->getFilterForRoute('admin/users')); + $this->assertSame('', $routes->getFilterForRoute('admin/bosses')); } public function testRouteGroupWithFilterWithParams() @@ -1388,7 +1380,7 @@ static function ($routes) { $this->assertTrue($routes->isFiltered('admin/users')); $this->assertFalse($routes->isFiltered('admin/franky')); - $this->assertEquals('role:admin,manager', $routes->getFilterForRoute('admin/users')); + $this->assertSame('role:admin,manager', $routes->getFilterForRoute('admin/users')); } //-------------------------------------------------------------------- @@ -1407,7 +1399,7 @@ public function test404OverrideString() $routes = $this->getCollector(); $routes->set404Override('Explode'); - $this->assertEquals('Explode', $routes->get404Override()); + $this->assertSame('Explode', $routes->get404Override()); } public function test404OverrideCallable() @@ -1430,7 +1422,7 @@ public function testOffsetParameters() $routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]); $expected = ['users/([0-9]+)' => '\users/show/$2']; - $this->assertEquals($expected, $routes->getRoutes()); + $this->assertSame($expected, $routes->getRoutes()); } /** @@ -1447,7 +1439,7 @@ public function testRouteToWithSubdomainMatch() $routes->get('i/(:any)', 'App\Controllers\Site\CDoc::item/$1', ['subdomain' => 'doc', 'as' => 'doc_item']); - $this->assertEquals('/i/sth', $routes->reverseRoute('doc_item', 'sth')); + $this->assertSame('/i/sth', $routes->reverseRoute('doc_item', 'sth')); } public function testRouteToWithSubdomainMismatch() @@ -1483,7 +1475,7 @@ public function testRouteToWithGenericSubdomainMatch() $routes->get('i/(:any)', 'App\Controllers\Site\CDoc::item/$1', ['subdomain' => '*', 'as' => 'doc_item']); - $this->assertEquals('/i/sth', $routes->reverseRoute('doc_item', 'sth')); + $this->assertSame('/i/sth', $routes->reverseRoute('doc_item', 'sth')); } public function testRouteToWithGenericSubdomainMismatch() @@ -1495,7 +1487,7 @@ public function testRouteToWithGenericSubdomainMismatch() $routes->get('i/(:any)', 'App\Controllers\Site\CDoc::item/$1', ['subdomain' => '*', 'as' => 'doc_item']); - $this->assertEquals('/i/sth', $routes->reverseRoute('doc_item', 'sth')); + $this->assertSame('/i/sth', $routes->reverseRoute('doc_item', 'sth')); } public function testRouteToWithGenericSubdomainNot() @@ -1507,7 +1499,7 @@ public function testRouteToWithGenericSubdomainNot() $routes->get('i/(:any)', 'App\Controllers\Site\CDoc::item/$1', ['subdomain' => '*', 'as' => 'doc_item']); - $this->assertEquals('/i/sth', $routes->reverseRoute('doc_item', 'sth')); + $this->assertSame('/i/sth', $routes->reverseRoute('doc_item', 'sth')); } public function testRouteToWithoutSubdomainMatch() @@ -1543,7 +1535,7 @@ public function testRouteToWithoutSubdomainNot() $routes->get('i/(:any)', 'App\Controllers\Site\CDoc::item/$1', ['hostname' => 'example.com', 'as' => 'doc_item']); - $this->assertEquals('/i/sth', $routes->reverseRoute('doc_item', 'sth')); + $this->assertSame('/i/sth', $routes->reverseRoute('doc_item', 'sth')); } /** @@ -1569,7 +1561,7 @@ public function testRouteOverwritingDifferentSubdomains() $expects = '\App\Controllers\Site\CDoc'; - $this->assertEquals($expects, $router->handle('/')); + $this->assertSame($expects, $router->handle('/')); } public function testRouteOverwritingTwoRules() @@ -1590,7 +1582,7 @@ public function testRouteOverwritingTwoRules() // the second rule applies, so overwrites the first $expects = '\App\Controllers\Home'; - $this->assertEquals($expects, $router->handle('/')); + $this->assertSame($expects, $router->handle('/')); } public function testRouteOverwritingTwoRulesLastApplies() @@ -1610,7 +1602,7 @@ public function testRouteOverwritingTwoRulesLastApplies() $expects = '\App\Controllers\Site\CDoc'; - $this->assertEquals($expects, $router->handle('/')); + $this->assertSame($expects, $router->handle('/')); } public function testRouteOverwritingMatchingSubdomain() @@ -1630,7 +1622,7 @@ public function testRouteOverwritingMatchingSubdomain() $expects = '\App\Controllers\Site\CDoc'; - $this->assertEquals($expects, $router->handle('/')); + $this->assertSame($expects, $router->handle('/')); } public function testRouteOverwritingMatchingHost() @@ -1650,7 +1642,7 @@ public function testRouteOverwritingMatchingHost() $expects = '\App\Controllers\Site\CDoc'; - $this->assertEquals($expects, $router->handle('/')); + $this->assertSame($expects, $router->handle('/')); } /** @@ -1669,7 +1661,7 @@ public function testRouteDefaultNameSpace() $expects = '\App\Controllers\Core\Home'; - $this->assertEquals($expects, $router->handle('/')); + $this->assertSame($expects, $router->handle('/')); } public function testZeroAsURIPath() @@ -1683,7 +1675,7 @@ public function testZeroAsURIPath() $expects = '\App\Controllers\Core\Home'; - $this->assertEquals($expects, $router->handle('/0')); + $this->assertSame($expects, $router->handle('/0')); } public function provideRouteDefaultNamespace() @@ -1706,7 +1698,7 @@ public function testAutoRoutesControllerNameReturnsFQCN($namespace) $router = new Router($routes, Services::request()); $router->handle('/product'); - $this->assertEquals('\App\\Controllers\\Product', $router->controllerName()); + $this->assertSame('\App\\Controllers\\Product', $router->controllerName()); } /** @@ -1722,7 +1714,7 @@ public function testRoutesControllerNameReturnsFQCN($namespace) $router = new Router($routes, Services::request()); $router->handle('/product'); - $this->assertEquals('\App\\Controllers\\Product', $router->controllerName()); + $this->assertSame('\App\\Controllers\\Product', $router->controllerName()); } public function testRoutePriorityDetected() @@ -1745,12 +1737,12 @@ public function testRoutePriorityValue() $collection = $this->getCollector(); $collection->add('string', 'Controller::method', ['priority' => 'string']); - $this->assertEquals(0, $collection->getRoutesOptions('string')['priority']); + $this->assertSame(0, $collection->getRoutesOptions('string')['priority']); $collection->add('negative-integer', 'Controller::method', ['priority' => -1]); - $this->assertEquals(1, $collection->getRoutesOptions('negative-integer')['priority']); + $this->assertSame(1, $collection->getRoutesOptions('negative-integer')['priority']); $collection->add('string-negative-integer', 'Controller::method', ['priority' => '-1']); - $this->assertEquals(1, $collection->getRoutesOptions('string-negative-integer')['priority']); + $this->assertSame(1, $collection->getRoutesOptions('string-negative-integer')['priority']); } } diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index f781fde06a46..99e49c9941c5 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -62,26 +62,20 @@ protected function setUp(): void $this->request->setMethod('get'); } - //-------------------------------------------------------------------- - protected function tearDown(): void { } - //-------------------------------------------------------------------- - public function testEmptyURIMatchesDefaults() { $router = new Router($this->collection, $this->request); $router->handle(''); - $this->assertEquals($this->collection->getDefaultController(), $router->controllerName()); - $this->assertEquals($this->collection->getDefaultMethod(), $router->methodName()); + $this->assertSame($this->collection->getDefaultController(), $router->controllerName()); + $this->assertSame($this->collection->getDefaultMethod(), $router->methodName()); } - //-------------------------------------------------------------------- - public function testZeroAsURIPath() { $router = new Router($this->collection, $this->request); @@ -91,80 +85,66 @@ public function testZeroAsURIPath() $router->handle('0'); } - //-------------------------------------------------------------------- - public function testURIMapsToController() { $router = new Router($this->collection, $this->request); $router->handle('users'); - $this->assertEquals('\Users', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('\Users', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } - //-------------------------------------------------------------------- - public function testURIMapsToControllerAltMethod() { $router = new Router($this->collection, $this->request); $router->handle('posts'); - $this->assertEquals('\Blog', $router->controllerName()); - $this->assertEquals('posts', $router->methodName()); + $this->assertSame('\Blog', $router->controllerName()); + $this->assertSame('posts', $router->methodName()); } - //-------------------------------------------------------------------- - public function testURIMapsToNamespacedController() { $router = new Router($this->collection, $this->request); $router->handle('pages'); - $this->assertEquals('\App\Pages', $router->controllerName()); - $this->assertEquals('list_all', $router->methodName()); + $this->assertSame('\App\Pages', $router->controllerName()); + $this->assertSame('list_all', $router->methodName()); } - //-------------------------------------------------------------------- - public function testURIMapsParamsToBackReferences() { $router = new Router($this->collection, $this->request); $router->handle('posts/123'); - $this->assertEquals('show', $router->methodName()); - $this->assertEquals([123], $router->params()); + $this->assertSame('show', $router->methodName()); + $this->assertSame(['123'], $router->params()); } - //-------------------------------------------------------------------- - public function testURIMapsParamsToRearrangedBackReferences() { $router = new Router($this->collection, $this->request); $router->handle('posts/123/edit'); - $this->assertEquals('edit', $router->methodName()); - $this->assertEquals([123], $router->params()); + $this->assertSame('edit', $router->methodName()); + $this->assertSame(['123'], $router->params()); } - //-------------------------------------------------------------------- - public function testURIMapsParamsToBackReferencesWithUnused() { $router = new Router($this->collection, $this->request); $router->handle('books/123/sometitle/456'); - $this->assertEquals('show', $router->methodName()); - $this->assertEquals([456, 123], $router->params()); + $this->assertSame('show', $router->methodName()); + $this->assertSame(['456', '123'], $router->params()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/672 */ @@ -174,12 +154,10 @@ public function testURIMapsParamsWithMany() $router->handle('objects/123/sort/abc/FOO'); - $this->assertEquals('objectsSortCreate', $router->methodName()); - $this->assertEquals([123, 'abc', 'FOO'], $router->params()); + $this->assertSame('objectsSortCreate', $router->methodName()); + $this->assertSame(['123', 'abc', 'FOO'], $router->params()); } - //-------------------------------------------------------------------- - public function testClosures() { $router = new Router($this->collection, $this->request); @@ -191,35 +169,29 @@ public function testClosures() $expects = $closure(...$router->params()); $this->assertIsCallable($router->controllerName()); - $this->assertEquals($expects, '123-alpha'); + $this->assertSame($expects, '123-alpha'); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsControllerWithFileAndMethod() { $router = new Router($this->collection, $this->request); $router->autoRoute('myController/someMethod'); - $this->assertEquals('MyController', $router->controllerName()); - $this->assertEquals('someMethod', $router->methodName()); + $this->assertSame('MyController', $router->controllerName()); + $this->assertSame('someMethod', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsControllerWithFile() { $router = new Router($this->collection, $this->request); $router->autoRoute('myController'); - $this->assertEquals('MyController', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('MyController', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsControllerWithSubfolder() { $router = new Router($this->collection, $this->request); @@ -230,12 +202,10 @@ public function testAutoRouteFindsControllerWithSubfolder() rmdir(APPPATH . 'Controllers/Subfolder'); - $this->assertEquals('MyController', $router->controllerName()); - $this->assertEquals('someMethod', $router->methodName()); + $this->assertSame('MyController', $router->controllerName()); + $this->assertSame('someMethod', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsDashedSubfolder() { $router = new Router($this->collection, $this->request); @@ -247,13 +217,11 @@ public function testAutoRouteFindsDashedSubfolder() rmdir(APPPATH . 'Controllers/Dash_folder'); - $this->assertEquals('Dash_folder/', $router->directory()); - $this->assertEquals('Mycontroller', $router->controllerName()); - $this->assertEquals('somemethod', $router->methodName()); + $this->assertSame('Dash_folder/', $router->directory()); + $this->assertSame('Mycontroller', $router->controllerName()); + $this->assertSame('somemethod', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsDashedController() { $router = new Router($this->collection, $this->request); @@ -267,13 +235,11 @@ public function testAutoRouteFindsDashedController() unlink(APPPATH . 'Controllers/Dash_folder/Dash_controller.php'); rmdir(APPPATH . 'Controllers/Dash_folder'); - $this->assertEquals('Dash_folder/', $router->directory()); - $this->assertEquals('Dash_controller', $router->controllerName()); - $this->assertEquals('somemethod', $router->methodName()); + $this->assertSame('Dash_folder/', $router->directory()); + $this->assertSame('Dash_controller', $router->controllerName()); + $this->assertSame('somemethod', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsDashedMethod() { $router = new Router($this->collection, $this->request); @@ -287,13 +253,11 @@ public function testAutoRouteFindsDashedMethod() unlink(APPPATH . 'Controllers/Dash_folder/Dash_controller.php'); rmdir(APPPATH . 'Controllers/Dash_folder'); - $this->assertEquals('Dash_folder/', $router->directory()); - $this->assertEquals('Dash_controller', $router->controllerName()); - $this->assertEquals('dash_method', $router->methodName()); + $this->assertSame('Dash_folder/', $router->directory()); + $this->assertSame('Dash_controller', $router->controllerName()); + $this->assertSame('dash_method', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsDefaultDashFolder() { $router = new Router($this->collection, $this->request); @@ -305,13 +269,11 @@ public function testAutoRouteFindsDefaultDashFolder() rmdir(APPPATH . 'Controllers/Dash_folder'); - $this->assertEquals('Dash_folder/', $router->directory()); - $this->assertEquals('Home', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('Dash_folder/', $router->directory()); + $this->assertSame('Home', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsMByteDir() { $router = new Router($this->collection, $this->request); @@ -323,13 +285,11 @@ public function testAutoRouteFindsMByteDir() rmdir(APPPATH . 'Controllers/Φ'); - $this->assertEquals('Φ/', $router->directory()); - $this->assertEquals('Home', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('Φ/', $router->directory()); + $this->assertSame('Home', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteFindsMByteController() { $router = new Router($this->collection, $this->request); @@ -341,12 +301,10 @@ public function testAutoRouteFindsMByteController() unlink(APPPATH . 'Controllers/Φ'); - $this->assertEquals('Φ', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('Φ', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } - //-------------------------------------------------------------------- - public function testAutoRouteRejectsSingleDot() { $router = new Router($this->collection, $this->request); @@ -357,8 +315,6 @@ public function testAutoRouteRejectsSingleDot() $router->autoRoute('.'); } - //-------------------------------------------------------------------- - public function testAutoRouteRejectsDoubleDot() { $router = new Router($this->collection, $this->request); @@ -369,8 +325,6 @@ public function testAutoRouteRejectsDoubleDot() $router->autoRoute('..'); } - //-------------------------------------------------------------------- - public function testAutoRouteRejectsMidDot() { $router = new Router($this->collection, $this->request); @@ -381,8 +335,6 @@ public function testAutoRouteRejectsMidDot() $router->autoRoute('Foo.bar'); } - //-------------------------------------------------------------------- - public function testDetectsLocales() { $router = new Router($this->collection, $this->request); @@ -390,31 +342,27 @@ public function testDetectsLocales() $router->handle('fr/pages'); $this->assertTrue($router->hasLocale()); - $this->assertEquals('fr', $router->getLocale()); + $this->assertSame('fr', $router->getLocale()); } - //-------------------------------------------------------------------- - public function testRouteResource() { $router = new Router($this->collection, $this->request); $router->handle('Admin/Admins'); - $this->assertEquals('\App\Admin\Admins', $router->controllerName()); - $this->assertEquals('list_all', $router->methodName()); + $this->assertSame('\App\Admin\Admins', $router->controllerName()); + $this->assertSame('list_all', $router->methodName()); } - //-------------------------------------------------------------------- - public function testRouteWithLeadingSlash() { $router = new Router($this->collection, $this->request); $router->handle('some/slash'); - $this->assertEquals('\App\Slash', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('\App\Slash', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } //-------------------------------------------------------------------- @@ -438,7 +386,7 @@ public function testMatchedRouteOptions() $router->handle('foo'); - $this->assertEquals($router->getMatchedRouteOptions(), ['as' => 'login', 'foo' => 'baz']); + $this->assertSame($router->getMatchedRouteOptions(), ['as' => 'login', 'foo' => 'baz']); } public function testRouteWorksWithFilters() @@ -453,13 +401,11 @@ public function testRouteWorksWithFilters() $router->handle('foo/bar'); - $this->assertEquals('\TestController', $router->controllerName()); - $this->assertEquals('foobar', $router->methodName()); - $this->assertEquals('test', $router->getFilter()); + $this->assertSame('\TestController', $router->controllerName()); + $this->assertSame('foobar', $router->methodName()); + $this->assertSame('test', $router->getFilter()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1247 */ @@ -485,27 +431,27 @@ static function (RouteCollection $routes) { $router->handle('api/posts'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('index', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); $router->handle('api/posts/new'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('new', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('new', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); $router->handle('api/posts/50'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('show', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('show', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); $router->handle('api/posts/50/edit'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('edit', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('edit', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); // POST $this->collection->group(...$group); @@ -515,9 +461,9 @@ static function (RouteCollection $routes) { $router->handle('api/posts'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('create', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('create', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); // PUT $this->collection->group(...$group); @@ -527,9 +473,9 @@ static function (RouteCollection $routes) { $router->handle('api/posts/50'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('update', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('update', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); // PATCH $this->collection->group(...$group); @@ -539,9 +485,9 @@ static function (RouteCollection $routes) { $router->handle('api/posts/50'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('update', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('update', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); // DELETE $this->collection->group(...$group); @@ -551,13 +497,11 @@ static function (RouteCollection $routes) { $router->handle('api/posts/50'); - $this->assertEquals('\App\Controllers\Api\PostController', $router->controllerName()); - $this->assertEquals('delete', $router->methodName()); - $this->assertEquals('api-auth', $router->getFilter()); + $this->assertSame('\App\Controllers\Api\PostController', $router->controllerName()); + $this->assertSame('delete', $router->methodName()); + $this->assertSame('api-auth', $router->getFilter()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1240 */ @@ -573,24 +517,22 @@ public function testMatchesCorrectlyWithMixedVerbs() $router = new Router($this->collection, $this->request); $router->handle('/'); - $this->assertEquals('\Home', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('\Home', $router->controllerName()); + $this->assertSame('index', $router->methodName()); $router->handle('news'); - $this->assertEquals('\News', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('\News', $router->controllerName()); + $this->assertSame('index', $router->methodName()); $router->handle('news/daily'); - $this->assertEquals('\News', $router->controllerName()); - $this->assertEquals('view', $router->methodName()); + $this->assertSame('\News', $router->controllerName()); + $this->assertSame('view', $router->methodName()); $router->handle('about'); - $this->assertEquals('\Pages', $router->controllerName()); - $this->assertEquals('view', $router->methodName()); + $this->assertSame('\Pages', $router->controllerName()); + $this->assertSame('view', $router->methodName()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1354 */ @@ -603,8 +545,8 @@ public function testRouteOrder() $this->collection->setHTTPVerb('post'); $router->handle('auth'); - $this->assertEquals('\Main', $router->controllerName()); - $this->assertEquals('auth_post', $router->methodName()); + $this->assertSame('\Main', $router->controllerName()); + $this->assertSame('auth_post', $router->methodName()); } public function testRoutePriorityOrder() @@ -618,14 +560,14 @@ public function testRoutePriorityOrder() $this->collection->setHTTPVerb('get'); $router->handle('module'); - $this->assertEquals('\Main', $router->controllerName()); - $this->assertEquals('wildcard', $router->methodName()); + $this->assertSame('\Main', $router->controllerName()); + $this->assertSame('wildcard', $router->methodName()); $this->collection->setPrioritize(); $router->handle('module'); - $this->assertEquals('\Module', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('\Module', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } /** @@ -639,12 +581,10 @@ public function testTranslateURIDashes() $router->setTranslateURIDashes(true); - $this->assertEquals('\User_setting', $router->controllerName()); - $this->assertEquals('show_list', $router->methodName()); + $this->assertSame('\User_setting', $router->controllerName()); + $this->assertSame('show_list', $router->methodName()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1564 */ @@ -655,13 +595,11 @@ public function testTranslateURIDashesForParams() $router->handle('user-setting/2018-12-02'); - $this->assertEquals('\User_setting', $router->controllerName()); - $this->assertEquals('detail', $router->methodName()); - $this->assertEquals(['2018-12-02'], $router->params()); + $this->assertSame('\User_setting', $router->controllerName()); + $this->assertSame('detail', $router->methodName()); + $this->assertSame(['2018-12-02'], $router->params()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1564 */ @@ -672,12 +610,10 @@ public function testTranslateURIDashesForAutoRoute() $router->autoRoute('admin-user/show-list'); - $this->assertEquals('Admin_user', $router->controllerName()); - $this->assertEquals('show_list', $router->methodName()); + $this->assertSame('Admin_user', $router->controllerName()); + $this->assertSame('show_list', $router->methodName()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/2032 */ @@ -687,14 +623,14 @@ public function testAutoRouteMatchesZeroParams() $router->autoRoute('myController/someMethod/0/abc'); - $this->assertEquals('MyController', $router->controllerName()); - $this->assertEquals('someMethod', $router->methodName()); + $this->assertSame('MyController', $router->controllerName()); + $this->assertSame('someMethod', $router->methodName()); $expected = [ '0', 'abc', ]; - $this->assertEquals($expected, $router->params()); + $this->assertSame($expected, $router->params()); } /** @@ -704,12 +640,10 @@ public function testAutoRouteMethodEmpty() { $router = new Router($this->collection, $this->request); $router->handle('Home/'); - $this->assertEquals('Home', $router->controllerName()); - $this->assertEquals('index', $router->methodName()); + $this->assertSame('Home', $router->controllerName()); + $this->assertSame('index', $router->methodName()); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/3169 */ @@ -720,13 +654,13 @@ public function testRegularExpressionWithUnicode() $router = new Router($this->collection, $this->request); $router->handle('news/a0%E0%A6%80%E0%A7%BF-'); - $this->assertEquals('\News', $router->controllerName()); - $this->assertEquals('view', $router->methodName()); + $this->assertSame('\News', $router->controllerName()); + $this->assertSame('view', $router->methodName()); $expected = [ 'a0ঀ৿-', ]; - $this->assertEquals($expected, $router->params()); + $this->assertSame($expected, $router->params()); } /** @@ -740,13 +674,13 @@ public function testRegularExpressionPlaceholderWithUnicode() $router = new Router($this->collection, $this->request); $router->handle('news/a0%E0%A6%80%E0%A7%BF-'); - $this->assertEquals('\News', $router->controllerName()); - $this->assertEquals('view', $router->methodName()); + $this->assertSame('\News', $router->controllerName()); + $this->assertSame('view', $router->methodName()); $expected = [ 'a0ঀ৿-', ]; - $this->assertEquals($expected, $router->params()); + $this->assertSame($expected, $router->params()); } public function testRouterPriorDirectory() @@ -756,9 +690,9 @@ public function testRouterPriorDirectory() $router->setDirectory('foo/bar/baz', false, true); $router->handle('Some_controller/some_method/param1/param2/param3'); - $this->assertEquals('foo/bar/baz/', $router->directory()); - $this->assertEquals('Some_controller', $router->controllerName()); - $this->assertEquals('some_method', $router->methodName()); + $this->assertSame('foo/bar/baz/', $router->directory()); + $this->assertSame('Some_controller', $router->controllerName()); + $this->assertSame('some_method', $router->methodName()); } public function testSetDirectoryValid() @@ -766,7 +700,7 @@ public function testSetDirectoryValid() $router = new Router($this->collection, $this->request); $router->setDirectory('foo/bar/baz', false, true); - $this->assertEquals('foo/bar/baz/', $router->directory()); + $this->assertSame('foo/bar/baz/', $router->directory()); } public function testSetDirectoryInvalid() @@ -777,6 +711,6 @@ public function testSetDirectoryInvalid() $internal = $this->getPrivateProperty($router, 'directory'); $this->assertNull($internal); - $this->assertEquals('', $router->directory()); + $this->assertSame('', $router->directory()); } } diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index bee38f996594..0743f4b36e69 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -36,8 +36,8 @@ public function testBasicConfigIsSaved() $hash = $security->getHash(); - $this->assertEquals(32, strlen($hash)); - $this->assertEquals('csrf_test_name', $security->getTokenName()); + $this->assertSame(32, strlen($hash)); + $this->assertSame('csrf_test_name', $security->getTokenName()); } public function testHashIsReadFromCookie() @@ -46,7 +46,7 @@ public function testHashIsReadFromCookie() $security = new Security(new MockAppConfig()); - $this->assertEquals('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); + $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); } public function testCSRFVerifySetsCookieWhenNotPOST() @@ -57,7 +57,7 @@ public function testCSRFVerifySetsCookieWhenNotPOST() $security->verify(new Request(new MockAppConfig())); - $this->assertEquals($_COOKIE['csrf_cookie_name'], $security->getHash()); + $this->assertSame($_COOKIE['csrf_cookie_name'], $security->getHash()); } public function testCSRFVerifyPostThrowsExceptionOnNoMatch() @@ -156,7 +156,7 @@ public function testSanitizeFilename() $filename = './'; - $this->assertEquals('foo', $security->sanitizeFilename($filename)); + $this->assertSame('foo', $security->sanitizeFilename($filename)); } public function testRegenerateWithFalseSecurityRegenerateProperty() diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index 09f080adf7eb..ab49c2830200 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -86,7 +86,7 @@ public function testCanSetSingleValue() $session->set('foo', 'bar'); - $this->assertEquals('bar', $_SESSION['foo']); + $this->assertSame('bar', $_SESSION['foo']); } public function testCanSetArray() @@ -99,8 +99,8 @@ public function testCanSetArray() 'bar' => 'baz', ]); - $this->assertEquals('bar', $_SESSION['foo']); - $this->assertEquals('baz', $_SESSION['bar']); + $this->assertSame('bar', $_SESSION['foo']); + $this->assertSame('baz', $_SESSION['bar']); $this->assertArrayNotHasKey('__ci_vars', $_SESSION); } @@ -119,7 +119,7 @@ public function testCanSerializeArray() ]; $session->set(['_ci_old_input' => ['location' => $locations]]); - $this->assertEquals($locations, $session->get('_ci_old_input')['location']); + $this->assertSame($locations, $session->get('_ci_old_input')['location']); } public function testGetSimpleKey() @@ -129,7 +129,7 @@ public function testGetSimpleKey() $session->set('foo', 'bar'); - $this->assertEquals('bar', $session->get('foo')); + $this->assertSame('bar', $session->get('foo')); } public function testGetReturnsNullWhenNotFound() @@ -161,7 +161,7 @@ public function testGetReturnsEmptyArrayWhenWithXmlHttpRequest() $session = $this->getInstance(); $session->start(); - $this->assertEquals([], $session->get()); + $this->assertSame([], $session->get()); } public function testGetReturnsItemValueisZero() @@ -199,7 +199,7 @@ public function testGetAsProperty() $session->set('foo', 'bar'); - $this->assertEquals('bar', $session->foo); + $this->assertSame('bar', $session->foo); } public function testGetAsNormal() @@ -209,7 +209,7 @@ public function testGetAsNormal() $session->set('foo', 'bar'); - $this->assertEquals('bar', $_SESSION['foo']); + $this->assertSame('bar', $_SESSION['foo']); } public function testHasReturnsTrueOnSuccess() @@ -260,7 +260,7 @@ public function testPushNewValueIntoArraySessionValue() $session->set('hobbies', ['cooking' => 'baking']); $session->push('hobbies', ['sport' => 'tennis']); - $this->assertEquals( + $this->assertSame( [ 'cooking' => 'baking', 'sport' => 'tennis', @@ -307,7 +307,7 @@ public function testSetMagicMethod() $session->foo = 'bar'; $this->assertArrayHasKey('foo', $_SESSION); - $this->assertEquals('bar', $_SESSION['foo']); + $this->assertSame('bar', $_SESSION['foo']); } public function testCanFlashData() @@ -318,13 +318,13 @@ public function testCanFlashData() $session->setFlashdata('foo', 'bar'); $this->assertTrue($session->has('foo')); - $this->assertEquals('new', $_SESSION['__ci_vars']['foo']); + $this->assertSame('new', $_SESSION['__ci_vars']['foo']); // Should reset the 'new' to 'old' $session->start(); $this->assertTrue($session->has('foo')); - $this->assertEquals('old', $_SESSION['__ci_vars']['foo']); + $this->assertSame('old', $_SESSION['__ci_vars']['foo']); // Should no longer be available $session->start(); @@ -343,9 +343,9 @@ public function testCanFlashArray() ]); $this->assertTrue($session->has('foo')); - $this->assertEquals('new', $_SESSION['__ci_vars']['foo']); + $this->assertSame('new', $_SESSION['__ci_vars']['foo']); $this->assertTrue($session->has('bar')); - $this->assertEquals('new', $_SESSION['__ci_vars']['bar']); + $this->assertSame('new', $_SESSION['__ci_vars']['bar']); } public function testKeepFlashData() @@ -356,23 +356,23 @@ public function testKeepFlashData() $session->setFlashdata('foo', 'bar'); $this->assertTrue($session->has('foo')); - $this->assertEquals('new', $_SESSION['__ci_vars']['foo']); + $this->assertSame('new', $_SESSION['__ci_vars']['foo']); // Should reset the 'new' to 'old' $session->start(); $this->assertTrue($session->has('foo')); - $this->assertEquals('old', $_SESSION['__ci_vars']['foo']); + $this->assertSame('old', $_SESSION['__ci_vars']['foo']); $session->keepFlashdata('foo'); - $this->assertEquals('new', $_SESSION['__ci_vars']['foo']); + $this->assertSame('new', $_SESSION['__ci_vars']['foo']); // Should no longer be available $session->start(); $this->assertTrue($session->has('foo')); - $this->assertEquals('old', $_SESSION['__ci_vars']['foo']); + $this->assertSame('old', $_SESSION['__ci_vars']['foo']); } public function testUnmarkFlashDataRemovesData() @@ -465,7 +465,7 @@ public function testGetTestDataReturnsAll() $session->setTempdata($data); $session->set('baz', 'ballywhoo'); - $this->assertEquals($data, $session->getTempdata()); + $this->assertSame($data, $session->getTempdata()); } public function testGetTestDataReturnsSingle() @@ -480,7 +480,7 @@ public function testGetTestDataReturnsSingle() $session->setTempdata($data); - $this->assertEquals('bar', $session->getTempdata('foo')); + $this->assertSame('bar', $session->getTempdata('foo')); } public function testRemoveTempDataActuallyDeletes() @@ -496,7 +496,7 @@ public function testRemoveTempDataActuallyDeletes() $session->setTempdata($data); $session->removeTempdata('foo'); - $this->assertEquals(['bar' => 'baz'], $session->getTempdata()); + $this->assertSame(['bar' => 'baz'], $session->getTempdata()); } public function testUnMarkTempDataSingle() @@ -512,7 +512,7 @@ public function testUnMarkTempDataSingle() $session->setTempdata($data); $session->unmarkTempdata('foo'); - $this->assertEquals(['bar' => 'baz'], $session->getTempdata()); + $this->assertSame(['bar' => 'baz'], $session->getTempdata()); } public function testUnMarkTempDataArray() @@ -528,7 +528,7 @@ public function testUnMarkTempDataArray() $session->setTempdata($data); $session->unmarkTempdata(['foo', 'bar']); - $this->assertEquals([], $session->getTempdata()); + $this->assertSame([], $session->getTempdata()); } public function testGetTempdataKeys() @@ -544,7 +544,7 @@ public function testGetTempdataKeys() $session->setTempdata($data); $session->set('baz', 'ballywhoo'); - $this->assertEquals(['foo', 'bar'], $session->getTempKeys()); + $this->assertSame(['foo', 'bar'], $session->getTempKeys()); } public function testGetDotKey() @@ -552,7 +552,7 @@ public function testGetDotKey() $session = $this->getInstance(); $session->start(); $session->set('test.1', 'value'); - $this->assertEquals('value', $session->get('test.1')); + $this->assertSame('value', $session->get('test.1')); } public function testLaxSameSite() diff --git a/tests/system/Test/BootstrapFCPATHTest.php b/tests/system/Test/BootstrapFCPATHTest.php index aadf61ef5ab4..5bff32d359b0 100644 --- a/tests/system/Test/BootstrapFCPATHTest.php +++ b/tests/system/Test/BootstrapFCPATHTest.php @@ -41,7 +41,7 @@ public function testSetFCPATH() { $result1 = $this->readOutput($this->file1); $correctPath = $this->correctFCPATH(); - $this->assertEquals($correctPath, $result1); + $this->assertSame($correctPath, $result1); } private function correctFCPATH() diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index b9f261abed5c..846e759b00c3 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -83,7 +83,7 @@ public function testPopcornIndex2() ->execute('index'); $body = $result->response()->getBody(); - $this->assertEquals('Hi there', $body); + $this->assertSame('Hi there', $body); } public function testPopcornFailure() @@ -94,7 +94,7 @@ public function testPopcornFailure() ->controller(Popcorn::class) ->execute('pop'); - $this->assertEquals(567, $result->response()->getStatusCode()); + $this->assertSame(567, $result->response()->getStatusCode()); } public function testPopcornException() @@ -105,7 +105,7 @@ public function testPopcornException() ->controller(Popcorn::class) ->execute('popper'); - $this->assertEquals(500, $result->response()->getStatusCode()); + $this->assertSame(500, $result->response()->getStatusCode()); } public function testPopcornIndexWithSupport() @@ -124,7 +124,7 @@ public function testPopcornIndexWithSupport() ->execute('index'); $body = $result->response()->getBody(); - $this->assertEquals('Hi there', $body); + $this->assertSame('Hi there', $body); } public function testRequestPassthrough() @@ -136,7 +136,7 @@ public function testRequestPassthrough() ->execute('popper'); $req = $result->request(); - $this->assertEquals('get', $req->getMethod()); + $this->assertSame('get', $req->getMethod()); } public function testFailureResponse() @@ -148,7 +148,7 @@ public function testFailureResponse() ->execute('oops'); $this->assertFalse($result->isOK()); - $this->assertEquals(401, $result->response()->getStatusCode()); + $this->assertSame(401, $result->response()->getStatusCode()); } public function testEmptyResponse() @@ -208,7 +208,7 @@ public function testResponseOverriding() ->execute('index3'); $response = json_decode($result->response()->getBody()); - $this->assertEquals('en', $response->lang); + $this->assertSame('en', $response->lang); } /** diff --git a/tests/system/Test/DOMParserTest.php b/tests/system/Test/DOMParserTest.php index 98474cb9f4c5..7eee8d5612e5 100644 --- a/tests/system/Test/DOMParserTest.php +++ b/tests/system/Test/DOMParserTest.php @@ -26,7 +26,7 @@ public function testCanRoundTripHTML() $expected = '' . "\n" . '

Hello

'; - $this->assertEquals($expected . "\n", $dom->withString($html)->getBody()); + $this->assertSame($expected . "\n", $dom->withString($html)->getBody()); } public function testParseSelectorWithID() @@ -35,8 +35,8 @@ public function testParseSelectorWithID() $selector = $dom->parseSelector('div#row'); - $this->assertEquals('div', $selector['tag']); - $this->assertEquals('row', $selector['id']); + $this->assertSame('div', $selector['tag']); + $this->assertSame('row', $selector['id']); } public function testParseSelectorWithClass() @@ -45,8 +45,8 @@ public function testParseSelectorWithClass() $selector = $dom->parseSelector('div.row'); - $this->assertEquals('div', $selector['tag']); - $this->assertEquals('row', $selector['class']); + $this->assertSame('div', $selector['tag']); + $this->assertSame('row', $selector['class']); } public function testParseSelectorWithClassMultiple() @@ -55,9 +55,9 @@ public function testParseSelectorWithClassMultiple() $selector = $dom->parseSelector('div.row.another'); - $this->assertEquals('div', $selector['tag']); + $this->assertSame('div', $selector['tag']); // Only parses the first class - $this->assertEquals('row', $selector['class']); + $this->assertSame('row', $selector['class']); } public function testParseSelectorWithAttribute() @@ -66,8 +66,8 @@ public function testParseSelectorWithAttribute() $selector = $dom->parseSelector('a[ href = http://example.com ]'); - $this->assertEquals('a', $selector['tag']); - $this->assertEquals(['href' => 'http://example.com'], $selector['attr']); + $this->assertSame('a', $selector['tag']); + $this->assertSame(['href' => 'http://example.com'], $selector['attr']); } public function provideText() @@ -394,7 +394,7 @@ public function testSeeAttribute() $path = '[ name = user ]'; $selector = $dom->parseSelector($path); - $this->assertEquals(['name' => 'user'], $selector['attr']); + $this->assertSame(['name' => 'user'], $selector['attr']); $html = '
George
'; $dom->withString($html); diff --git a/tests/system/Test/FabricatorTest.php b/tests/system/Test/FabricatorTest.php index 4d8e39693c32..c92ac6fb7839 100644 --- a/tests/system/Test/FabricatorTest.php +++ b/tests/system/Test/FabricatorTest.php @@ -65,21 +65,21 @@ public function testConstructorSetsFormatters() { $fabricator = new Fabricator(UserModel::class, $this->formatters); - $this->assertEquals($this->formatters, $fabricator->getFormatters()); + $this->assertSame($this->formatters, $fabricator->getFormatters()); } public function testConstructorGuessesFormatters() { $fabricator = new Fabricator(UserModel::class, null); - $this->assertEquals($this->formatters, $fabricator->getFormatters()); + $this->assertSame($this->formatters, $fabricator->getFormatters()); } public function testConstructorDefaultsToAppLocale() { $fabricator = new Fabricator(UserModel::class); - $this->assertEquals(config('App')->defaultLocale, $fabricator->getLocale()); + $this->assertSame(config('App')->defaultLocale, $fabricator->getLocale()); } public function testConstructorUsesProvidedLocale() @@ -88,7 +88,7 @@ public function testConstructorUsesProvidedLocale() $fabricator = new Fabricator(UserModel::class, null, $locale); - $this->assertEquals($locale, $fabricator->getLocale()); + $this->assertSame($locale, $fabricator->getLocale()); } //-------------------------------------------------------------------- @@ -131,7 +131,7 @@ public function testSetFormattersChangesFormatters() $fabricator->setFormatters($formatters); - $this->assertEquals($formatters, $fabricator->getFormatters()); + $this->assertSame($formatters, $fabricator->getFormatters()); } public function testSetFormattersDetectsFormatters() @@ -141,7 +141,7 @@ public function testSetFormattersDetectsFormatters() $fabricator->setFormatters(); - $this->assertEquals($this->formatters, $fabricator->getFormatters()); + $this->assertSame($this->formatters, $fabricator->getFormatters()); } public function testDetectFormattersDetectsFormatters() @@ -153,7 +153,7 @@ public function testDetectFormattersDetectsFormatters() $method(); - $this->assertEquals($this->formatters, $fabricator->getFormatters()); + $this->assertSame($this->formatters, $fabricator->getFormatters()); } //-------------------------------------------------------------------- @@ -165,7 +165,7 @@ public function testSetOverridesSets() $fabricator->setOverrides($overrides); - $this->assertEquals($overrides, $fabricator->getOverrides()); + $this->assertSame($overrides, $fabricator->getOverrides()); } public function testSetOverridesDefaultPersists() @@ -176,7 +176,7 @@ public function testSetOverridesDefaultPersists() $fabricator->setOverrides($overrides); $fabricator->getOverrides(); - $this->assertEquals($overrides, $fabricator->getOverrides()); + $this->assertSame($overrides, $fabricator->getOverrides()); } public function testSetOverridesOnce() @@ -187,7 +187,7 @@ public function testSetOverridesOnce() $fabricator->setOverrides($overrides, false); $fabricator->getOverrides(); - $this->assertEquals([], $fabricator->getOverrides()); + $this->assertSame([], $fabricator->getOverrides()); } //-------------------------------------------------------------------- @@ -201,7 +201,7 @@ public function testGuessFormattersReturnsActual() $field = 'catchPhrase'; $formatter = $method($field); - $this->assertEquals($field, $formatter); + $this->assertSame($field, $formatter); } public function testGuessFormattersFieldReturnsDateFormat() @@ -213,7 +213,7 @@ public function testGuessFormattersFieldReturnsDateFormat() $field = 'created_at'; $formatter = $method($field); - $this->assertEquals('date', $formatter); + $this->assertSame('date', $formatter); } public function testGuessFormattersPrimaryReturnsNumberBetween() @@ -225,7 +225,7 @@ public function testGuessFormattersPrimaryReturnsNumberBetween() $field = 'id'; $formatter = $method($field); - $this->assertEquals('numberBetween', $formatter); + $this->assertSame('numberBetween', $formatter); } public function testGuessFormattersMatchesPartial() @@ -237,7 +237,7 @@ public function testGuessFormattersMatchesPartial() $field = 'business_email'; $formatter = $method($field); - $this->assertEquals('email', $formatter); + $this->assertSame('email', $formatter); } public function testGuessFormattersFallback() @@ -249,7 +249,7 @@ public function testGuessFormattersFallback() $field = 'zaboomafoo'; $formatter = $method($field); - $this->assertEquals($fabricator->defaultFormatter, $formatter); + $this->assertSame($fabricator->defaultFormatter, $formatter); } //-------------------------------------------------------------------- @@ -272,7 +272,7 @@ public function testMakeArrayUsesOverrides() $result = $fabricator->makeArray(); - $this->assertEquals($overrides['name'], $result['name']); + $this->assertSame($overrides['name'], $result['name']); } public function testMakeArrayReturnsValidData() @@ -281,7 +281,7 @@ public function testMakeArrayReturnsValidData() $result = $fabricator->makeArray(); - $this->assertEquals($result['email'], filter_var($result['email'], FILTER_VALIDATE_EMAIL)); + $this->assertSame($result['email'], filter_var($result['email'], FILTER_VALIDATE_EMAIL)); } public function testMakeArrayUsesFakeMethod() @@ -290,7 +290,7 @@ public function testMakeArrayUsesFakeMethod() $result = $fabricator->makeArray(); - $this->assertEquals($result['name'], filter_var($result['name'], FILTER_VALIDATE_IP)); + $this->assertSame($result['name'], filter_var($result['name'], FILTER_VALIDATE_IP)); } //-------------------------------------------------------------------- @@ -342,7 +342,7 @@ public function testMakeObjectUsesOverrides() $result = $fabricator->makeObject(); - $this->assertEquals($overrides['name'], $result->name); + $this->assertSame($overrides['name'], $result->name); } public function testMakeObjectReturnsValidData() @@ -351,7 +351,7 @@ public function testMakeObjectReturnsValidData() $result = $fabricator->makeObject(); - $this->assertEquals($result->email, filter_var($result->email, FILTER_VALIDATE_EMAIL)); + $this->assertSame($result->email, filter_var($result->email, FILTER_VALIDATE_EMAIL)); } public function testMakeObjectUsesFakeMethod() @@ -360,7 +360,7 @@ public function testMakeObjectUsesFakeMethod() $result = $fabricator->makeObject(); - $this->assertEquals($result->name, filter_var($result->name, FILTER_VALIDATE_IP)); + $this->assertSame($result->name, filter_var($result->name, FILTER_VALIDATE_IP)); } //-------------------------------------------------------------------- @@ -427,7 +427,7 @@ public function testSetCountReturnsCount() { $result = Fabricator::setCount('goblins', 42); - $this->assertEquals(42, $result); + $this->assertSame(42, $result); } public function testSetCountSetsValue() @@ -435,14 +435,14 @@ public function testSetCountSetsValue() Fabricator::setCount('trolls', 3); $result = Fabricator::getCount('trolls'); - $this->assertEquals(3, $result); + $this->assertSame(3, $result); } public function testGetCountNewTableReturnsZero() { $result = Fabricator::getCount('gremlins'); - $this->assertEquals(0, $result); + $this->assertSame(0, $result); } public function testUpCountIncrementsValue() @@ -450,7 +450,7 @@ public function testUpCountIncrementsValue() Fabricator::setCount('orcs', 12); Fabricator::upCount('orcs'); - $this->assertEquals(13, Fabricator::getCount('orcs')); + $this->assertSame(13, Fabricator::getCount('orcs')); } public function testUpCountReturnsValue() @@ -458,14 +458,14 @@ public function testUpCountReturnsValue() Fabricator::setCount('hobgoblins', 12); $result = Fabricator::upCount('hobgoblins'); - $this->assertEquals(13, $result); + $this->assertSame(13, $result); } public function testUpCountNewTableReturnsOne() { $result = Fabricator::upCount('ogres'); - $this->assertEquals(1, $result); + $this->assertSame(1, $result); } public function testDownCountDecrementsValue() @@ -473,7 +473,7 @@ public function testDownCountDecrementsValue() Fabricator::setCount('orcs', 12); Fabricator::downCount('orcs'); - $this->assertEquals(11, Fabricator::getCount('orcs')); + $this->assertSame(11, Fabricator::getCount('orcs')); } public function testDownCountReturnsValue() @@ -481,14 +481,14 @@ public function testDownCountReturnsValue() Fabricator::setCount('hobgoblins', 12); $result = Fabricator::downCount('hobgoblins'); - $this->assertEquals(11, $result); + $this->assertSame(11, $result); } public function testDownCountNewTableReturnsNegativeOne() { $result = Fabricator::downCount('ogres'); - $this->assertEquals(-1, $result); + $this->assertSame(-1, $result); } public function testResetClearsValue() @@ -496,6 +496,6 @@ public function testResetClearsValue() Fabricator::setCount('giants', 1000); Fabricator::resetCounts(); - $this->assertEquals(0, Fabricator::getCount('giants')); + $this->assertSame(0, Fabricator::getCount('giants')); } } diff --git a/tests/system/Test/FeatureTestTraitTest.php b/tests/system/Test/FeatureTestTraitTest.php index 3e5d9a1abb08..27eb76a3f500 100644 --- a/tests/system/Test/FeatureTestTraitTest.php +++ b/tests/system/Test/FeatureTestTraitTest.php @@ -59,8 +59,8 @@ static function () { $this->assertInstanceOf(TestResponse::class, $response); $this->assertInstanceOf(Response::class, $response->response()); $this->assertTrue($response->isOK()); - $this->assertEquals('Hello Earth', $response->response()->getBody()); - $this->assertEquals(200, $response->response()->getStatusCode()); + $this->assertSame('Hello Earth', $response->response()->getBody()); + $this->assertSame(200, $response->response()->getStatusCode()); } public function testCallPost() @@ -369,7 +369,7 @@ public function testSetupRequestBodyWithXml() bar '; - $this->assertEquals($expectedXml, $request->getBody()); + $this->assertSame($expectedXml, $request->getBody()); $this->assertTrue($request->header('Content-Type')->getValue() === 'application/xml'); } @@ -379,6 +379,6 @@ public function testSetupRequestBodyWithBody() $request = $this->withBody('test')->setRequestBody($request); - $this->assertEquals('test', $request->getBody()); + $this->assertSame('test', $request->getBody()); } } diff --git a/tests/system/Test/FilterTestTraitTest.php b/tests/system/Test/FilterTestTraitTest.php index 149426b4fa2f..b7567ae437a0 100644 --- a/tests/system/Test/FilterTestTraitTest.php +++ b/tests/system/Test/FilterTestTraitTest.php @@ -67,14 +67,14 @@ public function testCallerUsesClonedInstance() $this->assertObjectNotHasAttribute('url', $this->request); $this->assertObjectHasAttribute('url', $result); - $this->assertEquals('http://hellowworld.com', $result->url); + $this->assertSame('http://hellowworld.com', $result->url); } public function testGetFiltersForRoute() { $result = $this->getFiltersForRoute('/', 'before'); - $this->assertEquals(['test-customfilter'], $result); + $this->assertSame(['test-customfilter'], $result); } public function testAssertFilter() diff --git a/tests/system/Test/ReflectionHelperTest.php b/tests/system/Test/ReflectionHelperTest.php index 6565bcccb09c..23ccb3605098 100644 --- a/tests/system/Test/ReflectionHelperTest.php +++ b/tests/system/Test/ReflectionHelperTest.php @@ -11,14 +11,14 @@ public function testGetPrivatePropertyWithObject() { $obj = new __TestForReflectionHelper(); $actual = $this->getPrivateProperty($obj, 'private'); - $this->assertEquals('secret', $actual); + $this->assertSame('secret', $actual); } public function testGetPrivatePropertyWithObjectStaticCall() { $obj = new __TestForReflectionHelper(); $actual = CIUnitTestCase::getPrivateProperty($obj, 'private'); - $this->assertEquals('secret', $actual); + $this->assertSame('secret', $actual); } public function testGetPrivatePropertyWithStatic() @@ -27,7 +27,7 @@ public function testGetPrivatePropertyWithStatic() __TestForReflectionHelper::class, 'static_private' ); - $this->assertEquals('xyz', $actual); + $this->assertSame('xyz', $actual); } public function testSetPrivatePropertyWithObject() @@ -38,7 +38,7 @@ public function testSetPrivatePropertyWithObject() 'private', 'open' ); - $this->assertEquals('open', $obj->getPrivate()); + $this->assertSame('open', $obj->getPrivate()); } public function testSetPrivatePropertyWithStatic() @@ -48,7 +48,7 @@ public function testSetPrivatePropertyWithStatic() 'static_private', 'abc' ); - $this->assertEquals( + $this->assertSame( 'abc', __TestForReflectionHelper::getStaticPrivate() ); @@ -61,7 +61,7 @@ public function testGetPrivateMethodInvokerWithObject() $obj, 'privateMethod' ); - $this->assertEquals( + $this->assertSame( 'private param1param2', $method('param1', 'param2') ); @@ -73,7 +73,7 @@ public function testGetPrivateMethodInvokerWithStatic() __TestForReflectionHelper::class, 'privateStaticMethod' ); - $this->assertEquals( + $this->assertSame( 'private_static param1param2', $method('param1', 'param2') ); diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index 1295e547dece..6c0306b856df 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -26,7 +26,7 @@ public function testGetPrivatePropertyWithObject() { $obj = new __TestForReflectionHelper(); $actual = $this->getPrivateProperty($obj, 'private'); - $this->assertEquals('secret', $actual); + $this->assertSame('secret', $actual); } //-------------------------------------------------------------------- @@ -58,7 +58,7 @@ public function testStreamFilter() $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); CLI::write('first.'); $expected = "first.\n"; - $this->assertEquals($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, CITestStreamFilter::$buffer); stream_filter_remove($this->stream_filter); } diff --git a/tests/system/Test/TestResponseTest.php b/tests/system/Test/TestResponseTest.php index 73d8e8010410..83050190b791 100644 --- a/tests/system/Test/TestResponseTest.php +++ b/tests/system/Test/TestResponseTest.php @@ -38,7 +38,7 @@ public function testIsOK(int $code, bool $isOk) $this->getTestResponse('Hello World'); $this->response->setStatusCode($code); - $this->assertEquals($isOk, $this->testResponse->isOK()); + $this->assertSame($isOk, $this->testResponse->isOK()); } /** @@ -167,7 +167,7 @@ public function testAssertRedirectSuccessWithoutRedirectResponse() $this->assertFalse($this->testResponse->response() instanceof RedirectResponse); $this->assertTrue($this->testResponse->isRedirect()); $this->testResponse->assertRedirect(); - $this->assertEquals('foo/bar', $this->testResponse->getRedirectUrl()); + $this->assertSame('foo/bar', $this->testResponse->getRedirectUrl()); } public function testGetRedirectUrlReturnsUrl() @@ -176,7 +176,7 @@ public function testGetRedirectUrlReturnsUrl() $this->testResponse->setResponse(new RedirectResponse(new App())); $this->testResponse->response()->redirect('foo/bar'); - $this->assertEquals('foo/bar', $this->testResponse->getRedirectUrl()); + $this->assertSame('foo/bar', $this->testResponse->getRedirectUrl()); } public function testGetRedirectUrlReturnsNull() @@ -300,7 +300,7 @@ public function testGetJSON() $this->getTestResponse(['foo' => 'bar']); $formatter = Services::format()->getFormatter('application/json'); - $this->assertEquals($formatter->format(['foo' => 'bar']), $this->testResponse->getJSON()); + $this->assertSame($formatter->format(['foo' => 'bar']), $this->testResponse->getJSON()); } public function testEmptyJSON() @@ -309,7 +309,7 @@ public function testEmptyJSON() $this->response->setJSON('', true); // this should be "" - json_encode(''); - $this->assertEquals('""', $this->testResponse->getJSON()); + $this->assertSame('""', $this->testResponse->getJSON()); } public function testFalseJSON() @@ -318,7 +318,7 @@ public function testFalseJSON() $this->response->setJSON(false, true); // this should be FALSE - json_encode(false) - $this->assertEquals('false', $this->testResponse->getJSON()); + $this->assertSame('false', $this->testResponse->getJSON()); } public function testTrueJSON() @@ -327,7 +327,7 @@ public function testTrueJSON() $this->response->setJSON(true, true); // this should be TRUE - json_encode(true) - $this->assertEquals('true', $this->testResponse->getJSON()); + $this->assertSame('true', $this->testResponse->getJSON()); } public function testInvalidJSON() @@ -345,7 +345,7 @@ public function testGetXML() $this->getTestResponse(['foo' => 'bar']); $formatter = Services::format()->getFormatter('application/xml'); - $this->assertEquals($formatter->format(['foo' => 'bar']), $this->testResponse->getXML()); + $this->assertSame($formatter->format(['foo' => 'bar']), $this->testResponse->getXML()); } public function testJsonFragment() diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index a3f1bf412558..19a9f1641d74 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -22,14 +22,14 @@ public function testTokenTime() $throttler = new Throttler($this->cache); // tokenTime should be 0 to start - $this->assertEquals(0, $throttler->getTokenTime()); + $this->assertSame(0, $throttler->getTokenTime()); // set $rate $rate = 1; // allow 1 request per minute // first check just creates a bucket, so tokenTime should be 0 $throttler->check('127.0.0.1', $rate, MINUTE); - $this->assertEquals(0, $throttler->getTokenTime()); + $this->assertSame(0, $throttler->getTokenTime()); // additional check affects tokenTime, so tokenTime should be 1 or greater $throttler->check('127.0.0.1', $rate, MINUTE); @@ -41,7 +41,7 @@ public function testIPSavesBucket() $throttler = new Throttler($this->cache); $this->assertTrue($throttler->check('127.0.0.1', 60, MINUTE)); - $this->assertEquals(59, $this->cache->get('throttler_127.0.0.1')); + $this->assertSame(59, $this->cache->get('throttler_127.0.0.1')); } public function testRemove() @@ -68,7 +68,7 @@ public function testDecrementsValues() $throttler->check('127.0.0.1', 60, MINUTE); $throttler->check('127.0.0.1', 60, MINUTE); - $this->assertEquals(57, $this->cache->get('throttler_127.0.0.1')); + $this->assertSame(57, $this->cache->get('throttler_127.0.0.1')); } public function testReturnsFalseIfBucketEmpty() @@ -87,7 +87,7 @@ public function testCosting() $rate = 60; // allow 1 per second $cost = 10; $throttler->check('127.0.0.1', $rate, MINUTE, $cost); - $this->assertEquals($rate - $cost, $this->cache->get('throttler_127.0.0.1')); + $this->assertSame($rate - $cost, $this->cache->get('throttler_127.0.0.1')); } public function testUnderload() @@ -96,12 +96,12 @@ public function testUnderload() $rate = 120; // allow 2 per second, in theory $throttler->check('127.0.0.1', $rate, MINUTE); - $this->assertEquals($rate - 1, $this->cache->get('throttler_127.0.0.1')); + $this->assertSame($rate - 1, $this->cache->get('throttler_127.0.0.1')); $throttler->setTestTime(strtotime('+2 seconds')); // should be more tokens available $this->assertTrue($throttler->check('127.0.0.1', $rate, MINUTE)); // but the bucket should not be over-filled - $this->assertEquals($rate - 1, $this->cache->get('throttler_127.0.0.1')); + $this->assertSame($rate - 1, $this->cache->get('throttler_127.0.0.1')); } public function testOverload() @@ -130,11 +130,11 @@ public function testFlooding() // Should be empty now. $this->assertFalse($throttler->check('127.0.0.1', $rate, MINUTE, $cost)); - $this->assertEquals(0, $this->cache->get('throttler_127.0.0.1')); + $this->assertSame(0, $this->cache->get('throttler_127.0.0.1')); $throttler = $throttler->setTestTime(strtotime('+10 seconds')); $this->assertTrue($throttler->check('127.0.0.1', $rate, MINUTE, 0)); - $this->assertEquals(10, round($this->cache->get('throttler_127.0.0.1'))); + $this->assertSame(10.0, round($this->cache->get('throttler_127.0.0.1'))); } } diff --git a/tests/system/Typography/TypographyTest.php b/tests/system/Typography/TypographyTest.php index 9ecf59d7b12c..9ed3646a07d5 100644 --- a/tests/system/Typography/TypographyTest.php +++ b/tests/system/Typography/TypographyTest.php @@ -19,7 +19,7 @@ protected function setUp(): void public function testAutoTypographyEmptyString() { - $this->assertEquals('', $this->typography->autoTypography('')); + $this->assertSame('', $this->typography->autoTypography('')); } public function testAutoTypographyNormalString() @@ -30,7 +30,7 @@ public function testAutoTypographyNormalString() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str)); + $this->assertSame($expect, $this->typography->autoTypography($str)); } } @@ -42,7 +42,7 @@ public function testAutoTypographyMultipleSpaces() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str)); + $this->assertSame($expect, $this->typography->autoTypography($str)); } } @@ -62,7 +62,7 @@ public function testAutoTypographyLineBreaks() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str)); + $this->assertSame($expect, $this->typography->autoTypography($str)); } } @@ -82,7 +82,7 @@ public function testAutoTypographyReduceLineBreaks() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str, true)); + $this->assertSame($expect, $this->typography->autoTypography($str, true)); } } @@ -95,7 +95,7 @@ public function testAutoTypographyHTMLComment() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str)); + $this->assertSame($expect, $this->typography->autoTypography($str)); } } @@ -110,7 +110,7 @@ public function testAutoTypographyHTMLTags() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str)); + $this->assertSame($expect, $this->typography->autoTypography($str)); } } @@ -123,7 +123,7 @@ public function testAutoTypographySpecialCharacters() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->autoTypography($str)); + $this->assertSame($expect, $this->typography->autoTypography($str)); } } @@ -136,7 +136,7 @@ public function testNewlinesToHTMLLineBreaksExceptWithinPRE() ]; foreach ($strs as $str => $expect) { - $this->assertEquals($expect, $this->typography->nl2brExceptPre($str)); + $this->assertSame($expect, $this->typography->nl2brExceptPre($str)); } } } diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php index e5a1ee1343c4..6a580fbea596 100644 --- a/tests/system/Validation/CreditCardRulesTest.php +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -66,7 +66,7 @@ public function testValidCCNumber($type, $number, $expected = false) 'cc' => "valid_cc_number[{$type}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index f5be8b078281..2c998d628f8a 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -88,7 +88,7 @@ public function testValidURL(?string $url, bool $expected) 'foo' => 'valid_url', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function urlProvider() @@ -171,7 +171,7 @@ public function testValidEmail($email, $expected) 'foo' => 'valid_email', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } /** @@ -190,7 +190,7 @@ public function testValidEmails($email, $expected) 'foo' => 'valid_emails', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function emailProviderSingle() @@ -258,7 +258,7 @@ public function testValidIP($ip, $which, $expected) 'foo' => "valid_ip[{$which}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function ipProvider() @@ -328,7 +328,7 @@ public function testString($str, $expected) 'foo' => 'string', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function stringProvider() @@ -365,7 +365,7 @@ public function testAlpha($str, $expected) 'foo' => 'alpha', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function alphaProvider() @@ -412,7 +412,7 @@ public function testAlphaSpace($value, $expected) 'foo' => 'alpha_space', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function alphaSpaceProvider() @@ -461,7 +461,7 @@ public function testAlphaNumeric($str, $expected) 'foo' => 'alpha_numeric', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function alphaNumericProvider() @@ -502,7 +502,7 @@ public function testAlphaNumericPunct($str, $expected) 'foo' => 'alpha_numeric_punct', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function alphaNumericPunctProvider() @@ -599,7 +599,7 @@ public function testAlphaNumericSpace($str, $expected) 'foo' => 'alpha_numeric_space', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function alphaNumericSpaceProvider() @@ -640,7 +640,7 @@ public function testAlphaDash($str, $expected) 'foo' => 'alpha_dash', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function alphaDashProvider() @@ -681,7 +681,7 @@ public function testHex($str, $expected) 'foo' => 'hex', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function hexProvider() @@ -722,7 +722,7 @@ public function testNumeric($str, $expected) 'foo' => 'numeric', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function numericProvider() @@ -779,7 +779,7 @@ public function testInteger($str, $expected) 'foo' => 'integer', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function integerProvider() @@ -836,7 +836,7 @@ public function testDecimal($str, $expected) 'foo' => 'decimal', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function decimalProvider() @@ -897,7 +897,7 @@ public function testNatural($first, $expected) 'foo' => 'is_natural', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function naturalProvider() @@ -942,7 +942,7 @@ public function testNaturalNoZero($first, $expected) 'foo' => 'is_natural_no_zero', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function naturalZeroProvider() @@ -987,7 +987,7 @@ public function testBase64($first, $expected) 'foo' => 'valid_base64', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function base64Provider() @@ -1024,7 +1024,7 @@ public function testJson($first, $expected) 'foo' => 'valid_json', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function jsonProvider() @@ -1085,7 +1085,7 @@ public function testTimeZone($value, $expected) 'foo' => 'timezone', ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function timezoneProvider() @@ -1127,7 +1127,7 @@ public function testValidDate($str, $format, $expected) 'foo' => "valid_date[{$format}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } public function validDateProvider() diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index 441e90cfc407..536a48e3e087 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -158,7 +158,7 @@ public function testIfExist($rules, $data, $expected) { $this->validation->setRules($rules); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -214,7 +214,7 @@ public function testEmptys($rules, $data, $expected) { $this->validation->setRules($rules); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1167,7 +1167,7 @@ public function testGreaterThan($first, $second, $expected) 'foo' => "greater_than[{$second}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1226,7 +1226,7 @@ public function testGreaterThanEqual($first, $second, $expected) 'foo' => "greater_than_equal_to[{$second}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1290,7 +1290,7 @@ public function testLessThan($first, $second, $expected) 'foo' => "less_than[{$second}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1354,7 +1354,7 @@ public function testLessEqualThan($first, $second, $expected) 'foo' => "less_than_equal_to[{$second}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1424,7 +1424,7 @@ public function testInList($first, $second, $expected) 'foo' => "in_list[{$second}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1448,7 +1448,7 @@ public function testNotInList($first, $second, $expected) 'foo' => "not_in_list[{$second}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1530,7 +1530,7 @@ public function testRequiredWith($field, $check, $expected = false) $field => "required_with[{$check}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- @@ -1617,7 +1617,7 @@ public function testRequiredWithout($field, $check, $expected = false) $field => "required_without[{$check}]", ]); - $this->assertEquals($expected, $this->validation->run($data)); + $this->assertSame($expected, $this->validation->run($data)); } //-------------------------------------------------------------------- diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 40f2a3d92447..a605df6a7c4f 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -84,7 +84,7 @@ public function testSetRulesStoresRules() $this->validation->setRules($rules); - $this->assertEquals($rules, $this->validation->getRules()); + $this->assertSame($rules, $this->validation->getRules()); } //-------------------------------------------------------------------- @@ -124,7 +124,7 @@ public function testRunReturnsLocalizedErrors() ]); $this->assertFalse($this->validation->run($data)); - $this->assertEquals('Validation.is_numeric', $this->validation->getError('foo')); + $this->assertSame('Validation.is_numeric', $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -146,7 +146,7 @@ public function testRunWithCustomErrors() ], $messages); $this->validation->run($data); - $this->assertEquals('Nope. Not a number.', $this->validation->getError('foo')); + $this->assertSame('Nope. Not a number.', $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -161,7 +161,7 @@ public function testCheck() public function testCheckLocalizedError() { $this->assertFalse($this->validation->check('notanumber', 'is_numeric')); - $this->assertEquals('Validation.is_numeric', $this->validation->getError()); + $this->assertSame('Validation.is_numeric', $this->validation->getError()); } //-------------------------------------------------------------------- @@ -171,7 +171,7 @@ public function testCheckCustomError() $this->validation->check('notanumber', 'is_numeric', [ 'is_numeric' => 'Nope. Not a number.', ]); - $this->assertEquals('Nope. Not a number.', $this->validation->getError()); + $this->assertSame('Nope. Not a number.', $this->validation->getError()); } //-------------------------------------------------------------------- @@ -188,7 +188,7 @@ public function testGetErrors() $this->validation->run($data); - $this->assertEquals(['foo' => 'Validation.is_numeric'], $this->validation->getErrors()); + $this->assertSame(['foo' => 'Validation.is_numeric'], $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -207,7 +207,7 @@ public function testGetErrorsWhenNone() $this->validation->run($data); - $this->assertEquals([], $this->validation->getErrors()); + $this->assertSame([], $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -220,7 +220,7 @@ public function testSetErrors() $this->validation->setError('foo', 'Nadda'); - $this->assertEquals(['foo' => 'Nadda'], $this->validation->getErrors()); + $this->assertSame(['foo' => 'Nadda'], $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -233,7 +233,7 @@ public function testRulesReturnErrors() $this->validation->run(['foo' => 'bar']); - $this->assertEquals(['foo' => 'My lovely error'], $this->validation->getErrors()); + $this->assertSame(['foo' => 'My lovely error'], $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -245,7 +245,7 @@ public function testGroupsReadFromConfig() ]; $this->assertFalse($this->validation->run($data, 'groupA')); - $this->assertEquals('Shame, shame. Too short.', $this->validation->getError('foo')); + $this->assertSame('Shame, shame. Too short.', $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -263,7 +263,7 @@ public function testGroupsReadFromConfigValid() public function testGetRuleGroup() { - $this->assertEquals([ + $this->assertSame([ 'foo' => 'required|min_length[5]', ], $this->validation->getRuleGroup('groupA')); } @@ -282,7 +282,7 @@ public function testSetRuleGroup() { $this->validation->setRuleGroup('groupA'); - $this->assertEquals([ + $this->assertSame([ 'foo' => 'required|min_length[5]', ], $this->validation->getRules()); } @@ -306,7 +306,7 @@ public function testSetRuleGroupWithCustomErrorMessage() 'username' => 'codeigniter', ]); - $this->assertEquals([ + $this->assertSame([ 'password' => 'custom password required error msg.', ], $this->validation->getErrors()); } @@ -320,7 +320,7 @@ public function testRunGroupWithCustomErrorMessage() 'username' => 'codeigniter', ], 'login'); - $this->assertEquals([ + $this->assertSame([ 'password' => 'custom password required error msg.', ], $this->validation->getErrors()); } @@ -342,7 +342,7 @@ public function testRulesSetup($rules, $expected, $errors = []) $this->validation->run($data); - $this->assertEquals($expected, $this->validation->getError('foo')); + $this->assertSame($expected, $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -416,7 +416,7 @@ public function testSetRulesRemovesErrorsArray() $this->validation->run(['foo' => 'abc']); - $this->assertEquals('The Foo Bar field is very short.', $this->validation->getError('foo')); + $this->assertSame('The Foo Bar field is very short.', $this->validation->getError('foo')); } public function testInvalidRule() @@ -452,7 +452,7 @@ public function testRawInput() $request = new IncomingRequest($config, new URI(), $rawstring, new UserAgent()); $this->validation->withRequest($request->withMethod('patch'))->run($data); - $this->assertEquals([], $this->validation->getErrors()); + $this->assertSame([], $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -482,7 +482,7 @@ public function testJsonInput() ->run(); $this->assertTrue($validated); - $this->assertEquals([], $this->validation->getErrors()); + $this->assertSame([], $this->validation->getErrors()); unset($_SERVER['CONTENT_TYPE']); } @@ -523,7 +523,7 @@ public function testShowNonError() $this->validation->setError('foo', 'Nadda'); - $this->assertEquals('', $this->validation->showError('bogus')); + $this->assertSame('', $this->validation->showError('bogus')); } //-------------------------------------------------------------------- @@ -537,7 +537,7 @@ public function testShowBadTemplate() ]); $this->validation->setError('foo', 'Nadda'); - $this->assertEquals('We should never get here', $this->validation->showError('foo', 'bogus_template')); + $this->assertSame('We should never get here', $this->validation->showError('foo', 'bogus_template')); } //-------------------------------------------------------------------- @@ -641,7 +641,7 @@ public function testSplitNotRegex() $result = $method('uploaded[avatar]|max_size[avatar,1024]'); - $this->assertEquals('uploaded[avatar]', $result[0]); + $this->assertSame('uploaded[avatar]', $result[0]); } public function testSplitRegex() @@ -650,7 +650,7 @@ public function testSplitRegex() $result = $method('required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]'); - $this->assertEquals('regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', $result[1]); + $this->assertSame('regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', $result[1]); } //-------------------------------------------------------------------- @@ -686,7 +686,7 @@ public function testTagReplacement() $expected = 'Supplied value (Pizza) for Username must have at least 6 characters.'; // check if they are the same! - $this->assertEquals($expected, $errors['Username']); + $this->assertSame($expected, $errors['Username']); } //-------------------------------------------------------------------- @@ -703,7 +703,7 @@ public function testRulesForArrayField($body, $rules, $results) $this->validation->setRules($rules); $this->validation->withRequest($request->withMethod('post'))->run($body); - $this->assertEquals($results, $this->validation->getErrors()); + $this->assertSame($results, $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -790,7 +790,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnNoError() ]); $this->validation->withRequest($request->withMethod('post'))->run(); - $this->assertEquals([], $this->validation->getErrors()); + $this->assertSame([], $this->validation->getErrors()); } //-------------------------------------------------------------------- @@ -819,7 +819,7 @@ public function testRulesForSingleRuleWithAsteriskWillReturnError() ]); $this->validation->withRequest($request->withMethod('post'))->run(); - $this->assertEquals([ + $this->assertSame([ 'id_user.*' => 'The id_user.* field must contain only numbers.', 'name_user.*' => 'The name_user.* field may only contain alphabetical characters.', ], $this->validation->getErrors()); @@ -843,7 +843,7 @@ public function testRulesForSingleRuleWithSingleValue() ]); $this->validation->withRequest($request->withMethod('post'))->run(); - $this->assertEquals([ + $this->assertSame([ 'id_user' => 'The id_user field must contain only numbers.', ], $this->validation->getErrors()); } @@ -863,7 +863,7 @@ public function testTranslatedLabel() $this->validation->run(['foo' => 'abc']); - $this->assertEquals('The Foo Bar Translated field must be at least 10 characters in length.', $this->validation->getError('foo')); + $this->assertSame('The Foo Bar Translated field must be at least 10 characters in length.', $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -881,7 +881,7 @@ public function testTranslatedLabelIsMissing() $this->validation->run(['foo' => 'abc']); - $this->assertEquals('The Foo.bar.is.missing field must be at least 10 characters in length.', $this->validation->getError('foo')); + $this->assertSame('The Foo.bar.is.missing field must be at least 10 characters in length.', $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -902,7 +902,7 @@ public function testTranslatedLabelWithCustomErrorMessage() $this->validation->run(['foo' => 'abc']); - $this->assertEquals('The Foo Bar Translated field is very short.', $this->validation->getError('foo')); + $this->assertSame('The Foo Bar Translated field is very short.', $this->validation->getError('foo')); } //-------------------------------------------------------------------- @@ -941,7 +941,7 @@ public function testTranslatedLabelTagReplacement() $expected = 'Supplied value (Pizza) for Foo Bar Translated must have at least 6 characters.'; // check if they are the same! - $this->assertEquals($expected, $errors['Username']); + $this->assertSame($expected, $errors['Username']); } /** diff --git a/tests/system/View/CellTest.php b/tests/system/View/CellTest.php index 6eecac3a2acb..1b374ce93461 100644 --- a/tests/system/View/CellTest.php +++ b/tests/system/View/CellTest.php @@ -33,14 +33,14 @@ protected function setUp(): void public function testPrepareParamsReturnsEmptyArrayWithInvalidParam() { - $this->assertEquals([], $this->cell->prepareParams(1.023)); + $this->assertSame([], $this->cell->prepareParams(1.023)); } //-------------------------------------------------------------------- public function testPrepareParamsReturnsNullWithEmptyString() { - $this->assertEquals([], $this->cell->prepareParams('')); + $this->assertSame([], $this->cell->prepareParams('')); } //-------------------------------------------------------------------- @@ -52,14 +52,14 @@ public function testPrepareParamsReturnsSelfWhenArray() 'three' => 'four', ]; - $this->assertEquals($object, $this->cell->prepareParams($object)); + $this->assertSame($object, $this->cell->prepareParams($object)); } //-------------------------------------------------------------------- public function testPrepareParamsReturnsEmptyArrayWithEmptyArray() { - $this->assertEquals([], $this->cell->prepareParams([])); + $this->assertSame([], $this->cell->prepareParams([])); } //-------------------------------------------------------------------- @@ -72,7 +72,7 @@ public function testPrepareParamsReturnsArrayWithString() 'three' => 'four', ]; - $this->assertEquals($expected, $this->cell->prepareParams($params)); + $this->assertSame($expected, $this->cell->prepareParams($params)); } //-------------------------------------------------------------------- @@ -81,11 +81,11 @@ public function testPrepareParamsHandlesCommas() { $params = 'one=2, three=4.15'; $expected = [ - 'one' => 2, - 'three' => 4.15, + 'one' => '2', + 'three' => '4.15', ]; - $this->assertEquals($expected, $this->cell->prepareParams($params)); + $this->assertSame($expected, $this->cell->prepareParams($params)); } //-------------------------------------------------------------------- @@ -98,7 +98,7 @@ public function testPrepareParamsWorksWithoutSpaces() 'three' => 'four', ]; - $this->assertEquals($expected, $this->cell->prepareParams($params)); + $this->assertSame($expected, $this->cell->prepareParams($params)); } //-------------------------------------------------------------------- @@ -112,7 +112,7 @@ public function testPrepareParamsWorksWithOddEqualsSpaces() 'five' => 'six', ]; - $this->assertEquals($expected, $this->cell->prepareParams($params)); + $this->assertSame($expected, $this->cell->prepareParams($params)); } //-------------------------------------------------------------------- @@ -124,7 +124,7 @@ public function testDisplayRendersWithNamespacedClass() { $expected = 'Hello'; - $this->assertEquals($expected, $this->cell->render('\Tests\Support\View\SampleClass::hello')); + $this->assertSame($expected, $this->cell->render('\Tests\Support\View\SampleClass::hello')); } //-------------------------------------------------------------------- @@ -137,7 +137,7 @@ public function testDisplayRendersWithValidParamString() 'three' => 'four', ]; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params)); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params)); } //-------------------------------------------------------------------- @@ -150,7 +150,7 @@ public function testDisplayRendersWithStaticMethods() 'three' => 'four', ]; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::staticEcho', $params)); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::staticEcho', $params)); } //-------------------------------------------------------------------- @@ -160,14 +160,14 @@ public function testOptionsEmptyArray() $params = []; $expected = []; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::staticEcho', $params)); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::staticEcho', $params)); } public function testOptionsNoParams() { $expected = []; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::staticEcho')); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::staticEcho')); } public function testCellEmptyParams() @@ -175,7 +175,7 @@ public function testCellEmptyParams() $params = ','; $expected = 'Hello World'; - $this->assertEquals($expected, $this->cell->render('\Tests\Support\View\SampleClass::index', $params)); + $this->assertSame($expected, $this->cell->render('\Tests\Support\View\SampleClass::index', $params)); } //-------------------------------------------------------------------- @@ -189,7 +189,7 @@ public function testCellClassMissing() 'three' => 'four', ]; - $this->assertEquals(implode(',', $expected), $this->cell->render('::echobox', $params)); + $this->assertSame(implode(',', $expected), $this->cell->render('::echobox', $params)); } public function testCellMethodMissing() @@ -201,7 +201,7 @@ public function testCellMethodMissing() 'three' => 'four', ]; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::', $params)); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::', $params)); } public function testCellBadClass() @@ -210,7 +210,7 @@ public function testCellBadClass() $params = 'one=two,three=four'; $expected = 'Hello World'; - $this->assertEquals($expected, $this->cell->render('\CodeIgniter\View\GoodQuestion::', $params)); + $this->assertSame($expected, $this->cell->render('\CodeIgniter\View\GoodQuestion::', $params)); } public function testCellBadMethod() @@ -219,7 +219,7 @@ public function testCellBadMethod() $params = 'one=two,three=four'; $expected = 'Hello World'; - $this->assertEquals($expected, $this->cell->render('\Tests\Support\View\SampleClass::notThere', $params)); + $this->assertSame($expected, $this->cell->render('\Tests\Support\View\SampleClass::notThere', $params)); } //-------------------------------------------------------------------- @@ -232,9 +232,9 @@ public function testRenderCached() 'three' => 'four', ]; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 60, 'rememberme')); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 60, 'rememberme')); $params = 'one=six,three=five'; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 1, 'rememberme')); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 1, 'rememberme')); } public function testRenderCachedAutoName() @@ -245,11 +245,11 @@ public function testRenderCachedAutoName() 'three' => 'four', ]; - $this->assertEquals(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 60)); + $this->assertSame(implode(',', $expected), $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 60)); $params = 'one=six,three=five'; // When auto-generating it takes the params as part of cachename, so it wouldn't have actually cached this, but // we want to make sure it doesn't throw us a curveball here. - $this->assertEquals('six,five', $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 1)); + $this->assertSame('six,five', $this->cell->render('\Tests\Support\View\SampleClass::echobox', $params, 1)); } //-------------------------------------------------------------------- @@ -263,7 +263,7 @@ public function testParametersMatch() ]; $expected = 'Right on'; - $this->assertEquals($expected, $this->cell->render('\Tests\Support\View\SampleClass::work', $params)); + $this->assertSame($expected, $this->cell->render('\Tests\Support\View\SampleClass::work', $params)); } public function testParametersDontMatch() @@ -272,11 +272,11 @@ public function testParametersDontMatch() $params = 'p1=one,p2=two,p3=three'; $expected = 'Right on'; - $this->assertEquals($expected, $this->cell->render('\Tests\Support\View\SampleClass::work', $params)); + $this->assertSame($expected, $this->cell->render('\Tests\Support\View\SampleClass::work', $params)); } public function testCallInitControllerIfMethodExists() { - $this->assertEquals('CodeIgniter\HTTP\Response', $this->cell->render('\Tests\Support\View\SampleClassWithInitController::index')); + $this->assertSame('CodeIgniter\HTTP\Response', $this->cell->render('\Tests\Support\View\SampleClassWithInitController::index')); } } diff --git a/tests/system/View/ParserFilterTest.php b/tests/system/View/ParserFilterTest.php index 64efc624f32f..7bc75f25b777 100644 --- a/tests/system/View/ParserFilterTest.php +++ b/tests/system/View/ParserFilterTest.php @@ -39,7 +39,7 @@ public function testAbs() $template = '{ value1|abs }{ value2|abs }'; $parser->setData($data); - $this->assertEquals('55', $parser->renderString($template)); + $this->assertSame('55', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -56,7 +56,7 @@ public function testCapitalize() $template = '{ value1|capitalize } { value2|capitalize }'; $parser->setData($data); - $this->assertEquals('Wonder Twins', $parser->renderString($template)); + $this->assertSame('Wonder Twins', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -80,7 +80,7 @@ public function testDate() $template = '{ value1|date(Y-m-d) } { value2|date(Y-m-d) } { value1|date(Y.m.d) } { value1|date(Y m d) } { value1|date(Y:m:d) } { value1|date(Y/m/d) } { value1|date(Y\\\m\\\d) }'; $parser->setData($data); - $this->assertEquals("{$todayDash} {$todayDash} {$todayDot} {$todaySpace} {$todayColon} {$todaySlash} {$todayBackslash}", $parser->renderString($template)); + $this->assertSame("{$todayDash} {$todayDash} {$todayDot} {$todaySpace} {$todayColon} {$todaySlash} {$todayBackslash}", $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -98,7 +98,7 @@ public function testDateModify() $template = '{ value1|date_modify(+1 day)|date(Y-m-d) } { value2|date_modify(+1 day)|date(Y-m-d) }'; $parser->setData($data); - $this->assertEquals("{$tommorrow} {$tommorrow}", $parser->renderString($template)); + $this->assertSame("{$tommorrow} {$tommorrow}", $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -116,7 +116,7 @@ public function testDefault() $template = '{ value1|default(foo) } { value2|default(bar) } { value3|default(baz) }'; $parser->setData($data); - $this->assertEquals('foo bar test', $parser->renderString($template)); + $this->assertSame('foo bar test', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -135,7 +135,7 @@ public function testEsc() $template = '{ value1|esc(html) } { value1|esc(js) }'; $parser->setData($data); - $this->assertEquals("{$value1} {$value2}", $parser->renderString($template)); + $this->assertSame("{$value1} {$value2}", $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -151,7 +151,7 @@ public function testExcerpt() $template = '{ value1|excerpt(jumped, 10) }'; $parser->setData($data); - $this->assertEquals('... red fox jumped over ...', $parser->renderString($template)); + $this->assertSame('... red fox jumped over ...', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -167,7 +167,7 @@ public function testHighlight() $template = '{ value1|highlight(jumped over) }'; $parser->setData($data); - $this->assertEquals('The quick red fox jumped over the lazy brown dog', $parser->renderString($template)); + $this->assertSame('The quick red fox jumped over the lazy brown dog', $parser->renderString($template)); } public function testHighlightCode() @@ -186,7 +186,7 @@ public function testHighlightCode() EOF; - $this->assertEquals($expected, $parser->renderString($template)); + $this->assertSame($expected, $parser->renderString($template)); } public function testProse() @@ -200,7 +200,7 @@ public function testProse() $template = '{ value1|prose }'; $expected = '

Sincerely\nMe

'; - $this->assertEquals($expected, $parser->renderString($template)); + $this->assertSame($expected, $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -216,7 +216,7 @@ public function testLimitChars() $template = '{ value1|limit_chars(10) }'; $parser->setData($data); - $this->assertEquals('The quick…', $parser->renderString($template)); + $this->assertSame('The quick…', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -232,7 +232,7 @@ public function testLimitWords() $template = '{ value1|limit_words(4) }'; $parser->setData($data); - $this->assertEquals('The quick red fox…', $parser->renderString($template)); + $this->assertSame('The quick red fox…', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -248,7 +248,7 @@ public function testLower() $template = '{ value1|lower }'; $parser->setData($data); - $this->assertEquals('something', $parser->renderString($template)); + $this->assertSame('something', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -264,7 +264,7 @@ public function testNL2BR() $template = '{ value1|nl2br }'; $parser->setData($data); - $this->assertEquals("first
\nsecond", $parser->renderString($template)); + $this->assertSame("first
\nsecond", $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -280,7 +280,7 @@ public function testNumberFormat() $template = '{ value1|number_format(2) }'; $parser->setData($data); - $this->assertEquals('1,098.35', $parser->renderString($template)); + $this->assertSame('1,098.35', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -296,7 +296,7 @@ public function testRound() $template = '{ value1|round(1) } { value1|round(1, common) } { value1|round(ceil) } { value1|round(floor) } { value1|round(unknown) }'; $parser->setData($data); - $this->assertEquals('5.6 5.6 6 5 5.55', $parser->renderString($template)); + $this->assertSame('5.6 5.6 6 5 5.55', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -312,7 +312,7 @@ public function testStripTags() $template = '{ value1|strip_tags } { value1|strip_tags() }'; $parser->setData($data); - $this->assertEquals('Middle Middle', $parser->renderString($template)); + $this->assertSame('Middle Middle', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -328,7 +328,7 @@ public function testTitle() $template = '{ value1|title }'; $parser->setData($data); - $this->assertEquals('Though She Be Little', $parser->renderString($template)); + $this->assertSame('Though She Be Little', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -344,7 +344,7 @@ public function testUpper() $template = '{ value1|upper }'; $parser->setData($data); - $this->assertEquals('THOUGH SHE BE LITTLE', $parser->renderString($template)); + $this->assertSame('THOUGH SHE BE LITTLE', $parser->renderString($template)); } //-------------------------------------------------------------------- @@ -360,7 +360,7 @@ public function testLocalNumberBase() $template = '{ mynum|local_number }'; $parser->setData($data); - $this->assertEquals('1,234,567.8912', $parser->renderString($template)); + $this->assertSame('1,234,567.8912', $parser->renderString($template)); } public function testLocalNumberPrecision() @@ -374,7 +374,7 @@ public function testLocalNumberPrecision() $template = '{ mynum|local_number(decimal,2) }'; $parser->setData($data); - $this->assertEquals('1,234,567.89', $parser->renderString($template)); + $this->assertSame('1,234,567.89', $parser->renderString($template)); } public function testLocalNumberType() @@ -388,7 +388,7 @@ public function testLocalNumberType() $template = '{ mynum|local_number(spellout) }'; $parser->setData($data); - $this->assertEquals('one million two hundred thirty-four thousand five hundred sixty-seven point eight nine one two three four six', $parser->renderString($template)); + $this->assertSame('one million two hundred thirty-four thousand five hundred sixty-seven point eight nine one two three four six', $parser->renderString($template)); } public function testLocalNumberLocale() @@ -402,7 +402,7 @@ public function testLocalNumberLocale() $template = '{ mynum|local_number(decimal,4,de_DE) }'; $parser->setData($data); - $this->assertEquals('1.234.567,8912', $parser->renderString($template)); + $this->assertSame('1.234.567,8912', $parser->renderString($template)); } public function testLocalCurrency() @@ -416,7 +416,7 @@ public function testLocalCurrency() $template = '{ mynum|local_currency(EUR,de_DE,2) }'; $parser->setData($data); - $this->assertEquals('1.234.567,89 €', $parser->renderString($template)); + $this->assertSame('1.234.567,89 €', $parser->renderString($template)); } public function testParsePairWithAbs() @@ -472,6 +472,6 @@ public function testParsePairWithAbs() . '{/nested}'; $parser->setData($data); - $this->assertEquals('112233445566', $parser->renderString($template)); + $this->assertSame('112233445566', $parser->renderString($template)); } } diff --git a/tests/system/View/ParserPluginTest.php b/tests/system/View/ParserPluginTest.php index 17dd2211516d..3b43d9c42d12 100644 --- a/tests/system/View/ParserPluginTest.php +++ b/tests/system/View/ParserPluginTest.php @@ -35,7 +35,7 @@ public function testCurrentURL() helper('url'); $template = '{+ current_url +}'; - $this->assertEquals(current_url(), $this->parser->renderString($template)); + $this->assertSame(current_url(), $this->parser->renderString($template)); } public function testPreviousURL() @@ -46,7 +46,7 @@ public function testPreviousURL() // Ensure a previous URL exists to work with. $_SESSION['_ci_previous_url'] = 'http://example.com/foo'; - $this->assertEquals(previous_url(), $this->parser->renderString($template)); + $this->assertSame(previous_url(), $this->parser->renderString($template)); } public function testMailto() @@ -54,7 +54,7 @@ public function testMailto() helper('url'); $template = '{+ mailto email=foo@example.com title=Silly +}'; - $this->assertEquals(mailto('foo@example.com', 'Silly'), $this->parser->renderString($template)); + $this->assertSame(mailto('foo@example.com', 'Silly'), $this->parser->renderString($template)); } /** @@ -73,14 +73,14 @@ public function testSafeMailto() helper('url'); $template = '{+ safe_mailto email=foo@example.com title=Silly +}'; - $this->assertEquals(safe_mailto('foo@example.com', 'Silly'), $this->parser->renderString($template)); + $this->assertSame(safe_mailto('foo@example.com', 'Silly'), $this->parser->renderString($template)); } public function testLang() { $template = '{+ lang Number.terabyteAbbr +}'; - $this->assertEquals('TB', $this->parser->renderString($template)); + $this->assertSame('TB', $this->parser->renderString($template)); } public function testValidationErrors() @@ -89,7 +89,7 @@ public function testValidationErrors() $template = '{+ validation_errors field=email +}'; - $this->assertEquals($this->setHints($this->validator->showError('email')), $this->setHints($this->parser->renderString($template))); + $this->assertSame($this->setHints($this->validator->showError('email')), $this->setHints($this->parser->renderString($template))); } public function testRoute() @@ -100,14 +100,14 @@ public function testRoute() $template = '{+ route myController::goto string 13 +}'; - $this->assertEquals('/path/string/to/13', $this->parser->renderString($template)); + $this->assertSame('/path/string/to/13', $this->parser->renderString($template)); } public function testSiteURL() { $template = '{+ siteURL +}'; - $this->assertEquals('http://example.com/index.php', $this->parser->renderString($template)); + $this->assertSame('http://example.com/index.php', $this->parser->renderString($template)); } public function testValidationErrorsList() @@ -116,7 +116,7 @@ public function testValidationErrorsList() $this->validator->setError('username', 'User name must be unique'); $template = '{+ validation_errors +}'; - $this->assertEquals($this->setHints($this->validator->listErrors()), $this->setHints($this->parser->renderString($template))); + $this->assertSame($this->setHints($this->validator->listErrors()), $this->setHints($this->parser->renderString($template))); } public function setHints($output) diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index 0cc95ebe2b1b..947e568ec349 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -50,22 +50,22 @@ protected function setUp(): void public function testSetDelimiters() { // Make sure default delimiters are there - $this->assertEquals('{', $this->parser->leftDelimiter); - $this->assertEquals('}', $this->parser->rightDelimiter); + $this->assertSame('{', $this->parser->leftDelimiter); + $this->assertSame('}', $this->parser->rightDelimiter); // Change them to square brackets $this->parser->setDelimiters('[', ']'); // Make sure they changed - $this->assertEquals('[', $this->parser->leftDelimiter); - $this->assertEquals(']', $this->parser->rightDelimiter); + $this->assertSame('[', $this->parser->leftDelimiter); + $this->assertSame(']', $this->parser->rightDelimiter); // Reset them $this->parser->setDelimiters(); // Make sure default delimiters are there - $this->assertEquals('{', $this->parser->leftDelimiter); - $this->assertEquals('}', $this->parser->rightDelimiter); + $this->assertSame('{', $this->parser->leftDelimiter); + $this->assertSame('}', $this->parser->rightDelimiter); } // -------------------------------------------------------------------- @@ -73,7 +73,7 @@ public function testSetDelimiters() public function testParseSimple() { $this->parser->setVar('teststring', 'Hello World'); - $this->assertEquals("

Hello World

\n", $this->parser->render('template1')); + $this->assertSame("

Hello World

\n", $this->parser->render('template1')); } // -------------------------------------------------------------------- @@ -90,7 +90,7 @@ public function testParseString() $result = implode("\n", $data); $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } // -------------------------------------------------------------------- @@ -107,7 +107,7 @@ public function testParseStringMissingData() $result = implode("\n", $data) . "\n{name}"; $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } // -------------------------------------------------------------------- @@ -125,14 +125,14 @@ public function testParseStringUnusedData() $result = "Page Title\nLorem ipsum dolor sit amet."; $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } // -------------------------------------------------------------------- public function testParseNoTemplate() { - $this->assertEquals('', $this->parser->renderString('')); + $this->assertSame('', $this->parser->renderString('')); } // -------------------------------------------------------------------- @@ -152,7 +152,7 @@ public function testParseArraySingle() $template = "{title}\n{powers}{invisibility}\n{flying}{/powers}"; $this->parser->setData($data); - $this->assertEquals("Super Heroes\nyes\nno", $this->parser->renderString($template)); + $this->assertSame("Super Heroes\nyes\nno", $this->parser->renderString($template)); } public function testParseArrayMulti() @@ -169,7 +169,7 @@ public function testParseArrayMulti() $template = "{powers}{invisibility}\n{flying}{/powers}\nsecond:{powers} {invisibility} {flying}{ /powers}"; $this->parser->setData($data); - $this->assertEquals("yes\nno\nsecond: yes no", $this->parser->renderString($template)); + $this->assertSame("yes\nno\nsecond: yes no", $this->parser->renderString($template)); } public function testParseArrayNested() @@ -193,7 +193,7 @@ public function testParseArrayNested() $template = "{title}\n{powers}{invisibility}\n{flying}{by} {with}{/flying}{/powers}"; $this->parser->setData($data); - $this->assertEquals("Super Heroes\nyes\nplane broomstick", $this->parser->renderString($template)); + $this->assertSame("Super Heroes\nyes\nplane broomstick", $this->parser->renderString($template)); } public function testParseArrayNestedObject() @@ -220,7 +220,7 @@ public function testParseArrayNestedObject() $template = '{birds}{mom} and {pop} work at {home}{/birds}'; $this->parser->setData($data); - $this->assertEquals('Owl and Class: stdClass work at Resource', $this->parser->renderString($template)); + $this->assertSame('Owl and Class: stdClass work at Resource', $this->parser->renderString($template)); } // -------------------------------------------------------------------- @@ -239,7 +239,7 @@ public function testParseLoop() $template = "{title}\n{powers}{name} {/powers}"; $this->parser->setData($data); - $this->assertEquals("Super Heroes\nTom Dick Henry ", $this->parser->renderString($template)); + $this->assertSame("Super Heroes\nTom Dick Henry ", $this->parser->renderString($template)); } public function testParseLoopObjectProperties() @@ -264,7 +264,7 @@ public function testParseLoopObjectProperties() $template = "{title}\n{powers}{name} {/powers}"; $this->parser->setData($data, 'html'); - $this->assertEquals("Super Heroes\nTom Dick Henry ", $this->parser->renderString($template)); + $this->assertSame("Super Heroes\nTom Dick Henry ", $this->parser->renderString($template)); } // -------------------------------------------------------------------- @@ -296,7 +296,7 @@ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recu $template = "{title}\n{powers} {foo} {bar} {bobbles}{name} {/bobbles}{/powers}"; $this->parser->setData($data); - $this->assertEquals("Super Heroes\n bar baz first second ", $this->parser->renderString($template)); + $this->assertSame("Super Heroes\n bar baz first second ", $this->parser->renderString($template)); } public function testParseLoopEntityObjectProperties() @@ -333,7 +333,7 @@ public function __construct() $template = "{title}\n{powers} {foo} {bar} {bobbles}{name} {/bobbles}{/powers}"; $this->parser->setData($data, 'html'); - $this->assertEquals("Super Heroes\n bar baz first second ", $this->parser->renderString($template)); + $this->assertSame("Super Heroes\n bar baz first second ", $this->parser->renderString($template)); } // -------------------------------------------------------------------- @@ -354,7 +354,7 @@ public function testMismatchedVarPair() $result = "Super Heroes\n{powers}{invisibility}\n{flying}"; $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } public function escValueTypes() @@ -419,7 +419,7 @@ public function testEscHandling($value, $expected = null) if ($expected === null) { $expected = $value; } - $this->assertEquals($expected, \esc($value)); + $this->assertSame($expected, \esc($value)); } //------------------------------------------------------------------------ @@ -432,7 +432,7 @@ public function testParseSimilarVariableNames() $template = '{foo} {foo_bar}'; $this->parser->setData(['foo' => 'bar', 'foo_bar' => 'foo-bar'], 'raw'); - $this->assertEquals('bar foo-bar', $this->parser->renderString($template)); + $this->assertSame('bar foo-bar', $this->parser->renderString($template)); } public function testParsePairSimilarVariableNames() @@ -449,7 +449,7 @@ public function testParsePairSimilarVariableNames() $template = '{title} {powers}{link} {link_second}{/powers}'; $this->parser->setData($data); - $this->assertEquals('<script>Heroes</script> <a href='test'>Link</a> <a href='test2'>Link second</a>', $this->parser->renderString($template)); + $this->assertSame('<script>Heroes</script> <a href='test'>Link</a> <a href='test2'>Link second</a>', $this->parser->renderString($template)); } //------------------------------------------------------------------------ @@ -462,7 +462,7 @@ public function testEscapingRespectsSetDataRaw() $template = '{ foo }'; $this->parser->setData(['foo' => '', $this->parser->renderString($template)); + $this->assertSame('', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -567,7 +567,7 @@ public function testIgnoresComments() $result = "Super Heroes\n{powers}{invisibility}\n{flying}"; $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -588,7 +588,7 @@ public function testNoParse() $result = "{title}\n{powers}{invisibility}\n{flying}"; $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -603,7 +603,7 @@ public function testIfConditionalTrue() $template = '{if $doit}Howdy{endif}{ if $dontdoit === false}Welcome{ endif }'; $this->parser->setData($data); - $this->assertEquals('HowdyWelcome', $this->parser->renderString($template)); + $this->assertSame('HowdyWelcome', $this->parser->renderString($template)); } public function testElseConditionalFalse() @@ -615,7 +615,7 @@ public function testElseConditionalFalse() $template = '{if $doit}Howdy{else}Welcome{ endif }'; $this->parser->setData($data); - $this->assertEquals('Howdy', $this->parser->renderString($template)); + $this->assertSame('Howdy', $this->parser->renderString($template)); } public function testElseConditionalTrue() @@ -627,7 +627,7 @@ public function testElseConditionalTrue() $template = '{if $doit}Howdy{else}Welcome{ endif }'; $this->parser->setData($data); - $this->assertEquals('Welcome', $this->parser->renderString($template)); + $this->assertSame('Welcome', $this->parser->renderString($template)); } public function testElseifConditionalTrue() @@ -640,7 +640,7 @@ public function testElseifConditionalTrue() $template = '{if $doit}Howdy{elseif $dontdoit}Welcome{ endif }'; $this->parser->setData($data); - $this->assertEquals('Welcome', $this->parser->renderString($template)); + $this->assertSame('Welcome', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -657,7 +657,7 @@ public function testConditionalBadSyntax() $template = '{if doit}Howdy{elseif doit}Welcome{ endif )}'; $this->parser->setData($data); - $this->assertEquals('HowdyWelcome', $this->parser->renderString($template)); + $this->assertSame('HowdyWelcome', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -665,7 +665,7 @@ public function testConditionalBadSyntax() public function testWontParsePHP() { $template = " - "; - $this->assertEquals('<?php echo \'Foo\' ?> - <?= \'Bar\' ?>', $this->parser->renderString($template)); + $this->assertSame('<?php echo \'Foo\' ?> - <?= \'Bar\' ?>', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -682,7 +682,7 @@ public function testParseHandlesSpaces() $result = implode("\n", $data); $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } // -------------------------------------------------------------------- @@ -699,7 +699,7 @@ public function testParseRuns() $result = implode("\n", $data); $this->parser->setData($data); - $this->assertEquals($result, $this->parser->renderString($template)); + $this->assertSame($result, $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -733,7 +733,7 @@ public function testParserPluginNoMatches() { $template = 'hit:it'; - $this->assertEquals('hit:it', $this->parser->renderString($template)); + $this->assertSame('hit:it', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -749,7 +749,7 @@ public function testParserPluginNoParams() $template = '{+ hit:it +} stuff here {+ /hit:it +}'; - $this->assertEquals(' stuff Hip to the Hop ', $this->parser->renderString($template)); + $this->assertSame(' stuff Hip to the Hop ', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -768,7 +768,7 @@ public function testParserPluginClosure() $template = '{+ hello world +}'; - $this->assertEquals('Hello, world', $this->parser->renderString($template)); + $this->assertSame('Hello, world', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -793,7 +793,7 @@ public function testParserPluginParams() $template = '{+ growth step=2 count=4 +} {+ /growth +}'; - $this->assertEquals(' 2 4 6 8', $this->parser->renderString($template)); + $this->assertSame(' 2 4 6 8', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -809,7 +809,7 @@ public function testParserSingleTag() $template = '{+ hit:it +}'; - $this->assertEquals('Hip to the Hop', $this->parser->renderString($template)); + $this->assertSame('Hip to the Hop', $this->parser->renderString($template)); } /** @@ -823,7 +823,7 @@ public function testParserSingleTagWithParams() $template = '{+ hit:it first=foo last=bar +}'; - $this->assertEquals('foo to the bar', $this->parser->renderString($template)); + $this->assertSame('foo to the bar', $this->parser->renderString($template)); } /** @@ -837,7 +837,7 @@ public function testParserSingleTagWithSingleParams() $template = '{+ hit:it foo bar +}'; - $this->assertEquals('foo to the bar', $this->parser->renderString($template)); + $this->assertSame('foo to the bar', $this->parser->renderString($template)); } /** @@ -857,7 +857,7 @@ public function testParserSingleTagWithQuotedParams() $template = '{+ count "foo bar" baz "foo bar" +}'; - $this->assertEquals('0. foo bar 1. baz 2. foo bar ', $this->parser->renderString($template)); + $this->assertSame('0. foo bar 1. baz 2. foo bar ', $this->parser->renderString($template)); } /** @@ -877,7 +877,7 @@ public function testParserSingleTagWithNamedParams() $template = '{+ read_params title="Hello world" page=5 email=test@test.net +}'; - $this->assertEquals('title: Hello world. page: 5. email: test@test.net. ', $this->parser->renderString($template)); + $this->assertSame('title: Hello world. page: 5. email: test@test.net. ', $this->parser->renderString($template)); } //-------------------------------------------------------------------- @@ -896,7 +896,7 @@ public function testParseLoopWithDollarSign() $template = '{books}

Price $: {price}

{/books}'; $this->parser->setData($data); - $this->assertEquals('

Price $: 12.50

', $this->parser->renderString($template)); + $this->assertSame('

Price $: 12.50

', $this->parser->renderString($template)); } /** @@ -958,9 +958,9 @@ public function testCachedRender() $this->parser->setVar('teststring', 'Hello World'); $expected = "

Hello World

\n"; - $this->assertEquals($expected, $this->parser->render('template1', ['cache' => 10, 'cache_name' => 'HelloWorld'])); + $this->assertSame($expected, $this->parser->render('template1', ['cache' => 10, 'cache_name' => 'HelloWorld'])); // this second renderings should go thru the cache - $this->assertEquals($expected, $this->parser->render('template1', ['cache' => 10, 'cache_name' => 'HelloWorld'])); + $this->assertSame($expected, $this->parser->render('template1', ['cache' => 10, 'cache_name' => 'HelloWorld'])); } //-------------------------------------------------------------------- @@ -968,7 +968,7 @@ public function testCachedRender() public function testRenderFindsView() { $this->parser->setData(['testString' => 'Hello World']); - $this->assertEquals("

Hello World

\n", $this->parser->render('Simpler')); + $this->assertSame("

Hello World

\n", $this->parser->render('Simpler')); } public function testRenderCannotFindView() @@ -987,11 +987,11 @@ public function testRenderSavingData() $expected = "

Hello World

\n"; $this->parser->setData(['testString' => 'Hello World']); - $this->assertEquals($expected, $this->parser->render('Simpler', [], false)); + $this->assertSame($expected, $this->parser->render('Simpler', [], false)); $this->assertArrayNotHasKey('testString', $this->parser->getData()); $this->parser->setData(['testString' => 'Hello World']); - $this->assertEquals($expected, $this->parser->render('Simpler', [], true)); + $this->assertSame($expected, $this->parser->render('Simpler', [], true)); $this->assertArrayHasKey('testString', $this->parser->getData()); } @@ -1001,11 +1001,11 @@ public function testRenderStringSavingData() $pattern = '

{testString}

'; $this->parser->setData(['testString' => 'Hello World']); - $this->assertEquals($expected, $this->parser->renderString($pattern, [], false)); + $this->assertSame($expected, $this->parser->renderString($pattern, [], false)); $this->assertArrayNotHasKey('testString', $this->parser->getData()); //last set data is not saved $this->parser->setData(['testString' => 'Hello World']); - $this->assertEquals($expected, $this->parser->renderString($pattern, [], true)); + $this->assertSame($expected, $this->parser->renderString($pattern, [], true)); $this->assertArrayHasKey('testString', $this->parser->getData()); } @@ -1013,6 +1013,6 @@ public function testRenderFindsOtherView() { $this->parser->setData(['testString' => 'Hello World']); $expected = '

Hello World

'; - $this->assertEquals($expected, $this->parser->render('Simpler.html')); + $this->assertSame($expected, $this->parser->render('Simpler.html')); } } diff --git a/tests/system/View/TableTest.php b/tests/system/View/TableTest.php index 4e6f3012719d..0c49ea01488d 100644 --- a/tests/system/View/TableTest.php +++ b/tests/system/View/TableTest.php @@ -27,19 +27,19 @@ public function testSetTemplate() $template = ['a' => 'b']; $this->table->setTemplate($template); - $this->assertEquals($template, $this->table->template); + $this->assertSame($template, $this->table->template); } public function testSetEmpty() { $this->table->setEmpty('nada'); - $this->assertEquals('nada', $this->table->emptyCells); + $this->assertSame('nada', $this->table->emptyCells); } public function testSetCaption() { $this->table->setCaption('awesome cap'); - $this->assertEquals('awesome cap', $this->table->caption); + $this->assertSame('awesome cap', $this->table->caption); } /** @@ -53,7 +53,7 @@ public function testSetHeading() $this->table->setHeading('name', 'color', 'size'); - $this->assertEquals( + $this->assertSame( [ ['data' => 'name'], ['data' => 'color'], @@ -73,7 +73,7 @@ public function testSetFooting() $this->table->setFooting('Subtotal', $subtotal); - $this->assertEquals( + $this->assertSame( [ ['data' => 'Subtotal'], ['data' => $subtotal], @@ -97,7 +97,7 @@ public function testAddRow() $this->assertCount(3, $this->table->rows); - $this->assertEquals( + $this->assertSame( [ ['data' => 'your'], ['data' => 'pony'], @@ -118,7 +118,7 @@ public function testPrepArgs() ['data' => 'size'], ]; - $this->assertEquals( + $this->assertSame( $expected, $this->table->prepArgs(['name', 'color', 'size']) ); @@ -130,7 +130,7 @@ public function testPrepArgs() 'class' => 'awesome', ]; - $this->assertEquals( + $this->assertSame( $expected, $this->table->prepArgs(['name', 'color', 'size', ['data' => 'weight', 'class' => 'awesome']]) ); @@ -173,14 +173,14 @@ public function testCompileTemplate() $this->table->compileTemplate(); $this->assertArrayHasKey('nonsense', $this->table->template); - $this->assertEquals('foo', $this->table->template['nonsense']); + $this->assertSame('foo', $this->table->template['nonsense']); // override default $this->table->setTemplate(['table_close' => '']); $this->table->compileTemplate(); $this->assertArrayHasKey('table_close', $this->table->template); - $this->assertEquals('', $this->table->template['table_close']); + $this->assertSame('', $this->table->template['table_close']); } public function testMakeColumns() @@ -201,13 +201,13 @@ public function testMakeColumns() ]; // No column count - no changes to the array - $this->assertEquals( + $this->assertSame( $fiveValues, $this->table->makeColumns($fiveValues) ); // Column count of 3 leaves us with one   - $this->assertEquals( + $this->assertSame( [ ['Laura', 'Red', '15'], ['Katie', 'Blue', ' '], @@ -278,14 +278,14 @@ public function testSetFromArray() ['data' => 'number'], ]; - $this->assertEquals($expected, $this->table->heading); + $this->assertSame($expected, $this->table->heading); $expected = [ ['data' => 'Katie'], ['data' => 'Blue'], ]; - $this->assertEquals($expected, $this->table->rows[1]); + $this->assertSame($expected, $this->table->rows[1]); } public function testSetFromObject() @@ -304,14 +304,14 @@ public function testSetFromObject() ['data' => 'email'], ]; - $this->assertEquals($expected, $this->table->heading); + $this->assertSame($expected, $this->table->heading); $expected = [ 'name' => ['data' => 'Foo Bar'], 'email' => ['data' => 'foo@bar.com'], ]; - $this->assertEquals($expected, $this->table->rows[1]); + $this->assertSame($expected, $this->table->rows[1]); } public function testGenerate() @@ -464,7 +464,7 @@ public function testUndefined() $table = $this->table->generate($data); - $this->assertEquals('Undefined table data', $table); + $this->assertSame('Undefined table data', $table); } // -------------------------------------------------------------------- diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index 81c223b88239..a440ef4a02c1 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -37,7 +37,7 @@ public function testSetVarStoresData() $view->setVar('foo', 'bar'); - $this->assertEquals(['foo' => 'bar'], $view->getData()); + $this->assertSame(['foo' => 'bar'], $view->getData()); } public function testSetVarOverwrites() @@ -47,7 +47,7 @@ public function testSetVarOverwrites() $view->setVar('foo', 'bar'); $view->setVar('foo', 'baz'); - $this->assertEquals(['foo' => 'baz'], $view->getData()); + $this->assertSame(['foo' => 'baz'], $view->getData()); } //-------------------------------------------------------------------- @@ -63,7 +63,7 @@ public function testSetDataStoresValue() $view->setData($expected); - $this->assertEquals($expected, $view->getData()); + $this->assertSame($expected, $view->getData()); } public function testSetDataMergesData() @@ -82,7 +82,7 @@ public function testSetDataMergesData() 'bar' => 'baz', ]); - $this->assertEquals($expected, $view->getData()); + $this->assertSame($expected, $view->getData()); } public function testSetDataOverwritesData() @@ -100,7 +100,7 @@ public function testSetDataOverwritesData() 'bar' => 'baz', ]); - $this->assertEquals($expected, $view->getData()); + $this->assertSame($expected, $view->getData()); } //-------------------------------------------------------------------- @@ -111,7 +111,7 @@ public function testSetVarWillEscape() $view->setVar('foo', 'bar&', 'html'); - $this->assertEquals(['foo' => 'bar&'], $view->getData()); + $this->assertSame(['foo' => 'bar&'], $view->getData()); } public function testSetDataWillEscapeAll() @@ -128,7 +128,7 @@ public function testSetDataWillEscapeAll() 'bar' => 'baz<', ], 'html'); - $this->assertEquals($expected, $view->getData()); + $this->assertSame($expected, $view->getData()); } //-------------------------------------------------------------------- @@ -152,13 +152,13 @@ public function testRenderString() $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; - $this->assertEquals($expected, $view->renderString('

')); + $this->assertSame($expected, $view->renderString('

')); } public function testRenderStringNullTempdata() { $view = new View($this->config, $this->viewsDir, $this->loader); - $this->assertEquals('test string', $view->renderString('test string')); + $this->assertSame('test string', $view->renderString('test string')); } //-------------------------------------------------------------------- @@ -196,7 +196,7 @@ public function testRenderCanSaveData() $expected = ['testString' => 'Hello World']; - $this->assertEquals($expected, $view->getData()); + $this->assertSame($expected, $view->getData()); } public function testRenderCanSaveDataThroughConfigSetting() @@ -210,7 +210,7 @@ public function testRenderCanSaveDataThroughConfigSetting() $expected = ['testString' => 'Hello World']; - $this->assertEquals($expected, $view->getData()); + $this->assertSame($expected, $view->getData()); } //-------------------------------------------------------------------- @@ -224,7 +224,7 @@ public function testCanDeleteData() $view->resetData(); - $this->assertEquals([], $view->getData()); + $this->assertSame([], $view->getData()); } //-------------------------------------------------------------------- @@ -250,11 +250,11 @@ public function testRenderStringSavingData() //I think saveData is sava current data, is not clean already set data. $view->setVar('testString', 'Hello World'); - $this->assertEquals($expected, $view->renderString('

', [], false)); + $this->assertSame($expected, $view->renderString('

', [], false)); $this->assertArrayNotHasKey('testString', $view->getData()); $view->setVar('testString', 'Hello World'); - $this->assertEquals($expected, $view->renderString('

', [], true)); + $this->assertSame($expected, $view->renderString('

', [], true)); $this->assertArrayHasKey('testString', $view->getData()); } @@ -268,7 +268,7 @@ public function testPerformanceLogging() $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; - $this->assertEquals($expected, $view->renderString('

', [], true)); + $this->assertSame($expected, $view->renderString('

', [], true)); $this->assertCount(1, $view->getPerformanceData()); } @@ -280,7 +280,7 @@ public function testPerformanceNonLogging() $view->setVar('testString', 'Hello World'); $expected = '

Hello World

'; - $this->assertEquals($expected, $view->renderString('

', [], true)); + $this->assertSame($expected, $view->renderString('

', [], true)); $this->assertCount(0, $view->getPerformanceData()); } @@ -336,7 +336,7 @@ public function testRenderLayoutWithInclude() $this->assertTrue(strpos($content, '

Open

') !== false); $this->assertTrue(strpos($content, '

Hello World

') !== false); - $this->assertEquals(2, substr_count($content, 'Hello World')); + $this->assertSame(2, substr_count($content, 'Hello World')); } public function testRenderLayoutBroken() diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index bdf28fa0eb19..ca3cc49cb19c 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -165,8 +165,16 @@ public function __construct() 'target' => 'newest', 'use_class_const' => true, ], - 'php_unit_set_up_tear_down_visibility' => true, - 'php_unit_size_class' => false, + 'php_unit_set_up_tear_down_visibility' => true, + 'php_unit_size_class' => false, + 'php_unit_strict' => [ + 'assertions' => [ + 'assertAttributeEquals', + 'assertAttributeNotEquals', + 'assertEquals', + 'assertNotEquals', + ], + ], 'php_unit_test_annotation' => ['style' => 'prefix'], 'php_unit_test_case_static_method_calls' => [ 'call_type' => 'this', From 7b7d251f898ddb8afcf3fcf0c7d498d448844c19 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Mon, 28 Jun 2021 22:08:40 +0800 Subject: [PATCH 0044/2325] Convert to explicit those implicit string variables (#4882) --- app/Views/errors/html/error_exception.php | 2 +- system/Commands/Encryption/GenerateKey.php | 4 ++-- system/Config/DotEnv.php | 4 ++-- system/Database/BaseBuilder.php | 21 ++++++++++----------- system/Database/Postgre/Builder.php | 4 ++-- system/Database/SQLSRV/Builder.php | 4 ++-- system/Debug/Toolbar.php | 2 +- system/Format/XMLFormatter.php | 4 ++-- system/Helpers/form_helper.php | 2 +- tests/system/CLI/CLITest.php | 4 ++-- tests/system/HTTP/MessageTest.php | 2 +- tests/system/Helpers/CookieHelperTest.php | 4 ++-- tests/system/Helpers/FormHelperTest.php | 10 +++++----- tests/system/Log/LoggerTest.php | 2 +- utils/PhpCsFixer/CodeIgniter4.php | 6 ++++-- 15 files changed, 38 insertions(+), 37 deletions(-) diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 626e92fb36df..4477ee08ff8b 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -92,7 +92,7 @@ foreach ($row['args'] as $key => $value) : ?> - name : "#$key") ?> + name : "#{$key}") ?>
diff --git a/system/Commands/Encryption/GenerateKey.php b/system/Commands/Encryption/GenerateKey.php index cd9e1f100296..1b7bbbef5801 100644 --- a/system/Commands/Encryption/GenerateKey.php +++ b/system/Commands/Encryption/GenerateKey.php @@ -190,7 +190,7 @@ protected function writeNewEncryptionKeyToFile(string $oldKey, string $newKey): $ret = file_put_contents($envFile, preg_replace( $this->keyPattern($oldKey), - "\nencryption.key = $newKey", + "\nencryption.key = {$newKey}", file_get_contents($envFile) )); @@ -209,7 +209,7 @@ protected function keyPattern(string $oldKey): string $escaped = preg_quote($oldKey, '/'); if ($escaped !== '') { - $escaped = "[$escaped]*"; + $escaped = "[{$escaped}]*"; } return "/^[#\s]*encryption.key[=\s]*{$escaped}$/m"; diff --git a/system/Config/DotEnv.php b/system/Config/DotEnv.php index 92fbad012784..b0b55b1195f2 100644 --- a/system/Config/DotEnv.php +++ b/system/Config/DotEnv.php @@ -107,7 +107,7 @@ public function parse(): ?array protected function setVariable(string $name, string $value = '') { if (! getenv($name, true)) { - putenv("$name=$value"); + putenv("{$name}={$value}"); } if (empty($_ENV[$name])) { @@ -192,7 +192,7 @@ protected function sanitizeValue(string $value): string ); $value = preg_replace($regexPattern, '$1', $value); - $value = str_replace("\\$quote", $quote, $value); + $value = str_replace("\\{$quote}", $quote, $value); $value = str_replace('\\\\', '\\', $value); } else { $parts = explode(' #', $value, 2); diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index c2c5f179d29a..2038c1f97cf2 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -776,14 +776,14 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type if (empty($op)) { $k .= ' ='; } else { - $k .= " $op"; + $k .= " {$op}"; } if ($v instanceof Closure) { $builder = $this->cleanClone(); $v = '(' . str_replace("\n", ' ', $v($builder)->getCompiledSelect()) . ')'; } else { - $v = " :$bind:"; + $v = " :{$bind}:"; } } elseif (! $this->hasOperator($k) && $qbKey !== 'QBHaving') { // value appears not to have been set, assign the test to IS NULL @@ -989,9 +989,8 @@ protected function _whereIn(string $key = null, $values = null, bool $not = fals if (CI_DEBUG) { throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); } - // @codeCoverageIgnoreStart - return $this; - // @codeCoverageIgnoreEnd + + return $this; // @codeCoverageIgnore } if (! is_bool($escape)) { @@ -1017,7 +1016,7 @@ protected function _whereIn(string $key = null, $values = null, bool $not = fals $prefix = empty($this->$clause) ? $this->groupGetType('') : $this->groupGetType($type); $whereIn = [ - 'condition' => $prefix . $key . $not . ($values instanceof Closure ? " IN ($ok)" : " IN :{$ok}:"), + 'condition' => $prefix . $key . $not . ($values instanceof Closure ? " IN ({$ok})" : " IN :{$ok}:"), 'escape' => false, ]; @@ -1236,11 +1235,11 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri if ($side === 'none') { $bind = $this->setBind($k, $v, $escape); } elseif ($side === 'before') { - $bind = $this->setBind($k, "%$v", $escape); + $bind = $this->setBind($k, "%{$v}", $escape); } elseif ($side === 'after') { - $bind = $this->setBind($k, "$v%", $escape); + $bind = $this->setBind($k, "{$v}%", $escape); } else { - $bind = $this->setBind($k, "%$v%", $escape); + $bind = $this->setBind($k, "%{$v}%", $escape); } $likeStatement = $this->_like_statement($prefix, $k, $not, $bind, $insensitiveSearch); @@ -1691,7 +1690,7 @@ public function set($key, ?string $value = '', bool $escape = null) foreach ($key as $k => $v) { if ($escape) { $bind = $this->setBind($k, $v, $escape); - $this->QBSet[$this->db->protectIdentifiers($k, false, $escape)] = ":$bind:"; + $this->QBSet[$this->db->protectIdentifiers($k, false, $escape)] = ":{$bind}:"; } else { $this->QBSet[$this->db->protectIdentifiers($k, false, $escape)] = $v; } @@ -2573,7 +2572,7 @@ public function setUpdateBatch($key, string $index = '', bool $escape = null) $bind = $this->setBind($k2, $v2, $escape); - $clean[$this->db->protectIdentifiers($k2, false, $escape)] = ":$bind:"; + $clean[$this->db->protectIdentifiers($k2, false, $escape)] = ":{$bind}:"; } if ($indexSet === false) { diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index ad2a25f06920..77079da69c66 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -173,13 +173,13 @@ public function replace(array $set = null) $value = $set[$key]; $builder = $this->db->table($table); - $exists = $builder->where("$key = $value", null, false)->get()->getFirstRow(); + $exists = $builder->where("{$key} = {$value}", null, false)->get()->getFirstRow(); if (empty($exists)) { $result = $builder->insert($set); } else { array_pop($set); - $result = $builder->update($set, "$key = $value"); + $result = $builder->update($set, "{$key} = {$value}"); } unset($builder); diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index 656854093ba0..d35516abb7e5 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -643,14 +643,14 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type if (empty($op)) { $k .= ' ='; } else { - $k .= " $op"; + $k .= " {$op}"; } if ($v instanceof Closure) { $builder = $this->cleanClone(); $v = '(' . str_replace("\n", ' ', $v($builder)->getCompiledSelect()) . ')'; } else { - $v = " :$bind:"; + $v = " :{$bind}:"; } } elseif (! $this->hasOperator($k) && $qbKey !== 'QBHaving') { // value appears not to have been set, assign the test to IS NULL diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 1dae2bd08f36..1ec5b1d41101 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -345,7 +345,7 @@ public function prepare(RequestInterface $request = null, ResponseInterface $res // then we send headers saying where to find the debug data // for this response if ($request->isAJAX() || strpos($format, 'html') === false) { - $response->setHeader('Debugbar-Time', "$time") + $response->setHeader('Debugbar-Time', "{$time}") ->setHeader('Debugbar-Link', site_url("?debugbar_time={$time}")) ->getBody(); diff --git a/system/Format/XMLFormatter.php b/system/Format/XMLFormatter.php index ff3c5698b6ed..ad129374687b 100644 --- a/system/Format/XMLFormatter.php +++ b/system/Format/XMLFormatter.php @@ -64,10 +64,10 @@ protected function arrayToXML(array $data, &$output) $key = $this->normalizeXMLTag($key); if (is_array($value)) { - $subnode = $output->addChild("$key"); + $subnode = $output->addChild("{$key}"); $this->arrayToXML($value, $subnode); } else { - $output->addChild("$key", htmlspecialchars("$value")); + $output->addChild("{$key}", htmlspecialchars("{$value}")); } } } diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index c1a4b8f0e91d..24954a87c6ef 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -571,7 +571,7 @@ function form_datalist(string $name, string $value, array $options): string $out .= ""; foreach ($options as $option) { - $out .= "' . "\n"); diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 3d8f3df3229c..117d87a136d4 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -111,7 +111,7 @@ public function testColorSupportOnNoColor() CLI::init(); // force re-check on env $this->assertSame('test', CLI::color('test', 'white', 'green')); - putenv($nocolor ? "NO_COLOR=$nocolor" : 'NO_COLOR'); + putenv($nocolor ? "NO_COLOR={$nocolor}" : 'NO_COLOR'); } public function testColorSupportOnHyperTerminals() @@ -121,7 +121,7 @@ public function testColorSupportOnHyperTerminals() CLI::init(); // force re-check on env $this->assertSame("\033[1;37m\033[42m\033[4mtest\033[0m", CLI::color('test', 'white', 'green', 'underline')); - putenv($termProgram ? "TERM_PROGRAM=$termProgram" : 'TERM_PROGRAM'); + putenv($termProgram ? "TERM_PROGRAM={$termProgram}" : 'TERM_PROGRAM'); } public function testStreamSupports() diff --git a/tests/system/HTTP/MessageTest.php b/tests/system/HTTP/MessageTest.php index 50f8a4e6cd04..1adb2bbade7d 100644 --- a/tests/system/HTTP/MessageTest.php +++ b/tests/system/HTTP/MessageTest.php @@ -275,7 +275,7 @@ public function testPopulateHeadersWithoutContentType() $this->message->populateHeaders(); $this->assertNull($this->message->header('content-type')); - putenv("CONTENT_TYPE=$originalEnv"); + putenv("CONTENT_TYPE={$originalEnv}"); $this->message->removeHeader('accept-language'); $_SERVER = $original; // restore so code coverage doesn't break } diff --git a/tests/system/Helpers/CookieHelperTest.php b/tests/system/Helpers/CookieHelperTest.php index 12dab4b9a2b7..f6060775e801 100755 --- a/tests/system/Helpers/CookieHelperTest.php +++ b/tests/system/Helpers/CookieHelperTest.php @@ -78,8 +78,8 @@ public function testSetCookieSecured() { $pre = 'Hello, I try to'; $pst = 'your site'; - $unsec = "$pre $pst"; - $sec = "$pre [removed]alert('Hack');[removed] $pst"; + $unsec = "{$pre} {$pst}"; + $sec = "{$pre} [removed]alert('Hack');[removed] {$pst}"; $unsecured = 'unsecured'; $secured = 'secured'; diff --git a/tests/system/Helpers/FormHelperTest.php b/tests/system/Helpers/FormHelperTest.php index c467d55c5194..f23cdf0d8ede 100644 --- a/tests/system/Helpers/FormHelperTest.php +++ b/tests/system/Helpers/FormHelperTest.php @@ -37,7 +37,7 @@ public function testFormOpenBasic() $Name = csrf_token(); $expected = << - + EOH; } else { @@ -95,7 +95,7 @@ public function testFormOpenWithoutAction() $Name = csrf_token(); $expected = << - + EOH; } else { @@ -129,7 +129,7 @@ public function testFormOpenWithoutMethod() $Name = csrf_token(); $expected = << - + EOH; } else { @@ -164,7 +164,7 @@ public function testFormOpenWithHidden() $expected = << - + EOH; } else { @@ -204,7 +204,7 @@ public function testFormOpenMultipart() $Name = csrf_token(); $expected = << - + EOH; } else { diff --git a/tests/system/Log/LoggerTest.php b/tests/system/Log/LoggerTest.php index 0a178086c549..c4ba3a9a67eb 100644 --- a/tests/system/Log/LoggerTest.php +++ b/tests/system/Log/LoggerTest.php @@ -213,7 +213,7 @@ public function testLogInterpolatesFileAndLine() $logger->log('debug', 'Test message {file} {line}'); $line = __LINE__ - 1; - $expected = "LoggerTest.php $line"; + $expected = "LoggerTest.php {$line}"; $logs = TestHandler::getLogs(); diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 2aee033b0889..acea9a43bfda 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -113,8 +113,9 @@ public function __construct() 'noise_remaining_usages' => false, 'noise_remaining_usages_exclude' => [], ], - 'final_class' => false, - 'final_internal_class' => [ + 'explicit_string_variable' => true, + 'final_class' => false, + 'final_internal_class' => [ 'annotation_exclude' => ['@no-final'], 'annotation_include' => ['@internal'], 'consider_absent_docblock_as_internal_class' => false, @@ -270,6 +271,7 @@ public function __construct() 'psr_autoloading' => ['dir' => null], 'set_type_to_cast' => true, 'short_scalar_cast' => true, + 'simple_to_complex_string_variable' => true, 'standardize_increment' => true, 'static_lambda' => true, 'switch_case_semicolon_to_colon' => true, From 308d0bed2dad24707deb2695c65706bb5e40c261 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Mon, 28 Jun 2021 22:10:44 +0800 Subject: [PATCH 0045/2325] Enable `explicit_indirect_variable` (#4881) --- system/BaseModel.php | 6 +++--- system/CLI/BaseCommand.php | 4 ++-- system/Common.php | 2 +- system/Config/BaseConfig.php | 21 ++++++++++----------- system/Config/Factories.php | 2 +- system/Controller.php | 6 +++--- system/Database/BaseBuilder.php | 18 +++++++++--------- system/Database/BaseConnection.php | 6 +++--- system/Database/BaseResult.php | 2 +- system/Database/Config.php | 6 +++--- system/Database/SQLSRV/Builder.php | 2 +- system/Database/SQLite3/Result.php | 2 +- system/Debug/Exceptions.php | 4 ++-- system/Email/Email.php | 6 +++--- system/Entity/Entity.php | 4 ++-- system/HTTP/ResponseTrait.php | 2 +- system/HTTP/UserAgent.php | 2 +- system/Helpers/array_helper.php | 2 +- system/I18n/Time.php | 4 ++-- system/Images/Handlers/BaseHandler.php | 2 +- system/Model.php | 6 +++--- system/Test/CIUnitTestCase.php | 6 +++--- system/Test/DatabaseTestTrait.php | 2 +- system/Test/Fabricator.php | 4 ++-- system/Validation/Validation.php | 24 ++++++++++++------------ system/View/Cell.php | 2 +- tests/system/API/ResponseTraitTest.php | 4 ++-- tests/system/CommonFunctionsTest.php | 2 +- tests/system/Session/SessionTest.php | 2 +- tests/system/Test/TestResponseTest.php | 2 +- utils/PhpCsFixer/CodeIgniter4.php | 7 ++++--- 31 files changed, 82 insertions(+), 82 deletions(-) diff --git a/system/BaseModel.php b/system/BaseModel.php index af0175352e93..b6bee0677f33 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1633,10 +1633,10 @@ protected function transformDataToArray($data, string $type): array public function __get(string $name) { if (property_exists($this, $name)) { - return $this->$name; + return $this->{$name}; } - return $this->db->$name ?? null; + return $this->db->{$name} ?? null; } /** @@ -1652,7 +1652,7 @@ public function __isset(string $name): bool return true; } - return isset($this->db->$name); + return isset($this->db->{$name}); } /** diff --git a/system/CLI/BaseCommand.php b/system/CLI/BaseCommand.php index 44e22a1b2a3f..d548f26c402e 100644 --- a/system/CLI/BaseCommand.php +++ b/system/CLI/BaseCommand.php @@ -230,7 +230,7 @@ public function getPad(array $array, int $pad): int */ public function __get(string $key) { - return $this->$key ?? null; + return $this->{$key} ?? null; } /** @@ -242,6 +242,6 @@ public function __get(string $key) */ public function __isset(string $key): bool { - return isset($this->$key); + return isset($this->{$key}); } } diff --git a/system/Common.php b/system/Common.php index ed2f57dd3f1a..da8edd0fcac0 100644 --- a/system/Common.php +++ b/system/Common.php @@ -457,7 +457,7 @@ function esc($data, string $context = 'html', string $encoding = null) $escaper = new Escaper($encoding); } - $data = $escaper->$method($data); + $data = $escaper->{$method}($data); } return $data; diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index bbe98ce3c4c3..48d80f08547b 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -69,16 +69,15 @@ public function __construct() $shortPrefix = strtolower(substr($prefix, $slashAt === false ? 0 : $slashAt + 1)); foreach ($properties as $property) { - $this->initEnvValue($this->$property, $property, $prefix, $shortPrefix); + $this->initEnvValue($this->{$property}, $property, $prefix, $shortPrefix); if ($this instanceof Encryption && $property === 'key') { - // Handle hex2bin prefix - if (strpos($this->$property, 'hex2bin:') === 0) { - $this->$property = hex2bin(substr($this->$property, 8)); - } - // Handle base64 prefix - elseif (strpos($this->$property, 'base64:') === 0) { - $this->$property = base64_decode(substr($this->$property, 7), true); + if (strpos($this->{$property}, 'hex2bin:') === 0) { + // Handle hex2bin prefix + $this->{$property} = hex2bin(substr($this->{$property}, 8)); + } elseif (strpos($this->{$property}, 'base64:') === 0) { + // Handle base64 prefix + $this->{$property} = base64_decode(substr($this->{$property}, 7), true); } } } @@ -188,10 +187,10 @@ protected function registerProperties() } foreach ($properties as $property => $value) { - if (isset($this->$property) && is_array($this->$property) && is_array($value)) { - $this->$property = array_merge($this->$property, $value); + if (isset($this->{$property}) && is_array($this->{$property}) && is_array($value)) { + $this->{$property} = array_merge($this->{$property}, $value); } else { - $this->$property = $value; + $this->{$property} = $value; } } } diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 88e905e61560..97218b6ea513 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -242,7 +242,7 @@ public static function getOptions(string $component): array // Handle Config as a special case to prevent logic loops ? self::$configOptions // Load values from the best Factory configuration (will include Registrars) - : config('Factory')->$component ?? []; + : config('Factory')->{$component} ?? []; return self::setOptions($component, $values); } diff --git a/system/Controller.php b/system/Controller.php index 93f8b0c3efbf..d19adf550fac 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -162,17 +162,17 @@ protected function validate($rules, array $messages = []): bool // If the rule wasn't found in the \Config\Validation, we // should throw an exception so the developer can find it. - if (! isset($validation->$rules)) { + if (! isset($validation->{$rules})) { throw ValidationException::forRuleNotFound($rules); } // If no error message is defined, use the error message in the Config\Validation file if (! $messages) { $errorName = $rules . '_errors'; - $messages = $validation->$errorName ?? []; + $messages = $validation->{$errorName} ?? []; } - $rules = $validation->$rules; + $rules = $validation->{$rules}; } return $this->validator->withRequest($this->request)->setRules($rules, $messages)->run(); diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 2038c1f97cf2..612794b4745f 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -272,7 +272,7 @@ public function __construct($tableName, ConnectionInterface &$db, array $options if (! empty($options)) { foreach ($options as $key => $value) { if (property_exists($this, $key)) { - $this->$key = $value; + $this->{$key} = $value; } } } @@ -754,7 +754,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type } foreach ($key as $k => $v) { - $prefix = empty($this->$qbKey) ? $this->groupGetType('') : $this->groupGetType($type); + $prefix = empty($this->{$qbKey}) ? $this->groupGetType('') : $this->groupGetType($type); if ($v !== null) { $op = $this->getOperator($k, true); @@ -1013,7 +1013,7 @@ protected function _whereIn(string $key = null, $values = null, bool $not = fals $ok = $this->setBind($ok, $whereIn, $escape); } - $prefix = empty($this->$clause) ? $this->groupGetType('') : $this->groupGetType($type); + $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); $whereIn = [ 'condition' => $prefix . $key . $not . ($values instanceof Closure ? " IN ({$ok})" : " IN :{$ok}:"), @@ -1230,7 +1230,7 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri $v = strtolower($v); } - $prefix = empty($this->$clause) ? $this->groupGetType('') : $this->groupGetType($type); + $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); if ($side === 'none') { $bind = $this->setBind($k, $v, $escape); @@ -1416,7 +1416,7 @@ protected function groupStartPrepare(string $not = '', string $type = 'AND ', st $type = $this->groupGetType($type); $this->QBWhereGroupStarted = true; - $prefix = empty($this->$clause) ? '' : $type; + $prefix = empty($this->{$clause}) ? '' : $type; $where = [ 'condition' => $prefix . $not . str_repeat(' ', ++$this->QBWhereGroupCount) . ' (', 'escape' => false, @@ -2917,8 +2917,8 @@ protected function compileIgnore(string $statement) */ protected function compileWhereHaving(string $qbKey): string { - if (! empty($this->$qbKey)) { - foreach ($this->$qbKey as &$qbkey) { + if (! empty($this->{$qbKey})) { + foreach ($this->{$qbKey} as &$qbkey) { // Is this condition already compiled? if (is_string($qbkey)) { continue; @@ -2974,7 +2974,7 @@ protected function compileWhereHaving(string $qbKey): string } return ($qbKey === 'QBHaving' ? "\nHAVING " : "\nWHERE ") - . implode("\n", $this->$qbKey); + . implode("\n", $this->{$qbKey}); } return ''; @@ -3172,7 +3172,7 @@ public function resetQuery() protected function resetRun(array $qbResetItems) { foreach ($qbResetItems as $item => $defaultValue) { - $this->$item = $defaultValue; + $this->{$item} = $defaultValue; } } diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 98422325cf15..30c1e4f5b443 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -307,7 +307,7 @@ abstract class BaseConnection implements ConnectionInterface public function __construct(array $params) { foreach ($params as $key => $value) { - $this->$key = $value; + $this->{$key} = $value; } $queryClass = str_replace('Connection', 'Query', static::class); @@ -360,7 +360,7 @@ public function initialize() // Replace the current settings with those of the failover foreach ($failover as $key => $val) { if (property_exists($this, $key)) { - $this->$key = $val; + $this->{$key} = $val; } } @@ -1783,7 +1783,7 @@ abstract protected function _foreignKeyData(string $table): array; public function __get(string $key) { if (property_exists($this, $key)) { - return $this->$key; + return $this->{$key}; } return null; diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index 9c22e34ca74a..189313248dae 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -144,7 +144,7 @@ public function getCustomResultObject(string $className) $this->customResultObject[$className][$i] = new $className(); foreach ($this->{$_data}[$i] as $key => $value) { - $this->customResultObject[$className][$i]->$key = $value; + $this->customResultObject[$className][$i]->{$key} = $value; } } diff --git a/system/Database/Config.php b/system/Database/Config.php index bde77f39c1e2..9201afb480b6 100644 --- a/system/Database/Config.php +++ b/system/Database/Config.php @@ -64,7 +64,7 @@ public static function connect($group = null, bool $getShared = true) $group = ENVIRONMENT === 'testing' ? 'tests' : $config->defaultGroup; } - if (is_string($group) && ! isset($config->$group) && strpos($group, 'custom-') !== 0) { + if (is_string($group) && ! isset($config->{$group}) && strpos($group, 'custom-') !== 0) { throw new InvalidArgumentException($group . ' is not a valid database connection group.'); } @@ -74,8 +74,8 @@ public static function connect($group = null, bool $getShared = true) static::ensureFactory(); - if (isset($config->$group)) { - $config = $config->$group; + if (isset($config->{$group})) { + $config = $config->{$group}; } $connection = static::$factory->load($config, $group); diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index d35516abb7e5..39d72d207aa8 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -621,7 +621,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type } foreach ($key as $k => $v) { - $prefix = empty($this->$qbKey) ? $this->groupGetType('') : $this->groupGetType($type); + $prefix = empty($this->{$qbKey}) ? $this->groupGetType('') : $this->groupGetType($type); if ($v !== null) { $op = $this->getOperator($k, true); diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 4bddc63fe854..b8902b5a81d4 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -164,7 +164,7 @@ protected function fetchObject(string $className = 'stdClass') } $classSet = Closure::bind(function ($key, $value) { - $this->$key = $value; + $this->{$key} = $value; }, $classObj, $className); foreach (array_keys($row) as $key) { diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 65222b0a6b06..c613579332f0 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -313,8 +313,8 @@ protected function maskSensitiveData(&$trace, array $keysToMask, string $path = if (strpos(strrev($path . '/' . $index), strrev($keyToMask)) === 0) { if (is_array($trace) && array_key_exists($index, $trace)) { $trace[$index] = '******************'; - } elseif (is_object($trace) && property_exists($trace, $index) && isset($trace->$index)) { - $trace->$index = '******************'; + } elseif (is_object($trace) && property_exists($trace, $index) && isset($trace->{$index})) { + $trace->{$index} = '******************'; } } } diff --git a/system/Email/Email.php b/system/Email/Email.php index 406a8c5ee7c9..1a49b03ab0ca 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -420,9 +420,9 @@ public function initialize($config) $method = 'set' . ucfirst($key); if (method_exists($this, $method)) { - $this->$method($config[$key]); + $this->{$method}($config[$key]); } else { - $this->$key = $config[$key]; + $this->{$key} = $config[$key]; } } } @@ -1741,7 +1741,7 @@ protected function spoolEmail() $method = 'sendWith' . ucfirst($protocol); try { - $success = $this->$method(); + $success = $this->{$method}(); } catch (ErrorException $e) { $success = false; log_message('error', 'Email: ' . $method . ' throwed ' . $e->getMessage()); diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 7a63503f2dc7..753f9106f975 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -477,7 +477,7 @@ public function __set(string $key, $value = null) $method = 'set' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $key))); if (method_exists($this, $method)) { - $this->$method($value); + $this->{$method}($value); return $this; } @@ -517,7 +517,7 @@ public function __get(string $key) // if a set* method exists for this key, // use that method to insert this value. if (method_exists($this, $method)) { - $result = $this->$method(); + $result = $this->{$method}(); } // Otherwise return the protected property diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 38ab87ba9e2c..2e88e71b7941 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -573,7 +573,7 @@ public function setCookie( // always leave 'name' in last place, as the loop will break otherwise, due to $$item foreach (['samesite', 'value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name'] as $item) { if (isset($name[$item])) { - $$item = $name[$item]; + ${$item} = $name[$item]; } } } diff --git a/system/HTTP/UserAgent.php b/system/HTTP/UserAgent.php index 26754bfe8fdc..6fe613f43de6 100644 --- a/system/HTTP/UserAgent.php +++ b/system/HTTP/UserAgent.php @@ -333,7 +333,7 @@ protected function compileData() $this->setPlatform(); foreach (['setRobot', 'setBrowser', 'setMobile'] as $function) { - if ($this->$function() === true) { + if ($this->{$function}() === true) { break; } } diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php index 7f95aecdaf80..d0af3e579d05 100644 --- a/system/Helpers/array_helper.php +++ b/system/Helpers/array_helper.php @@ -169,7 +169,7 @@ function array_sort_by_multiple_keys(array &$array, array $sortColumns): bool if (is_object(reset($carry))) { // Extract the object attribute foreach ($carry as $index => $object) { - $carry[$index] = $object->$keySegment; + $carry[$index] = $object->{$keySegment}; } continue; diff --git a/system/I18n/Time.php b/system/I18n/Time.php index d3899a7b883a..e1af6f06e522 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -778,7 +778,7 @@ protected function setValue(string $name, $value) { [$year, $month, $day, $hour, $minute, $second] = explode('-', $this->format('Y-n-j-G-i-s')); - $$name = $value; + ${$name} = $value; return Time::create( (int) $year, @@ -1352,7 +1352,7 @@ public function __get($name) $method = 'get' . ucfirst($name); if (method_exists($this, $method)) { - return $this->$method(); + return $this->{$method}(); } return null; diff --git a/system/Images/Handlers/BaseHandler.php b/system/Images/Handlers/BaseHandler.php index bcda8e98561e..4a8cc941735c 100644 --- a/system/Images/Handlers/BaseHandler.php +++ b/system/Images/Handlers/BaseHandler.php @@ -812,7 +812,7 @@ abstract protected function process(string $action); public function __call(string $name, array $args = []) { if (method_exists($this->image(), $name)) { - return $this->image()->$name(...$args); + return $this->image()->{$name}(...$args); } } diff --git a/system/Model.php b/system/Model.php index 7376d59e3cde..3a8d1fe96d6b 100644 --- a/system/Model.php +++ b/system/Model.php @@ -710,8 +710,8 @@ public function __get(string $name) return parent::__get($name); } - if (isset($this->builder()->$name)) { - return $this->builder()->$name; + if (isset($this->builder()->{$name})) { + return $this->builder()->{$name}; } return null; @@ -730,7 +730,7 @@ public function __isset(string $name): bool return true; } - return isset($this->builder()->$name); + return isset($this->builder()->{$name}); } /** diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index ef625c340210..6a0d6dd10354 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -236,7 +236,7 @@ protected function setUp(): void } foreach ($this->setUpMethods as $method) { - $this->$method(); + $this->{$method}(); } // Check for the database trait @@ -253,7 +253,7 @@ protected function tearDown(): void parent::tearDown(); foreach ($this->tearDownMethods as $method) { - $this->$method(); + $this->{$method}(); } // Check for the database trait @@ -283,7 +283,7 @@ private function callTraitMethods(string $stage): void $method = $stage . class_basename($trait); if (method_exists($this, $method)) { - $this->$method(); + $this->{$method}(); } } } diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index cd444c57406a..b39ec500d542 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -273,7 +273,7 @@ public function grabFromDatabase(string $table, string $column, array $where) $query = $query->getRow(); - return $query->$column ?? false; + return $query->{$column} ?? false; } //-------------------------------------------------------------------- diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index 0505298d634c..cc1260995322 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -126,8 +126,8 @@ public function __construct($model, array $formatters = null, string $locale = n // Determine eligible date fields foreach (['createdField', 'updatedField', 'deletedField'] as $field) { - if (! empty($this->model->$field)) { - $this->dateFields[] = $this->model->$field; + if (! empty($this->model->{$field})) { + $this->dateFields[] = $this->model->{$field}; } } diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 476b161e8aaa..2c5eee378fda 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -243,7 +243,7 @@ protected function processRules(string $field, string $label = null, $value, $ru continue; } - $passed = $passed && $set->$rule($value, $param, $data); + $passed = $passed && $set->{$rule}($value, $param, $data); break; } } @@ -284,7 +284,7 @@ protected function processRules(string $field, string $label = null, $value, $ru } $found = true; - $passed = $param === false ? $set->$rule($value, $error) : $set->$rule($value, $param, $data, $error); + $passed = $param === false ? $set->{$rule}($value, $error) : $set->{$rule}($value, $param, $data, $error); break; } @@ -450,15 +450,15 @@ public function hasRule(string $field): bool */ public function getRuleGroup(string $group): array { - if (! isset($this->config->$group)) { + if (! isset($this->config->{$group})) { throw ValidationException::forGroupNotFound($group); } - if (! is_array($this->config->$group)) { + if (! is_array($this->config->{$group})) { throw ValidationException::forGroupNotArray($group); } - return $this->config->$group; + return $this->config->{$group}; } /** @@ -474,8 +474,8 @@ public function setRuleGroup(string $group) $this->setRules($rules); $errorName = $group . '_errors'; - if (isset($this->config->$errorName)) { - $this->customErrors = $this->config->$errorName; + if (isset($this->config->{$errorName})) { + $this->customErrors = $this->config->{$errorName}; } } @@ -553,22 +553,22 @@ public function loadRuleGroup(string $group = null) return null; } - if (! isset($this->config->$group)) { + if (! isset($this->config->{$group})) { throw ValidationException::forGroupNotFound($group); } - if (! is_array($this->config->$group)) { + if (! is_array($this->config->{$group})) { throw ValidationException::forGroupNotArray($group); } - $this->setRules($this->config->$group); + $this->setRules($this->config->{$group}); // If {group}_errors exists in the config file, // then override our custom errors with them. $errorName = $group . '_errors'; - if (isset($this->config->$errorName)) { - $this->customErrors = $this->config->$errorName; + if (isset($this->config->{$errorName})) { + $this->customErrors = $this->config->{$errorName}; } return $this->rules; diff --git a/system/View/Cell.php b/system/View/Cell.php index e168596add4f..c97625a2ef66 100644 --- a/system/View/Cell.php +++ b/system/View/Cell.php @@ -137,7 +137,7 @@ public function render(string $library, $params = null, int $ttl = 0, string $ca } } - $output = $instance->$method(...array_values($fireArgs)); + $output = $instance->{$method}(...array_values($fireArgs)); } // Can we cache it? if (! empty($this->cache) && $ttl !== 0) { diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index 7ec5f5418623..865fc72eb7e5 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -51,7 +51,7 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// 'proxyIPs' => [], 'cookieSameSite' => 'Lax', ] as $key => $value) { - $config->$key = $value; + $config->{$key} = $value; } if (is_null($this->request)) { @@ -509,7 +509,7 @@ public function testFormatByRequestNegotiateIfFormatIsNotJsonOrXML() 'proxyIPs' => [], 'cookieSameSite' => 'Lax', ] as $key => $value) { - $config->$key = $value; + $config->{$key} = $value; } $request = new MockIncomingRequest($config, new URI($config->baseURL), null, new UserAgent()); diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index c76c3191e992..ce8a7c474175 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -371,7 +371,7 @@ protected function injectSessionMock() $appConfig = new App(); foreach ($defaults as $key => $config) { - $appConfig->$key = $config; + $appConfig->{$key} = $config; } $session = new MockSession(new FileHandler($appConfig, '127.0.0.1'), $appConfig); diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index ab49c2830200..a125badd461b 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -50,7 +50,7 @@ protected function getInstance($options = []) $appConfig = new AppConfig(); foreach ($config as $key => $c) { - $appConfig->$key = $c; + $appConfig->{$key} = $c; } $session = new MockSession(new FileHandler($appConfig, '127.0.0.1'), $appConfig); diff --git a/tests/system/Test/TestResponseTest.php b/tests/system/Test/TestResponseTest.php index 83050190b791..f63bf6429685 100644 --- a/tests/system/Test/TestResponseTest.php +++ b/tests/system/Test/TestResponseTest.php @@ -419,7 +419,7 @@ protected function getTestResponse($body = null, array $responseOptions = [], ar $method = 'set' . ucfirst($key); if (method_exists($this->response, $method)) { - $this->response = $this->response->$method($value); + $this->response = $this->response->{$method}($value); } } diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index acea9a43bfda..47faf8c2317a 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -113,9 +113,10 @@ public function __construct() 'noise_remaining_usages' => false, 'noise_remaining_usages_exclude' => [], ], - 'explicit_string_variable' => true, - 'final_class' => false, - 'final_internal_class' => [ + 'explicit_indirect_variable' => true, + 'explicit_string_variable' => true, + 'final_class' => false, + 'final_internal_class' => [ 'annotation_exclude' => ['@no-final'], 'annotation_include' => ['@internal'], 'consider_absent_docblock_as_internal_class' => false, From 9acff4fe0444e2264720e0550a1a11e29aa38f2f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 16:43:44 +0000 Subject: [PATCH 0046/2325] Update rector/rector requirement from 0.11.23 to 0.11.28 (#4889) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index b5805b3a510a..6cd2bf12c4ec 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "0.12.90", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.23", + "rector/rector": "0.11.28", "symplify/package-builder": "^9.3" }, "suggest": { From e524097492e1cbf1544416d09f0f4d82e88c8785 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 30 Jun 2021 17:03:52 +0700 Subject: [PATCH 0047/2325] Update to rector 0.11.29 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 6cd2bf12c4ec..4744042b7d0e 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "0.12.90", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.28", + "rector/rector": "0.11.29", "symplify/package-builder": "^9.3" }, "suggest": { From 0641dd9023a6595aa30534b6a99c9ae0854981de Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 15:37:38 +0000 Subject: [PATCH 0048/2325] Update rector/rector requirement from 0.11.29 to 0.11.32 (#4895) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4744042b7d0e..957d5a0220f2 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "0.12.90", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.29", + "rector/rector": "0.11.32", "symplify/package-builder": "^9.3" }, "suggest": { From 05988508d191ddea319054b46bbeaa306f6d160b Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 2 Jul 2021 16:58:12 +0800 Subject: [PATCH 0049/2325] Enable remaining rules in "f" (#4888) --- system/HTTP/CURLRequest.php | 2 +- system/HTTP/Files/UploadedFile.php | 2 +- tests/system/Log/Handlers/FileHandlerTest.php | 4 +- utils/PhpCsFixer/CodeIgniter4.php | 41 +++++++++++-------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index d1d4ace131c2..20e1fa32379b 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -617,7 +617,7 @@ protected function setCURLOptions(array $curlOptions = [], array $config = []) // Debug if ($config['debug']) { $curlOptions[CURLOPT_VERBOSE] = 1; - $curlOptions[CURLOPT_STDERR] = is_string($config['debug']) ? fopen($config['debug'], 'a+') : fopen('php://stderr', 'w'); + $curlOptions[CURLOPT_STDERR] = is_string($config['debug']) ? fopen($config['debug'], 'a+b') : fopen('php://stderr', 'wb'); } // Decode Content diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index e73cea923896..351ffa7de24d 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -177,7 +177,7 @@ protected function setPath(string $path): string mkdir($path, 0777, true); //create the index.html file if (! is_file($path . 'index.html')) { - $file = fopen($path . 'index.html', 'x+'); + $file = fopen($path . 'index.html', 'x+b'); fclose($file); } } diff --git a/tests/system/Log/Handlers/FileHandlerTest.php b/tests/system/Log/Handlers/FileHandlerTest.php index dca8d3ad1bc5..ef55dcbbc6ef 100644 --- a/tests/system/Log/Handlers/FileHandlerTest.php +++ b/tests/system/Log/Handlers/FileHandlerTest.php @@ -56,7 +56,7 @@ public function testHandleCreateFile() vfsStream::newFile($expected)->at(vfsStream::setup('root'))->withContent('This is a test log'); $logger->handle('warning', 'This is a test log'); - $fp = fopen($config->handlers['Tests\Support\Log\Handlers\TestHandler']['path'] . $expected, 'r'); + $fp = fopen($config->handlers['Tests\Support\Log\Handlers\TestHandler']['path'] . $expected, 'rb'); $line = fgets($fp); fclose($fp); @@ -75,7 +75,7 @@ public function testHandleDateTimeCorrectly() $expected = 'log-' . date('Y-m-d') . '.log'; vfsStream::newFile($expected)->at(vfsStream::setup('root'))->withContent('Test message'); $logger->handle('debug', 'Test message'); - $fp = fopen($config->handlers['Tests\Support\Log\Handlers\TestHandler']['path'] . $expected, 'r'); + $fp = fopen($config->handlers['Tests\Support\Log\Handlers\TestHandler']['path'] . $expected, 'rb'); $line = fgets($fp); // and get the second line fclose($fp); diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 47faf8c2317a..09838317afe1 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -121,23 +121,30 @@ public function __construct() 'annotation_include' => ['@internal'], 'consider_absent_docblock_as_internal_class' => false, ], - 'function_to_constant' => true, - 'heredoc_indentation' => ['indentation' => 'start_plus_one'], - 'heredoc_to_nowdoc' => true, - 'increment_style' => ['style' => 'post'], - 'indentation_type' => true, - 'lambda_not_used_import' => true, - 'line_ending' => true, - 'linebreak_after_opening_tag' => true, - 'list_syntax' => ['syntax' => 'short'], - 'logical_operators' => true, - 'lowercase_cast' => true, - 'lowercase_keywords' => true, - 'lowercase_static_reference' => true, - 'magic_constant_casing' => true, - 'magic_method_casing' => true, - 'mb_str_functions' => false, - 'method_argument_space' => [ + 'final_public_method_for_abstract_class' => false, + 'fopen_flag_order' => true, + 'fopen_flags' => ['b_mode' => true], + 'full_opening_tag' => true, + 'fully_qualified_strict_types' => true, + 'function_declaration' => ['closure_function_spacing' => 'one'], + 'function_typehint_space' => true, + 'function_to_constant' => true, + 'heredoc_indentation' => ['indentation' => 'start_plus_one'], + 'heredoc_to_nowdoc' => true, + 'increment_style' => ['style' => 'post'], + 'indentation_type' => true, + 'lambda_not_used_import' => true, + 'line_ending' => true, + 'linebreak_after_opening_tag' => true, + 'list_syntax' => ['syntax' => 'short'], + 'logical_operators' => true, + 'lowercase_cast' => true, + 'lowercase_keywords' => true, + 'lowercase_static_reference' => true, + 'magic_constant_casing' => true, + 'magic_method_casing' => true, + 'mb_str_functions' => false, + 'method_argument_space' => [ 'after_heredoc' => false, 'keep_multiple_spaces_after_comma' => false, 'on_multiline' => 'ensure_fully_multiline', From e1b3ec08355bff8efba71feb190d6240a5efc8f2 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 2 Jul 2021 23:58:00 +0800 Subject: [PATCH 0050/2325] Enable `escape_implicit_backslashes` fixer (#4880) --- system/CLI/CLI.php | 2 +- system/CLI/GeneratorTrait.php | 2 +- system/Commands/Encryption/GenerateKey.php | 2 +- system/Database/BaseBuilder.php | 2 +- system/Database/Database.php | 2 +- system/Database/SQLSRV/Builder.php | 2 +- system/Helpers/text_helper.php | 2 +- system/Typography/Typography.php | 2 +- tests/system/Commands/ScaffoldGeneratorTest.php | 10 +++++----- tests/system/Database/Live/EscapeTest.php | 2 +- tests/system/Database/Live/InsertTest.php | 2 +- tests/system/Helpers/TextHelperTest.php | 4 ++-- utils/PhpCsFixer/CodeIgniter4.php | 5 +++++ 13 files changed, 22 insertions(+), 17 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 4d5ad1ec8ab5..8e293d66a565 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -506,7 +506,7 @@ public static function color(string $text, string $foreground, string $backgroun if (strpos($text, "\033[0m") !== false) { // Split the text into parts so that we can see // if any part missing the color definition - $chunks = mb_split("\\033\[0m", $text); + $chunks = mb_split("\\033\\[0m", $text); // Reset text $text = ''; diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php index 925f1c73a6b5..ce3b97ec253f 100644 --- a/system/CLI/GeneratorTrait.php +++ b/system/CLI/GeneratorTrait.php @@ -254,7 +254,7 @@ protected function renderTemplate(array $data = []): string } catch (Throwable $e) { log_message('error', $e->getMessage()); - return view("CodeIgniter\Commands\Generators\Views\\{$this->template}", $data, ['debug' => false]); + return view("CodeIgniter\\Commands\\Generators\\Views\\{$this->template}", $data, ['debug' => false]); } } diff --git a/system/Commands/Encryption/GenerateKey.php b/system/Commands/Encryption/GenerateKey.php index 1b7bbbef5801..f87563a3cc23 100644 --- a/system/Commands/Encryption/GenerateKey.php +++ b/system/Commands/Encryption/GenerateKey.php @@ -212,6 +212,6 @@ protected function keyPattern(string $oldKey): string $escaped = "[{$escaped}]*"; } - return "/^[#\s]*encryption.key[=\s]*{$escaped}$/m"; + return "/^[#\\s]*encryption.key[=\\s]*{$escaped}$/m"; } } diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 612794b4745f..28213478a76b 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -671,7 +671,7 @@ public function join(string $table, string $cond, string $type = '', bool $escap $operator = $this->getOperator($condition); $cond .= $joints[$i]; - $cond .= preg_match("/(\(*)?([\[\]\w\.'-]+)" . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; + $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; } } diff --git a/system/Database/Database.php b/system/Database/Database.php index d7f629aba203..35cff46ae161 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -167,7 +167,7 @@ protected function initDriver(string $driver, string $class, $argument): object $class = $driver . '\\' . $class; if (strpos($driver, '\\') === false) { - $class = "CodeIgniter\Database\\{$class}"; + $class = "CodeIgniter\\Database\\{$class}"; } return new $class($argument); diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index 39d72d207aa8..7ad2f9269bec 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -160,7 +160,7 @@ public function join(string $table, string $cond, string $type = '', bool $escap $operator = $this->getOperator($condition); $cond .= $joints[$i]; - $cond .= preg_match("/(\(*)?([\[\]\w\.'-]+)" . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; + $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; } } diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 4d97522a21a1..52e423ff64af 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -550,7 +550,7 @@ function strip_quotes(string $str): string */ function quotes_to_entities(string $str): string { - return str_replace(["\'", '"', "'", '"'], [''', '"', ''', '"'], $str); + return str_replace(["\\'", '"', "'", '"'], [''', '"', ''', '"'], $str); } } diff --git a/system/Typography/Typography.php b/system/Typography/Typography.php index fa91bb8f49fb..ca56634b5c34 100644 --- a/system/Typography/Typography.php +++ b/system/Typography/Typography.php @@ -267,7 +267,7 @@ public function formatCharacters(string $str): string '/"(\W)/' => '”$1', '/(\W)"/' => '$1“', // apostrophes - "/(\w)'(\w)/" => '$1’$2', + '/(\w)\'(\w)/' => '$1’$2', // Em dash and ellipses dots '/\s?\-\-\s?/' => '—', '/(\w)\.{3}/' => '$1…', diff --git a/tests/system/Commands/ScaffoldGeneratorTest.php b/tests/system/Commands/ScaffoldGeneratorTest.php index 46cd3b113a80..89a41bfcb955 100644 --- a/tests/system/Commands/ScaffoldGeneratorTest.php +++ b/tests/system/Commands/ScaffoldGeneratorTest.php @@ -39,7 +39,7 @@ public function testCreateComponentProducesManyFiles() command('make:scaffold people'); $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); @@ -62,7 +62,7 @@ public function testCreateComponentWithManyOptions() command('make:scaffold user -restful -return entity'); $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); @@ -91,7 +91,7 @@ public function testCreateComponentWithOptionSuffix() command('make:scaffold order -suffix'); $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); @@ -120,7 +120,7 @@ public function testCreateComponentWithOptionForce() command('make:scaffold fixer -bare -force'); $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); @@ -147,7 +147,7 @@ public function testCreateComponentWithOptionNamespace() command('make:scaffold product -namespace App'); $dir = '\\' . DIRECTORY_SEPARATOR; - $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\.php"; + $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); diff --git a/tests/system/Database/Live/EscapeTest.php b/tests/system/Database/Live/EscapeTest.php index dbf6396d5bff..f99d2c778d96 100644 --- a/tests/system/Database/Live/EscapeTest.php +++ b/tests/system/Database/Live/EscapeTest.php @@ -72,7 +72,7 @@ public function testEscapeLikeString() public function testEscapeLikeStringDirect() { if ($this->db->DBDriver === 'MySQLi') { - $expected = "SHOW COLUMNS FROM brands WHERE column LIKE 'wild\_chars%'"; + $expected = "SHOW COLUMNS FROM brands WHERE column LIKE 'wild\\_chars%'"; $sql = "SHOW COLUMNS FROM brands WHERE column LIKE '" . $this->db->escapeLikeStringDirect('wild_chars') . "%'"; $this->assertSame($expected, $sql); diff --git a/tests/system/Database/Live/InsertTest.php b/tests/system/Database/Live/InsertTest.php index 74cb782410b4..d6817742d40b 100644 --- a/tests/system/Database/Live/InsertTest.php +++ b/tests/system/Database/Live/InsertTest.php @@ -93,7 +93,7 @@ public function testReplaceWithMatchingData() public function testBug302() { - $code = "my code \'CodeIgniter\Autoloader\'"; + $code = "my code \\'CodeIgniter\\Autoloader\\'"; $this->db->table('misc')->insert([ 'key' => 'test', diff --git a/tests/system/Helpers/TextHelperTest.php b/tests/system/Helpers/TextHelperTest.php index bdee7678e06e..919e9f6254b8 100755 --- a/tests/system/Helpers/TextHelperTest.php +++ b/tests/system/Helpers/TextHelperTest.php @@ -27,8 +27,8 @@ public function testStripSlashes() "No, my name is O'connor.", ]; $str = [ - "Is your name O\'reilly?", - "No, my name is O\'connor.", + "Is your name O\\'reilly?", + "No, my name is O\\'connor.", ]; $this->assertSame($expected, strip_slashes($str)); } diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 09838317afe1..8585cf656fea 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -113,6 +113,11 @@ public function __construct() 'noise_remaining_usages' => false, 'noise_remaining_usages_exclude' => [], ], + 'escape_implicit_backslashes' => [ + 'double_quoted' => true, + 'heredoc_syntax' => true, + 'single_quoted' => false, + ], 'explicit_indirect_variable' => true, 'explicit_string_variable' => true, 'final_class' => false, From 86ece118f578e44acf6b149a7199d977c4fcaab5 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 3 Jul 2021 00:36:27 +0800 Subject: [PATCH 0051/2325] Enable `no_blank_lines_after_class_opening` fixer --- tests/_support/Log/Handlers/TestHandler.php | 1 - tests/system/ControllerTest.php | 1 - tests/system/Files/FileWithVfsTest.php | 1 - tests/system/HTTP/IncomingRequestDetectingTest.php | 1 - tests/system/HTTP/MessageTest.php | 1 - tests/system/HTTP/NegotiateTest.php | 1 - tests/system/HTTP/RequestTest.php | 1 - tests/system/HTTP/ResponseSendTest.php | 1 - tests/system/Models/GeneralModelTest.php | 1 - tests/system/Pager/PagerTest.php | 1 - tests/system/RESTful/ResourceControllerTest.php | 1 - tests/system/RESTful/ResourcePresenterTest.php | 1 - tests/system/Router/RouterTest.php | 1 - tests/system/Test/TestCaseEmissionsTest.php | 1 - tests/system/Validation/CreditCardRulesTest.php | 1 - tests/system/Validation/FileRulesTest.php | 1 - utils/PhpCsFixer/CodeIgniter4.php | 1 + 17 files changed, 1 insertion(+), 16 deletions(-) diff --git a/tests/_support/Log/Handlers/TestHandler.php b/tests/_support/Log/Handlers/TestHandler.php index d37bc331b457..a3257bb45496 100644 --- a/tests/_support/Log/Handlers/TestHandler.php +++ b/tests/_support/Log/Handlers/TestHandler.php @@ -11,7 +11,6 @@ class TestHandler extends \CodeIgniter\Log\Handlers\FileHandler { - /** * Local storage for logs. * diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index acf2b436971f..9221410669b5 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -24,7 +24,6 @@ */ final class ControllerTest extends CIUnitTestCase { - /** * @var CodeIgniter */ diff --git a/tests/system/Files/FileWithVfsTest.php b/tests/system/Files/FileWithVfsTest.php index 219fb8bdb4cb..d62dbf29690f 100644 --- a/tests/system/Files/FileWithVfsTest.php +++ b/tests/system/Files/FileWithVfsTest.php @@ -10,7 +10,6 @@ */ final class FileWithVfsTest extends CIUnitTestCase { - // For VFS stuff protected $root; protected $path; diff --git a/tests/system/HTTP/IncomingRequestDetectingTest.php b/tests/system/HTTP/IncomingRequestDetectingTest.php index af1d4faec73c..257bb034b5f2 100644 --- a/tests/system/HTTP/IncomingRequestDetectingTest.php +++ b/tests/system/HTTP/IncomingRequestDetectingTest.php @@ -12,7 +12,6 @@ */ final class IncomingRequestDetectingTest extends CIUnitTestCase { - /** * @var IncomingRequest */ diff --git a/tests/system/HTTP/MessageTest.php b/tests/system/HTTP/MessageTest.php index 1adb2bbade7d..18d75e408796 100644 --- a/tests/system/HTTP/MessageTest.php +++ b/tests/system/HTTP/MessageTest.php @@ -10,7 +10,6 @@ */ final class MessageTest extends CIUnitTestCase { - /** * @var Message */ diff --git a/tests/system/HTTP/NegotiateTest.php b/tests/system/HTTP/NegotiateTest.php index fabb5cfa2949..7896059df768 100644 --- a/tests/system/HTTP/NegotiateTest.php +++ b/tests/system/HTTP/NegotiateTest.php @@ -11,7 +11,6 @@ */ final class NegotiateTest extends CIUnitTestCase { - /** * @var Request */ diff --git a/tests/system/HTTP/RequestTest.php b/tests/system/HTTP/RequestTest.php index 8620c7d4d133..141fafd79639 100644 --- a/tests/system/HTTP/RequestTest.php +++ b/tests/system/HTTP/RequestTest.php @@ -12,7 +12,6 @@ */ final class RequestTest extends CIUnitTestCase { - /** * @var Request */ diff --git a/tests/system/HTTP/ResponseSendTest.php b/tests/system/HTTP/ResponseSendTest.php index 27948ba0504c..2ee2392d19df 100644 --- a/tests/system/HTTP/ResponseSendTest.php +++ b/tests/system/HTTP/ResponseSendTest.php @@ -15,7 +15,6 @@ */ final class ResponseSendTest extends CIUnitTestCase { - /** * These need to be run as a separate process, since phpunit * has already captured the "normal" output, and we will get diff --git a/tests/system/Models/GeneralModelTest.php b/tests/system/Models/GeneralModelTest.php index 0c24929773a5..5242631b78e8 100644 --- a/tests/system/Models/GeneralModelTest.php +++ b/tests/system/Models/GeneralModelTest.php @@ -144,7 +144,6 @@ public function testBuilderWithParameterIgnoresShared(): void public function testInitialize(): void { $model = new class() extends Model { - /** * @var bool */ diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 571df88afeb4..912a02a95b1a 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -16,7 +16,6 @@ */ final class PagerTest extends CIUnitTestCase { - /** * @var \CodeIgniter\Pager\Pager */ diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index 6a87d92363e6..4b47db042ef9 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -30,7 +30,6 @@ */ final class ResourceControllerTest extends CIUnitTestCase { - /** * @var CodeIgniter */ diff --git a/tests/system/RESTful/ResourcePresenterTest.php b/tests/system/RESTful/ResourcePresenterTest.php index 9910891f90c2..5576b9b32fc9 100644 --- a/tests/system/RESTful/ResourcePresenterTest.php +++ b/tests/system/RESTful/ResourcePresenterTest.php @@ -24,7 +24,6 @@ */ final class ResourcePresenterTest extends CIUnitTestCase { - /** * @var CodeIgniter */ diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index 99e49c9941c5..c29a99d16a93 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -13,7 +13,6 @@ */ final class RouterTest extends CIUnitTestCase { - /** * @var RouteCollection */ diff --git a/tests/system/Test/TestCaseEmissionsTest.php b/tests/system/Test/TestCaseEmissionsTest.php index a6a4d603b4d8..387a9fd24652 100644 --- a/tests/system/Test/TestCaseEmissionsTest.php +++ b/tests/system/Test/TestCaseEmissionsTest.php @@ -15,7 +15,6 @@ */ final class TestCaseEmissionsTest extends CIUnitTestCase { - /** * These need to be run as a separate process, since phpunit * has already captured the "normal" output, and we will get diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php index 6a580fbea596..95e52ac56227 100644 --- a/tests/system/Validation/CreditCardRulesTest.php +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -11,7 +11,6 @@ */ final class CreditCardRulesTest extends CIUnitTestCase { - /** * @var Validation */ diff --git a/tests/system/Validation/FileRulesTest.php b/tests/system/Validation/FileRulesTest.php index 78f44d321380..7d1019049959 100644 --- a/tests/system/Validation/FileRulesTest.php +++ b/tests/system/Validation/FileRulesTest.php @@ -11,7 +11,6 @@ */ final class FileRulesTest extends CIUnitTestCase { - /** * @var Validation */ diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 8585cf656fea..8209bfb329a7 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -163,6 +163,7 @@ public function __construct() 'new_with_braces' => true, 'no_alias_functions' => ['sets' => ['@all']], 'no_alias_language_construct_call' => true, + 'no_blank_lines_after_class_opening' => true, 'no_short_bool_cast' => true, 'no_trailing_comma_in_singleline_array' => true, 'no_unset_cast' => true, From 8ac891bd3f139cc206bec291a1ba47156fe7d4c5 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 3 Jul 2021 00:44:18 +0800 Subject: [PATCH 0052/2325] Conditionally enable `no_blank_lines_after_phpdoc` fixer --- admin/starter/app/Config/Paths.php | 1 - app/Config/Mimes.php | 1 - app/Config/Paths.php | 1 - app/Controllers/BaseController.php | 1 - tests/_support/Config/BadRegistrar.php | 1 - tests/_support/Config/Registrar.php | 1 - tests/_support/Config/TestRegistrar.php | 1 - tests/_support/Log/Handlers/TestHandler.php | 1 - tests/_support/View/SampleClass.php | 1 - tests/_support/View/SampleClassWithInitController.php | 1 - tests/system/Test/BootstrapFCPATHTest.php | 1 - utils/PhpCsFixer/CodeIgniter4.php | 1 + 12 files changed, 1 insertion(+), 11 deletions(-) diff --git a/admin/starter/app/Config/Paths.php b/admin/starter/app/Config/Paths.php index 5b9739ee5d0b..d97bbb35a820 100644 --- a/admin/starter/app/Config/Paths.php +++ b/admin/starter/app/Config/Paths.php @@ -13,7 +13,6 @@ * * All paths are relative to the project's root folder. */ - class Paths { /** diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index 4edcfa4edc5c..a7cca8788d00 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -16,7 +16,6 @@ * When working with mime types, please make sure you have the ´fileinfo´ * extension enabled to reliably detect the media types. */ - class Mimes { /** diff --git a/app/Config/Paths.php b/app/Config/Paths.php index 137fc486e409..f701b7570507 100644 --- a/app/Config/Paths.php +++ b/app/Config/Paths.php @@ -13,7 +13,6 @@ * * All paths are relative to the project's root folder. */ - class Paths { /** diff --git a/app/Controllers/BaseController.php b/app/Controllers/BaseController.php index 7a7d104425c1..b6740e940202 100644 --- a/app/Controllers/BaseController.php +++ b/app/Controllers/BaseController.php @@ -19,7 +19,6 @@ * * For security be sure to declare any new methods as protected or private. */ - class BaseController extends Controller { /** diff --git a/tests/_support/Config/BadRegistrar.php b/tests/_support/Config/BadRegistrar.php index ff7aba3aa377..6f9fdd2b354a 100644 --- a/tests/_support/Config/BadRegistrar.php +++ b/tests/_support/Config/BadRegistrar.php @@ -8,7 +8,6 @@ * Doesn't provides a basic registrar class for testing BaseConfig registration functions, * because it doesn't return an associative array */ - class BadRegistrar { public static function RegistrarConfig() diff --git a/tests/_support/Config/Registrar.php b/tests/_support/Config/Registrar.php index 32d114b25f3d..c8a607ae7e43 100644 --- a/tests/_support/Config/Registrar.php +++ b/tests/_support/Config/Registrar.php @@ -7,7 +7,6 @@ * * Provides a basic registrar class for testing BaseConfig registration functions. */ - class Registrar { /** diff --git a/tests/_support/Config/TestRegistrar.php b/tests/_support/Config/TestRegistrar.php index 947587d84069..8ac4c9655c90 100644 --- a/tests/_support/Config/TestRegistrar.php +++ b/tests/_support/Config/TestRegistrar.php @@ -7,7 +7,6 @@ * * Provides a basic registrar class for testing BaseConfig registration functions. */ - class TestRegistrar { public static function RegistrarConfig() diff --git a/tests/_support/Log/Handlers/TestHandler.php b/tests/_support/Log/Handlers/TestHandler.php index a3257bb45496..3559856059e5 100644 --- a/tests/_support/Log/Handlers/TestHandler.php +++ b/tests/_support/Log/Handlers/TestHandler.php @@ -8,7 +8,6 @@ * A simple LogHandler that stores the logs in memory. * Only used for testing purposes. */ - class TestHandler extends \CodeIgniter\Log\Handlers\FileHandler { /** diff --git a/tests/_support/View/SampleClass.php b/tests/_support/View/SampleClass.php index 3c7e58db2a82..08bdb1da0760 100644 --- a/tests/_support/View/SampleClass.php +++ b/tests/_support/View/SampleClass.php @@ -8,7 +8,6 @@ * This class is only used to provide a reference point * during tests to make sure that things work as expected. */ - class SampleClass { public function index() diff --git a/tests/_support/View/SampleClassWithInitController.php b/tests/_support/View/SampleClassWithInitController.php index bb8c04376347..5e402b1b7f6f 100644 --- a/tests/_support/View/SampleClassWithInitController.php +++ b/tests/_support/View/SampleClassWithInitController.php @@ -12,7 +12,6 @@ * This class is only used to provide a reference point * during tests to make sure that things work as expected. */ - class SampleClassWithInitController { public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) diff --git a/tests/system/Test/BootstrapFCPATHTest.php b/tests/system/Test/BootstrapFCPATHTest.php index 5bff32d359b0..cfeef89ee227 100644 --- a/tests/system/Test/BootstrapFCPATHTest.php +++ b/tests/system/Test/BootstrapFCPATHTest.php @@ -14,7 +14,6 @@ * * @internal */ - final class BootstrapFCPATHTest extends CIUnitTestCase { private $currentDir = __DIR__; diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 8209bfb329a7..86fb3ba80f3b 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -164,6 +164,7 @@ public function __construct() 'no_alias_functions' => ['sets' => ['@all']], 'no_alias_language_construct_call' => true, 'no_blank_lines_after_class_opening' => true, + 'no_blank_lines_after_phpdoc' => false, // @todo enable fully when `header_comment` is required 'no_short_bool_cast' => true, 'no_trailing_comma_in_singleline_array' => true, 'no_unset_cast' => true, From 3e1b2052051d23fb5ceb8ad154203aae974464f7 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sat, 3 Jul 2021 00:56:44 +0800 Subject: [PATCH 0053/2325] Enable PSR-12 normative rules --- system/Debug/Toolbar.php | 4 ++-- tests/system/CodeIgniterTest.php | 2 +- tests/system/Commands/InfoCacheTest.php | 2 +- tests/system/Database/Builder/InsertTest.php | 4 ++-- tests/system/Database/Builder/UpdateTest.php | 2 +- .../Database/Migrations/MigrationRunnerTest.php | 2 +- tests/system/HTTP/Files/FileCollectionTest.php | 10 +++++----- tests/system/HTTP/Files/FileMovingTest.php | 2 +- tests/system/Test/BootstrapFCPATHTest.php | 8 ++++---- utils/PhpCsFixer/CodeIgniter4.php | 12 ++++++++++++ 10 files changed, 30 insertions(+), 18 deletions(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 1ec5b1d41101..a230440e6a7d 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -122,7 +122,7 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques Kint::$display_called_from = false; $kint = @Kint::dump($value); - $kint = substr($kint, strpos($kint, '') + 8 ); + $kint = substr($kint, strpos($kint, '') + 8); Kint::$mode_default = $oldKintMode; Kint::$display_called_from = $oldKintCalledFrom; @@ -356,7 +356,7 @@ public function prepare(RequestInterface $request = null, ResponseInterface $res Kint::$mode_default = Kint::MODE_RICH; $kintScript = @Kint::dump(''); Kint::$mode_default = $oldKintMode; - $kintScript = substr($kintScript, 0, strpos($kintScript, '') + 8 ); + $kintScript = substr($kintScript, 0, strpos($kintScript, '') + 8); $script = PHP_EOL . '', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testIgnoresComments() { $data = [ @@ -570,8 +540,6 @@ public function testIgnoresComments() $this->assertSame($result, $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testNoParse() { $data = [ @@ -591,8 +559,6 @@ public function testNoParse() $this->assertSame($result, $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testIfConditionalTrue() { $data = [ @@ -643,8 +609,6 @@ public function testElseifConditionalTrue() $this->assertSame('Welcome', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testConditionalBadSyntax() { $this->expectException(ViewException::class); @@ -660,16 +624,12 @@ public function testConditionalBadSyntax() $this->assertSame('HowdyWelcome', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testWontParsePHP() { $template = " - "; $this->assertSame('<?php echo \'Foo\' ?> - <?= \'Bar\' ?>', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testParseHandlesSpaces() { $data = [ @@ -685,8 +645,6 @@ public function testParseHandlesSpaces() $this->assertSame($result, $this->parser->renderString($template)); } - // -------------------------------------------------------------------- - public function testParseRuns() { $data = [ @@ -702,8 +660,6 @@ public function testParseRuns() $this->assertSame($result, $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - /** * @group parserplugins */ @@ -724,8 +680,6 @@ public function testCanAddAndRemovePlugins() $this->assertArrayNotHasKey('first', $setParsers); } - //-------------------------------------------------------------------- - /** * @group parserplugins */ @@ -736,8 +690,6 @@ public function testParserPluginNoMatches() $this->assertSame('hit:it', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - /** * @group parserplugins */ @@ -752,8 +704,6 @@ public function testParserPluginNoParams() $this->assertSame(' stuff Hip to the Hop ', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - /** * @group parserplugins */ @@ -771,8 +721,6 @@ public function testParserPluginClosure() $this->assertSame('Hello, world', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - /** * @group parserplugins */ @@ -796,8 +744,6 @@ public function testParserPluginParams() $this->assertSame(' 2 4 6 8', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - /** * @group parserplugins */ @@ -880,8 +826,6 @@ public function testParserSingleTagWithNamedParams() $this->assertSame('title: Hello world. page: 5. email: test@test.net. ', $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/705 */ @@ -951,8 +895,6 @@ public function testParseLoopWithHashInPrecession(): void $this->assertSame($expected, $this->parser->renderString($template)); } - //-------------------------------------------------------------------- - public function testCachedRender() { $this->parser->setVar('teststring', 'Hello World'); @@ -963,8 +905,6 @@ public function testCachedRender() $this->assertSame($expected, $this->parser->render('template1', ['cache' => 10, 'cache_name' => 'HelloWorld'])); } - //-------------------------------------------------------------------- - public function testRenderFindsView() { $this->parser->setData(['testString' => 'Hello World']); @@ -980,8 +920,6 @@ public function testRenderCannotFindView() $this->parser->render('Simplest'); } - //-------------------------------------------------------------------- - public function testRenderSavingData() { $expected = "

Hello World

\n"; diff --git a/tests/system/View/TableTest.php b/tests/system/View/TableTest.php index 0c49ea01488d..efb0e31ad00b 100644 --- a/tests/system/View/TableTest.php +++ b/tests/system/View/TableTest.php @@ -18,7 +18,6 @@ protected function setUp(): void } // Setter Methods - // -------------------------------------------------------------------- public function testSetTemplate() { @@ -108,7 +107,6 @@ public function testAddRow() } // Uility Methods - // -------------------------------------------------------------------- public function testPrepArgs() { @@ -399,8 +397,6 @@ public function testGenerateEmptyCell() $this->assertStringContainsString('Huh?', $table); } - // -------------------------------------------------------------------- - public function testWithConfig() { $customSettings = [ @@ -467,8 +463,6 @@ public function testUndefined() $this->assertSame('Undefined table data', $table); } - // -------------------------------------------------------------------- - public function testCallback() { $this->table->setHeading('Name', 'Color', 'Size'); diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index 5be61ecbc798..7f8b0e24cbb7 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -17,8 +17,6 @@ final class ViewTest extends CIUnitTestCase protected $viewsDir; protected $config; - //-------------------------------------------------------------------- - protected function setUp(): void { parent::setUp(); @@ -28,8 +26,6 @@ protected function setUp(): void $this->config = new Config\View(); } - //-------------------------------------------------------------------- - public function testSetVarStoresData() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -49,8 +45,6 @@ public function testSetVarOverwrites() $this->assertSame(['foo' => 'baz'], $view->getData()); } - //-------------------------------------------------------------------- - public function testSetDataStoresValue() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -102,8 +96,6 @@ public function testSetDataOverwritesData() $this->assertSame($expected, $view->getData()); } - //-------------------------------------------------------------------- - public function testSetVarWillEscape() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -130,8 +122,6 @@ public function testSetDataWillEscapeAll() $this->assertSame($expected, $view->getData()); } - //-------------------------------------------------------------------- - public function testRenderFindsView() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -142,8 +132,6 @@ public function testRenderFindsView() $this->assertStringContainsString($expected, $view->render('simple')); } - //-------------------------------------------------------------------- - public function testRenderString() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -160,8 +148,6 @@ public function testRenderStringNullTempdata() $this->assertSame('test string', $view->renderString('test string')); } - //-------------------------------------------------------------------- - public function testRendersThrowsExceptionIfFileNotFound() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -172,8 +158,6 @@ public function testRendersThrowsExceptionIfFileNotFound() $view->render('missing'); } - //-------------------------------------------------------------------- - public function testRenderScrapsData() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -184,8 +168,6 @@ public function testRenderScrapsData() $this->assertEmpty($view->getData()); } - //-------------------------------------------------------------------- - public function testRenderCanSaveData() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -212,8 +194,6 @@ public function testRenderCanSaveDataThroughConfigSetting() $this->assertSame($expected, $view->getData()); } - //-------------------------------------------------------------------- - public function testCanDeleteData() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -226,8 +206,6 @@ public function testCanDeleteData() $this->assertSame([], $view->getData()); } - //-------------------------------------------------------------------- - public function testCachedRender() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -240,8 +218,6 @@ public function testCachedRender() $this->assertStringContainsString($expected, $view->render('simple', ['cache' => 10])); } - //-------------------------------------------------------------------- - public function testRenderStringSavingData() { $view = new View($this->config, $this->viewsDir, $this->loader); @@ -257,8 +233,6 @@ public function testRenderStringSavingData() $this->assertArrayHasKey('testString', $view->getData()); } - //-------------------------------------------------------------------- - public function testPerformanceLogging() { // Make sure debugging is on for our view diff --git a/user_guide_src/source/general/logging.rst b/user_guide_src/source/general/logging.rst index 19921b648b17..32953792a136 100644 --- a/user_guide_src/source/general/logging.rst +++ b/user_guide_src/source/general/logging.rst @@ -80,13 +80,8 @@ Each handler's section will have one property in common: ``handles``, which is a :: public $handlers = [ - - //-------------------------------------------------------------------- // File Handler - //-------------------------------------------------------------------- - 'CodeIgniter\Log\Handlers\FileHandler' => [ - 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'], ] ]; diff --git a/user_guide_src/source/libraries/throttler.rst b/user_guide_src/source/libraries/throttler.rst index 9513d266ea16..cdefb935ba1d 100644 --- a/user_guide_src/source/libraries/throttler.rst +++ b/user_guide_src/source/libraries/throttler.rst @@ -49,8 +49,8 @@ start using it in your application. The Code ======== -You could make your own Throttler filter, at **app/Filters/Throttle.php**, -along the lines of:: +You could make your own Throttler filter, at **app/Filters/Throttle.php**, +along the lines of:: Date: Mon, 19 Jul 2021 21:21:30 +0800 Subject: [PATCH 0091/2325] Split config files into which has headers or not --- .no-header.php-cs-fixer.dist.php | 26 ++++++++++++++++++++++++++ .php-cs-fixer.dist.php | 11 ++++++----- utils/PhpCsFixer/CodeIgniter4.php | 4 ++-- 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 .no-header.php-cs-fixer.dist.php diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php new file mode 100644 index 000000000000..8220fe3d6091 --- /dev/null +++ b/.no-header.php-cs-fixer.dist.php @@ -0,0 +1,26 @@ +files() + ->in([ + __DIR__ . '/admin', + __DIR__ . '/app', + __DIR__ . '/public', + ]); + +$overrides = [ + 'no_blank_lines_after_phpdoc' => false, +]; + +$options = [ + 'cacheFile' => 'build/.no-header.php-cs-fixer.cache', + 'finder' => $finder, +]; + +return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects(); diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 7e02b76a134e..1cd558071c3e 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -9,9 +9,6 @@ $finder = Finder::create() ->files() ->in([ - __DIR__ . '/admin', // @todo relocate when `header_comment` is enabled - __DIR__ . '/app', // @todo relocate when `header_comment` is enabled - __DIR__ . '/public', // @todo relocate when `header_comment` is enabled __DIR__ . '/system', __DIR__ . '/tests', __DIR__ . '/utils', @@ -20,6 +17,7 @@ ->notName('#Foobar.php$#') ->append([ __FILE__, + __DIR__ . '/.no-header.php-cs-fixer.dist.php', __DIR__ . '/rector.php', __DIR__ . '/spark', ]); @@ -31,5 +29,8 @@ 'finder' => $finder, ]; -// @todo change to `forLibrary()` when `header_comment` is enabled -return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects(); +return Factory::create(new CodeIgniter4(), $overrides, $options)->forLibrary( + 'CodeIgniter 4 framework', + 'CodeIgniter Foundation', + 'admin@codeigniter.com' +); diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 209c513c4dcf..3f8cfeba35d2 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -20,7 +20,7 @@ public function __construct() $this->rules = [ 'align_multiline_comment' => ['comment_type' => 'phpdocs_only'], 'array_indentation' => true, - 'array_push' => true, // risky + 'array_push' => true, 'array_syntax' => ['syntax' => 'short'], 'backtick_to_shell_exec' => true, 'binary_operator_spaces' => [ @@ -196,7 +196,7 @@ public function __construct() 'no_alternative_syntax' => false, 'no_binary_string' => true, 'no_blank_lines_after_class_opening' => true, - 'no_blank_lines_after_phpdoc' => false, // @todo enable fully when `header_comment` is required + 'no_blank_lines_after_phpdoc' => true, 'no_blank_lines_before_namespace' => false, // conflicts with `single_blank_line_before_namespace` 'no_break_comment' => ['comment_text' => 'no break'], 'no_closing_tag' => true, From 0ee2b2f9221c04dbdb56e62ed9cf599b20667011 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 19 Jul 2021 21:32:33 +0800 Subject: [PATCH 0092/2325] Add file-level headers --- .no-header.php-cs-fixer.dist.php | 11 ++++++++++- .php-cs-fixer.dist.php | 9 +++++++++ rector.php | 9 +++++++++ system/API/ResponseTrait.php | 6 +++--- system/Autoloader/Autoloader.php | 6 +++--- system/Autoloader/FileLocator.php | 6 +++--- system/BaseModel.php | 6 +++--- system/CLI/BaseCommand.php | 6 +++--- system/CLI/CLI.php | 6 +++--- system/CLI/CommandRunner.php | 6 +++--- system/CLI/Commands.php | 6 +++--- system/CLI/Console.php | 6 +++--- system/CLI/Exceptions/CLIException.php | 6 +++--- system/CLI/GeneratorTrait.php | 6 +++--- system/Cache/CacheFactory.php | 6 +++--- system/Cache/CacheInterface.php | 6 +++--- system/Cache/Exceptions/CacheException.php | 6 +++--- .../Cache/Exceptions/ExceptionInterface.php | 6 +++--- system/Cache/Handlers/BaseHandler.php | 6 +++--- system/Cache/Handlers/DummyHandler.php | 6 +++--- system/Cache/Handlers/FileHandler.php | 6 +++--- system/Cache/Handlers/MemcachedHandler.php | 6 +++--- system/Cache/Handlers/PredisHandler.php | 6 +++--- system/Cache/Handlers/RedisHandler.php | 6 +++--- system/Cache/Handlers/WincacheHandler.php | 6 +++--- system/CodeIgniter.php | 6 +++--- system/Commands/Cache/ClearCache.php | 6 +++--- system/Commands/Cache/InfoCache.php | 6 +++--- system/Commands/Database/CreateDatabase.php | 6 +++--- system/Commands/Database/Migrate.php | 6 +++--- system/Commands/Database/MigrateRefresh.php | 6 +++--- system/Commands/Database/MigrateRollback.php | 6 +++--- system/Commands/Database/MigrateStatus.php | 6 +++--- system/Commands/Database/Seed.php | 6 +++--- system/Commands/Encryption/GenerateKey.php | 6 +++--- .../Commands/Generators/CommandGenerator.php | 6 +++--- .../Commands/Generators/ConfigGenerator.php | 6 +++--- .../Generators/ControllerGenerator.php | 6 +++--- .../Commands/Generators/EntityGenerator.php | 6 +++--- .../Commands/Generators/FilterGenerator.php | 6 +++--- system/Commands/Generators/MigrateCreate.php | 6 +++--- .../Generators/MigrationGenerator.php | 6 +++--- system/Commands/Generators/ModelGenerator.php | 6 +++--- .../Commands/Generators/ScaffoldGenerator.php | 6 +++--- .../Commands/Generators/SeederGenerator.php | 6 +++--- .../Generators/SessionMigrationGenerator.php | 6 +++--- .../Generators/ValidationGenerator.php | 6 +++--- system/Commands/Help.php | 6 +++--- .../Commands/Housekeeping/ClearDebugbar.php | 6 +++--- system/Commands/Housekeeping/ClearLogs.php | 6 +++--- system/Commands/ListCommands.php | 6 +++--- system/Commands/Server/Serve.php | 6 +++--- system/Commands/Server/rewrite.php | 6 +++--- system/Commands/Utilities/Environment.php | 9 +++++++++ system/Commands/Utilities/Namespaces.php | 6 +++--- system/Commands/Utilities/Routes.php | 6 +++--- system/Common.php | 6 +++--- system/ComposerScripts.php | 6 +++--- system/Config/AutoloadConfig.php | 6 +++--- system/Config/BaseConfig.php | 6 +++--- system/Config/BaseService.php | 6 +++--- system/Config/Config.php | 6 +++--- system/Config/DotEnv.php | 6 +++--- system/Config/Factories.php | 6 +++--- system/Config/Factory.php | 6 +++--- system/Config/ForeignCharacters.php | 6 +++--- system/Config/Routes.php | 6 +++--- system/Config/Services.php | 6 +++--- system/Config/View.php | 6 +++--- system/Controller.php | 6 +++--- system/Cookie/CloneableCookieInterface.php | 6 +++--- system/Cookie/Cookie.php | 6 +++--- system/Cookie/CookieInterface.php | 6 +++--- system/Cookie/CookieStore.php | 6 +++--- system/Cookie/Exceptions/CookieException.php | 6 +++--- system/Database/BaseBuilder.php | 6 +++--- system/Database/BaseConnection.php | 6 +++--- system/Database/BasePreparedQuery.php | 6 +++--- system/Database/BaseResult.php | 6 +++--- system/Database/BaseUtils.php | 6 +++--- system/Database/Config.php | 6 +++--- system/Database/ConnectionInterface.php | 6 +++--- system/Database/Database.php | 6 +++--- system/Database/Exceptions/DataException.php | 6 +++--- .../Database/Exceptions/DatabaseException.php | 6 +++--- .../Exceptions/ExceptionInterface.php | 6 +++--- system/Database/Forge.php | 6 +++--- system/Database/Migration.php | 6 +++--- system/Database/MigrationRunner.php | 6 +++--- system/Database/ModelFactory.php | 6 +++--- system/Database/MySQLi/Builder.php | 6 +++--- system/Database/MySQLi/Connection.php | 6 +++--- system/Database/MySQLi/Forge.php | 6 +++--- system/Database/MySQLi/PreparedQuery.php | 6 +++--- system/Database/MySQLi/Result.php | 6 +++--- system/Database/MySQLi/Utils.php | 6 +++--- system/Database/Postgre/Builder.php | 6 +++--- system/Database/Postgre/Connection.php | 6 +++--- system/Database/Postgre/Forge.php | 6 +++--- system/Database/Postgre/PreparedQuery.php | 6 +++--- system/Database/Postgre/Result.php | 6 +++--- system/Database/Postgre/Utils.php | 6 +++--- system/Database/PreparedQueryInterface.php | 6 +++--- system/Database/Query.php | 6 +++--- system/Database/QueryInterface.php | 6 +++--- system/Database/ResultInterface.php | 6 +++--- system/Database/SQLSRV/Builder.php | 6 +++--- system/Database/SQLSRV/Connection.php | 6 +++--- system/Database/SQLSRV/Forge.php | 6 +++--- system/Database/SQLSRV/PreparedQuery.php | 6 +++--- system/Database/SQLSRV/Result.php | 6 +++--- system/Database/SQLSRV/Utils.php | 6 +++--- system/Database/SQLite3/Builder.php | 6 +++--- system/Database/SQLite3/Connection.php | 6 +++--- system/Database/SQLite3/Forge.php | 6 +++--- system/Database/SQLite3/PreparedQuery.php | 6 +++--- system/Database/SQLite3/Result.php | 6 +++--- system/Database/SQLite3/Table.php | 6 +++--- system/Database/SQLite3/Utils.php | 6 +++--- system/Database/Seeder.php | 6 +++--- system/Debug/Exceptions.php | 6 +++--- system/Debug/Iterator.php | 6 +++--- system/Debug/Timer.php | 6 +++--- system/Debug/Toolbar.php | 7 +++---- .../Toolbar/Collectors/BaseCollector.php | 6 +++--- system/Debug/Toolbar/Collectors/Config.php | 6 +++--- system/Debug/Toolbar/Collectors/Database.php | 6 +++--- system/Debug/Toolbar/Collectors/Events.php | 6 +++--- system/Debug/Toolbar/Collectors/Files.php | 6 +++--- system/Debug/Toolbar/Collectors/History.php | 6 +++--- system/Debug/Toolbar/Collectors/Logs.php | 6 +++--- system/Debug/Toolbar/Collectors/Routes.php | 6 +++--- system/Debug/Toolbar/Collectors/Timers.php | 6 +++--- system/Debug/Toolbar/Collectors/Views.php | 6 +++--- system/Debug/Toolbar/Views/toolbar.tpl.php | 1 - system/Email/Email.php | 6 +++--- system/Encryption/EncrypterInterface.php | 6 +++--- system/Encryption/Encryption.php | 6 +++--- .../Exceptions/EncryptionException.php | 6 +++--- system/Encryption/Handlers/BaseHandler.php | 6 +++--- system/Encryption/Handlers/OpenSSLHandler.php | 6 +++--- system/Encryption/Handlers/SodiumHandler.php | 6 +++--- system/Entity.php | 6 +++--- system/Entity/Cast/ArrayCast.php | 6 +++--- system/Entity/Cast/BaseCast.php | 6 +++--- system/Entity/Cast/BooleanCast.php | 6 +++--- system/Entity/Cast/CSVCast.php | 6 +++--- system/Entity/Cast/CastInterface.php | 6 +++--- system/Entity/Cast/DatetimeCast.php | 6 +++--- system/Entity/Cast/FloatCast.php | 6 +++--- system/Entity/Cast/IntegerCast.php | 6 +++--- system/Entity/Cast/JsonCast.php | 6 +++--- system/Entity/Cast/ObjectCast.php | 6 +++--- system/Entity/Cast/StringCast.php | 6 +++--- system/Entity/Cast/TimestampCast.php | 6 +++--- system/Entity/Cast/URICast.php | 6 +++--- system/Entity/Entity.php | 6 +++--- system/Entity/Exceptions/CastException.php | 6 +++--- system/Events/Events.php | 6 +++--- system/Exceptions/AlertError.php | 6 +++--- system/Exceptions/CastException.php | 6 +++--- system/Exceptions/ConfigException.php | 6 +++--- system/Exceptions/CriticalError.php | 6 +++--- system/Exceptions/DebugTraceableTrait.php | 9 +++++++++ system/Exceptions/DownloadException.php | 6 +++--- system/Exceptions/EmergencyError.php | 6 +++--- system/Exceptions/ExceptionInterface.php | 7 +++---- system/Exceptions/FrameworkException.php | 6 +++--- system/Exceptions/ModelException.php | 7 +++---- system/Exceptions/PageNotFoundException.php | 6 +++--- system/Files/Exceptions/FileException.php | 6 +++--- .../Exceptions/FileNotFoundException.php | 6 +++--- system/Files/File.php | 6 +++--- system/Filters/CSRF.php | 6 +++--- system/Filters/DebugToolbar.php | 6 +++--- system/Filters/Exceptions/FilterException.php | 6 +++--- system/Filters/FilterInterface.php | 6 +++--- system/Filters/Filters.php | 6 +++--- system/Filters/Honeypot.php | 6 +++--- system/Format/Exceptions/FormatException.php | 6 +++--- system/Format/Format.php | 6 +++--- system/Format/FormatterInterface.php | 6 +++--- system/Format/JSONFormatter.php | 6 +++--- system/Format/XMLFormatter.php | 6 +++--- system/HTTP/CLIRequest.php | 6 +++--- system/HTTP/CURLRequest.php | 6 +++--- system/HTTP/ContentSecurityPolicy.php | 6 +++--- system/HTTP/DownloadResponse.php | 6 +++--- system/HTTP/Exceptions/HTTPException.php | 6 +++--- system/HTTP/Files/FileCollection.php | 6 +++--- system/HTTP/Files/UploadedFile.php | 6 +++--- system/HTTP/Files/UploadedFileInterface.php | 6 +++--- system/HTTP/Header.php | 6 +++--- system/HTTP/IncomingRequest.php | 6 +++--- system/HTTP/Message.php | 6 +++--- system/HTTP/MessageInterface.php | 6 +++--- system/HTTP/MessageTrait.php | 6 +++--- system/HTTP/Negotiate.php | 6 +++--- system/HTTP/RedirectResponse.php | 6 +++--- system/HTTP/Request.php | 6 +++--- system/HTTP/RequestInterface.php | 6 +++--- system/HTTP/RequestTrait.php | 6 +++--- system/HTTP/Response.php | 6 +++--- system/HTTP/ResponseInterface.php | 6 +++--- system/HTTP/ResponseTrait.php | 6 +++--- system/HTTP/URI.php | 6 +++--- system/HTTP/UserAgent.php | 6 +++--- system/Helpers/array_helper.php | 6 +++--- system/Helpers/cookie_helper.php | 6 +++--- system/Helpers/date_helper.php | 6 +++--- system/Helpers/filesystem_helper.php | 6 +++--- system/Helpers/form_helper.php | 6 +++--- system/Helpers/html_helper.php | 6 +++--- system/Helpers/inflector_helper.php | 6 +++--- system/Helpers/number_helper.php | 6 +++--- system/Helpers/security_helper.php | 6 +++--- system/Helpers/test_helper.php | 6 +++--- system/Helpers/text_helper.php | 6 +++--- system/Helpers/url_helper.php | 6 +++--- system/Helpers/xml_helper.php | 6 +++--- .../Honeypot/Exceptions/HoneypotException.php | 6 +++--- system/Honeypot/Honeypot.php | 6 +++--- system/I18n/Exceptions/I18nException.php | 6 +++--- system/I18n/Time.php | 6 +++--- system/I18n/TimeDifference.php | 6 +++--- system/Images/Exceptions/ImageException.php | 6 +++--- system/Images/Handlers/BaseHandler.php | 6 +++--- system/Images/Handlers/GDHandler.php | 6 +++--- system/Images/Handlers/ImageMagickHandler.php | 6 +++--- system/Images/Image.php | 6 +++--- system/Images/ImageHandlerInterface.php | 6 +++--- system/Language/Language.php | 6 +++--- system/Language/en/CLI.php | 6 +++--- system/Language/en/Cache.php | 6 +++--- system/Language/en/Cast.php | 6 +++--- system/Language/en/Cookie.php | 6 +++--- system/Language/en/Core.php | 6 +++--- system/Language/en/Database.php | 6 +++--- system/Language/en/Email.php | 6 +++--- system/Language/en/Encryption.php | 6 +++--- system/Language/en/Fabricator.php | 6 +++--- system/Language/en/Files.php | 6 +++--- system/Language/en/Filters.php | 6 +++--- system/Language/en/Format.php | 6 +++--- system/Language/en/HTTP.php | 6 +++--- system/Language/en/Images.php | 6 +++--- system/Language/en/Log.php | 6 +++--- system/Language/en/Migrations.php | 6 +++--- system/Language/en/Number.php | 6 +++--- system/Language/en/Pager.php | 6 +++--- system/Language/en/RESTful.php | 6 +++--- system/Language/en/Router.php | 6 +++--- system/Language/en/Security.php | 6 +++--- system/Language/en/Session.php | 6 +++--- system/Language/en/Time.php | 6 +++--- system/Language/en/Validation.php | 6 +++--- system/Language/en/View.php | 6 +++--- system/Log/Exceptions/LogException.php | 6 +++--- system/Log/Handlers/BaseHandler.php | 6 +++--- system/Log/Handlers/ChromeLoggerHandler.php | 6 +++--- system/Log/Handlers/ErrorlogHandler.php | 6 +++--- system/Log/Handlers/FileHandler.php | 6 +++--- system/Log/Handlers/HandlerInterface.php | 6 +++--- system/Log/Logger.php | 6 +++--- system/Model.php | 6 +++--- system/Modules/Modules.php | 6 +++--- system/Pager/Exceptions/PagerException.php | 6 +++--- system/Pager/Pager.php | 6 +++--- system/Pager/PagerInterface.php | 6 +++--- system/Pager/PagerRenderer.php | 6 +++--- system/Pager/Views/default_head.php | 6 +++--- system/RESTful/BaseResource.php | 6 +++--- system/RESTful/ResourceController.php | 6 +++--- system/RESTful/ResourcePresenter.php | 6 +++--- .../Router/Exceptions/RedirectException.php | 6 +++--- system/Router/Exceptions/RouterException.php | 6 +++--- system/Router/RouteCollection.php | 6 +++--- system/Router/RouteCollectionInterface.php | 6 +++--- system/Router/Router.php | 6 +++--- system/Router/RouterInterface.php | 6 +++--- .../Security/Exceptions/SecurityException.php | 6 +++--- system/Security/Security.php | 6 +++--- system/Security/SecurityInterface.php | 6 +++--- .../Session/Exceptions/SessionException.php | 6 +++--- system/Session/Handlers/ArrayHandler.php | 6 +++--- system/Session/Handlers/BaseHandler.php | 6 +++--- system/Session/Handlers/DatabaseHandler.php | 6 +++--- system/Session/Handlers/FileHandler.php | 6 +++--- system/Session/Handlers/MemcachedHandler.php | 6 +++--- system/Session/Handlers/RedisHandler.php | 6 +++--- system/Session/Session.php | 6 +++--- system/Session/SessionInterface.php | 6 +++--- system/Test/CIDatabaseTestCase.php | 6 +++--- system/Test/CIUnitTestCase.php | 6 +++--- system/Test/Constraints/SeeInDatabase.php | 9 +++++++++ system/Test/ControllerResponse.php | 6 +++--- system/Test/ControllerTestTrait.php | 6 +++--- system/Test/ControllerTester.php | 6 +++--- system/Test/DOMParser.php | 6 +++--- system/Test/DatabaseTestTrait.php | 6 +++--- system/Test/Fabricator.php | 6 +++--- system/Test/FeatureResponse.php | 6 +++--- system/Test/FeatureTestCase.php | 6 +++--- system/Test/FeatureTestTrait.php | 6 +++--- system/Test/FilterTestTrait.php | 6 +++--- system/Test/Filters/CITestStreamFilter.php | 6 +++--- system/Test/Interfaces/FabricatorModel.php | 6 +++--- system/Test/Mock/MockAppConfig.php | 6 +++--- system/Test/Mock/MockAutoload.php | 6 +++--- system/Test/Mock/MockBuilder.php | 6 +++--- system/Test/Mock/MockCLIConfig.php | 6 +++--- system/Test/Mock/MockCURLRequest.php | 6 +++--- system/Test/Mock/MockCache.php | 6 +++--- system/Test/Mock/MockCodeIgniter.php | 6 +++--- system/Test/Mock/MockCommon.php | 6 +++--- system/Test/Mock/MockConnection.php | 6 +++--- system/Test/Mock/MockEmail.php | 6 +++--- system/Test/Mock/MockEvents.php | 6 +++--- system/Test/Mock/MockFileLogger.php | 6 +++--- system/Test/Mock/MockIncomingRequest.php | 6 +++--- system/Test/Mock/MockLanguage.php | 6 +++--- system/Test/Mock/MockLogger.php | 6 +++--- system/Test/Mock/MockQuery.php | 6 +++--- system/Test/Mock/MockResourceController.php | 6 +++--- system/Test/Mock/MockResourcePresenter.php | 6 +++--- system/Test/Mock/MockResponse.php | 6 +++--- system/Test/Mock/MockResult.php | 6 +++--- system/Test/Mock/MockSecurity.php | 6 +++--- system/Test/Mock/MockSecurityConfig.php | 9 +++++++++ system/Test/Mock/MockServices.php | 6 +++--- system/Test/Mock/MockSession.php | 6 +++--- system/Test/Mock/MockTable.php | 6 +++--- system/Test/ReflectionHelper.php | 6 +++--- system/Test/TestLogger.php | 6 +++--- system/Test/TestResponse.php | 6 +++--- system/Test/bootstrap.php | 6 +++--- system/Throttle/Throttler.php | 6 +++--- system/Throttle/ThrottlerInterface.php | 6 +++--- system/Typography/Typography.php | 6 +++--- system/Validation/CreditCardRules.php | 6 +++--- .../Exceptions/ValidationException.php | 6 +++--- system/Validation/FileRules.php | 6 +++--- system/Validation/FormatRules.php | 6 +++--- system/Validation/Rules.php | 6 +++--- system/Validation/Validation.php | 6 +++--- system/Validation/ValidationInterface.php | 6 +++--- system/View/Cell.php | 6 +++--- system/View/Exceptions/ViewException.php | 6 +++--- system/View/Filters.php | 6 +++--- system/View/Parser.php | 6 +++--- system/View/Plugins.php | 6 +++--- system/View/RendererInterface.php | 6 +++--- system/View/Table.php | 6 +++--- system/View/View.php | 6 +++--- system/bootstrap.php | 6 +++--- tests/_support/Autoloader/FatalLocator.php | 9 +++++++++ .../_support/Autoloader/UnnamespacedClass.php | 9 +++++++++ tests/_support/Autoloader/functions.php | 9 +++++++++ tests/_support/Cache/RestrictiveHandler.php | 6 +++--- tests/_support/Commands/AbstractInfo.php | 9 +++++++++ tests/_support/Commands/AppInfo.php | 9 +++++++++ tests/_support/Commands/InvalidCommand.php | 9 +++++++++ tests/_support/Commands/LanguageCommand.php | 9 +++++++++ tests/_support/Commands/ParamsReveal.php | 9 +++++++++ tests/_support/Commands/Unsuffixable.php | 9 +++++++++ tests/_support/Config/BadRegistrar.php | 9 +++++++++ tests/_support/Config/Filters.php | 9 +++++++++ tests/_support/Config/Registrar.php | 9 +++++++++ tests/_support/Config/Routes.php | 9 +++++++++ tests/_support/Config/Services.php | 9 +++++++++ tests/_support/Config/TestRegistrar.php | 9 +++++++++ tests/_support/Controllers/Hello.php | 9 +++++++++ tests/_support/Controllers/Popcorn.php | 9 +++++++++ .../20160428212500_Create_test_tables.php | 9 +++++++++ .../_support/Database/Seeds/AnotherSeeder.php | 9 +++++++++ .../_support/Database/Seeds/CITestSeeder.php | 9 +++++++++ tests/_support/Entity/Cast/CastBase64.php | 9 +++++++++ .../Entity/Cast/CastPassParameters.php | 9 +++++++++ .../Entity/Cast/NotExtendsBaseCast.php | 9 +++++++++ tests/_support/Files/able/apple.php | 12 ++++++++---- tests/_support/Files/able/fig_3.php | 12 ++++++++---- tests/_support/Files/able/prune_ripe.php | 12 ++++++++---- tests/_support/Files/baker/banana.php | 12 ++++++++---- tests/_support/Filters/Customfilter.php | 9 +++++++++ tests/_support/Helpers/baguette_helper.php | 9 ++++++++- .../_support/Language/SecondMockLanguage.php | 9 +++++++++ tests/_support/Language/ab-CD/Allin.php | 10 +++++++++- tests/_support/Language/ab/Allin.php | 10 +++++++++- tests/_support/Language/en-ZZ/More.php | 9 +++++++++ tests/_support/Language/en/Allin.php | 10 +++++++++- tests/_support/Language/en/Core.php | 10 +++++++++- tests/_support/Language/en/Foo.php | 9 +++++++++ tests/_support/Language/en/Language.php | 6 +++--- tests/_support/Language/en/More.php | 9 +++++++++ tests/_support/Language/en/Nested.php | 9 +++++++++ tests/_support/Language/ru/Language.php | 9 +++++++++ tests/_support/Log/Handlers/TestHandler.php | 9 +++++++++ .../2018-01-24-102301_Some_migration.php | 9 +++++++++ .../2018-01-24-102302_Another_migration.php | 9 +++++++++ tests/_support/Models/EntityModel.php | 9 +++++++++ tests/_support/Models/EventModel.php | 9 +++++++++ tests/_support/Models/FabricatorModel.php | 9 +++++++++ tests/_support/Models/JobModel.php | 9 +++++++++ tests/_support/Models/SecondaryModel.php | 9 +++++++++ tests/_support/Models/SimpleEntity.php | 9 +++++++++ tests/_support/Models/StringifyPkeyModel.php | 9 +++++++++ tests/_support/Models/UserModel.php | 9 +++++++++ tests/_support/Models/ValidErrorsModel.php | 9 +++++++++ tests/_support/Models/ValidModel.php | 9 +++++++++ .../Models/WithoutAutoIncrementModel.php | 9 +++++++++ tests/_support/RESTful/Worker.php | 9 +++++++++ tests/_support/RESTful/Worker2.php | 9 +++++++++ tests/_support/Services.php | 9 +++++++++ tests/_support/SomeEntity.php | 9 +++++++++ tests/_support/Validation/TestRules.php | 9 +++++++++ tests/_support/View/SampleClass.php | 9 +++++++++ .../View/SampleClassWithInitController.php | 9 +++++++++ tests/_support/Widgets/NopeWidget.php | 10 +++++++++- tests/_support/Widgets/OtherWidget.php | 9 +++++++++ tests/_support/Widgets/SomeWidget.php | 9 +++++++++ tests/system/API/ResponseTraitTest.php | 9 +++++++++ tests/system/Autoloader/AutoloaderTest.php | 9 +++++++++ tests/system/Autoloader/FileLocatorTest.php | 9 +++++++++ tests/system/CLI/CLITest.php | 9 +++++++++ tests/system/CLI/CommandRunnerTest.php | 9 +++++++++ tests/system/CLI/ConsoleTest.php | 9 +++++++++ tests/system/Cache/CacheFactoryTest.php | 9 +++++++++ .../system/Cache/Handlers/BaseHandlerTest.php | 9 +++++++++ .../Cache/Handlers/DummyHandlerTest.php | 9 +++++++++ .../system/Cache/Handlers/FileHandlerTest.php | 9 +++++++++ .../Cache/Handlers/MemcachedHandlerTest.php | 9 +++++++++ .../Cache/Handlers/PredisHandlerTest.php | 9 +++++++++ .../Cache/Handlers/RedisHandlerTest.php | 9 +++++++++ tests/system/CodeIgniterTest.php | 9 +++++++++ tests/system/Commands/BaseCommandTest.php | 9 +++++++++ tests/system/Commands/ClearCacheTest.php | 9 +++++++++ tests/system/Commands/ClearDebugbarTest.php | 9 +++++++++ tests/system/Commands/ClearLogsTest.php | 9 +++++++++ .../system/Commands/CommandGeneratorTest.php | 9 +++++++++ tests/system/Commands/CommandTest.php | 9 +++++++++ tests/system/Commands/ConfigGeneratorTest.php | 9 +++++++++ .../Commands/ConfigurableSortImportsTest.php | 9 +++++++++ .../Commands/ControllerGeneratorTest.php | 9 +++++++++ tests/system/Commands/CreateDatabaseTest.php | 9 +++++++++ .../system/Commands/DatabaseCommandsTest.php | 9 +++++++++ tests/system/Commands/EntityGeneratorTest.php | 9 +++++++++ .../Commands/EnvironmentCommandTest.php | 9 +++++++++ tests/system/Commands/FilterGeneratorTest.php | 9 +++++++++ tests/system/Commands/GenerateKeyTest.php | 9 +++++++++ tests/system/Commands/GeneratorsTest.php | 9 +++++++++ tests/system/Commands/HelpCommandTest.php | 9 +++++++++ tests/system/Commands/InfoCacheTest.php | 9 +++++++++ .../Commands/MigrationGeneratorTest.php | 9 +++++++++ .../Commands/MigrationIntegrationTest.php | 9 +++++++++ tests/system/Commands/ModelGeneratorTest.php | 9 +++++++++ .../system/Commands/ScaffoldGeneratorTest.php | 9 +++++++++ tests/system/Commands/SeederGeneratorTest.php | 9 +++++++++ .../system/Commands/SessionsCommandsTest.php | 9 +++++++++ .../Commands/ValidationGeneratorTest.php | 9 +++++++++ tests/system/CommonFunctionsSendTest.php | 9 +++++++++ tests/system/CommonFunctionsTest.php | 9 +++++++++ tests/system/CommonSingleServiceTest.php | 9 +++++++++ tests/system/Config/BaseConfigTest.php | 9 +++++++++ tests/system/Config/ConfigTest.php | 9 +++++++++ tests/system/Config/DotEnvTest.php | 9 +++++++++ tests/system/Config/FactoriesTest.php | 9 +++++++++ tests/system/Config/MimesTest.php | 9 +++++++++ tests/system/Config/ServicesTest.php | 9 +++++++++ tests/system/Config/fixtures/Encryption.php | 9 +++++++++ .../Config/fixtures/RegistrarConfig.php | 9 +++++++++ tests/system/Config/fixtures/SimpleConfig.php | 9 +++++++++ tests/system/ControllerTest.php | 9 +++++++++ tests/system/Cookie/CookieStoreTest.php | 9 +++++++++ tests/system/Cookie/CookieTest.php | 9 +++++++++ tests/system/Database/BaseConnectionTest.php | 9 +++++++++ tests/system/Database/BaseQueryTest.php | 9 +++++++++ tests/system/Database/Builder/AliasTest.php | 9 +++++++++ tests/system/Database/Builder/BaseTest.php | 9 +++++++++ tests/system/Database/Builder/CountTest.php | 9 +++++++++ tests/system/Database/Builder/DeleteTest.php | 9 +++++++++ .../system/Database/Builder/DistinctTest.php | 9 +++++++++ tests/system/Database/Builder/EmptyTest.php | 9 +++++++++ tests/system/Database/Builder/FromTest.php | 9 +++++++++ tests/system/Database/Builder/GetTest.php | 9 +++++++++ tests/system/Database/Builder/GroupTest.php | 9 +++++++++ tests/system/Database/Builder/InsertTest.php | 9 +++++++++ tests/system/Database/Builder/JoinTest.php | 9 +++++++++ tests/system/Database/Builder/LikeTest.php | 9 +++++++++ tests/system/Database/Builder/LimitTest.php | 9 +++++++++ tests/system/Database/Builder/OrderTest.php | 9 +++++++++ tests/system/Database/Builder/PrefixTest.php | 9 +++++++++ tests/system/Database/Builder/ReplaceTest.php | 9 +++++++++ tests/system/Database/Builder/SelectTest.php | 9 +++++++++ .../system/Database/Builder/TruncateTest.php | 9 +++++++++ tests/system/Database/Builder/UpdateTest.php | 9 +++++++++ tests/system/Database/Builder/WhereTest.php | 9 +++++++++ tests/system/Database/ConfigTest.php | 9 +++++++++ tests/system/Database/DatabaseSeederTest.php | 9 +++++++++ .../DatabaseTestCaseMigrationOnce1Test.php | 9 +++++++++ .../DatabaseTestCaseMigrationOnce2Test.php | 9 +++++++++ .../system/Database/DatabaseTestCaseTest.php | 9 +++++++++ tests/system/Database/Live/AliasTest.php | 9 +++++++++ tests/system/Database/Live/BadQueryTest.php | 9 +++++++++ tests/system/Database/Live/ConnectTest.php | 9 +++++++++ tests/system/Database/Live/CountTest.php | 9 +++++++++ .../Live/DatabaseTestTraitCaseTest.php | 9 +++++++++ tests/system/Database/Live/DbDebugTest.php | 9 +++++++++ tests/system/Database/Live/DbUtilsTest.php | 9 +++++++++ tests/system/Database/Live/DeleteTest.php | 9 +++++++++ tests/system/Database/Live/EmptyTest.php | 9 +++++++++ tests/system/Database/Live/EscapeTest.php | 9 +++++++++ .../Database/Live/FabricatorLiveTest.php | 9 +++++++++ tests/system/Database/Live/ForgeTest.php | 9 +++++++++ tests/system/Database/Live/FromTest.php | 9 +++++++++ tests/system/Database/Live/GetNumRowsTest.php | 9 +++++++++ tests/system/Database/Live/GetTest.php | 9 +++++++++ tests/system/Database/Live/GroupTest.php | 9 +++++++++ tests/system/Database/Live/IncrementTest.php | 9 +++++++++ tests/system/Database/Live/InsertTest.php | 9 +++++++++ tests/system/Database/Live/JoinTest.php | 9 +++++++++ tests/system/Database/Live/LikeTest.php | 9 +++++++++ tests/system/Database/Live/LimitTest.php | 9 +++++++++ tests/system/Database/Live/MetadataTest.php | 9 +++++++++ tests/system/Database/Live/OrderTest.php | 9 +++++++++ .../Database/Live/PreparedQueryTest.php | 9 +++++++++ tests/system/Database/Live/PretendTest.php | 9 +++++++++ .../Database/Live/SQLite/AlterTableTest.php | 9 +++++++++ tests/system/Database/Live/SelectTest.php | 9 +++++++++ tests/system/Database/Live/UpdateTest.php | 9 +++++++++ tests/system/Database/Live/WhereTest.php | 9 +++++++++ .../Database/Live/WriteTypeQueryTest.php | 9 +++++++++ .../Migrations/MigrationRunnerTest.php | 9 +++++++++ .../Database/Migrations/MigrationTest.php | 9 +++++++++ tests/system/Database/ModelFactoryTest.php | 9 +++++++++ tests/system/Debug/ExceptionsTest.php | 9 +++++++++ tests/system/Debug/TimerTest.php | 9 +++++++++ tests/system/DebugTraceableTraitTest.php | 19 ++++++++++++++----- tests/system/Email/EmailTest.php | 9 +++++++++ tests/system/Encryption/EncryptionTest.php | 9 +++++++++ .../Handlers/OpenSSLHandlerTest.php | 9 +++++++++ .../Encryption/Handlers/SodiumHandlerTest.php | 9 +++++++++ tests/system/Entity/EntityTest.php | 9 +++++++++ tests/system/Events/EventsTest.php | 9 +++++++++ tests/system/Files/FileTest.php | 9 +++++++++ tests/system/Files/FileWithVfsTest.php | 9 +++++++++ tests/system/Filters/CSRFTest.php | 9 +++++++++ tests/system/Filters/DebugToolbarTest.php | 9 +++++++++ tests/system/Filters/FiltersTest.php | 9 +++++++++ tests/system/Filters/HoneypotTest.php | 9 +++++++++ .../system/Filters/fixtures/GoogleCurious.php | 9 +++++++++ tests/system/Filters/fixtures/GoogleEmpty.php | 9 +++++++++ tests/system/Filters/fixtures/GoogleMe.php | 9 +++++++++ tests/system/Filters/fixtures/GoogleYou.php | 9 +++++++++ .../system/Filters/fixtures/InvalidClass.php | 9 +++++++++ tests/system/Filters/fixtures/Multiple1.php | 9 +++++++++ tests/system/Filters/fixtures/Multiple2.php | 9 +++++++++ tests/system/Filters/fixtures/Role.php | 9 +++++++++ tests/system/Format/FormatTest.php | 9 +++++++++ tests/system/Format/JSONFormatterTest.php | 9 +++++++++ tests/system/Format/XMLFormatterTest.php | 9 +++++++++ tests/system/HTTP/CLIRequestTest.php | 9 +++++++++ tests/system/HTTP/CURLRequestTest.php | 9 +++++++++ .../system/HTTP/ContentSecurityPolicyTest.php | 9 +++++++++ tests/system/HTTP/DownloadResponseTest.php | 9 +++++++++ .../system/HTTP/Files/FileCollectionTest.php | 9 +++++++++ tests/system/HTTP/Files/FileMovingTest.php | 9 +++++++++ tests/system/HTTP/HeaderTest.php | 9 +++++++++ .../HTTP/IncomingRequestDetectingTest.php | 9 +++++++++ tests/system/HTTP/IncomingRequestTest.php | 9 +++++++++ tests/system/HTTP/MessageTest.php | 9 +++++++++ tests/system/HTTP/NegotiateTest.php | 9 +++++++++ tests/system/HTTP/RedirectResponseTest.php | 9 +++++++++ tests/system/HTTP/RequestTest.php | 9 +++++++++ tests/system/HTTP/ResponseCookieTest.php | 9 +++++++++ tests/system/HTTP/ResponseSendTest.php | 9 +++++++++ tests/system/HTTP/ResponseTest.php | 9 +++++++++ tests/system/HTTP/URITest.php | 9 +++++++++ tests/system/HTTP/UserAgentTest.php | 9 +++++++++ tests/system/Helpers/ArrayHelperTest.php | 9 +++++++++ tests/system/Helpers/CookieHelperTest.php | 9 +++++++++ tests/system/Helpers/DateHelperTest.php | 9 +++++++++ tests/system/Helpers/FilesystemHelperTest.php | 9 +++++++++ tests/system/Helpers/FormHelperTest.php | 9 +++++++++ tests/system/Helpers/HTMLHelperTest.php | 9 +++++++++ tests/system/Helpers/InflectorHelperTest.php | 9 +++++++++ tests/system/Helpers/NumberHelperTest.php | 9 +++++++++ tests/system/Helpers/SecurityHelperTest.php | 9 +++++++++ tests/system/Helpers/TextHelperTest.php | 9 +++++++++ .../Helpers/URLHelper/CurrentUrlTest.php | 9 +++++++++ .../system/Helpers/URLHelper/MiscUrlTest.php | 9 +++++++++ .../system/Helpers/URLHelper/SiteUrlTest.php | 9 +++++++++ tests/system/Helpers/XMLHelperTest.php | 9 +++++++++ tests/system/HomeTest.php | 9 +++++++++ tests/system/Honeypot/HoneypotTest.php | 9 +++++++++ tests/system/I18n/TimeDifferenceTest.php | 9 +++++++++ tests/system/I18n/TimeTest.php | 9 +++++++++ tests/system/Images/BaseHandlerTest.php | 9 +++++++++ tests/system/Images/GDHandlerTest.php | 9 +++++++++ .../system/Images/ImageMagickHandlerTest.php | 9 +++++++++ tests/system/Images/ImageTest.php | 9 +++++++++ tests/system/Language/LanguageTest.php | 9 +++++++++ .../Log/Handlers/ChromeLoggerHandlerTest.php | 9 +++++++++ .../Log/Handlers/ErrorlogHandlerTest.php | 9 +++++++++ tests/system/Log/Handlers/FileHandlerTest.php | 9 +++++++++ tests/system/Log/LoggerTest.php | 9 +++++++++ tests/system/Models/CountAllModelTest.php | 9 +++++++++ tests/system/Models/DeleteModelTest.php | 9 +++++++++ tests/system/Models/EventsModelTest.php | 9 +++++++++ tests/system/Models/FindModelTest.php | 9 +++++++++ tests/system/Models/GeneralModelTest.php | 9 +++++++++ tests/system/Models/InsertModelTest.php | 9 +++++++++ tests/system/Models/LiveModelTestCase.php | 9 +++++++++ .../system/Models/MiscellaneousModelTest.php | 9 +++++++++ tests/system/Models/PaginateModelTest.php | 9 +++++++++ tests/system/Models/SaveModelTest.php | 9 +++++++++ tests/system/Models/UpdateModelTest.php | 9 +++++++++ tests/system/Models/ValidationModelTest.php | 9 +++++++++ tests/system/Pager/PagerRendererTest.php | 9 +++++++++ tests/system/Pager/PagerTest.php | 9 +++++++++ .../system/RESTful/ResourceControllerTest.php | 9 +++++++++ .../system/RESTful/ResourcePresenterTest.php | 9 +++++++++ tests/system/Router/RouteCollectionTest.php | 9 +++++++++ tests/system/Router/RouterTest.php | 9 +++++++++ tests/system/Security/SecurityTest.php | 9 +++++++++ tests/system/Session/SessionTest.php | 9 +++++++++ tests/system/Test/BootstrapFCPATHTest.php | 9 +++++++++ tests/system/Test/ControllerTestTraitTest.php | 9 +++++++++ tests/system/Test/DOMParserTest.php | 9 +++++++++ tests/system/Test/FabricatorTest.php | 9 +++++++++ tests/system/Test/FeatureTestTraitTest.php | 9 +++++++++ tests/system/Test/FilterTestTraitTest.php | 9 +++++++++ tests/system/Test/ReflectionHelperTest.php | 9 +++++++++ tests/system/Test/TestCaseEmissionsTest.php | 9 +++++++++ tests/system/Test/TestCaseTest.php | 9 +++++++++ tests/system/Test/TestResponseTest.php | 9 +++++++++ tests/system/Throttle/ThrottleTest.php | 9 +++++++++ tests/system/Typography/TypographyTest.php | 9 +++++++++ .../system/Validation/CreditCardRulesTest.php | 9 +++++++++ tests/system/Validation/FileRulesTest.php | 9 +++++++++ tests/system/Validation/FormatRulesTest.php | 9 +++++++++ tests/system/Validation/RulesTest.php | 9 +++++++++ tests/system/Validation/ValidationTest.php | 9 +++++++++ tests/system/View/CellTest.php | 9 +++++++++ tests/system/View/ParserFilterTest.php | 9 +++++++++ tests/system/View/ParserPluginTest.php | 9 +++++++++ tests/system/View/ParserTest.php | 9 +++++++++ tests/system/View/TableTest.php | 9 +++++++++ tests/system/View/ViewTest.php | 9 +++++++++ ...onInstantiationViaNamedConstructorRule.php | 9 +++++++++ .../CheckUseStatementsAfterLicenseRule.php | 9 +++++++++ utils/PhpCsFixer/CodeIgniter4.php | 9 +++++++++ ...rictParameterToFunctionParameterRector.php | 9 +++++++++ ...moveErrorSuppressInTryCatchStmtsRector.php | 9 +++++++++ .../RemoveVarTagFromClassConstantRector.php | 9 +++++++++ ...nderscoreToCamelCaseVariableNameRector.php | 9 +++++++++ 655 files changed, 3793 insertions(+), 1079 deletions(-) diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php index 8220fe3d6091..4bee79703546 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.no-header.php-cs-fixer.dist.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/** + * This file is part of CodeIgniter 4 framework. + * + * (c) CodeIgniter Foundation + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use Nexus\CsConfig\Factory; use PhpCsFixer\Finder; use Utils\PhpCsFixer\CodeIgniter4; @@ -15,7 +24,7 @@ ]); $overrides = [ - 'no_blank_lines_after_phpdoc' => false, + 'no_blank_lines_after_phpdoc' => false, ]; $options = [ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 1cd558071c3e..15db678cbd35 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -2,6 +2,15 @@ declare(strict_types=1); +/** + * This file is part of CodeIgniter 4 framework. + * + * (c) CodeIgniter Foundation + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use Nexus\CsConfig\Factory; use PhpCsFixer\Finder; use Utils\PhpCsFixer\CodeIgniter4; diff --git a/rector.php b/rector.php index bc01a45eb11f..aadbef2a766c 100644 --- a/rector.php +++ b/rector.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector; use Rector\CodeQuality\Rector\For_\ForToForeachRector; use Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector; diff --git a/system/API/ResponseTrait.php b/system/API/ResponseTrait.php index 3dbb249634a2..d83238f66e35 100644 --- a/system/API/ResponseTrait.php +++ b/system/API/ResponseTrait.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\API; diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index b73065d3e0cd..53d5654905ad 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Autoloader; diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index 2c645416e920..00d4a8ffe993 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Autoloader; diff --git a/system/BaseModel.php b/system/BaseModel.php index 4d26ab92465d..12747fef78e7 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter; diff --git a/system/CLI/BaseCommand.php b/system/CLI/BaseCommand.php index d548f26c402e..2d15f15f57a5 100644 --- a/system/CLI/BaseCommand.php +++ b/system/CLI/BaseCommand.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI; diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 2705c0cdac70..be3d444fbed2 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI; diff --git a/system/CLI/CommandRunner.php b/system/CLI/CommandRunner.php index 08bb52082b0f..79d21ff8ea72 100644 --- a/system/CLI/CommandRunner.php +++ b/system/CLI/CommandRunner.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI; diff --git a/system/CLI/Commands.php b/system/CLI/Commands.php index 8e82f4699edd..888d266e46b0 100644 --- a/system/CLI/Commands.php +++ b/system/CLI/Commands.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI; diff --git a/system/CLI/Console.php b/system/CLI/Console.php index 486c6d9d4d3c..20110d0fc25d 100644 --- a/system/CLI/Console.php +++ b/system/CLI/Console.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI; diff --git a/system/CLI/Exceptions/CLIException.php b/system/CLI/Exceptions/CLIException.php index 9859ae14ef90..07c60a8af85f 100644 --- a/system/CLI/Exceptions/CLIException.php +++ b/system/CLI/Exceptions/CLIException.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI\Exceptions; diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php index 0b8fb5310e2d..13c36d674a88 100644 --- a/system/CLI/GeneratorTrait.php +++ b/system/CLI/GeneratorTrait.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\CLI; diff --git a/system/Cache/CacheFactory.php b/system/Cache/CacheFactory.php index ff326c8f03ad..691b350a9968 100644 --- a/system/Cache/CacheFactory.php +++ b/system/Cache/CacheFactory.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache; diff --git a/system/Cache/CacheInterface.php b/system/Cache/CacheInterface.php index 3dc344d6f149..52502f5e6742 100644 --- a/system/Cache/CacheInterface.php +++ b/system/Cache/CacheInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache; diff --git a/system/Cache/Exceptions/CacheException.php b/system/Cache/Exceptions/CacheException.php index 3b3d2edec3c2..a3269072ecdf 100644 --- a/system/Cache/Exceptions/CacheException.php +++ b/system/Cache/Exceptions/CacheException.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Exceptions; diff --git a/system/Cache/Exceptions/ExceptionInterface.php b/system/Cache/Exceptions/ExceptionInterface.php index 371301153b56..067e8aa208b5 100644 --- a/system/Cache/Exceptions/ExceptionInterface.php +++ b/system/Cache/Exceptions/ExceptionInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Exceptions; diff --git a/system/Cache/Handlers/BaseHandler.php b/system/Cache/Handlers/BaseHandler.php index 9397959f2da0..cae03b901664 100644 --- a/system/Cache/Handlers/BaseHandler.php +++ b/system/Cache/Handlers/BaseHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/Cache/Handlers/DummyHandler.php b/system/Cache/Handlers/DummyHandler.php index cd1cf0a029a4..8d4a9a6e2972 100644 --- a/system/Cache/Handlers/DummyHandler.php +++ b/system/Cache/Handlers/DummyHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index d5277c2496fa..d169a9258a37 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index 4c9ec7878320..d1fbdf2b8cac 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/Cache/Handlers/PredisHandler.php b/system/Cache/Handlers/PredisHandler.php index c1b8d33991a0..978e48dd8b17 100644 --- a/system/Cache/Handlers/PredisHandler.php +++ b/system/Cache/Handlers/PredisHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/Cache/Handlers/RedisHandler.php b/system/Cache/Handlers/RedisHandler.php index 92323984b5c1..2320de73cf05 100644 --- a/system/Cache/Handlers/RedisHandler.php +++ b/system/Cache/Handlers/RedisHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/Cache/Handlers/WincacheHandler.php b/system/Cache/Handlers/WincacheHandler.php index 1c114ddeb738..04697a32a232 100644 --- a/system/Cache/Handlers/WincacheHandler.php +++ b/system/Cache/Handlers/WincacheHandler.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cache\Handlers; diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 9d23f80d0290..a8d54bb0e0be 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter; diff --git a/system/Commands/Cache/ClearCache.php b/system/Commands/Cache/ClearCache.php index 5e3f4c48f57c..dd9850c381e5 100644 --- a/system/Commands/Cache/ClearCache.php +++ b/system/Commands/Cache/ClearCache.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Cache; diff --git a/system/Commands/Cache/InfoCache.php b/system/Commands/Cache/InfoCache.php index 0b2fd5dec30b..6d4a543c1f91 100644 --- a/system/Commands/Cache/InfoCache.php +++ b/system/Commands/Cache/InfoCache.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Cache; diff --git a/system/Commands/Database/CreateDatabase.php b/system/Commands/Database/CreateDatabase.php index 474342018a48..1040383a1434 100644 --- a/system/Commands/Database/CreateDatabase.php +++ b/system/Commands/Database/CreateDatabase.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Database; diff --git a/system/Commands/Database/Migrate.php b/system/Commands/Database/Migrate.php index f930a044e0d9..24c7ecbddff3 100644 --- a/system/Commands/Database/Migrate.php +++ b/system/Commands/Database/Migrate.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Database; diff --git a/system/Commands/Database/MigrateRefresh.php b/system/Commands/Database/MigrateRefresh.php index c38c749d5d43..733b0eed35d8 100644 --- a/system/Commands/Database/MigrateRefresh.php +++ b/system/Commands/Database/MigrateRefresh.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Database; diff --git a/system/Commands/Database/MigrateRollback.php b/system/Commands/Database/MigrateRollback.php index f09f32bfdeea..fe9c28df7f46 100644 --- a/system/Commands/Database/MigrateRollback.php +++ b/system/Commands/Database/MigrateRollback.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Database; diff --git a/system/Commands/Database/MigrateStatus.php b/system/Commands/Database/MigrateStatus.php index 53ca46e3ec08..28144cd1d144 100644 --- a/system/Commands/Database/MigrateStatus.php +++ b/system/Commands/Database/MigrateStatus.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Database; diff --git a/system/Commands/Database/Seed.php b/system/Commands/Database/Seed.php index 1ff762af9c8b..5de640f3c103 100644 --- a/system/Commands/Database/Seed.php +++ b/system/Commands/Database/Seed.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Database; diff --git a/system/Commands/Encryption/GenerateKey.php b/system/Commands/Encryption/GenerateKey.php index f87563a3cc23..79cce1f20af8 100644 --- a/system/Commands/Encryption/GenerateKey.php +++ b/system/Commands/Encryption/GenerateKey.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Encryption; diff --git a/system/Commands/Generators/CommandGenerator.php b/system/Commands/Generators/CommandGenerator.php index a26c26664731..be979ebf46eb 100644 --- a/system/Commands/Generators/CommandGenerator.php +++ b/system/Commands/Generators/CommandGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/ConfigGenerator.php b/system/Commands/Generators/ConfigGenerator.php index 3bec83d4b75b..301091a0019f 100644 --- a/system/Commands/Generators/ConfigGenerator.php +++ b/system/Commands/Generators/ConfigGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/ControllerGenerator.php b/system/Commands/Generators/ControllerGenerator.php index 05f3fa0c979e..05ffd58ef02d 100644 --- a/system/Commands/Generators/ControllerGenerator.php +++ b/system/Commands/Generators/ControllerGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/EntityGenerator.php b/system/Commands/Generators/EntityGenerator.php index c1c406b39ca8..0b8baf4cb4cc 100644 --- a/system/Commands/Generators/EntityGenerator.php +++ b/system/Commands/Generators/EntityGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/FilterGenerator.php b/system/Commands/Generators/FilterGenerator.php index da42476635c7..4bbc9102bdef 100644 --- a/system/Commands/Generators/FilterGenerator.php +++ b/system/Commands/Generators/FilterGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/MigrateCreate.php b/system/Commands/Generators/MigrateCreate.php index d376762513c2..6501ae0ee492 100644 --- a/system/Commands/Generators/MigrateCreate.php +++ b/system/Commands/Generators/MigrateCreate.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php index 23cdf7f62725..dded6a7f5fb8 100644 --- a/system/Commands/Generators/MigrationGenerator.php +++ b/system/Commands/Generators/MigrationGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/ModelGenerator.php b/system/Commands/Generators/ModelGenerator.php index a8990264a207..808968b84542 100644 --- a/system/Commands/Generators/ModelGenerator.php +++ b/system/Commands/Generators/ModelGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/ScaffoldGenerator.php b/system/Commands/Generators/ScaffoldGenerator.php index d619acb830fd..db9eb1420589 100644 --- a/system/Commands/Generators/ScaffoldGenerator.php +++ b/system/Commands/Generators/ScaffoldGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/SeederGenerator.php b/system/Commands/Generators/SeederGenerator.php index c36ed337b767..233595495576 100644 --- a/system/Commands/Generators/SeederGenerator.php +++ b/system/Commands/Generators/SeederGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/SessionMigrationGenerator.php b/system/Commands/Generators/SessionMigrationGenerator.php index 2727257b9dbd..60258e6b1548 100644 --- a/system/Commands/Generators/SessionMigrationGenerator.php +++ b/system/Commands/Generators/SessionMigrationGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Generators/ValidationGenerator.php b/system/Commands/Generators/ValidationGenerator.php index 2115d280efb1..322ecb190b28 100644 --- a/system/Commands/Generators/ValidationGenerator.php +++ b/system/Commands/Generators/ValidationGenerator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Generators; diff --git a/system/Commands/Help.php b/system/Commands/Help.php index 7aa9a5cc6ad7..32df294e222d 100644 --- a/system/Commands/Help.php +++ b/system/Commands/Help.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands; diff --git a/system/Commands/Housekeeping/ClearDebugbar.php b/system/Commands/Housekeeping/ClearDebugbar.php index 7e34a8ec681b..5f81b2eeeda8 100644 --- a/system/Commands/Housekeeping/ClearDebugbar.php +++ b/system/Commands/Housekeeping/ClearDebugbar.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Housekeeping; diff --git a/system/Commands/Housekeeping/ClearLogs.php b/system/Commands/Housekeeping/ClearLogs.php index eb0741b7796e..1c063d80929e 100644 --- a/system/Commands/Housekeeping/ClearLogs.php +++ b/system/Commands/Housekeeping/ClearLogs.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Housekeeping; diff --git a/system/Commands/ListCommands.php b/system/Commands/ListCommands.php index fd57bfc9e73a..f74736832a8b 100644 --- a/system/Commands/ListCommands.php +++ b/system/Commands/ListCommands.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands; diff --git a/system/Commands/Server/Serve.php b/system/Commands/Server/Serve.php index 04cced6c9c2d..4d1d64e6c071 100644 --- a/system/Commands/Server/Serve.php +++ b/system/Commands/Server/Serve.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Server; diff --git a/system/Commands/Server/rewrite.php b/system/Commands/Server/rewrite.php index bb19e4596e76..ef5dc0734f23 100644 --- a/system/Commands/Server/rewrite.php +++ b/system/Commands/Server/rewrite.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ /* diff --git a/system/Commands/Utilities/Environment.php b/system/Commands/Utilities/Environment.php index 5b44ea02bdf9..2ad0dc394e5b 100644 --- a/system/Commands/Utilities/Environment.php +++ b/system/Commands/Utilities/Environment.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + namespace CodeIgniter\Commands\Utilities; use CodeIgniter\CLI\BaseCommand; diff --git a/system/Commands/Utilities/Namespaces.php b/system/Commands/Utilities/Namespaces.php index f4ef07a5c1ee..639a861e5271 100644 --- a/system/Commands/Utilities/Namespaces.php +++ b/system/Commands/Utilities/Namespaces.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Utilities; diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index 0d914d766f84..bdc5db9da181 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Utilities; diff --git a/system/Common.php b/system/Common.php index 2e76c2cab237..97caeee4efae 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ use CodeIgniter\Cache\CacheInterface; diff --git a/system/ComposerScripts.php b/system/ComposerScripts.php index 52bc46e09e18..cf74406883df 100644 --- a/system/ComposerScripts.php +++ b/system/ComposerScripts.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter; diff --git a/system/Config/AutoloadConfig.php b/system/Config/AutoloadConfig.php index 140d62c42970..0818271e002f 100644 --- a/system/Config/AutoloadConfig.php +++ b/system/Config/AutoloadConfig.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index a3386c118cac..1468c84271e8 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index ec5bea060e63..49d3688db112 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/Config.php b/system/Config/Config.php index aa7249410ca2..229e1e35d279 100644 --- a/system/Config/Config.php +++ b/system/Config/Config.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/DotEnv.php b/system/Config/DotEnv.php index 49a2a70a3a1d..e9761c63edd6 100644 --- a/system/Config/DotEnv.php +++ b/system/Config/DotEnv.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/Factories.php b/system/Config/Factories.php index c03264b422fa..9df4fec5a6a4 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/Factory.php b/system/Config/Factory.php index b259a68a0a49..5889bf4d7336 100644 --- a/system/Config/Factory.php +++ b/system/Config/Factory.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/ForeignCharacters.php b/system/Config/ForeignCharacters.php index 591870de92fe..f2e7cc57cabf 100644 --- a/system/Config/ForeignCharacters.php +++ b/system/Config/ForeignCharacters.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/Routes.php b/system/Config/Routes.php index 1867bdd1ae98..4ace952bc3c8 100644 --- a/system/Config/Routes.php +++ b/system/Config/Routes.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ use CodeIgniter\Exceptions\PageNotFoundException; diff --git a/system/Config/Services.php b/system/Config/Services.php index 65f5b7cc368d..8760b8bb9f96 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Config/View.php b/system/Config/View.php index d5201c2b2cfa..0699f45ceaf6 100644 --- a/system/Config/View.php +++ b/system/Config/View.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; diff --git a/system/Controller.php b/system/Controller.php index 255322391a7f..9138d930ac53 100644 --- a/system/Controller.php +++ b/system/Controller.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter; diff --git a/system/Cookie/CloneableCookieInterface.php b/system/Cookie/CloneableCookieInterface.php index 9b45da371973..8cbbeb985804 100644 --- a/system/Cookie/CloneableCookieInterface.php +++ b/system/Cookie/CloneableCookieInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cookie; diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index 75f5e667d57d..84f067442119 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cookie; diff --git a/system/Cookie/CookieInterface.php b/system/Cookie/CookieInterface.php index 7b27ba604348..0576d7ee48c6 100644 --- a/system/Cookie/CookieInterface.php +++ b/system/Cookie/CookieInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cookie; diff --git a/system/Cookie/CookieStore.php b/system/Cookie/CookieStore.php index bd2468778050..a7c1e37bb297 100644 --- a/system/Cookie/CookieStore.php +++ b/system/Cookie/CookieStore.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cookie; diff --git a/system/Cookie/Exceptions/CookieException.php b/system/Cookie/Exceptions/CookieException.php index da64d8591c89..89fd75e9ff5c 100644 --- a/system/Cookie/Exceptions/CookieException.php +++ b/system/Cookie/Exceptions/CookieException.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Cookie\Exceptions; diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 763ce0ace0b1..2dd7933113e4 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index e2a9bb81e601..675c9958d086 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/BasePreparedQuery.php b/system/Database/BasePreparedQuery.php index 6e2c296bb8cc..db2b02e054bf 100644 --- a/system/Database/BasePreparedQuery.php +++ b/system/Database/BasePreparedQuery.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index fdb4bf186a62..e44de7b47b9a 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/BaseUtils.php b/system/Database/BaseUtils.php index 7b45f6a43103..4f6c5712362e 100644 --- a/system/Database/BaseUtils.php +++ b/system/Database/BaseUtils.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/Config.php b/system/Database/Config.php index f227017c3317..681662a436a4 100644 --- a/system/Database/Config.php +++ b/system/Database/Config.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/ConnectionInterface.php b/system/Database/ConnectionInterface.php index d458bc8abd8c..4ebd0fb0a36a 100644 --- a/system/Database/ConnectionInterface.php +++ b/system/Database/ConnectionInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/Database.php b/system/Database/Database.php index 43da80375459..a0797190d893 100644 --- a/system/Database/Database.php +++ b/system/Database/Database.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/Exceptions/DataException.php b/system/Database/Exceptions/DataException.php index 1142be6193ef..fb713038df82 100644 --- a/system/Database/Exceptions/DataException.php +++ b/system/Database/Exceptions/DataException.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Exceptions; diff --git a/system/Database/Exceptions/DatabaseException.php b/system/Database/Exceptions/DatabaseException.php index 8951de8a525c..a2b3b7637ce7 100644 --- a/system/Database/Exceptions/DatabaseException.php +++ b/system/Database/Exceptions/DatabaseException.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Exceptions; diff --git a/system/Database/Exceptions/ExceptionInterface.php b/system/Database/Exceptions/ExceptionInterface.php index 3820c555c025..815652349324 100644 --- a/system/Database/Exceptions/ExceptionInterface.php +++ b/system/Database/Exceptions/ExceptionInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Exceptions; diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 3e591e63efaf..0f9f6bf5772b 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/Migration.php b/system/Database/Migration.php index 45e87049a072..6b1cf82d642d 100644 --- a/system/Database/Migration.php +++ b/system/Database/Migration.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/MigrationRunner.php b/system/Database/MigrationRunner.php index 7437dda86b39..08963796358a 100644 --- a/system/Database/MigrationRunner.php +++ b/system/Database/MigrationRunner.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/ModelFactory.php b/system/Database/ModelFactory.php index 148820fc2e60..7db233e8b2cd 100644 --- a/system/Database/ModelFactory.php +++ b/system/Database/ModelFactory.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/MySQLi/Builder.php b/system/Database/MySQLi/Builder.php index 73f1df25e5b7..55b7cd58f610 100644 --- a/system/Database/MySQLi/Builder.php +++ b/system/Database/MySQLi/Builder.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\MySQLi; diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 804ac807aa8a..e56d0d19c3bc 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\MySQLi; diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index 14e04552f395..fd9f705162d7 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\MySQLi; diff --git a/system/Database/MySQLi/PreparedQuery.php b/system/Database/MySQLi/PreparedQuery.php index d14fc1125a80..8f5dcf66553c 100644 --- a/system/Database/MySQLi/PreparedQuery.php +++ b/system/Database/MySQLi/PreparedQuery.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\MySQLi; diff --git a/system/Database/MySQLi/Result.php b/system/Database/MySQLi/Result.php index 83d2556638b5..04e91c8eee48 100644 --- a/system/Database/MySQLi/Result.php +++ b/system/Database/MySQLi/Result.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\MySQLi; diff --git a/system/Database/MySQLi/Utils.php b/system/Database/MySQLi/Utils.php index 2e91ad291ce1..39f27e24b052 100644 --- a/system/Database/MySQLi/Utils.php +++ b/system/Database/MySQLi/Utils.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\MySQLi; diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index 03cf05e3a079..465b4ff3f7fc 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Postgre; diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index 98adb01c13a6..74ad88664ade 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Postgre; diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index 335c37a9280f..426e5a3606d7 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Postgre; diff --git a/system/Database/Postgre/PreparedQuery.php b/system/Database/Postgre/PreparedQuery.php index 9c94b5c304dd..52256530e357 100644 --- a/system/Database/Postgre/PreparedQuery.php +++ b/system/Database/Postgre/PreparedQuery.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Postgre; diff --git a/system/Database/Postgre/Result.php b/system/Database/Postgre/Result.php index 9cc47e135ebe..feb5c1ca0584 100644 --- a/system/Database/Postgre/Result.php +++ b/system/Database/Postgre/Result.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Postgre; diff --git a/system/Database/Postgre/Utils.php b/system/Database/Postgre/Utils.php index 7de2b127ff22..8c4d6d6967be 100644 --- a/system/Database/Postgre/Utils.php +++ b/system/Database/Postgre/Utils.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\Postgre; diff --git a/system/Database/PreparedQueryInterface.php b/system/Database/PreparedQueryInterface.php index 99fad9af2c20..c40ef2f4d455 100644 --- a/system/Database/PreparedQueryInterface.php +++ b/system/Database/PreparedQueryInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/Query.php b/system/Database/Query.php index 9b512647cf4d..688ffb1323d5 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/QueryInterface.php b/system/Database/QueryInterface.php index 73b65faba561..fd81ab7c4bc7 100644 --- a/system/Database/QueryInterface.php +++ b/system/Database/QueryInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/ResultInterface.php b/system/Database/ResultInterface.php index be24679f96c9..9a0d79698623 100644 --- a/system/Database/ResultInterface.php +++ b/system/Database/ResultInterface.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index 4276c5359056..8478293343fd 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLSRV; diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index 0b0e729a7c30..a37c6119ae61 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLSRV; diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index 6e87cd23a508..4a52695a653f 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLSRV; diff --git a/system/Database/SQLSRV/PreparedQuery.php b/system/Database/SQLSRV/PreparedQuery.php index 843bbbf597a3..7972ba725298 100755 --- a/system/Database/SQLSRV/PreparedQuery.php +++ b/system/Database/SQLSRV/PreparedQuery.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLSRV; diff --git a/system/Database/SQLSRV/Result.php b/system/Database/SQLSRV/Result.php index 94eaecebf80d..6330b58ba2ad 100755 --- a/system/Database/SQLSRV/Result.php +++ b/system/Database/SQLSRV/Result.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLSRV; diff --git a/system/Database/SQLSRV/Utils.php b/system/Database/SQLSRV/Utils.php index d1223ce5d855..0776f3a68c45 100755 --- a/system/Database/SQLSRV/Utils.php +++ b/system/Database/SQLSRV/Utils.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLSRV; diff --git a/system/Database/SQLite3/Builder.php b/system/Database/SQLite3/Builder.php index f5896739c539..fd071957d04d 100644 --- a/system/Database/SQLite3/Builder.php +++ b/system/Database/SQLite3/Builder.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index cf499268c838..b4252e1a19a3 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/SQLite3/Forge.php b/system/Database/SQLite3/Forge.php index eb0492971494..373c0bce0bf9 100644 --- a/system/Database/SQLite3/Forge.php +++ b/system/Database/SQLite3/Forge.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/SQLite3/PreparedQuery.php b/system/Database/SQLite3/PreparedQuery.php index d33f016d67f3..8c00c2b3d10e 100644 --- a/system/Database/SQLite3/PreparedQuery.php +++ b/system/Database/SQLite3/PreparedQuery.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 1e25d0e58bb4..7485d36dca4b 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index e1be8388e92e..c4f6b77bf636 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/SQLite3/Utils.php b/system/Database/SQLite3/Utils.php index bad750babecb..192b81846cc7 100644 --- a/system/Database/SQLite3/Utils.php +++ b/system/Database/SQLite3/Utils.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database\SQLite3; diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index 515d90e94d5f..c809fbcd1a32 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Database; diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index a9cb75c0bf74..c1b262060d87 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug; diff --git a/system/Debug/Iterator.php b/system/Debug/Iterator.php index 6fcf741f0b4b..01a9d58a0104 100644 --- a/system/Debug/Iterator.php +++ b/system/Debug/Iterator.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug; diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php index 975e7cc29d99..fc26abae1aaf 100644 --- a/system/Debug/Timer.php +++ b/system/Debug/Timer.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug; diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 1bda0619801b..df266710d150 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug; @@ -292,7 +292,6 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r * @var IncomingRequest $request * @var Response $response */ - if (CI_DEBUG && ! is_cli()) { global $app; diff --git a/system/Debug/Toolbar/Collectors/BaseCollector.php b/system/Debug/Toolbar/Collectors/BaseCollector.php index fbe92410f363..7a77e79aa649 100644 --- a/system/Debug/Toolbar/Collectors/BaseCollector.php +++ b/system/Debug/Toolbar/Collectors/BaseCollector.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Config.php b/system/Debug/Toolbar/Collectors/Config.php index 83d80a120072..1233d76260a5 100644 --- a/system/Debug/Toolbar/Collectors/Config.php +++ b/system/Debug/Toolbar/Collectors/Config.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index 5b45c182ceca..1f9fa37d7215 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Events.php b/system/Debug/Toolbar/Collectors/Events.php index 4515f26bf110..741cb5a927d9 100644 --- a/system/Debug/Toolbar/Collectors/Events.php +++ b/system/Debug/Toolbar/Collectors/Events.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Files.php b/system/Debug/Toolbar/Collectors/Files.php index 26256660befa..16be0e90a15e 100644 --- a/system/Debug/Toolbar/Collectors/Files.php +++ b/system/Debug/Toolbar/Collectors/Files.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/History.php b/system/Debug/Toolbar/Collectors/History.php index 6beea6386fb3..5a8053ca46b7 100644 --- a/system/Debug/Toolbar/Collectors/History.php +++ b/system/Debug/Toolbar/Collectors/History.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Logs.php b/system/Debug/Toolbar/Collectors/Logs.php index 80eee730762b..dfa91da6854e 100644 --- a/system/Debug/Toolbar/Collectors/Logs.php +++ b/system/Debug/Toolbar/Collectors/Logs.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Routes.php b/system/Debug/Toolbar/Collectors/Routes.php index 4f50ef7201bd..945c80cb6148 100644 --- a/system/Debug/Toolbar/Collectors/Routes.php +++ b/system/Debug/Toolbar/Collectors/Routes.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Timers.php b/system/Debug/Toolbar/Collectors/Timers.php index 940ff67a5c56..ec09a0fe3e05 100644 --- a/system/Debug/Toolbar/Collectors/Timers.php +++ b/system/Debug/Toolbar/Collectors/Timers.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Collectors/Views.php b/system/Debug/Toolbar/Collectors/Views.php index 0cf25ccdd24e..b716ffa3b178 100644 --- a/system/Debug/Toolbar/Collectors/Views.php +++ b/system/Debug/Toolbar/Collectors/Views.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Debug\Toolbar\Collectors; diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php index f6366958e1be..1c84ee541bd6 100644 --- a/system/Debug/Toolbar/Views/toolbar.tpl.php +++ b/system/Debug/Toolbar/Views/toolbar.tpl.php @@ -17,7 +17,6 @@ * @var array $styles * @var \CodeIgniter\View\Parser $parser */ - ?> ') + 8); $script = PHP_EOL - . '' - . '' - . '' - . $kintScript - . PHP_EOL; + . '' + . '' + . '' + . $kintScript + . PHP_EOL; if (strpos($response->getBody(), '') !== false) { $response->setBody(preg_replace('//', '' . $script, $response->getBody(), 1)); @@ -397,9 +390,6 @@ public function respond() /** * Format output - * - * @param string $data JSON encoded Toolbar data - * @param string $format html, json, xml */ protected function format(string $data, string $format = 'html'): string { diff --git a/system/Email/Email.php b/system/Email/Email.php index 3ce079879293..c07f79d80df6 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -337,8 +337,6 @@ class Email ]; /** - * Base charsets - * * Character sets valid for 7-bit encoding, * excluding language suffix. * @@ -386,10 +384,6 @@ class Email protected static $func_overload; /** - * Constructor - Sets Email Preferences - * - * The constructor can be passed an array of config values - * * @param array|null $config */ public function __construct($config = null) @@ -434,8 +428,6 @@ public function initialize($config) } /** - * Initialize the Email Data - * * @param bool $clearAttachments * * @return Email @@ -463,8 +455,6 @@ public function clear($clearAttachments = false) } /** - * Set FROM - * * @param string $from * @param string $name * @param string|null $returnPath Return-Path @@ -485,15 +475,12 @@ public function setFrom($from, $name = '', $returnPath = null) } } - // Store the plain text values $this->tmpArchive['fromEmail'] = $from; $this->tmpArchive['fromName'] = $name; - // prepare the display name if ($name !== '') { // only use Q encoding if there are characters that would require it if (! preg_match('/[\200-\377]/', $name)) { - // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes $name = '"' . addcslashes($name, "\0..\37\177'\"\\") . '"'; } else { $name = $this->prepQEncoding($name); @@ -511,8 +498,6 @@ public function setFrom($from, $name = '', $returnPath = null) } /** - * Set Reply-to - * * @param string $replyto * @param string $name * @@ -533,7 +518,6 @@ public function setReplyTo($replyto, $name = '') // only use Q encoding if there are characters that would require it if (! preg_match('/[\200-\377]/', $name)) { - // add slashes for non-printing characters, slashes, and double quotes, and surround it in double quotes $name = '"' . addcslashes($name, "\0..\37\177'\"\\") . '"'; } else { $name = $this->prepQEncoding($name); @@ -548,8 +532,6 @@ public function setReplyTo($replyto, $name = '') } /** - * Set Recipients - * * @param array|string $to * * @return Email @@ -573,8 +555,6 @@ public function setTo($to) } /** - * Set CC - * * @param string $cc * * @return Email @@ -599,8 +579,6 @@ public function setCC($cc) } /** - * Set BCC - * * @param string $bcc * @param string $limit * @@ -630,8 +608,6 @@ public function setBCC($bcc, $limit = '') } /** - * Set Email Subject - * * @param string $subject * * @return Email @@ -647,8 +623,6 @@ public function setSubject($subject) } /** - * Set Body - * * @param string $body * * @return Email @@ -661,8 +635,6 @@ public function setMessage($body) } /** - * Assign file attachments - * * @param string $file Can be local path, URL or buffered content * @param string $disposition 'attachment' * @param string|null $newname @@ -695,10 +667,7 @@ public function attach($file, $disposition = '', $newname = null, $mime = '') } // declare names on their own, to make phpcbf happy - $namesAttached = [ - $file, - $newname, - ]; + $namesAttached = [$file, $newname]; $this->attachments[] = [ 'name' => $namesAttached, @@ -714,7 +683,6 @@ public function attach($file, $disposition = '', $newname = null, $mime = '') /** * Set and return attachment Content-ID - * * Useful for attached inline pictures * * @param string $filename @@ -737,8 +705,6 @@ public function setAttachmentCID($filename) } /** - * Add a Header Item - * * @param string $header * @param string $value * @@ -752,8 +718,6 @@ public function setHeader($header, $value) } /** - * Convert a String to an Array - * * @param string $email * * @return array @@ -768,8 +732,6 @@ protected function stringToArray($email) } /** - * Set Multipart Value - * * @param string $str * * @return Email @@ -782,8 +744,6 @@ public function setAltMessage($str) } /** - * Set Mailtype - * * @param string $type * * @return Email @@ -796,8 +756,6 @@ public function setMailType($type = 'text') } /** - * Set Wordwrap - * * @param bool $wordWrap * * @return Email @@ -810,8 +768,6 @@ public function setWordWrap($wordWrap = true) } /** - * Set Protocol - * * @param string $protocol * * @return Email @@ -824,8 +780,6 @@ public function setProtocol($protocol = 'mail') } /** - * Set Priority - * * @param int $n * * @return Email @@ -838,8 +792,6 @@ public function setPriority($n = 3) } /** - * Set Newline Character - * * @param string $newline * * @return Email @@ -852,8 +804,6 @@ public function setNewline($newline = "\n") } /** - * Set CRLF - * * @param string $CRLF * * @return Email @@ -866,8 +816,6 @@ public function setCRLF($CRLF = "\n") } /** - * Get the Message ID - * * @return string */ protected function getMessageID() @@ -878,8 +826,6 @@ protected function getMessageID() } /** - * Get Mail Protocol - * * @return string */ protected function getProtocol() @@ -894,8 +840,6 @@ protected function getProtocol() } /** - * Get Mail Encoding - * * @return string */ protected function getEncoding() @@ -916,8 +860,6 @@ protected function getEncoding() } /** - * Get content type (text/html/attachment) - * * @return string */ protected function getContentType() @@ -949,8 +891,6 @@ protected function setDate() } /** - * Mime message - * * @return string */ protected function getMimeMessage() @@ -959,8 +899,6 @@ protected function getMimeMessage() } /** - * Validate Email Address - * * @param array|string $email * * @return bool @@ -985,8 +923,6 @@ public function validateEmail($email) } /** - * Email Validation - * * @param string $email * * @return bool @@ -1002,8 +938,6 @@ public function isValidEmail($email) } /** - * Clean Extended Email Address: Joe Smith - * * @param array|string $email * * @return array|string @@ -1028,6 +962,7 @@ public function cleanEmail($email) * * Provides the raw message for use in plain-text headers of * HTML-formatted emails. + * * If the user hasn't specified his own alternative message * it creates one by stripping the HTML * @@ -1046,15 +981,12 @@ protected function getAltMessage() $body = str_replace(str_repeat("\n", $i), "\n\n", $body); } - // Reduce multiple spaces $body = preg_replace('| +|', ' ', $body); return ($this->wordWrap) ? $this->wordWrap($body, 76) : $body; } /** - * Word Wrap - * * @param string $str * @param int|null $charlim Line-length limit * @@ -1062,21 +994,16 @@ protected function getAltMessage() */ public function wordWrap($str, $charlim = null) { - // Set the character limit, if not already present if (empty($charlim)) { $charlim = empty($this->wrapChars) ? 76 : $this->wrapChars; } - // Standardize newlines if (strpos($str, "\r") !== false) { $str = str_replace(["\r\n", "\r"], "\n", $str); } - // Reduce multiple spaces at end of line $str = preg_replace('| +\n|', "\n", $str); - // If the current word is surrounded by {unwrap} tags we'll - // strip the entire chunk and replace it with a marker. $unwrap = []; if (preg_match_all('|\{unwrap\}(.+?)\{/unwrap\}|s', $str, $matches)) { @@ -1095,8 +1022,6 @@ public function wordWrap($str, $charlim = null) $output = ''; foreach (explode("\n", $str) as $line) { - // Is the line within the allowed character count? - // If so we'll join it to the output and continue if (static::strlen($line) <= $charlim) { $output .= $line . $this->newline; @@ -1106,18 +1031,14 @@ public function wordWrap($str, $charlim = null) $temp = ''; do { - // If the over-length word is a URL we won't wrap it if (preg_match('!\[url.+\]|://|www\.!', $line)) { break; } - // Trim the word down $temp .= static::substr($line, 0, $charlim - 1); $line = static::substr($line, $charlim - 1); } while (static::strlen($line) > $charlim); - // If $temp contains data it means we had to split up an over-length - // word into smaller chunks so we'll add it back to our current line if ($temp !== '') { $output .= $temp . $this->newline; } @@ -1125,7 +1046,6 @@ public function wordWrap($str, $charlim = null) $output .= $line . $this->newline; } - // Put our markers back if ($unwrap) { foreach ($unwrap as $key => $val) { $output = str_replace('{{unwrapped' . $key . '}}', $val, $output); @@ -1333,13 +1253,9 @@ protected function attachmentsHaveMultipart($type) } /** - * Prepares attachment string - * * @param string $body Message body to append to * @param string $boundary Multipart boundary * @param string|null $multipart When provided, only attachments of this type will be processed - * - * @return void */ protected function appendAttachments(&$body, $boundary, $multipart = null) { @@ -1366,8 +1282,6 @@ protected function appendAttachments(&$body, $boundary, $multipart = null) } /** - * Prep Quoted Printable - * * Prepares string for Quoted-Printable Content-Transfer-Encoding * Refer to RFC 2045 http://www.ietf.org/rfc/rfc2045.txt * @@ -1531,8 +1445,6 @@ protected function prepQuotedPrintable($str) } /** - * Prep Q Encoding - * * Performs "Q Encoding" on a string for use in email headers. * It's related but not identical to quoted-printable, so it has its * own method. @@ -1600,8 +1512,6 @@ protected function prepQEncoding($str) } /** - * Send Email - * * @param bool $autoClear * * @return bool @@ -1822,9 +1732,7 @@ protected function sendWithSendmail() $from = $this->validateEmailForShell($from) ? '-f ' . $from : ''; - // is popen() enabled? if (! function_usable('popen') || false === ($fp = @popen($this->mailPath . ' -oi ' . $from . ' -t', 'w'))) { - // server probably has popen disabled, so nothing we can do to get a verbose error. return false; } @@ -1912,8 +1820,6 @@ protected function sendWithSmtp() } /** - * SMTP End - * * Shortcut to send RSET or QUIT depending on keep-alive */ protected function SMTPEnd() @@ -1922,8 +1828,6 @@ protected function SMTPEnd() } /** - * SMTP Connect - * * @return bool|string */ protected function SMTPConnect() @@ -1977,8 +1881,6 @@ protected function SMTPConnect() } /** - * Send SMTP command - * * @param string $cmd * @param string $data * @@ -2053,8 +1955,6 @@ protected function sendCommand($cmd, $data = '') } /** - * SMTP Authenticate - * * @return bool */ protected function SMTPAuthenticate() @@ -2108,8 +2008,6 @@ protected function SMTPAuthenticate() } /** - * Send SMTP data - * * @param string $data * * @return bool @@ -2153,8 +2051,6 @@ protected function sendData($data) } /** - * Get SMTP data - * * @return string */ protected function getSMTPData() @@ -2173,8 +2069,6 @@ protected function getSMTPData() } /** - * Get Hostname - * * There are only two legal types of hostname - either a fully * qualified domain name (eg: "mail.example.com") or an IP literal * (eg: "[1.2.3.4]"). @@ -2198,8 +2092,6 @@ protected function getHostname() } /** - * Get Debug Message - * * @param array $include List of raw data chunks to include in the output * Valid options are: 'headers', 'subject', 'body' * @@ -2230,8 +2122,6 @@ public function printDebugger($include = ['headers', 'subject', 'body']) } /** - * Set Message - * * @param string $msg */ protected function setErrorMessage($msg) @@ -2253,9 +2143,6 @@ protected function mimeTypes($ext = '') return ! empty($mime) ? $mime : 'application/x-unknown-content-type'; } - /** - * Destructor - */ public function __destruct() { if (is_resource($this->SMTPConnect)) { diff --git a/system/Encryption/Encryption.php b/system/Encryption/Encryption.php index 0b5925902f84..35c3568120ca 100644 --- a/system/Encryption/Encryption.php +++ b/system/Encryption/Encryption.php @@ -76,13 +76,7 @@ class Encryption protected $handlers = []; /** - * Class constructor - * - * @param EncryptionConfig $config Configuration parameters - * * @throws EncryptionException - * - * @return void */ public function __construct(?EncryptionConfig $config = null) { @@ -92,16 +86,13 @@ public function __construct(?EncryptionConfig $config = null) $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; - // Map what we have installed $this->handlers = [ 'OpenSSL' => extension_loaded('openssl'), // the SodiumHandler uses some API (like sodium_pad) that is available only on v1.0.14+ 'Sodium' => extension_loaded('sodium') && version_compare(SODIUM_LIBRARY_VERSION, '1.0.14', '>='), ]; - // If requested driver is not active, bail if (! in_array($this->driver, $this->drivers, true) || (array_key_exists($this->driver, $this->handlers) && ! $this->handlers[$this->driver])) { - // this should never happen in travis-ci throw EncryptionException::forNoHandlerAvailable($this->driver); } } @@ -109,27 +100,22 @@ public function __construct(?EncryptionConfig $config = null) /** * Initialize or re-initialize an encrypter * - * @param EncryptionConfig $config Configuration parameters - * * @throws EncryptionException * * @return EncrypterInterface */ public function initialize(?EncryptionConfig $config = null) { - // override config? if ($config) { $this->key = $config->key; $this->driver = $config->driver; $this->digest = $config->digest ?? 'SHA512'; } - // Insist on a driver if (empty($this->driver)) { throw EncryptionException::forNoDriverRequested(); } - // Check for an unknown driver if (! in_array($this->driver, $this->drivers, true)) { throw EncryptionException::forUnKnownHandler($this->driver); } @@ -138,7 +124,6 @@ public function initialize(?EncryptionConfig $config = null) throw EncryptionException::forNeedsStarterKey(); } - // Derive a secret key for the encrypter $this->hmacKey = bin2hex(\hash_hkdf($this->digest, $this->key)); $handlerName = 'CodeIgniter\\Encryption\\Handlers\\' . $this->driver . 'Handler'; diff --git a/system/Encryption/Handlers/SodiumHandler.php b/system/Encryption/Handlers/SodiumHandler.php index f6903a3bed6b..9dc4cdbdec44 100644 --- a/system/Encryption/Handlers/SodiumHandler.php +++ b/system/Encryption/Handlers/SodiumHandler.php @@ -113,8 +113,6 @@ public function decrypt($data, $params = null) * @param array|string|null $params * * @throws EncryptionException If key is empty - * - * @return void */ protected function parseParams($params) { diff --git a/system/Events/Events.php b/system/Events/Events.php index d32ff339126b..a0d9c7616451 100644 --- a/system/Events/Events.php +++ b/system/Events/Events.php @@ -63,8 +63,6 @@ class Events /** * Ensures that we have a events file ready. - * - * @return void */ public static function initialize() { @@ -113,8 +111,6 @@ public static function initialize() * @param string $eventName * @param callable $callback * @param int $priority - * - * @return void */ public static function on($eventName, $callback, $priority = EVENT_PRIORITY_NORMAL) { @@ -229,8 +225,6 @@ public static function removeListener($eventName, callable $listener): bool * removed, otherwise all listeners for all events are removed. * * @param string|null $eventName - * - * @return void */ public static function removeAllListeners($eventName = null) { @@ -243,8 +237,6 @@ public static function removeAllListeners($eventName = null) /** * Sets the path to the file that routes are read from. - * - * @return void */ public static function setFiles(array $files) { @@ -265,8 +257,6 @@ public function getFiles() * Turns simulation on or off. When on, events will not be triggered, * simply logged. Useful during testing when you don't actually want * the tests to run. - * - * @return void */ public static function simulate(bool $choice = true) { diff --git a/system/Filters/DebugToolbar.php b/system/Filters/DebugToolbar.php index cc57cd50b81e..ae4c09c8bf9c 100644 --- a/system/Filters/DebugToolbar.php +++ b/system/Filters/DebugToolbar.php @@ -24,8 +24,6 @@ class DebugToolbar implements FilterInterface * We don't need to do anything here. * * @param array|null $arguments - * - * @return void */ public function before(RequestInterface $request, $arguments = null) { @@ -36,8 +34,6 @@ public function before(RequestInterface $request, $arguments = null) * and debug information and display it in a toolbar. * * @param array|null $arguments - * - * @return void */ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index 42ba65617954..bce502a3f4e9 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -372,8 +372,6 @@ public function getArguments(?string $key = null) * Add any applicable (not excluded) global filter settings to the mix. * * @param string $uri - * - * @return void */ protected function processGlobals(?string $uri = null) { @@ -417,8 +415,6 @@ protected function processGlobals(?string $uri = null) /** * Add any method-specific filters to the mix. - * - * @return void */ protected function processMethods() { @@ -440,8 +436,6 @@ protected function processMethods() * Add any applicable configured filters to the mix. * * @param string $uri - * - * @return void */ protected function processFilters(?string $uri = null) { @@ -474,8 +468,6 @@ protected function processFilters(?string $uri = null) * Maps filter aliases to the equivalent filter classes * * @throws FilterException - * - * @return void */ protected function processAliasesToClass(string $position) { diff --git a/system/Filters/Honeypot.php b/system/Filters/Honeypot.php index 022999bcfac3..539513e7cb8a 100644 --- a/system/Filters/Honeypot.php +++ b/system/Filters/Honeypot.php @@ -28,8 +28,6 @@ class Honeypot implements FilterInterface * @param array|null $arguments * * @throws HoneypotException - * - * @return void */ public function before(RequestInterface $request, $arguments = null) { @@ -42,8 +40,6 @@ public function before(RequestInterface $request, $arguments = null) * Attach a honeypot to the current response. * * @param array|null $arguments - * - * @return void */ public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) { diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index ed19d2d9b020..3b18fc8bf1df 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -210,8 +210,6 @@ public function __construct(ContentSecurityPolicyConfig $config) * Compiles and sets the appropriate headers in the request. * * Should be called just prior to sending the response to the user agent. - * - * @return void */ public function finalize(ResponseInterface &$response) { @@ -552,8 +550,6 @@ public function upgradeInsecureRequests(bool $value = true) * DRY method to add an string or array to a class property. * * @param array|string $options - * - * @return void */ protected function addOption($options, string $target, ?bool $explicitReporting = null) { @@ -575,8 +571,6 @@ protected function addOption($options, string $target, ?bool $explicitReporting * Scans the body of the request message and replaces any nonce * placeholders with actual nonces, that we'll then add to our * headers. - * - * @return void */ protected function generateNonces(ResponseInterface &$response) { @@ -619,8 +613,6 @@ protected function generateNonces(ResponseInterface &$response) * Based on the current state of the elements, will add the appropriate * Content-Security-Policy and Content-Security-Policy-Report-Only headers * with their values to the response object. - * - * @return void */ protected function buildHeaders(ResponseInterface &$response) { @@ -705,8 +697,6 @@ protected function buildHeaders(ResponseInterface &$response) * reportOnly header, since it's viable to have both simultaneously. * * @param array|string|null $values - * - * @return void */ protected function addToHeader(string $name, $values = null) { diff --git a/system/HTTP/UserAgent.php b/system/HTTP/UserAgent.php index 89db334b64b3..10088111cec1 100644 --- a/system/HTTP/UserAgent.php +++ b/system/HTTP/UserAgent.php @@ -247,8 +247,6 @@ public function getReferrer(): string /** * Parse a custom user-agent string - * - * @return void */ public function parse(string $string) { @@ -271,8 +269,6 @@ public function parse(string $string) /** * Compile the User Agent Data - * - * @return void */ protected function compileData() { diff --git a/system/Helpers/cookie_helper.php b/system/Helpers/cookie_helper.php index 7eeed052b2e1..e47a86356dbf 100755 --- a/system/Helpers/cookie_helper.php +++ b/system/Helpers/cookie_helper.php @@ -80,8 +80,6 @@ function get_cookie($index, bool $xssClean = false) * @param string $path the cookie path * @param string $prefix the cookie prefix * - * @return void - * * @see \CodeIgniter\HTTP\Response::deleteCookie() */ function delete_cookie($name, string $domain = '', string $path = '/', string $prefix = '') diff --git a/system/Images/Handlers/BaseHandler.php b/system/Images/Handlers/BaseHandler.php index 9e6217f5c564..3e0d81c2dc68 100644 --- a/system/Images/Handlers/BaseHandler.php +++ b/system/Images/Handlers/BaseHandler.php @@ -720,13 +720,10 @@ public function __call(string $name, array $args = []) * * This function lets us re-proportion the width/height * if users choose to maintain the aspect ratio when resizing. - * - * @return void */ protected function reproportion() { - if (($this->width === 0 && $this->height === 0) || $this->image()->origWidth === 0 || $this->image()->origHeight === 0 || (! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) || ! ctype_digit((string) $this->image()->origWidth) || ! ctype_digit((string) $this->image()->origHeight) - ) { + if (($this->width === 0 && $this->height === 0) || $this->image()->origWidth === 0 || $this->image()->origHeight === 0 || (! ctype_digit((string) $this->width) && ! ctype_digit((string) $this->height)) || ! ctype_digit((string) $this->image()->origWidth) || ! ctype_digit((string) $this->image()->origHeight)) { return; } diff --git a/system/Images/Handlers/GDHandler.php b/system/Images/Handlers/GDHandler.php index a3f0a0eb88df..02d61c40a007 100644 --- a/system/Images/Handlers/GDHandler.php +++ b/system/Images/Handlers/GDHandler.php @@ -30,12 +30,9 @@ public function __construct($config = null) { parent::__construct($config); - // We should never see this, so can't test it - // @codeCoverageIgnoreStart if (! extension_loaded('gd')) { - throw ImageException::forMissingExtension('GD'); + throw ImageException::forMissingExtension('GD'); // @codeCoverageIgnore } - // @codeCoverageIgnoreEnd } /** @@ -367,8 +364,6 @@ protected function getImageResource(string $path, int $imageType) /** * Add text overlay to an image. - * - * @return void */ protected function _text(string $text, array $options = []) { @@ -446,8 +441,6 @@ protected function _text(string $text, array $options = []) * Handler-specific method for overlaying text on an image. * * @param bool $isShadow Whether we are drawing the dropshadow or actual text - * - * @return void */ protected function textOverlay(string $text, array $options = [], bool $isShadow = false) { diff --git a/system/Model.php b/system/Model.php index 8c36b5d5ace8..3617f83f69cb 100644 --- a/system/Model.php +++ b/system/Model.php @@ -29,8 +29,6 @@ use ReflectionProperty; /** - * Class Model - * * The Model class extends BaseModel and provides additional * convenient features that makes working with a SQL database * table less painful. @@ -40,7 +38,7 @@ * - allow intermingling calls to the builder * - removes the need to use Result object directly in most cases * - * @mixin BaseBuilder + * @mixin BaseBuilder * * @property BaseConnection $db */ @@ -91,12 +89,6 @@ class Model extends BaseModel */ protected $escape = []; - /** - * Model constructor. - * - * @param ConnectionInterface|null $db DB Connection - * @param ValidationInterface|null $validation Validation - */ public function __construct(?ConnectionInterface &$db = null, ?ValidationInterface $validation = null) { /** @@ -284,8 +276,8 @@ protected function doInsertBatch(?array $set = null, ?bool $escape = null, int $ * Updates a single record in $this->table. * This methods works only with dbCalls * - * @param array|int|string|null $id ID - * @param array|null $data Data + * @param array|int|string|null $id + * @param array|null $data */ protected function doUpdate($id = null, $data = null): bool { @@ -385,8 +377,6 @@ protected function doPurgeDeleted() * Works with the find* methods to return only the rows that * have been deleted. * This methods works only with dbCalls - * - * @return void */ protected function doOnlyDeleted() { @@ -467,12 +457,7 @@ public function getIdValue($data) * determine the rows to operate on. * This methods works only with dbCalls * - * @param int $size Size - * @param Closure $userFunc Callback Function - * * @throws DataException - * - * @return void */ public function chunk(int $size, Closure $userFunc) { @@ -506,9 +491,6 @@ public function chunk(int $size, Closure $userFunc) /** * Override countAllResults to account for soft deleted accounts. * - * @param bool $reset Reset - * @param bool $test Test - * * @return mixed */ public function countAllResults(bool $reset = true, bool $test = false) @@ -530,8 +512,6 @@ public function countAllResults(bool $reset = true, bool $test = false) /** * Provides a shared instance of the Query Builder. * - * @param string|null $table Table name - * * @throws ModelException * * @return BaseBuilder @@ -577,9 +557,9 @@ public function builder(?string $table = null) * data here. This allows it to be used with any of the other * builder methods and still get validated data, like replace. * - * @param mixed $key Field name, or an array of field/value pairs - * @param string|null $value Field value, if $key is a single field - * @param bool|null $escape Whether to escape values and identifiers + * @param array|string $key Field name, or an array of field/value pairs + * @param string|null $value Field value, if $key is a single field + * @param bool|null $escape Whether to escape values and identifiers * * @return $this */ @@ -616,7 +596,7 @@ protected function shouldUpdate($data): bool * Inserts data into the database. If an object is provided, * it will attempt to convert it to an array. * - * @param array|object|null $data Data + * @param array|object|null $data * @param bool $returnID Whether insert ID should be returned or not. * * @throws ReflectionException @@ -644,8 +624,8 @@ public function insert($data = null, bool $returnID = true) * Updates a single record in the database. If an object is provided, * it will attempt to convert it into an array. * - * @param array|int|string|null $id ID - * @param array|object|null $data Data + * @param array|int|string|null $id + * @param array|object|null $data * * @throws ReflectionException */ @@ -670,9 +650,8 @@ public function update($id = null, $data = null): bool * Takes a class an returns an array of it's public and protected * properties as an array with raw values. * - * @param object|string $data Data - * @param bool $onlyChanged Only Changed Property - * @param bool $recursive If true, inner entities will be casted as array as well + * @param object|string $data + * @param bool $recursive If true, inner entities will be casted as array as well * * @throws ReflectionException * @@ -683,8 +662,10 @@ protected function objectToRawArray($data, bool $onlyChanged = true, bool $recur $properties = parent::objectToRawArray($data, $onlyChanged); // Always grab the primary key otherwise updates will fail. - if (method_exists($data, 'toRawArray') && (! empty($properties) && ! empty($this->primaryKey) && ! in_array($this->primaryKey, $properties, true) - && ! empty($data->{$this->primaryKey}))) { + if ( + method_exists($data, 'toRawArray') && (! empty($properties) && ! empty($this->primaryKey) && ! in_array($this->primaryKey, $properties, true) + && ! empty($data->{$this->primaryKey})) + ) { $properties[$this->primaryKey] = $data->{$this->primaryKey}; } @@ -729,9 +710,6 @@ public function __isset(string $name): bool * Provides direct access to method in the builder (if available) * and the database connection. * - * @param string $name Name - * @param array $params Params - * * @return $this|null */ public function __call(string $name, array $params) @@ -763,10 +741,8 @@ public function __call(string $name, array $params) * Takes a class an returns an array of it's public and protected * properties as an array suitable for use in creates and updates. * - * @param object|string $data Data - * @param string|null $primaryKey Primary Key - * @param string $dateFormat Date Format - * @param bool $onlyChanged Only Changed + * @param object|string $data + * @param string|null $primaryKey * * @throws ReflectionException * diff --git a/system/RESTful/BaseResource.php b/system/RESTful/BaseResource.php index d699230b6fa5..65ad21251a3d 100644 --- a/system/RESTful/BaseResource.php +++ b/system/RESTful/BaseResource.php @@ -34,8 +34,6 @@ abstract class BaseResource extends Controller public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) { parent::initController($request, $response, $logger); - - // instantiate our model, if needed $this->setModel($this->modelName); } @@ -44,23 +42,18 @@ public function initController(RequestInterface $request, ResponseInterface $res * Given either the name or the object, determine the other. * * @param object|string|null $which - * - * @return void */ public function setModel($which = null) { - // save what we have been given if ($which) { $this->model = is_object($which) ? $which : null; $this->modelName = is_object($which) ? null : $which; } - // make a model object if needed if (empty($this->model) && ! empty($this->modelName) && class_exists($this->modelName)) { $this->model = model($this->modelName); } - // determine model name if needed if (! empty($this->model) && empty($this->modelName)) { $this->modelName = get_class($this->model); } diff --git a/system/RESTful/ResourceController.php b/system/RESTful/ResourceController.php index 3dae1b80d253..809545c1513b 100644 --- a/system/RESTful/ResourceController.php +++ b/system/RESTful/ResourceController.php @@ -100,8 +100,6 @@ public function delete($id = null) /** * Set/change the expected response representation for returned objects - * - * @return void */ public function setFormat(string $format = 'json') { diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index a5b5a52c17af..7a9ab5010872 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -588,8 +588,6 @@ public function getRedirectCode(string $from): int * * @param string $name The name to group/prefix the routes with. * @param array|callable ...$params - * - * @return void */ public function group(string $name, ...$params) { diff --git a/system/Session/Session.php b/system/Session/Session.php index f95d57ca990a..808e5fd65f49 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -339,8 +339,6 @@ protected function configure() * * So we were forced to make changes, and OF COURSE something was * going to break and now we have this pile of shit. -- Narf - * - * @return void */ protected function configureSidLength() { @@ -514,8 +512,6 @@ public function has(string $key): bool * * @param string $key Identifier of the session property we are interested in. * @param array $data value to be pushed to existing session key. - * - * @return void */ public function push(string $key, array $data) { diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index 2dc69aeb4b9b..4ad164cd272d 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -199,8 +199,6 @@ protected function runSeeds() /** * Seeds that database with a specific seeder. - * - * @return void */ public function seed(string $name) { @@ -277,8 +275,6 @@ public function grabFromDatabase(string $table, string $column, array $where) * exist in the database. * * @throws DatabaseException - * - * @return void */ public function seeInDatabase(string $table, array $where) { @@ -289,8 +285,6 @@ public function seeInDatabase(string $table, array $where) /** * Asserts that records that match the conditions in $where do * not exist in the database. - * - * @return void */ public function dontSeeInDatabase(string $table, array $where) { @@ -322,8 +316,6 @@ public function hasInDatabase(string $table, array $data) * is equal to $expected. * * @throws DatabaseException - * - * @return void */ public function seeNumRecords(int $expected, string $table, array $where) { diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 0240eac92607..680515ed107b 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -221,8 +221,6 @@ protected function assertFilter(string $route, string $position, string $alias): * @param string $route The route to test * @param string $position "before" or "after" * @param string $alias Alias for the anticipated filter - * - * @return void */ protected function assertNotFilter(string $route, string $position, string $alias) { @@ -241,8 +239,6 @@ protected function assertNotFilter(string $route, string $position, string $alia * * @param string $route The route to test * @param string $position "before" or "after" - * - * @return void */ protected function assertHasFilters(string $route, string $position) { @@ -260,8 +256,6 @@ protected function assertHasFilters(string $route, string $position) * * @param string $route The route to test * @param string $position "before" or "after" - * - * @return void */ protected function assertNotHasFilters(string $route, string $position) { diff --git a/system/View/Table.php b/system/View/Table.php index 8eab66bbd8a1..d57a7092de00 100644 --- a/system/View/Table.php +++ b/system/View/Table.php @@ -87,8 +87,6 @@ class Table * Set the template from the table config file if it exists * * @param array $config (default: array()) - * - * @return void */ public function __construct($config = []) { @@ -404,8 +402,6 @@ public function clear() * Set table data from a database result object * * @param BaseResult $object Database result object - * - * @return void */ protected function _setFromDBResult($object) { @@ -423,8 +419,6 @@ protected function _setFromDBResult($object) * Set table data from an array * * @param array $data - * - * @return void */ protected function _setFromArray($data) { @@ -439,8 +433,6 @@ protected function _setFromArray($data) /** * Compile Template - * - * @return void */ protected function _compileTemplate() { diff --git a/system/View/View.php b/system/View/View.php index 966dcf0feacb..cba8c70c06f6 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -134,11 +134,6 @@ class View implements RendererInterface */ protected $sectionStack = []; - /** - * Constructor - * - * @param LoggerInterface $logger - */ public function __construct(ViewConfig $config, ?string $viewPath = null, ?FileLocator $loader = null, ?bool $debug = null, ?LoggerInterface $logger = null) { $this->config = $config; @@ -331,14 +326,14 @@ public function setData(array $data = [], ?string $context = null): RendererInte /** * Sets a single piece of view data. * - * @param mixed $value - * @param string $context The context to escape it for: html, css, js, url - * If null, no escaping will happen + * @param mixed $value + * @param string|null $context The context to escape it for: html, css, js, url + * If null, no escaping will happen */ public function setVar(string $name, $value = null, ?string $context = null): RendererInterface { if ($context) { - $value = \esc($value, $context); + $value = esc($value, $context); } $this->tempData = $this->tempData ?? $this->data; @@ -367,8 +362,6 @@ public function getData(): array /** * Specifies that the current view should extend an existing layout. - * - * @return void */ public function extend(string $layout) { @@ -379,8 +372,6 @@ public function extend(string $layout) * Starts holds content for a section within the layout. * * @param string $name Section name - * - * @return void */ public function section(string $name) { @@ -395,8 +386,6 @@ public function section(string $name) * Captures the last section * * @throws RuntimeException - * - * @return void */ public function endSection() { @@ -454,8 +443,6 @@ public function getPerformanceData(): array /** * Logs performance data for rendering a view. - * - * @return void */ protected function logPerformance(float $start, float $end, string $view) { From 31bfbbaa510853ddd730944dc6af203791f23e1b Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 25 Jul 2021 00:44:13 +0800 Subject: [PATCH 0111/2325] Fix notice in pre-commit hook --- admin/pre-commit | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/pre-commit b/admin/pre-commit index 46b36987da2a..d05724d58146 100644 --- a/admin/pre-commit +++ b/admin/pre-commit @@ -69,7 +69,7 @@ if [ "$FILES" != "" ]; then php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --using-cache=no --diff fi - if [ $? != 0]; then + if [ $? != 0 ]; then echo "Files in system, tests, utils, or root are not following the coding standards. Please fix them before commit." exit 1 fi From 3ab3adeabedc41f4cbb762591d13f4555caa2acd Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 29 Jul 2021 00:15:42 +0800 Subject: [PATCH 0112/2325] Delete `docs` directly, not `api/docs` (#4976) --- .github/workflows/deploy-apidocs.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 4edf916d1a27..b3aab2a1c83a 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -32,7 +32,7 @@ jobs: uses: actions/checkout@v2 with: repository: codeigniter4/api - token: ${{ secrets.ACCESS_TOKEN }} + token: ${{ secrets.GITHUB_TOKEN }} path: api - name: Setup PHP @@ -41,10 +41,6 @@ jobs: php-version: '8.0' coverage: none - - name: Install GraphViz for phpDocumentor - run: | - sudo apt-get install -yq graphviz - - name: Download phpDocumentor v3.1 run: | cd ./source @@ -56,8 +52,8 @@ jobs: working-directory: api run: | git reset --hard master - rm -rfv api/docs - mkdir --parents --verbose api/docs + rm -rfv docs + mkdir --parents --verbose docs - name: Build API in source repo working-directory: source From cb4fe4d8a841070b27f38629798d2399e1d27a59 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 29 Jul 2021 00:18:19 +0800 Subject: [PATCH 0113/2325] Revert to use `ACCESS_TOKEN` --- .github/workflows/deploy-apidocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index b3aab2a1c83a..3b441e36485d 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -32,7 +32,7 @@ jobs: uses: actions/checkout@v2 with: repository: codeigniter4/api - token: ${{ secrets.GITHUB_TOKEN }} + token: ${{ secrets.ACCESS_TOKEN }} path: api - name: Setup PHP From f730dbada303307b663fb7da8a74294375d10fd4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 29 Jul 2021 09:00:08 +0700 Subject: [PATCH 0114/2325] [Rector] Apply Rector: RemoveDuplicatedArrayKeyRector --- rector.php | 2 + tests/system/Helpers/InflectorHelperTest.php | 6 --- .../system/Validation/CreditCardRulesTest.php | 45 ------------------- 3 files changed, 2 insertions(+), 51 deletions(-) diff --git a/rector.php b/rector.php index 32b09bd95311..6f47b388576d 100644 --- a/rector.php +++ b/rector.php @@ -28,6 +28,7 @@ use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; use Rector\Core\Configuration\Option; use Rector\Core\ValueObject\PhpVersion; +use Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector; use Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector; use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; @@ -113,4 +114,5 @@ $services->set(RemoveUnusedVariableAssignRector::class); $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); + $services->set(RemoveDuplicatedArrayKeyRector::class); }; diff --git a/tests/system/Helpers/InflectorHelperTest.php b/tests/system/Helpers/InflectorHelperTest.php index 9085edf4a395..81939b461c7f 100755 --- a/tests/system/Helpers/InflectorHelperTest.php +++ b/tests/system/Helpers/InflectorHelperTest.php @@ -244,12 +244,6 @@ public function testDasherize() public function testOrdinal() { $suffixes = [ - 'st' => 1, - 'nd' => 2, - 'rd' => 3, - 'th' => 4, - 'th' => 11, - 'th' => 20, 'st' => 21, 'nd' => 22, 'rd' => 23, diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php index 61b3076bc34b..fe912f9684d7 100644 --- a/tests/system/Validation/CreditCardRulesTest.php +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -148,46 +148,6 @@ public function creditCardProvider() '6011 0009 9013 9424', true, ], - 'jcb1' => [ - 'jcb', - '3530 1113 3330 0000', - true, - ], - 'jcb2' => [ - 'jcb', - '3566 0020 2036 0505', - true, - ], - 'mastercard1' => [ - 'mastercard', - '5555 5555 5555 4444', - true, - ], - 'mastercard2' => [ - 'mastercard', - '5105 1051 0510 5100', - true, - ], - 'visa1' => [ - 'visa', - '4111 1111 1111 1111', - true, - ], - 'visa2' => [ - 'visa', - '4012 8888 8888 1881', - true, - ], - 'visa3' => [ - 'visa', - '4222 2222 2222 2', - true, - ], - 'dankort1' => [ - 'dankort', - '5019 7170 1010 3742', - true, - ], 'unionpay1' => [ 'unionpay', $this->generateCardNum(62, 16), @@ -1203,11 +1163,6 @@ public function creditCardProvider() $this->generateCardNum(500, 16), true, ], - 'hsbc' => [ - 'hsbc', - $this->generateCardNum(56, 16), - true, - ], 'hsbc' => [ 'hsbc', $this->generateCardNum(57, 16), From 241abc9194c74677247bbee13686839b89b8d8e0 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 29 Jul 2021 10:11:25 +0700 Subject: [PATCH 0115/2325] remove key in creditCardProvider --- .../system/Validation/CreditCardRulesTest.php | 479 ++++++++++-------- 1 file changed, 262 insertions(+), 217 deletions(-) diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php index fe912f9684d7..21182127266a 100644 --- a/tests/system/Validation/CreditCardRulesTest.php +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -83,1087 +83,1132 @@ public function testValidCCNumber($type, $number, $expected = false) public function creditCardProvider() { return [ - 'null_test' => [ + [ 'amex', null, false, ], - 'random_test' => [ + [ 'amex', $this->generateCardNum('37', 16), false, ], - 'invalid_type' => [ + [ 'shorty', '1111 1111 1111 1111', false, ], - 'invalid_length' => [ + [ 'amex', '', false, ], - 'not_numeric' => [ + [ 'amex', 'abcd efgh ijkl mnop', false, ], - 'bad_length' => [ + [ 'amex', '3782 8224 6310 0051', false, ], - 'bad_prefix' => [ + [ 'amex', '3582 8224 6310 0051', false, ], - 'amex1' => [ + [ 'amex', '3782 8224 6310 005', true, ], - 'amex2' => [ + [ 'amex', '3714 4963 5398 431', true, ], - 'dinersclub1' => [ + [ 'dinersclub', '3056 9309 0259 04', true, ], - 'dinersculb2' => [ + [ 'dinersclub', '3852 0000 0232 37', true, ], - 'discover1' => [ + [ 'discover', '6011 1111 1111 1117', true, ], - 'discover2' => [ + [ 'discover', '6011 0009 9013 9424', true, ], - 'unionpay1' => [ + [ + 'jcb', + '3530 1113 3330 0000', + true, + ], + [ + 'jcb', + '3566 0020 2036 0505', + true, + ], + [ + 'mastercard', + '5555 5555 5555 4444', + true, + ], + [ + 'mastercard', + '5105 1051 0510 5100', + true, + ], + [ + 'visa', + '4111 1111 1111 1111', + true, + ], + [ + 'visa', + '4012 8888 8888 1881', + true, + ], + [ + 'visa', + '4222 2222 2222 2', + true, + ], + [ + 'dankort', + '5019 7170 1010 3742', + true, + ], + [ 'unionpay', $this->generateCardNum(62, 16), true, ], - 'unionpay2' => [ + [ 'unionpay', $this->generateCardNum(62, 17), true, ], - 'unionpay3' => [ + [ 'unionpay', $this->generateCardNum(62, 18), true, ], - 'unionpay4' => [ + [ 'unionpay', $this->generateCardNum(62, 19), true, ], - 'unionpay5' => [ + [ 'unionpay', $this->generateCardNum(63, 19), false, ], - 'carteblanche1' => [ + [ 'carteblanche', $this->generateCardNum(300, 14), true, ], - 'carteblanche2' => [ + [ 'carteblanche', $this->generateCardNum(301, 14), true, ], - 'carteblanche3' => [ + [ 'carteblanche', $this->generateCardNum(302, 14), true, ], - 'carteblanche4' => [ + [ 'carteblanche', $this->generateCardNum(303, 14), true, ], - 'carteblanche5' => [ + [ 'carteblanche', $this->generateCardNum(304, 14), true, ], - 'carteblanche6' => [ + [ 'carteblanche', $this->generateCardNum(305, 14), true, ], - 'carteblanche7' => [ + [ 'carteblanche', $this->generateCardNum(306, 14), false, ], - 'dinersclub3' => [ + [ 'dinersclub', $this->generateCardNum(300, 14), true, ], - 'dinersclub4' => [ + [ 'dinersclub', $this->generateCardNum(301, 14), true, ], - 'dinersclub5' => [ + [ 'dinersclub', $this->generateCardNum(302, 14), true, ], - 'dinersclub6' => [ + [ 'dinersclub', $this->generateCardNum(303, 14), true, ], - 'dinersclub7' => [ + [ 'dinersclub', $this->generateCardNum(304, 14), true, ], - 'dinersclub8' => [ + [ 'dinersclub', $this->generateCardNum(305, 14), true, ], - 'dinersclub9' => [ + [ 'dinersclub', $this->generateCardNum(309, 14), true, ], - 'dinersclub10' => [ + [ 'dinersclub', $this->generateCardNum(36, 14), true, ], - 'dinersclub11' => [ + [ 'dinersclub', $this->generateCardNum(38, 14), true, ], - 'dinersclub12' => [ + [ 'dinersclub', $this->generateCardNum(39, 14), true, ], - 'dinersclub13' => [ + [ 'dinersclub', $this->generateCardNum(54, 14), true, ], - 'dinersclub14' => [ + [ 'dinersclub', $this->generateCardNum(55, 14), true, ], - 'dinersclub15' => [ + [ 'dinersclub', $this->generateCardNum(300, 16), true, ], - 'dinersclub16' => [ + [ 'dinersclub', $this->generateCardNum(301, 16), true, ], - 'dinersclub17' => [ + [ 'dinersclub', $this->generateCardNum(302, 16), true, ], - 'dinersclub18' => [ + [ 'dinersclub', $this->generateCardNum(303, 16), true, ], - 'dinersclub19' => [ + [ 'dinersclub', $this->generateCardNum(304, 16), true, ], - 'dinersclub20' => [ + [ 'dinersclub', $this->generateCardNum(305, 16), true, ], - 'dinersclub21' => [ + [ 'dinersclub', $this->generateCardNum(309, 16), true, ], - 'dinersclub22' => [ + [ 'dinersclub', $this->generateCardNum(36, 16), true, ], - 'dinersclub23' => [ + [ 'dinersclub', $this->generateCardNum(38, 16), true, ], - 'dinersclub24' => [ + [ 'dinersclub', $this->generateCardNum(39, 16), true, ], - 'dinersclub25' => [ + [ 'dinersclub', $this->generateCardNum(54, 16), true, ], - 'dinersclub26' => [ + [ 'dinersclub', $this->generateCardNum(55, 16), true, ], - 'discover3' => [ + [ 'discover', $this->generateCardNum(6011, 16), true, ], - 'discover4' => [ + [ 'discover', $this->generateCardNum(622, 16), true, ], - 'discover5' => [ + [ 'discover', $this->generateCardNum(644, 16), true, ], - 'discover6' => [ + [ 'discover', $this->generateCardNum(645, 16), true, ], - 'discover7' => [ + [ 'discover', $this->generateCardNum(656, 16), true, ], - 'discover8' => [ + [ 'discover', $this->generateCardNum(647, 16), true, ], - 'discover9' => [ + [ 'discover', $this->generateCardNum(648, 16), true, ], - 'discover10' => [ + [ 'discover', $this->generateCardNum(649, 16), true, ], - 'discover11' => [ + [ 'discover', $this->generateCardNum(65, 16), true, ], - 'discover12' => [ + [ 'discover', $this->generateCardNum(6011, 19), true, ], - 'discover13' => [ + [ 'discover', $this->generateCardNum(622, 19), true, ], - 'discover14' => [ + [ 'discover', $this->generateCardNum(644, 19), true, ], - 'discover15' => [ + [ 'discover', $this->generateCardNum(645, 19), true, ], - 'discover16' => [ + [ 'discover', $this->generateCardNum(656, 19), true, ], - 'discover17' => [ + [ 'discover', $this->generateCardNum(647, 19), true, ], - 'discover18' => [ + [ 'discover', $this->generateCardNum(648, 19), true, ], - 'discover19' => [ + [ 'discover', $this->generateCardNum(649, 19), true, ], - 'discover20' => [ + [ 'discover', $this->generateCardNum(65, 19), true, ], - 'interpayment1' => [ + [ 'interpayment', $this->generateCardNum(4, 16), true, ], - 'interpayment2' => [ + [ 'interpayment', $this->generateCardNum(4, 17), true, ], - 'interpayment3' => [ + [ 'interpayment', $this->generateCardNum(4, 18), true, ], - 'interpayment4' => [ + [ 'interpayment', $this->generateCardNum(4, 19), true, ], - 'jcb1' => [ + [ 'jcb', $this->generateCardNum(352, 16), true, ], - 'jcb2' => [ + [ 'jcb', $this->generateCardNum(353, 16), true, ], - 'jcb3' => [ + [ 'jcb', $this->generateCardNum(354, 16), true, ], - 'jcb4' => [ + [ 'jcb', $this->generateCardNum(355, 16), true, ], - 'jcb5' => [ + [ 'jcb', $this->generateCardNum(356, 16), true, ], - 'jcb6' => [ + [ 'jcb', $this->generateCardNum(357, 16), true, ], - 'jcb7' => [ + [ 'jcb', $this->generateCardNum(358, 16), true, ], - 'maestro1' => [ + [ 'maestro', $this->generateCardNum(50, 12), true, ], - 'maestro2' => [ + [ 'maestro', $this->generateCardNum(56, 12), true, ], - 'maestro3' => [ + [ 'maestro', $this->generateCardNum(57, 12), true, ], - 'maestro4' => [ + [ 'maestro', $this->generateCardNum(58, 12), true, ], - 'maestro5' => [ + [ 'maestro', $this->generateCardNum(59, 12), true, ], - 'maestro6' => [ + [ 'maestro', $this->generateCardNum(60, 12), true, ], - 'maestro7' => [ + [ 'maestro', $this->generateCardNum(61, 12), true, ], - 'maestro8' => [ + [ 'maestro', $this->generateCardNum(62, 12), true, ], - 'maestro9' => [ + [ 'maestro', $this->generateCardNum(63, 12), true, ], - 'maestro10' => [ + [ 'maestro', $this->generateCardNum(64, 12), true, ], - 'maestro11' => [ + [ 'maestro', $this->generateCardNum(65, 12), true, ], - 'maestro12' => [ + [ 'maestro', $this->generateCardNum(66, 12), true, ], - 'maestro13' => [ + [ 'maestro', $this->generateCardNum(67, 12), true, ], - 'maestro14' => [ + [ 'maestro', $this->generateCardNum(68, 12), true, ], - 'maestro15' => [ + [ 'maestro', $this->generateCardNum(69, 12), true, ], - 'maestro16' => [ + [ 'maestro', $this->generateCardNum(50, 13), true, ], - 'maestro17' => [ + [ 'maestro', $this->generateCardNum(56, 13), true, ], - 'maestro18' => [ + [ 'maestro', $this->generateCardNum(57, 13), true, ], - 'maestro19' => [ + [ 'maestro', $this->generateCardNum(58, 13), true, ], - 'maestro20' => [ + [ 'maestro', $this->generateCardNum(59, 13), true, ], - 'maestro21' => [ + [ 'maestro', $this->generateCardNum(60, 13), true, ], - 'maestro22' => [ + [ 'maestro', $this->generateCardNum(61, 13), true, ], - 'maestro23' => [ + [ 'maestro', $this->generateCardNum(62, 13), true, ], - 'maestro24' => [ + [ 'maestro', $this->generateCardNum(63, 13), true, ], - 'maestro25' => [ + [ 'maestro', $this->generateCardNum(64, 13), true, ], - 'maestro26' => [ + [ 'maestro', $this->generateCardNum(65, 13), true, ], - 'maestro27' => [ + [ 'maestro', $this->generateCardNum(66, 13), true, ], - 'maestro28' => [ + [ 'maestro', $this->generateCardNum(67, 13), true, ], - 'maestro29' => [ + [ 'maestro', $this->generateCardNum(68, 13), true, ], - 'maestro30' => [ + [ 'maestro', $this->generateCardNum(69, 13), true, ], - 'maestro31' => [ + [ 'maestro', $this->generateCardNum(50, 14), true, ], - 'maestro32' => [ + [ 'maestro', $this->generateCardNum(56, 14), true, ], - 'maestro33' => [ + [ 'maestro', $this->generateCardNum(57, 14), true, ], - 'maestro34' => [ + [ 'maestro', $this->generateCardNum(58, 14), true, ], - 'maestro35' => [ + [ 'maestro', $this->generateCardNum(59, 14), true, ], - 'maestro36' => [ + [ 'maestro', $this->generateCardNum(60, 14), true, ], - 'maestro37' => [ + [ 'maestro', $this->generateCardNum(61, 14), true, ], - 'maestro38' => [ + [ 'maestro', $this->generateCardNum(62, 14), true, ], - 'maestro39' => [ + [ 'maestro', $this->generateCardNum(63, 14), true, ], - 'maestro40' => [ + [ 'maestro', $this->generateCardNum(64, 14), true, ], - 'maestro41' => [ + [ 'maestro', $this->generateCardNum(65, 14), true, ], - 'maestro42' => [ + [ 'maestro', $this->generateCardNum(66, 14), true, ], - 'maestro43' => [ + [ 'maestro', $this->generateCardNum(67, 14), true, ], - 'maestro44' => [ + [ 'maestro', $this->generateCardNum(68, 14), true, ], - 'maestro45' => [ + [ 'maestro', $this->generateCardNum(69, 14), true, ], - 'maestro46' => [ + [ 'maestro', $this->generateCardNum(50, 15), true, ], - 'maestro47' => [ + [ 'maestro', $this->generateCardNum(56, 15), true, ], - 'maestro48' => [ + [ 'maestro', $this->generateCardNum(57, 15), true, ], - 'maestro49' => [ + [ 'maestro', $this->generateCardNum(58, 15), true, ], - 'maestro50' => [ + [ 'maestro', $this->generateCardNum(59, 15), true, ], - 'maestro51' => [ + [ 'maestro', $this->generateCardNum(60, 15), true, ], - 'maestro52' => [ + [ 'maestro', $this->generateCardNum(61, 15), true, ], - 'maestro53' => [ + [ 'maestro', $this->generateCardNum(62, 15), true, ], - 'maestro54' => [ + [ 'maestro', $this->generateCardNum(63, 15), true, ], - 'maestro55' => [ + [ 'maestro', $this->generateCardNum(64, 15), true, ], - 'maestro56' => [ + [ 'maestro', $this->generateCardNum(65, 15), true, ], - 'maestro57' => [ + [ 'maestro', $this->generateCardNum(66, 15), true, ], - 'maestro58' => [ + [ 'maestro', $this->generateCardNum(67, 15), true, ], - 'maestro59' => [ + [ 'maestro', $this->generateCardNum(68, 15), true, ], - 'maestro60' => [ + [ 'maestro', $this->generateCardNum(69, 15), true, ], - 'maestro61' => [ + [ 'maestro', $this->generateCardNum(50, 16), true, ], - 'maestro62' => [ + [ 'maestro', $this->generateCardNum(56, 16), true, ], - 'maestro63' => [ + [ 'maestro', $this->generateCardNum(57, 16), true, ], - 'maestro64' => [ + [ 'maestro', $this->generateCardNum(58, 16), true, ], - 'maestro65' => [ + [ 'maestro', $this->generateCardNum(59, 16), true, ], - 'maestro66' => [ + [ 'maestro', $this->generateCardNum(60, 16), true, ], - 'maestro67' => [ + [ 'maestro', $this->generateCardNum(61, 16), true, ], - 'maestro68' => [ + [ 'maestro', $this->generateCardNum(62, 16), true, ], - 'maestro69' => [ + [ 'maestro', $this->generateCardNum(63, 16), true, ], - 'maestro70' => [ + [ 'maestro', $this->generateCardNum(64, 16), true, ], - 'maestro71' => [ + [ 'maestro', $this->generateCardNum(65, 16), true, ], - 'maestro72' => [ + [ 'maestro', $this->generateCardNum(66, 16), true, ], - 'maestro73' => [ + [ 'maestro', $this->generateCardNum(67, 16), true, ], - 'maestro74' => [ + [ 'maestro', $this->generateCardNum(68, 16), true, ], - 'maestro75' => [ + [ 'maestro', $this->generateCardNum(69, 16), true, ], - 'maestro91' => [ + [ 'maestro', $this->generateCardNum(50, 18), true, ], - 'maestro92' => [ + [ 'maestro', $this->generateCardNum(56, 18), true, ], - 'maestro93' => [ + [ 'maestro', $this->generateCardNum(57, 18), true, ], - 'maestro94' => [ + [ 'maestro', $this->generateCardNum(58, 18), true, ], - 'maestro95' => [ + [ 'maestro', $this->generateCardNum(59, 18), true, ], - 'maestro96' => [ + [ 'maestro', $this->generateCardNum(60, 18), true, ], - 'maestro97' => [ + [ 'maestro', $this->generateCardNum(61, 18), true, ], - 'maestro98' => [ + [ 'maestro', $this->generateCardNum(62, 18), true, ], - 'maestro99' => [ + [ 'maestro', $this->generateCardNum(63, 18), true, ], - 'maestro100' => [ + [ 'maestro', $this->generateCardNum(64, 18), true, ], - 'maestro101' => [ + [ 'maestro', $this->generateCardNum(65, 18), true, ], - 'maestro102' => [ + [ 'maestro', $this->generateCardNum(66, 18), true, ], - 'maestro103' => [ + [ 'maestro', $this->generateCardNum(67, 18), true, ], - 'maestro104' => [ + [ 'maestro', $this->generateCardNum(68, 18), true, ], - 'maestro105' => [ + [ 'maestro', $this->generateCardNum(69, 18), true, ], - 'maestro106' => [ + [ 'maestro', $this->generateCardNum(50, 19), true, ], - 'maestro107' => [ + [ 'maestro', $this->generateCardNum(56, 19), true, ], - 'maestro108' => [ + [ 'maestro', $this->generateCardNum(57, 19), true, ], - 'maestro109' => [ + [ 'maestro', $this->generateCardNum(58, 19), true, ], - 'maestro110' => [ + [ 'maestro', $this->generateCardNum(59, 19), true, ], - 'maestro111' => [ + [ 'maestro', $this->generateCardNum(60, 19), true, ], - 'maestro112' => [ + [ 'maestro', $this->generateCardNum(61, 19), true, ], - 'maestro113' => [ + [ 'maestro', $this->generateCardNum(62, 19), true, ], - 'maestro114' => [ + [ 'maestro', $this->generateCardNum(63, 19), true, ], - 'maestro115' => [ + [ 'maestro', $this->generateCardNum(64, 19), true, ], - 'maestro116' => [ + [ 'maestro', $this->generateCardNum(65, 19), true, ], - 'maestro117' => [ + [ 'maestro', $this->generateCardNum(66, 19), true, ], - 'maestro118' => [ + [ 'maestro', $this->generateCardNum(67, 19), true, ], - 'maestro119' => [ + [ 'maestro', $this->generateCardNum(68, 19), true, ], - 'maestro120' => [ + [ 'maestro', $this->generateCardNum(69, 19), true, ], - 'dankort1' => [ + [ 'dankort', $this->generateCardNum(5019, 16), true, ], - 'dankort2' => [ + [ 'dankort', $this->generateCardNum(4175, 16), true, ], - 'dankort3' => [ + [ 'dankort', $this->generateCardNum(4571, 16), true, ], - 'dankort4' => [ + [ 'dankort', $this->generateCardNum(4, 16), true, ], - 'mir1' => [ + [ 'mir', $this->generateCardNum(2200, 16), true, ], - 'mir2' => [ + [ 'mir', $this->generateCardNum(2201, 16), true, ], - 'mir3' => [ + [ 'mir', $this->generateCardNum(2202, 16), true, ], - 'mir4' => [ + [ 'mir', $this->generateCardNum(2203, 16), true, ], - 'mir5' => [ + [ 'mir', $this->generateCardNum(2204, 16), true, ], - 'mastercard1' => [ + [ 'mastercard', $this->generateCardNum(51, 16), true, ], - 'mastercard2' => [ + [ 'mastercard', $this->generateCardNum(52, 16), true, ], - 'mastercard3' => [ + [ 'mastercard', $this->generateCardNum(53, 16), true, ], - 'mastercard4' => [ + [ 'mastercard', $this->generateCardNum(54, 16), true, ], - 'mastercard5' => [ + [ 'mastercard', $this->generateCardNum(55, 16), true, ], - 'mastercard6' => [ + [ 'mastercard', $this->generateCardNum(22, 16), true, ], - 'mastercard7' => [ + [ 'mastercard', $this->generateCardNum(23, 16), true, ], - 'mastercard8' => [ + [ 'mastercard', $this->generateCardNum(24, 16), true, ], - 'mastercard9' => [ + [ 'mastercard', $this->generateCardNum(25, 16), true, ], - 'mastercard10' => [ + [ 'mastercard', $this->generateCardNum(26, 16), true, ], - 'mastercard11' => [ + [ 'mastercard', $this->generateCardNum(27, 16), true, ], - 'visa1' => [ + [ 'visa', $this->generateCardNum(4, 13), true, ], - 'visa2' => [ + [ 'visa', $this->generateCardNum(4, 16), true, ], - 'visa3' => [ + [ 'visa', $this->generateCardNum(4, 19), true, ], - 'uatp' => [ + [ 'uatp', $this->generateCardNum(1, 15), true, ], - 'verve1' => [ + [ 'verve', $this->generateCardNum(506, 16), true, ], - 'verve2' => [ + [ 'verve', $this->generateCardNum(650, 16), true, ], - 'verve3' => [ + [ 'verve', $this->generateCardNum(506, 19), true, ], - 'verve4' => [ + [ 'verve', $this->generateCardNum(650, 19), true, ], - 'cibc1' => [ + [ 'cibc', $this->generateCardNum(4506, 16), true, ], - 'rbc1' => [ + [ 'rbc', $this->generateCardNum(45, 16), true, ], - 'tdtrust' => [ + [ 'tdtrust', $this->generateCardNum(589297, 16), true, ], - 'scotia1' => [ + [ 'scotia', $this->generateCardNum(4536, 16), true, ], - 'bmoabm1' => [ + [ 'bmoabm', $this->generateCardNum(500, 16), true, ], - 'hsbc' => [ + [ + 'hsbc', + $this->generateCardNum(56, 16), + true, + ], + [ 'hsbc', $this->generateCardNum(57, 16), false, From b254cf190e8650a806fc4f863d78223ccf337c05 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 29 Jul 2021 10:19:38 +0700 Subject: [PATCH 0116/2325] using dataProvider for Ordinal test --- tests/system/Helpers/InflectorHelperTest.php | 30 +++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/tests/system/Helpers/InflectorHelperTest.php b/tests/system/Helpers/InflectorHelperTest.php index 81939b461c7f..e949b83bc707 100755 --- a/tests/system/Helpers/InflectorHelperTest.php +++ b/tests/system/Helpers/InflectorHelperTest.php @@ -241,19 +241,29 @@ public function testDasherize() } } - public function testOrdinal() + public function provideOrdinal() { - $suffixes = [ - 'st' => 21, - 'nd' => 22, - 'rd' => 23, - 'th' => 24, + return [ + ['st', 1], + ['nd', 2], + ['rd', 3], + ['th', 4], + ['th', 11], + ['th', 20], + ['st', 21], + ['nd', 22], + ['rd', 23], + ['th', 24], ]; + } - foreach ($suffixes as $suffix => $number) { - $ordinal = ordinal($number); - $this->assertSame($suffix, $ordinal); - } + /** + * @dataProvider provideOrdinal + */ + public function testOrdinal(string $suffix, int $number) + { + $ordinal = ordinal($number); + $this->assertSame($suffix, $ordinal); } public function testOrdinalize() From 3908d0cba5ac170059147c6a5e41e5a39f917ea7 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 29 Jul 2021 10:34:47 +0700 Subject: [PATCH 0117/2325] Update tests/system/Helpers/InflectorHelperTest.php Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- tests/system/Helpers/InflectorHelperTest.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/system/Helpers/InflectorHelperTest.php b/tests/system/Helpers/InflectorHelperTest.php index e949b83bc707..86ff1e2e9f58 100755 --- a/tests/system/Helpers/InflectorHelperTest.php +++ b/tests/system/Helpers/InflectorHelperTest.php @@ -262,8 +262,7 @@ public function provideOrdinal() */ public function testOrdinal(string $suffix, int $number) { - $ordinal = ordinal($number); - $this->assertSame($suffix, $ordinal); + $this->assertSame($suffix, ordinal($number)); } public function testOrdinalize() From cba23285957692e8a2be7a73a36e593238461a9f Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 31 Jul 2021 20:46:52 +0700 Subject: [PATCH 0118/2325] index Credit card provider --- .../system/Validation/CreditCardRulesTest.php | 452 +++++++++--------- 1 file changed, 226 insertions(+), 226 deletions(-) diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php index 21182127266a..a1e8f74d8a27 100644 --- a/tests/system/Validation/CreditCardRulesTest.php +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -83,1132 +83,1132 @@ public function testValidCCNumber($type, $number, $expected = false) public function creditCardProvider() { return [ - [ + 'null_test' => [ 'amex', null, false, ], - [ + 'random_test' => [ 'amex', $this->generateCardNum('37', 16), false, ], - [ + 'invalid_type' => [ 'shorty', '1111 1111 1111 1111', false, ], - [ + 'invalid_length' => [ 'amex', '', false, ], - [ + 'not_numeric' => [ 'amex', 'abcd efgh ijkl mnop', false, ], - [ + 'bad_length' => [ 'amex', '3782 8224 6310 0051', false, ], - [ + 'bad_prefix' => [ 'amex', '3582 8224 6310 0051', false, ], - [ + 'amex1' => [ 'amex', '3782 8224 6310 005', true, ], - [ + 'amex2' => [ 'amex', '3714 4963 5398 431', true, ], - [ + 'dinersclub1' => [ 'dinersclub', '3056 9309 0259 04', true, ], - [ + 'dinersculb2' => [ 'dinersclub', '3852 0000 0232 37', true, ], - [ + 'discover1' => [ 'discover', '6011 1111 1111 1117', true, ], - [ + 'discover2' => [ 'discover', '6011 0009 9013 9424', true, ], - [ + 'jcb8' => [ 'jcb', '3530 1113 3330 0000', true, ], - [ + 'jcb9' => [ 'jcb', '3566 0020 2036 0505', true, ], - [ + 'mastercard12' => [ 'mastercard', '5555 5555 5555 4444', true, ], - [ + 'mastercard13' => [ 'mastercard', '5105 1051 0510 5100', true, ], - [ + 'visa4' => [ 'visa', '4111 1111 1111 1111', true, ], - [ + 'visa5' => [ 'visa', '4012 8888 8888 1881', true, ], - [ + 'visa6' => [ 'visa', '4222 2222 2222 2', true, ], - [ + 'dankort5' => [ 'dankort', '5019 7170 1010 3742', true, ], - [ + 'unionpay1' => [ 'unionpay', $this->generateCardNum(62, 16), true, ], - [ + 'unionpay2' => [ 'unionpay', $this->generateCardNum(62, 17), true, ], - [ + 'unionpay3' => [ 'unionpay', $this->generateCardNum(62, 18), true, ], - [ + 'unionpay4' => [ 'unionpay', $this->generateCardNum(62, 19), true, ], - [ + 'unionpay5' => [ 'unionpay', $this->generateCardNum(63, 19), false, ], - [ + 'carteblanche1' => [ 'carteblanche', $this->generateCardNum(300, 14), true, ], - [ + 'carteblanche2' => [ 'carteblanche', $this->generateCardNum(301, 14), true, ], - [ + 'carteblanche3' => [ 'carteblanche', $this->generateCardNum(302, 14), true, ], - [ + 'carteblanche4' => [ 'carteblanche', $this->generateCardNum(303, 14), true, ], - [ + 'carteblanche5' => [ 'carteblanche', $this->generateCardNum(304, 14), true, ], - [ + 'carteblanche6' => [ 'carteblanche', $this->generateCardNum(305, 14), true, ], - [ + 'carteblanche7' => [ 'carteblanche', $this->generateCardNum(306, 14), false, ], - [ + 'dinersclub3' => [ 'dinersclub', $this->generateCardNum(300, 14), true, ], - [ + 'dinersclub4' => [ 'dinersclub', $this->generateCardNum(301, 14), true, ], - [ + 'dinersclub5' => [ 'dinersclub', $this->generateCardNum(302, 14), true, ], - [ + 'dinersclub6' => [ 'dinersclub', $this->generateCardNum(303, 14), true, ], - [ + 'dinersclub7' => [ 'dinersclub', $this->generateCardNum(304, 14), true, ], - [ + 'dinersclub8' => [ 'dinersclub', $this->generateCardNum(305, 14), true, ], - [ + 'dinersclub9' => [ 'dinersclub', $this->generateCardNum(309, 14), true, ], - [ + 'dinersclub10' => [ 'dinersclub', $this->generateCardNum(36, 14), true, ], - [ + 'dinersclub11' => [ 'dinersclub', $this->generateCardNum(38, 14), true, ], - [ + 'dinersclub12' => [ 'dinersclub', $this->generateCardNum(39, 14), true, ], - [ + 'dinersclub13' => [ 'dinersclub', $this->generateCardNum(54, 14), true, ], - [ + 'dinersclub14' => [ 'dinersclub', $this->generateCardNum(55, 14), true, ], - [ + 'dinersclub15' => [ 'dinersclub', $this->generateCardNum(300, 16), true, ], - [ + 'dinersclub16' => [ 'dinersclub', $this->generateCardNum(301, 16), true, ], - [ + 'dinersclub17' => [ 'dinersclub', $this->generateCardNum(302, 16), true, ], - [ + 'dinersclub18' => [ 'dinersclub', $this->generateCardNum(303, 16), true, ], - [ + 'dinersclub19' => [ 'dinersclub', $this->generateCardNum(304, 16), true, ], - [ + 'dinersclub20' => [ 'dinersclub', $this->generateCardNum(305, 16), true, ], - [ + 'dinersclub21' => [ 'dinersclub', $this->generateCardNum(309, 16), true, ], - [ + 'dinersclub22' => [ 'dinersclub', $this->generateCardNum(36, 16), true, ], - [ + 'dinersclub23' => [ 'dinersclub', $this->generateCardNum(38, 16), true, ], - [ + 'dinersclub24' => [ 'dinersclub', $this->generateCardNum(39, 16), true, ], - [ + 'dinersclub25' => [ 'dinersclub', $this->generateCardNum(54, 16), true, ], - [ + 'dinersclub26' => [ 'dinersclub', $this->generateCardNum(55, 16), true, ], - [ + 'discover3' => [ 'discover', $this->generateCardNum(6011, 16), true, ], - [ + 'discover4' => [ 'discover', $this->generateCardNum(622, 16), true, ], - [ + 'discover5' => [ 'discover', $this->generateCardNum(644, 16), true, ], - [ + 'discover6' => [ 'discover', $this->generateCardNum(645, 16), true, ], - [ + 'discover7' => [ 'discover', $this->generateCardNum(656, 16), true, ], - [ + 'discover8' => [ 'discover', $this->generateCardNum(647, 16), true, ], - [ + 'discover9' => [ 'discover', $this->generateCardNum(648, 16), true, ], - [ + 'discover10' => [ 'discover', $this->generateCardNum(649, 16), true, ], - [ + 'discover11' => [ 'discover', $this->generateCardNum(65, 16), true, ], - [ + 'discover12' => [ 'discover', $this->generateCardNum(6011, 19), true, ], - [ + 'discover13' => [ 'discover', $this->generateCardNum(622, 19), true, ], - [ + 'discover14' => [ 'discover', $this->generateCardNum(644, 19), true, ], - [ + 'discover15' => [ 'discover', $this->generateCardNum(645, 19), true, ], - [ + 'discover16' => [ 'discover', $this->generateCardNum(656, 19), true, ], - [ + 'discover17' => [ 'discover', $this->generateCardNum(647, 19), true, ], - [ + 'discover18' => [ 'discover', $this->generateCardNum(648, 19), true, ], - [ + 'discover19' => [ 'discover', $this->generateCardNum(649, 19), true, ], - [ + 'discover20' => [ 'discover', $this->generateCardNum(65, 19), true, ], - [ + 'interpayment1' => [ 'interpayment', $this->generateCardNum(4, 16), true, ], - [ + 'interpayment2' => [ 'interpayment', $this->generateCardNum(4, 17), true, ], - [ + 'interpayment3' => [ 'interpayment', $this->generateCardNum(4, 18), true, ], - [ + 'interpayment4' => [ 'interpayment', $this->generateCardNum(4, 19), true, ], - [ + 'jcb1' => [ 'jcb', $this->generateCardNum(352, 16), true, ], - [ + 'jcb2' => [ 'jcb', $this->generateCardNum(353, 16), true, ], - [ + 'jcb3' => [ 'jcb', $this->generateCardNum(354, 16), true, ], - [ + 'jcb4' => [ 'jcb', $this->generateCardNum(355, 16), true, ], - [ + 'jcb5' => [ 'jcb', $this->generateCardNum(356, 16), true, ], - [ + 'jcb6' => [ 'jcb', $this->generateCardNum(357, 16), true, ], - [ + 'jcb7' => [ 'jcb', $this->generateCardNum(358, 16), true, ], - [ + 'maestro1' => [ 'maestro', $this->generateCardNum(50, 12), true, ], - [ + 'maestro2' => [ 'maestro', $this->generateCardNum(56, 12), true, ], - [ + 'maestro3' => [ 'maestro', $this->generateCardNum(57, 12), true, ], - [ + 'maestro4' => [ 'maestro', $this->generateCardNum(58, 12), true, ], - [ + 'maestro5' => [ 'maestro', $this->generateCardNum(59, 12), true, ], - [ + 'maestro6' => [ 'maestro', $this->generateCardNum(60, 12), true, ], - [ + 'maestro7' => [ 'maestro', $this->generateCardNum(61, 12), true, ], - [ + 'maestro8' => [ 'maestro', $this->generateCardNum(62, 12), true, ], - [ + 'maestro9' => [ 'maestro', $this->generateCardNum(63, 12), true, ], - [ + 'maestro10' => [ 'maestro', $this->generateCardNum(64, 12), true, ], - [ + 'maestro11' => [ 'maestro', $this->generateCardNum(65, 12), true, ], - [ + 'maestro12' => [ 'maestro', $this->generateCardNum(66, 12), true, ], - [ + 'maestro13' => [ 'maestro', $this->generateCardNum(67, 12), true, ], - [ + 'maestro14' => [ 'maestro', $this->generateCardNum(68, 12), true, ], - [ + 'maestro15' => [ 'maestro', $this->generateCardNum(69, 12), true, ], - [ + 'maestro16' => [ 'maestro', $this->generateCardNum(50, 13), true, ], - [ + 'maestro17' => [ 'maestro', $this->generateCardNum(56, 13), true, ], - [ + 'maestro18' => [ 'maestro', $this->generateCardNum(57, 13), true, ], - [ + 'maestro19' => [ 'maestro', $this->generateCardNum(58, 13), true, ], - [ + 'maestro20' => [ 'maestro', $this->generateCardNum(59, 13), true, ], - [ + 'maestro21' => [ 'maestro', $this->generateCardNum(60, 13), true, ], - [ + 'maestro22' => [ 'maestro', $this->generateCardNum(61, 13), true, ], - [ + 'maestro23' => [ 'maestro', $this->generateCardNum(62, 13), true, ], - [ + 'maestro24' => [ 'maestro', $this->generateCardNum(63, 13), true, ], - [ + 'maestro25' => [ 'maestro', $this->generateCardNum(64, 13), true, ], - [ + 'maestro26' => [ 'maestro', $this->generateCardNum(65, 13), true, ], - [ + 'maestro27' => [ 'maestro', $this->generateCardNum(66, 13), true, ], - [ + 'maestro28' => [ 'maestro', $this->generateCardNum(67, 13), true, ], - [ + 'maestro29' => [ 'maestro', $this->generateCardNum(68, 13), true, ], - [ + 'maestro30' => [ 'maestro', $this->generateCardNum(69, 13), true, ], - [ + 'maestro31' => [ 'maestro', $this->generateCardNum(50, 14), true, ], - [ + 'maestro32' => [ 'maestro', $this->generateCardNum(56, 14), true, ], - [ + 'maestro33' => [ 'maestro', $this->generateCardNum(57, 14), true, ], - [ + 'maestro34' => [ 'maestro', $this->generateCardNum(58, 14), true, ], - [ + 'maestro35' => [ 'maestro', $this->generateCardNum(59, 14), true, ], - [ + 'maestro36' => [ 'maestro', $this->generateCardNum(60, 14), true, ], - [ + 'maestro37' => [ 'maestro', $this->generateCardNum(61, 14), true, ], - [ + 'maestro38' => [ 'maestro', $this->generateCardNum(62, 14), true, ], - [ + 'maestro39' => [ 'maestro', $this->generateCardNum(63, 14), true, ], - [ + 'maestro40' => [ 'maestro', $this->generateCardNum(64, 14), true, ], - [ + 'maestro41' => [ 'maestro', $this->generateCardNum(65, 14), true, ], - [ + 'maestro42' => [ 'maestro', $this->generateCardNum(66, 14), true, ], - [ + 'maestro43' => [ 'maestro', $this->generateCardNum(67, 14), true, ], - [ + 'maestro44' => [ 'maestro', $this->generateCardNum(68, 14), true, ], - [ + 'maestro45' => [ 'maestro', $this->generateCardNum(69, 14), true, ], - [ + 'maestro46' => [ 'maestro', $this->generateCardNum(50, 15), true, ], - [ + 'maestro47' => [ 'maestro', $this->generateCardNum(56, 15), true, ], - [ + 'maestro48' => [ 'maestro', $this->generateCardNum(57, 15), true, ], - [ + 'maestro49' => [ 'maestro', $this->generateCardNum(58, 15), true, ], - [ + 'maestro50' => [ 'maestro', $this->generateCardNum(59, 15), true, ], - [ + 'maestro51' => [ 'maestro', $this->generateCardNum(60, 15), true, ], - [ + 'maestro52' => [ 'maestro', $this->generateCardNum(61, 15), true, ], - [ + 'maestro53' => [ 'maestro', $this->generateCardNum(62, 15), true, ], - [ + 'maestro54' => [ 'maestro', $this->generateCardNum(63, 15), true, ], - [ + 'maestro55' => [ 'maestro', $this->generateCardNum(64, 15), true, ], - [ + 'maestro56' => [ 'maestro', $this->generateCardNum(65, 15), true, ], - [ + 'maestro57' => [ 'maestro', $this->generateCardNum(66, 15), true, ], - [ + 'maestro58' => [ 'maestro', $this->generateCardNum(67, 15), true, ], - [ + 'maestro59' => [ 'maestro', $this->generateCardNum(68, 15), true, ], - [ + 'maestro60' => [ 'maestro', $this->generateCardNum(69, 15), true, ], - [ + 'maestro61' => [ 'maestro', $this->generateCardNum(50, 16), true, ], - [ + 'maestro62' => [ 'maestro', $this->generateCardNum(56, 16), true, ], - [ + 'maestro63' => [ 'maestro', $this->generateCardNum(57, 16), true, ], - [ + 'maestro64' => [ 'maestro', $this->generateCardNum(58, 16), true, ], - [ + 'maestro65' => [ 'maestro', $this->generateCardNum(59, 16), true, ], - [ + 'maestro66' => [ 'maestro', $this->generateCardNum(60, 16), true, ], - [ + 'maestro67' => [ 'maestro', $this->generateCardNum(61, 16), true, ], - [ + 'maestro68' => [ 'maestro', $this->generateCardNum(62, 16), true, ], - [ + 'maestro69' => [ 'maestro', $this->generateCardNum(63, 16), true, ], - [ + 'maestro70' => [ 'maestro', $this->generateCardNum(64, 16), true, ], - [ + 'maestro71' => [ 'maestro', $this->generateCardNum(65, 16), true, ], - [ + 'maestro72' => [ 'maestro', $this->generateCardNum(66, 16), true, ], - [ + 'maestro73' => [ 'maestro', $this->generateCardNum(67, 16), true, ], - [ + 'maestro74' => [ 'maestro', $this->generateCardNum(68, 16), true, ], - [ + 'maestro75' => [ 'maestro', $this->generateCardNum(69, 16), true, ], - [ + 'maestro91' => [ 'maestro', $this->generateCardNum(50, 18), true, ], - [ + 'maestro92' => [ 'maestro', $this->generateCardNum(56, 18), true, ], - [ + 'maestro93' => [ 'maestro', $this->generateCardNum(57, 18), true, ], - [ + 'maestro94' => [ 'maestro', $this->generateCardNum(58, 18), true, ], - [ + 'maestro95' => [ 'maestro', $this->generateCardNum(59, 18), true, ], - [ + 'maestro96' => [ 'maestro', $this->generateCardNum(60, 18), true, ], - [ + 'maestro97' => [ 'maestro', $this->generateCardNum(61, 18), true, ], - [ + 'maestro98' => [ 'maestro', $this->generateCardNum(62, 18), true, ], - [ + 'maestro99' => [ 'maestro', $this->generateCardNum(63, 18), true, ], - [ + 'maestro100' => [ 'maestro', $this->generateCardNum(64, 18), true, ], - [ + 'maestro101' => [ 'maestro', $this->generateCardNum(65, 18), true, ], - [ + 'maestro102' => [ 'maestro', $this->generateCardNum(66, 18), true, ], - [ + 'maestro103' => [ 'maestro', $this->generateCardNum(67, 18), true, ], - [ + 'maestro104' => [ 'maestro', $this->generateCardNum(68, 18), true, ], - [ + 'maestro105' => [ 'maestro', $this->generateCardNum(69, 18), true, ], - [ + 'maestro106' => [ 'maestro', $this->generateCardNum(50, 19), true, ], - [ + 'maestro107' => [ 'maestro', $this->generateCardNum(56, 19), true, ], - [ + 'maestro108' => [ 'maestro', $this->generateCardNum(57, 19), true, ], - [ + 'maestro109' => [ 'maestro', $this->generateCardNum(58, 19), true, ], - [ + 'maestro110' => [ 'maestro', $this->generateCardNum(59, 19), true, ], - [ + 'maestro111' => [ 'maestro', $this->generateCardNum(60, 19), true, ], - [ + 'maestro112' => [ 'maestro', $this->generateCardNum(61, 19), true, ], - [ + 'maestro113' => [ 'maestro', $this->generateCardNum(62, 19), true, ], - [ + 'maestro114' => [ 'maestro', $this->generateCardNum(63, 19), true, ], - [ + 'maestro115' => [ 'maestro', $this->generateCardNum(64, 19), true, ], - [ + 'maestro116' => [ 'maestro', $this->generateCardNum(65, 19), true, ], - [ + 'maestro117' => [ 'maestro', $this->generateCardNum(66, 19), true, ], - [ + 'maestro118' => [ 'maestro', $this->generateCardNum(67, 19), true, ], - [ + 'maestro119' => [ 'maestro', $this->generateCardNum(68, 19), true, ], - [ + 'maestro120' => [ 'maestro', $this->generateCardNum(69, 19), true, ], - [ + 'dankort1' => [ 'dankort', $this->generateCardNum(5019, 16), true, ], - [ + 'dankort2' => [ 'dankort', $this->generateCardNum(4175, 16), true, ], - [ + 'dankort3' => [ 'dankort', $this->generateCardNum(4571, 16), true, ], - [ + 'dankort4' => [ 'dankort', $this->generateCardNum(4, 16), true, ], - [ + 'mir1' => [ 'mir', $this->generateCardNum(2200, 16), true, ], - [ + 'mir2' => [ 'mir', $this->generateCardNum(2201, 16), true, ], - [ + 'mir3' => [ 'mir', $this->generateCardNum(2202, 16), true, ], - [ + 'mir4' => [ 'mir', $this->generateCardNum(2203, 16), true, ], - [ + 'mir5' => [ 'mir', $this->generateCardNum(2204, 16), true, ], - [ + 'mastercard1' => [ 'mastercard', $this->generateCardNum(51, 16), true, ], - [ + 'mastercard2' => [ 'mastercard', $this->generateCardNum(52, 16), true, ], - [ + 'mastercard3' => [ 'mastercard', $this->generateCardNum(53, 16), true, ], - [ + 'mastercard4' => [ 'mastercard', $this->generateCardNum(54, 16), true, ], - [ + 'mastercard5' => [ 'mastercard', $this->generateCardNum(55, 16), true, ], - [ + 'mastercard6' => [ 'mastercard', $this->generateCardNum(22, 16), true, ], - [ + 'mastercard7' => [ 'mastercard', $this->generateCardNum(23, 16), true, ], - [ + 'mastercard8' => [ 'mastercard', $this->generateCardNum(24, 16), true, ], - [ + 'mastercard9' => [ 'mastercard', $this->generateCardNum(25, 16), true, ], - [ + 'mastercard10' => [ 'mastercard', $this->generateCardNum(26, 16), true, ], - [ + 'mastercard11' => [ 'mastercard', $this->generateCardNum(27, 16), true, ], - [ + 'visa1' => [ 'visa', $this->generateCardNum(4, 13), true, ], - [ + 'visa2' => [ 'visa', $this->generateCardNum(4, 16), true, ], - [ + 'visa3' => [ 'visa', $this->generateCardNum(4, 19), true, ], - [ + 'uatp' => [ 'uatp', $this->generateCardNum(1, 15), true, ], - [ + 'verve1' => [ 'verve', $this->generateCardNum(506, 16), true, ], - [ + 'verve2' => [ 'verve', $this->generateCardNum(650, 16), true, ], - [ + 'verve3' => [ 'verve', $this->generateCardNum(506, 19), true, ], - [ + 'verve4' => [ 'verve', $this->generateCardNum(650, 19), true, ], - [ + 'cibc1' => [ 'cibc', $this->generateCardNum(4506, 16), true, ], - [ + 'rbc1' => [ 'rbc', $this->generateCardNum(45, 16), true, ], - [ + 'tdtrust' => [ 'tdtrust', $this->generateCardNum(589297, 16), true, ], - [ + 'scotia1' => [ 'scotia', $this->generateCardNum(4536, 16), true, ], - [ + 'bmoabm1' => [ 'bmoabm', $this->generateCardNum(500, 16), true, ], - [ + 'hsbc1' => [ 'hsbc', $this->generateCardNum(56, 16), true, ], - [ + 'hsbc2' => [ 'hsbc', $this->generateCardNum(57, 16), false, From aa96117dc68a93a4ce2746cbb501903e5dc7b893 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Aug 2021 16:47:37 +0000 Subject: [PATCH 0119/2325] Update rector/rector requirement from 0.11.40 to 0.11.42 (#4984) --- composer.json | 2 +- rector.php | 2 -- tests/system/API/ResponseTraitTest.php | 6 +++--- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 648f7b4fc88b..077bad29c198 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.40", + "rector/rector": "0.11.42", "symplify/package-builder": "^9.3" }, "suggest": { diff --git a/rector.php b/rector.php index 6f47b388576d..3f65b0a273e6 100644 --- a/rector.php +++ b/rector.php @@ -22,7 +22,6 @@ use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector; use Rector\CodeQuality\Rector\Return_\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\Ternary\UnnecessaryTernaryExpressionRector; -use Rector\CodeQualityStrict\Rector\Variable\MoveVariableDeclarationNearReferenceRector; use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector; use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector; use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; @@ -106,7 +105,6 @@ $services->set(RemoveErrorSuppressInTryCatchStmtsRector::class); $services->set(TernaryToNullCoalescingRector::class); $services->set(ListToArrayDestructRector::class); - $services->set(MoveVariableDeclarationNearReferenceRector::class); $services->set(RemoveVarTagFromClassConstantRector::class); $services->set(AddPregQuoteDelimiterRector::class); $services->set(SimplifyRegexPatternRector::class); diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index 4f6e5a097bdf..fd35469dd5ec 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -429,9 +429,9 @@ public function testServerError() $controller = $this->makeController(); $controller->failServerError('Nope.', 'FAT-CHANCE', 'A custom reason.'); - $this::assertEquals('A custom reason.', $this->response->getReason()); - $this::assertEquals(500, $this->response->getStatusCode()); - $this::assertEquals($this->formatter->format([ + $this->assertSame('A custom reason.', $this->response->getReason()); + $this->assertSame(500, $this->response->getStatusCode()); + $this->assertSame($this->formatter->format([ 'status' => 500, 'error' => 'FAT-CHANCE', 'messages' => [ From fc52b058487ef6ef7274e6e7e02ccbb3f6ff73e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Aug 2021 16:40:20 +0000 Subject: [PATCH 0120/2325] Update rector/rector requirement from 0.11.42 to 0.11.43 (#4985) --- composer.json | 2 +- system/Cache/Handlers/MemcachedHandler.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 077bad29c198..5a591c7ed877 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.42", + "rector/rector": "0.11.43", "symplify/package-builder": "^9.3" }, "suggest": { diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index 07cd85b3a29a..7684dffdbbbe 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -138,7 +138,7 @@ public function get(string $key) } } elseif ($this->memcached instanceof Memcache) { $flags = false; - $data = $this->memcached->get($key, $flags); // @phpstan-ignore-line + $data = $this->memcached->get($key, $flags); // check for unmatched key (i.e. $flags is untouched) if ($flags === false) { From 781aa9eb0a89afeaafb58c8422faf6ac776b51fa Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 6 Aug 2021 19:51:19 +0800 Subject: [PATCH 0121/2325] Remove override (#4991) --- .no-header.php-cs-fixer.dist.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php index 4bee79703546..b7e082dff72d 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.no-header.php-cs-fixer.dist.php @@ -23,9 +23,7 @@ __DIR__ . '/public', ]); -$overrides = [ - 'no_blank_lines_after_phpdoc' => false, -]; +$overrides = []; $options = [ 'cacheFile' => 'build/.no-header.php-cs-fixer.cache', From 5f09c247320c966f12a889a0821684daeb82f9bb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Aug 2021 17:55:41 +0000 Subject: [PATCH 0122/2325] Update rector/rector requirement from 0.11.43 to 0.11.46 (#4995) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5a591c7ed877..4dd874b1bb1d 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.43", + "rector/rector": "0.11.46", "symplify/package-builder": "^9.3" }, "suggest": { From 77b79109dda59c8974f89a99bec96fcec2f2868f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Aug 2021 10:13:28 +0800 Subject: [PATCH 0123/2325] Update rector/rector requirement from 0.11.46 to 0.11.47 (#4997) 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.11.46...0.11.47) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 4dd874b1bb1d..224164546dc3 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.46", + "rector/rector": "0.11.47", "symplify/package-builder": "^9.3" }, "suggest": { From dcb54b3e1f6f470930c2dfaf06bd5ae1ee1e8bee Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 13 Aug 2021 16:48:41 +0800 Subject: [PATCH 0124/2325] Add SpaceAfterCommentFixer --- .no-header.php-cs-fixer.dist.php | 11 +- .php-cs-fixer.dist.php | 11 +- system/BaseModel.php | 2 +- system/Cache/Handlers/MemcachedHandler.php | 2 +- system/Common.php | 4 +- system/Database/BaseConnection.php | 2 +- system/Debug/Exceptions.php | 2 +- system/Entity/Entity.php | 4 +- system/HTTP/Files/UploadedFile.php | 4 +- system/Helpers/inflector_helper.php | 2 +- system/Router/RouteCollection.php | 2 +- system/Test/DOMParser.php | 2 +- system/View/Parser.php | 2 +- system/View/View.php | 2 +- .../20160428212500_Create_test_tables.php | 6 +- .../_support/Database/Seeds/CITestSeeder.php | 2 +- tests/system/Cache/CacheFactoryTest.php | 6 +- .../Cache/Handlers/RedisHandlerTest.php | 16 +-- tests/system/Database/Live/GetTest.php | 134 +++++++++--------- tests/system/HTTP/CLIRequestTest.php | 2 +- tests/system/HTTP/RequestTest.php | 2 +- tests/system/Helpers/HTMLHelperTest.php | 2 +- tests/system/Router/RouteCollectionTest.php | 2 +- tests/system/View/ParserTest.php | 2 +- tests/system/View/ViewTest.php | 2 +- .../Comment/SpaceAfterCommentStartFixer.php | 95 +++++++++++++ 26 files changed, 216 insertions(+), 107 deletions(-) create mode 100644 utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php index b7e082dff72d..8f7eb0a71cf1 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.no-header.php-cs-fixer.dist.php @@ -14,6 +14,7 @@ use Nexus\CsConfig\Factory; use PhpCsFixer\Finder; use Utils\PhpCsFixer\CodeIgniter4; +use Utils\PhpCsFixer\Fixer\Comment\SpaceAfterCommentStartFixer; $finder = Finder::create() ->files() @@ -26,8 +27,14 @@ $overrides = []; $options = [ - 'cacheFile' => 'build/.no-header.php-cs-fixer.cache', - 'finder' => $finder, + 'cacheFile' => 'build/.no-header.php-cs-fixer.cache', + 'finder' => $finder, + 'customFixers' => [ + new SpaceAfterCommentStartFixer(), + ], + 'customRules' => [ + 'CodeIgniter4/space_after_comment_start' => true, + ], ]; return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects(); diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 15db678cbd35..95478343a53a 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -14,6 +14,7 @@ use Nexus\CsConfig\Factory; use PhpCsFixer\Finder; use Utils\PhpCsFixer\CodeIgniter4; +use Utils\PhpCsFixer\Fixer\Comment\SpaceAfterCommentStartFixer; $finder = Finder::create() ->files() @@ -34,8 +35,14 @@ $overrides = []; $options = [ - 'cacheFile' => 'build/.php-cs-fixer.cache', - 'finder' => $finder, + 'cacheFile' => 'build/.php-cs-fixer.cache', + 'finder' => $finder, + 'customFixers' => [ + new SpaceAfterCommentStartFixer(), + ], + 'customRules' => [ + 'CodeIgniter4/space_after_comment_start' => true, + ], ]; return Factory::create(new CodeIgniter4(), $overrides, $options)->forLibrary( diff --git a/system/BaseModel.php b/system/BaseModel.php index 1d777506976f..e57ac4fec6bd 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1327,7 +1327,7 @@ public function validate($data): bool return true; } - //Validation requires array, so cast away. + // Validation requires array, so cast away. if (is_object($data)) { $data = (array) $data; } diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index 7684dffdbbbe..2667abca92a6 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -220,7 +220,7 @@ public function decrement(string $key, int $offset = 1) $key = static::validateKey($key, $this->prefix); - //FIXME: third parameter isn't other handler actions. + // FIXME: third parameter isn't other handler actions. // @phpstan-ignore-next-line return $this->memcached->decrement($key, $offset, $offset, 60); } diff --git a/system/Common.php b/system/Common.php index 4a3a6102e4de..129a3374738e 100644 --- a/system/Common.php +++ b/system/Common.php @@ -978,8 +978,8 @@ function single_service(string $name, ...$params) } if (! function_exists('slash_item')) { - //Unlike CI3, this function is placed here because - //it's not a config, or part of a config. + // Unlike CI3, this function is placed here because + // it's not a config, or part of a config. /** * Fetch a config file item with slash appended (if not empty) * diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 80cc2b962191..c7bec269c472 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -461,7 +461,7 @@ abstract public function reconnect(); */ public function getConnection(?string $alias = null) { - //@todo work with read/write connections + // @todo work with read/write connections return $this->connID; } diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 07218ed47ba2..5950148984ef 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -85,7 +85,7 @@ public function __construct(ExceptionsConfig $config, IncomingRequest $request, */ public function initialize() { - //Set the Exception Handler + // Set the Exception Handler set_exception_handler([$this, 'exceptionHandler']); // Set the Error Handler diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 74339dd6eefe..03f6327f8142 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -353,7 +353,7 @@ protected function castAs($value, string $attribute, string $method = 'get') $type = substr($type, 1); } - //In order not to create a separate handler for the + // In order not to create a separate handler for the // json-array type, we transform the required one. $type = $type === 'json-array' ? 'json[array]' : $type; @@ -363,7 +363,7 @@ protected function castAs($value, string $attribute, string $method = 'get') $params = []; - //Attempt to retrieve additional parameters if specified + // Attempt to retrieve additional parameters if specified // type[param, param2,param3] if (preg_match('/^(.+)\[(.+)\]$/', $type, $matches)) { $type = $matches[1]; diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 17e9130694fe..6455a5106d8d 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -127,7 +127,7 @@ public function __construct(string $path, string $originalName, ?string $mimeTyp public function move(string $targetPath, ?string $name = null, bool $overwrite = false) { $targetPath = rtrim($targetPath, '/') . '/'; - $targetPath = $this->setPath($targetPath); //set the target path + $targetPath = $this->setPath($targetPath); // set the target path if ($this->hasMoved) { throw HTTPException::forAlreadyMoved(); @@ -169,7 +169,7 @@ protected function setPath(string $path): string { if (! is_dir($path)) { mkdir($path, 0777, true); - //create the index.html file + // create the index.html file if (! is_file($path . 'index.html')) { $file = fopen($path . 'index.html', 'x+b'); fclose($file); diff --git a/system/Helpers/inflector_helper.php b/system/Helpers/inflector_helper.php index ad632a3f12c8..b4d38015564f 100755 --- a/system/Helpers/inflector_helper.php +++ b/system/Helpers/inflector_helper.php @@ -27,7 +27,7 @@ function singular(string $string): string return $result; } - //Arranged in order. + // Arranged in order. $singularRules = [ '/(matr)ices$/' => '\1ix', '/(vert|ind)ices$/' => '\1ex', diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 7a9ab5010872..b3a3f8e75f56 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1155,7 +1155,7 @@ static function ($m) use ($i) { $from = str_ireplace(':' . $tag, $pattern, $from); } - //If is redirect, No processing + // If is redirect, No processing if (! isset($options['redirect']) && is_string($to)) { // If no namespace found, add the default namespace if (strpos($to, '\\') === false || strpos($to, '\\') > 0) { diff --git a/system/Test/DOMParser.php b/system/Test/DOMParser.php index 90062f05c158..531adf737364 100644 --- a/system/Test/DOMParser.php +++ b/system/Test/DOMParser.php @@ -64,7 +64,7 @@ public function withString(string $content) // converts all special characters to utf-8 $content = mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'); - //turning off some errors + // turning off some errors libxml_use_internal_errors(true); if (! $this->dom->loadHTML($content)) { diff --git a/system/View/Parser.php b/system/View/Parser.php index 080a30c35674..c58f2b427dc5 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -333,7 +333,7 @@ protected function parsePair(string $variable, array $data, string $template): a $str .= $out; } - //Escape | character from filters as it's handled as OR in regex + // Escape | character from filters as it's handled as OR in regex $escapedMatch = preg_replace('/(?currentSection = $name; $this->sectionStack[] = $name; diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index b79866b446ae..07b61cdd2451 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -45,9 +45,9 @@ public function up() 'value' => ['type' => 'VARCHAR', 'constraint' => 400, 'null' => true], ])->addKey('id', true)->createTable('misc', true); - //Database Type test table - //missing types : - //TINYINT,MEDIUMINT,BIT,YEAR,BINARY , VARBINARY, TINYTEXT,LONGTEXT,YEAR,JSON,Spatial data types + // Database Type test table + // missing types : + // TINYINT,MEDIUMINT,BIT,YEAR,BINARY , VARBINARY, TINYTEXT,LONGTEXT,YEAR,JSON,Spatial data types // id must be interger else SQLite3 error on not null for autoinc field $data_type_fields = [ 'id' => ['type' => 'INTEGER', 'constraint' => 20, 'auto_increment' => true], diff --git a/tests/_support/Database/Seeds/CITestSeeder.php b/tests/_support/Database/Seeds/CITestSeeder.php index 2f90f86cdee9..0319896159ab 100644 --- a/tests/_support/Database/Seeds/CITestSeeder.php +++ b/tests/_support/Database/Seeds/CITestSeeder.php @@ -110,7 +110,7 @@ public function run() ], ]; - //set SQL times to more correct format + // set SQL times to more correct format if ($this->db->DBDriver === 'SQLite3') { $data['type_test'][0]['type_date'] = '2020/01/11'; $data['type_test'][0]['type_time'] = '15:22:00'; diff --git a/tests/system/Cache/CacheFactoryTest.php b/tests/system/Cache/CacheFactoryTest.php index 237554d5e5fd..ec978504fcfb 100644 --- a/tests/system/Cache/CacheFactoryTest.php +++ b/tests/system/Cache/CacheFactoryTest.php @@ -30,7 +30,7 @@ protected function setUp(): void $this->cacheFactory = new CacheFactory(); - //Initialize path + // Initialize path $this->config = new Cache(); $this->config->storePath .= self::$directory; } @@ -98,7 +98,7 @@ public function testGetDummyHandler() $this->assertInstanceOf(DummyHandler::class, $this->cacheFactory->getHandler($this->config)); - //Initialize path + // Initialize path $this->config = new Cache(); $this->config->storePath .= self::$directory; } @@ -117,7 +117,7 @@ public function testHandlesBadHandler() $this->assertInstanceOf(DummyHandler::class, $this->cacheFactory->getHandler($this->config, 'wincache', 'wincache')); } - //Initialize path + // Initialize path $this->config = new Cache(); $this->config->storePath .= self::$directory; } diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php index 9c0a13147c5c..66f3c7fd2244 100644 --- a/tests/system/Cache/Handlers/RedisHandlerTest.php +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php @@ -157,14 +157,14 @@ public function testDeleteMatchingSuffix() $this->assertSame('keys=90', $dbInfo[0]); } - //FIXME: I don't like all Hash logic very much. It's wasting memory. - //public function testIncrement() - //{ - //} - - //public function testDecrement() - //{ - //} + // FIXME: I don't like all Hash logic very much. It's wasting memory. + // public function testIncrement() + // { + // } + + // public function testDecrement() + // { + // } public function testClean() { diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index e361ce2bafc4..16424c252d29 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -93,79 +93,79 @@ public function testGetFieldData() $typeTest = $this->db->table('type_test')->get()->getFieldData(); if ($this->db->DBDriver === 'SQLite3') { - $this->assertSame('integer', $typeTest[0]->type_name); //INTEGER AUTO INC - $this->assertSame('text', $typeTest[1]->type_name); //VARCHAR - $this->assertSame('text', $typeTest[2]->type_name); //CHAR - $this->assertSame('text', $typeTest[3]->type_name); //TEXT - $this->assertSame('integer', $typeTest[4]->type_name); //SMALLINT - $this->assertSame('integer', $typeTest[5]->type_name); //INTEGER - $this->assertSame('float', $typeTest[6]->type_name); //FLOAT - $this->assertSame('float', $typeTest[7]->type_name); //NUMERIC - $this->assertSame('text', $typeTest[8]->type_name); //DATE - $this->assertSame('text', $typeTest[9]->type_name); //TIME - $this->assertSame('text', $typeTest[10]->type_name); //DATETIME - $this->assertSame('text', $typeTest[11]->type_name); //TIMESTAMP - $this->assertSame('integer', $typeTest[12]->type_name); //BIGINT - $this->assertSame('float', $typeTest[13]->type_name); //REAL - $this->assertSame('text', $typeTest[14]->type_name); //ENUM - $this->assertSame('text', $typeTest[15]->type_name); //SET - $this->assertSame('text', $typeTest[16]->type_name); //MEDIUMTEXT - $this->assertSame('float', $typeTest[17]->type_name); //DOUBLE - $this->assertSame('float', $typeTest[18]->type_name); //DECIMAL - $this->assertSame('text', $typeTest[19]->type_name); //BLOB + $this->assertSame('integer', $typeTest[0]->type_name); // INTEGER AUTO INC + $this->assertSame('text', $typeTest[1]->type_name); // VARCHAR + $this->assertSame('text', $typeTest[2]->type_name); // CHAR + $this->assertSame('text', $typeTest[3]->type_name); // TEXT + $this->assertSame('integer', $typeTest[4]->type_name); // SMALLINT + $this->assertSame('integer', $typeTest[5]->type_name); // INTEGER + $this->assertSame('float', $typeTest[6]->type_name); // FLOAT + $this->assertSame('float', $typeTest[7]->type_name); // NUMERIC + $this->assertSame('text', $typeTest[8]->type_name); // DATE + $this->assertSame('text', $typeTest[9]->type_name); // TIME + $this->assertSame('text', $typeTest[10]->type_name); // DATETIME + $this->assertSame('text', $typeTest[11]->type_name); // TIMESTAMP + $this->assertSame('integer', $typeTest[12]->type_name); // BIGINT + $this->assertSame('float', $typeTest[13]->type_name); // REAL + $this->assertSame('text', $typeTest[14]->type_name); // ENUM + $this->assertSame('text', $typeTest[15]->type_name); // SET + $this->assertSame('text', $typeTest[16]->type_name); // MEDIUMTEXT + $this->assertSame('float', $typeTest[17]->type_name); // DOUBLE + $this->assertSame('float', $typeTest[18]->type_name); // DECIMAL + $this->assertSame('text', $typeTest[19]->type_name); // BLOB } if ($this->db->DBDriver === 'MySQLi') { - $this->assertSame('long', $typeTest[0]->type_name); //INTEGER AUTOINC - $this->assertSame('var_string', $typeTest[1]->type_name); //VARCHAR - $this->assertSame('string', $typeTest[2]->type_name); //CHAR - $this->assertSame('blob', $typeTest[3]->type_name); //TEXT - $this->assertSame('short', $typeTest[4]->type_name); //SMALLINT - $this->assertSame('long', $typeTest[5]->type_name); //INTEGER - $this->assertSame('float', $typeTest[6]->type_name); //FLOAT - $this->assertSame('newdecimal', $typeTest[7]->type_name); //NUMERIC - $this->assertSame('date', $typeTest[8]->type_name); //DATE - $this->assertSame('time', $typeTest[9]->type_name); //TIME - $this->assertSame('datetime', $typeTest[10]->type_name); //DATETIME - $this->assertSame('timestamp', $typeTest[11]->type_name); //TIMESTAMP - $this->assertSame('longlong', $typeTest[12]->type_name); //BIGINT - $this->assertSame('double', $typeTest[13]->type_name); //REAL - $this->assertSame('string', $typeTest[14]->type_name); //ENUM - $this->assertSame('string', $typeTest[15]->type_name); //SET - $this->assertSame('blob', $typeTest[16]->type_name); //MEDIUMTEXT - $this->assertSame('double', $typeTest[17]->type_name); //DOUBLE - $this->assertSame('newdecimal', $typeTest[18]->type_name); //DECIMAL - $this->assertSame('blob', $typeTest[19]->type_name); //BLOB + $this->assertSame('long', $typeTest[0]->type_name); // INTEGER AUTOINC + $this->assertSame('var_string', $typeTest[1]->type_name); // VARCHAR + $this->assertSame('string', $typeTest[2]->type_name); // CHAR + $this->assertSame('blob', $typeTest[3]->type_name); // TEXT + $this->assertSame('short', $typeTest[4]->type_name); // SMALLINT + $this->assertSame('long', $typeTest[5]->type_name); // INTEGER + $this->assertSame('float', $typeTest[6]->type_name); // FLOAT + $this->assertSame('newdecimal', $typeTest[7]->type_name); // NUMERIC + $this->assertSame('date', $typeTest[8]->type_name); // DATE + $this->assertSame('time', $typeTest[9]->type_name); // TIME + $this->assertSame('datetime', $typeTest[10]->type_name); // DATETIME + $this->assertSame('timestamp', $typeTest[11]->type_name); // TIMESTAMP + $this->assertSame('longlong', $typeTest[12]->type_name); // BIGINT + $this->assertSame('double', $typeTest[13]->type_name); // REAL + $this->assertSame('string', $typeTest[14]->type_name); // ENUM + $this->assertSame('string', $typeTest[15]->type_name); // SET + $this->assertSame('blob', $typeTest[16]->type_name); // MEDIUMTEXT + $this->assertSame('double', $typeTest[17]->type_name); // DOUBLE + $this->assertSame('newdecimal', $typeTest[18]->type_name); // DECIMAL + $this->assertSame('blob', $typeTest[19]->type_name); // BLOB } if ($this->db->DBDriver === 'Postgre') { - $this->assertSame('int4', $typeTest[0]->type_name); //INTEGER AUTOINC - $this->assertSame('varchar', $typeTest[1]->type_name); //VARCHAR - $this->assertSame('bpchar', $typeTest[2]->type_name); //CHAR - $this->assertSame('text', $typeTest[3]->type_name); //TEXT - $this->assertSame('int2', $typeTest[4]->type_name); //SMALLINT - $this->assertSame('int4', $typeTest[5]->type_name); //INTEGER - $this->assertSame('float8', $typeTest[6]->type_name); //FLOAT - $this->assertSame('numeric', $typeTest[7]->type_name); //NUMERIC - $this->assertSame('date', $typeTest[8]->type_name); //DATE - $this->assertSame('time', $typeTest[9]->type_name); //TIME - $this->assertSame('timestamp', $typeTest[10]->type_name); //DATETIME - $this->assertSame('timestamp', $typeTest[11]->type_name); //TIMESTAMP - $this->assertSame('int8', $typeTest[12]->type_name); //BIGINT + $this->assertSame('int4', $typeTest[0]->type_name); // INTEGER AUTOINC + $this->assertSame('varchar', $typeTest[1]->type_name); // VARCHAR + $this->assertSame('bpchar', $typeTest[2]->type_name); // CHAR + $this->assertSame('text', $typeTest[3]->type_name); // TEXT + $this->assertSame('int2', $typeTest[4]->type_name); // SMALLINT + $this->assertSame('int4', $typeTest[5]->type_name); // INTEGER + $this->assertSame('float8', $typeTest[6]->type_name); // FLOAT + $this->assertSame('numeric', $typeTest[7]->type_name); // NUMERIC + $this->assertSame('date', $typeTest[8]->type_name); // DATE + $this->assertSame('time', $typeTest[9]->type_name); // TIME + $this->assertSame('timestamp', $typeTest[10]->type_name); // DATETIME + $this->assertSame('timestamp', $typeTest[11]->type_name); // TIMESTAMP + $this->assertSame('int8', $typeTest[12]->type_name); // BIGINT } if ($this->db->DBDriver === 'SQLSRV') { - $this->assertSame('int', $typeTest[0]->type_name); //INTEGER AUTOINC - $this->assertSame('varchar', $typeTest[1]->type_name); //VARCHAR - $this->assertSame('char', $typeTest[2]->type_name); //CHAR - $this->assertSame('text', $typeTest[3]->type_name); //TEXT - $this->assertSame('smallint', $typeTest[4]->type_name); //SMALLINT - $this->assertSame('int', $typeTest[5]->type_name); //INTEGER - $this->assertSame('float', $typeTest[6]->type_name); //FLOAT - $this->assertSame('numeric', $typeTest[7]->type_name); //NUMERIC - $this->assertNull($typeTest[8]->type_name); //DATE - $this->assertNull($typeTest[9]->type_name); //TIME - $this->assertNull($typeTest[10]->type_name); //DATETIME - $this->assertSame('bigint', $typeTest[11]->type_name); //BIGINT - $this->assertSame('real', $typeTest[12]->type_name); //REAL - $this->assertSame('decimal', $typeTest[13]->type_name); //DECIMAL + $this->assertSame('int', $typeTest[0]->type_name); // INTEGER AUTOINC + $this->assertSame('varchar', $typeTest[1]->type_name); // VARCHAR + $this->assertSame('char', $typeTest[2]->type_name); // CHAR + $this->assertSame('text', $typeTest[3]->type_name); // TEXT + $this->assertSame('smallint', $typeTest[4]->type_name); // SMALLINT + $this->assertSame('int', $typeTest[5]->type_name); // INTEGER + $this->assertSame('float', $typeTest[6]->type_name); // FLOAT + $this->assertSame('numeric', $typeTest[7]->type_name); // NUMERIC + $this->assertNull($typeTest[8]->type_name); // DATE + $this->assertNull($typeTest[9]->type_name); // TIME + $this->assertNull($typeTest[10]->type_name); // DATETIME + $this->assertSame('bigint', $typeTest[11]->type_name); // BIGINT + $this->assertSame('real', $typeTest[12]->type_name); // REAL + $this->assertSame('decimal', $typeTest[13]->type_name); // DECIMAL } } diff --git a/tests/system/HTTP/CLIRequestTest.php b/tests/system/HTTP/CLIRequestTest.php index 7940624e68bb..c31bace6b554 100644 --- a/tests/system/HTTP/CLIRequestTest.php +++ b/tests/system/HTTP/CLIRequestTest.php @@ -604,7 +604,7 @@ public function testGetIPAddressThruProxyOutofSubnet() $this->assertSame('192.168.5.21', $this->request->getIPAddress()); } - //FIXME getIPAddress should have more testing, to 100% code coverage + // FIXME getIPAddress should have more testing, to 100% code coverage public function testMethodReturnsRightStuff() { diff --git a/tests/system/HTTP/RequestTest.php b/tests/system/HTTP/RequestTest.php index d75cd0ed8665..e4ad2d6bf340 100644 --- a/tests/system/HTTP/RequestTest.php +++ b/tests/system/HTTP/RequestTest.php @@ -671,7 +671,7 @@ public function testGetIPAddressThruProxyOutofSubnet() $this->assertSame('192.168.5.21', $this->request->getIPAddress()); } - //FIXME getIPAddress should have more testing, to 100% code coverage + // FIXME getIPAddress should have more testing, to 100% code coverage public function testMethodReturnsRightStuff() { diff --git a/tests/system/Helpers/HTMLHelperTest.php b/tests/system/Helpers/HTMLHelperTest.php index 71c145fc26da..c5665ea94e05 100755 --- a/tests/system/Helpers/HTMLHelperTest.php +++ b/tests/system/Helpers/HTMLHelperTest.php @@ -35,7 +35,7 @@ protected function setUp(): void { parent::setUp(); - //URL is needed by the HTML Helper. + // URL is needed by the HTML Helper. helper('url'); helper('html'); diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index 8220f1857485..8f586a4fcbb8 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -950,7 +950,7 @@ public function testAddRedirect() { $routes = $this->getCollector(); - //The second parameter is either the new URI to redirect to, or the name of a named route. + // The second parameter is either the new URI to redirect to, or the name of a named route. $routes->addRedirect('users', 'users/index', 307); $expected = [ diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index 98c6c56ed9b4..547d9b549d0f 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -953,7 +953,7 @@ public function testRenderStringSavingData() $this->parser->setData(['testString' => 'Hello World']); $this->assertSame($expected, $this->parser->renderString($pattern, [], false)); $this->assertArrayNotHasKey('testString', $this->parser->getData()); - //last set data is not saved + // last set data is not saved $this->parser->setData(['testString' => 'Hello World']); $this->assertSame($expected, $this->parser->renderString($pattern, [], true)); $this->assertArrayHasKey('testString', $this->parser->getData()); diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index 6003e5134b6a..7abeff5793e6 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -232,7 +232,7 @@ public function testRenderStringSavingData() $view = new View($this->config, $this->viewsDir, $this->loader); $expected = '

Hello World

'; - //I think saveData is sava current data, is not clean already set data. + // I think saveData is sava current data, is not clean already set data. $view->setVar('testString', 'Hello World'); $this->assertSame($expected, $view->renderString('

', [], false)); $this->assertArrayNotHasKey('testString', $view->getData()); diff --git a/utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php b/utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php new file mode 100644 index 000000000000..d7322c32d308 --- /dev/null +++ b/utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php @@ -0,0 +1,95 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Utils\PhpCsFixer\Fixer\Comment; + +use PhpCsFixer\AbstractFixer; +use PhpCsFixer\FixerDefinition\CodeSample; +use PhpCsFixer\FixerDefinition\FixerDefinition; +use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; +use PhpCsFixer\Preg; +use PhpCsFixer\Tokenizer\Token; +use PhpCsFixer\Tokenizer\Tokens; +use SplFileInfo; + +/** + * @internal + */ +final class SpaceAfterCommentStartFixer extends AbstractFixer +{ + /** + * {@inheritDoc} + */ + public function getName(): string + { + return 'CodeIgniter4/' . parent::getName(); + } + + /** + * {@inheritDoc} + */ + public function getDefinition(): FixerDefinitionInterface + { + return new FixerDefinition( + 'There should be a single whitespace after the comment start', + [new CodeSample("isTokenKindFound(T_COMMENT); + } + + /** + * {@inheritDoc} + * + * Must run after NoEmptyCommentFixer + */ + public function getPriority(): int + { + return 3; + } + + /** + * {@inheritDoc} + */ + protected function applyFix(SplFileInfo $file, Tokens $tokens): void + { + for ($index = 1, $count = $tokens->count(); $index < $count; $index++) { + /** @var Token $token */ + $token = $tokens[$index]; + + if (! $token->isGivenKind(T_COMMENT)) { + continue; + } + + $comment = $token->getContent(); + + if (substr($comment, 0, 2) !== '//') { + continue; + } + + if (Preg::match('/^\/\/(?!\s+)(.+)/', $comment, $matches) !== 1) { + continue; + } + + if (Preg::match('/\-+/', $matches[1]) === 1 || Preg::match('/\=+/', $matches[1]) === 1) { + continue; + } + + $tokens[$index] = new Token([T_COMMENT, '// ' . $matches[1]]); + } + } +} From 7e8fc189217bf22e405842f47afd922f67c44b1f Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 14 Aug 2021 18:50:09 +0700 Subject: [PATCH 0125/2325] [Rector] Apply Rector: RemoveDoubleAssignRector --- rector.php | 2 ++ tests/system/HTTP/IncomingRequestDetectingTest.php | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rector.php b/rector.php index 3f65b0a273e6..22e33e3d0730 100644 --- a/rector.php +++ b/rector.php @@ -28,6 +28,7 @@ use Rector\Core\Configuration\Option; use Rector\Core\ValueObject\PhpVersion; use Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector; +use Rector\DeadCode\Rector\Assign\RemoveDoubleAssignRector; use Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector; use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; @@ -113,4 +114,5 @@ $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); $services->set(RemoveDuplicatedArrayKeyRector::class); + $services->set(RemoveDoubleAssignRector::class); }; diff --git a/tests/system/HTTP/IncomingRequestDetectingTest.php b/tests/system/HTTP/IncomingRequestDetectingTest.php index dfb963d05c34..a28fd86525da 100644 --- a/tests/system/HTTP/IncomingRequestDetectingTest.php +++ b/tests/system/HTTP/IncomingRequestDetectingTest.php @@ -152,7 +152,6 @@ public function testPathPathInfo() public function testPathPathInfoGlobal() { - $this->request->uri = '/index.php/woot?code=good#pos'; $this->request->uri = '/index.php/woot?code=good#pos'; $this->request->setGlobal('server', [ 'PATH_INFO' => 'silliness', From 0c38916535d4bbb14caff220bc815f008e7e8c16 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 17 Aug 2021 18:14:12 +0700 Subject: [PATCH 0126/2325] [Rector] Apply Rector dead code set list --- composer.json | 2 +- rector.php | 60 ++++++++++++++----- system/Database/Forge.php | 20 +++---- system/Database/MySQLi/Result.php | 2 +- system/Database/SQLSRV/Connection.php | 6 +- system/Database/SQLSRV/Forge.php | 22 ++++--- system/Debug/Toolbar.php | 9 +-- system/Debug/Toolbar/Collectors/Files.php | 2 +- system/Events/Events.php | 4 +- system/Filters/Filters.php | 4 -- system/HTTP/URI.php | 3 - system/Helpers/html_helper.php | 18 ++---- system/Helpers/text_helper.php | 6 +- system/Log/Logger.php | 2 +- system/Pager/Pager.php | 2 - system/Pager/PagerRenderer.php | 6 +- system/Router/RouteCollectionInterface.php | 4 -- system/Router/Router.php | 6 -- system/Security/Security.php | 8 ++- system/Session/Session.php | 4 +- system/Test/Fabricator.php | 6 -- system/Test/Mock/MockBuilder.php | 5 -- system/Throttle/Throttler.php | 2 - system/Validation/Rules.php | 4 +- tests/system/API/ResponseTraitTest.php | 4 +- .../system/Cache/Handlers/FileHandlerTest.php | 2 +- tests/system/Cookie/CookieStoreTest.php | 2 +- tests/system/Database/Live/UpdateTest.php | 4 -- tests/system/Events/EventsTest.php | 2 +- tests/system/Pager/PagerTest.php | 10 ++-- tests/system/Session/SessionTest.php | 4 +- 31 files changed, 110 insertions(+), 125 deletions(-) diff --git a/composer.json b/composer.json index 224164546dc3..26fd890bf6bc 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.47", + "rector/rector": "0.11.48", "symplify/package-builder": "^9.3" }, "suggest": { diff --git a/rector.php b/rector.php index 22e33e3d0730..7ed60ffb1382 100644 --- a/rector.php +++ b/rector.php @@ -27,13 +27,14 @@ use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; use Rector\Core\Configuration\Option; use Rector\Core\ValueObject\PhpVersion; -use Rector\DeadCode\Rector\Array_\RemoveDuplicatedArrayKeyRector; -use Rector\DeadCode\Rector\Assign\RemoveDoubleAssignRector; -use Rector\DeadCode\Rector\Assign\RemoveUnusedVariableAssignRector; -use Rector\DeadCode\Rector\Concat\RemoveConcatAutocastRector; -use Rector\DeadCode\Rector\Foreach_\RemoveUnusedForeachKeyRector; -use Rector\DeadCode\Rector\Property\RemoveUnusedPrivatePropertyRector; -use Rector\DeadCode\Rector\Switch_\RemoveDuplicatedCaseInSwitchRector; +use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPromotedPropertyRector; +use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector; +use Rector\DeadCode\Rector\Expression\RemoveDeadStmtRector; +use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; +use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; +use Rector\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; use Rector\EarlyReturn\Rector\If_\ChangeIfElseValueAssignToEarlyReturnRector; use Rector\EarlyReturn\Rector\If_\RemoveAlwaysElseRector; @@ -51,6 +52,7 @@ use Utils\Rector\UnderscoreToCamelCaseVariableNameRector; return static function (ContainerConfigurator $containerConfigurator): void { + $containerConfigurator->import(SetList::DEAD_CODE); $containerConfigurator->import(SetList::PHP_73); $parameters = $containerConfigurator->parameters(); @@ -72,6 +74,43 @@ __DIR__ . '/tests/_support', JsonThrowOnErrorRector::class, StringifyStrNeedlesRector::class, + + // requires php 8 + RemoveUnusedPromotedPropertyRector::class, + + // currently buggy on call inside assign, wait for next release + RemoveParentCallWithoutParentRector::class, + + // private method called via getPrivateMethodInvoker + RemoveUnusedPrivateMethodRector::class => [ + __DIR__ . '/system/Entity/Entity.php', + __DIR__ . '/tests/system/Test/ReflectionHelperTest.php', + ], + + // call on purpose for nothing happen check + RemoveEmptyMethodCallRector::class => [ + __DIR__ . '/tests', + ], + + // currently buggy on class implements ArrayAccess, wait for next release + RemoveDeadStmtRector::class => [ + __DIR__ . '/tests/system/Cookie/CookieTest.php', + ], + + // check on constant compare + UnwrapFutureCompatibleIfPhpVersionRector::class => [ + __DIR__ . '/system/CodeIgniter.php', + ], + + // check context ResponseTrait + RemoveUselessReturnTagRector::class => [ + __DIR__ . '/system/HTTP/MessageTrait.php', + ], + + // casted to Entity via EntityTest->getCastEntity() + RecastingRemovalRector::class => [ + __DIR__ . '/tests/system/Entity/EntityTest.php', + ], ]); // auto import fully qualified class names @@ -92,17 +131,13 @@ $services->set(SimplifyStrposLowerRector::class); $services->set(CombineIfRector::class); $services->set(SimplifyIfReturnBoolRector::class); - $services->set(RemoveDuplicatedCaseInSwitchRector::class); $services->set(InlineIfToExplicitIfRector::class); $services->set(PreparedValueToEarlyReturnRector::class); $services->set(ShortenElseIfRector::class); - $services->set(RemoveUnusedForeachKeyRector::class); $services->set(SimplifyIfElseToTernaryRector::class); $services->set(UnusedForeachValueToArrayKeysRector::class); - $services->set(RemoveConcatAutocastRector::class); $services->set(ChangeArrayPushToArrayAssignRector::class); $services->set(UnnecessaryTernaryExpressionRector::class); - $services->set(RemoveUnusedPrivatePropertyRector::class); $services->set(RemoveErrorSuppressInTryCatchStmtsRector::class); $services->set(TernaryToNullCoalescingRector::class); $services->set(ListToArrayDestructRector::class); @@ -110,9 +145,6 @@ $services->set(AddPregQuoteDelimiterRector::class); $services->set(SimplifyRegexPatternRector::class); $services->set(RemoveExtraParametersRector::class); - $services->set(RemoveUnusedVariableAssignRector::class); $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); - $services->set(RemoveDuplicatedArrayKeyRector::class); - $services->set(RemoveDoubleAssignRector::class); }; diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 4e3048290d42..ba3423a890ea 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -996,20 +996,18 @@ protected function _processForeignKeys(string $table): string 'SET DEFAULT', ]; - if ($this->foreignKeys !== []) { - foreach ($this->foreignKeys as $field => $fkey) { - $nameIndex = $table . '_' . $field . '_foreign'; + foreach ($this->foreignKeys as $field => $fkey) { + $nameIndex = $table . '_' . $field . '_foreign'; - $sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) - . ' FOREIGN KEY(' . $this->db->escapeIdentifiers($field) . ') REFERENCES ' . $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; + $sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) + . ' FOREIGN KEY(' . $this->db->escapeIdentifiers($field) . ') REFERENCES ' . $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; - if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { - $sql .= ' ON DELETE ' . $fkey['onDelete']; - } + if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { + $sql .= ' ON DELETE ' . $fkey['onDelete']; + } - if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { - $sql .= ' ON UPDATE ' . $fkey['onUpdate']; - } + if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { + $sql .= ' ON UPDATE ' . $fkey['onUpdate']; } } diff --git a/system/Database/MySQLi/Result.php b/system/Database/MySQLi/Result.php index b115697e65b9..7eab7d86c685 100644 --- a/system/Database/MySQLi/Result.php +++ b/system/Database/MySQLi/Result.php @@ -89,7 +89,7 @@ public function getFieldData(): array $retVal[$i]->type = $data->type; $retVal[$i]->type_name = in_array($data->type, [1, 247], true) ? 'char' : ($dataTypes[$data->type] ?? null); $retVal[$i]->max_length = $data->max_length; - $retVal[$i]->primary_key = (int) ($data->flags & 2); + $retVal[$i]->primary_key = $data->flags & 2; $retVal[$i]->length = $data->length; $retVal[$i]->default = $data->def; } diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index 24aa409ed1de..f09a96d69213 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -354,7 +354,7 @@ protected function _fieldData(string $table): array */ protected function _transBegin(): bool { - return (bool) sqlsrv_begin_transaction($this->connID); + return sqlsrv_begin_transaction($this->connID); } /** @@ -362,7 +362,7 @@ protected function _transBegin(): bool */ protected function _transCommit(): bool { - return (bool) sqlsrv_commit($this->connID); + return sqlsrv_commit($this->connID); } /** @@ -370,7 +370,7 @@ protected function _transCommit(): bool */ protected function _transRollback(): bool { - return (bool) sqlsrv_rollback($this->connID); + return sqlsrv_rollback($this->connID); } /** diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index ab5c3f2d5316..43131698703f 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -224,21 +224,19 @@ protected function _processForeignKeys(string $table): string $allowActions = ['CASCADE', 'SET NULL', 'NO ACTION', 'RESTRICT', 'SET DEFAULT']; - if ($this->foreignKeys !== []) { - foreach ($this->foreignKeys as $field => $fkey) { - $nameIndex = $table . '_' . $field . '_foreign'; + foreach ($this->foreignKeys as $field => $fkey) { + $nameIndex = $table . '_' . $field . '_foreign'; - $sql .= ",\n\t CONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) - . ' FOREIGN KEY (' . $this->db->escapeIdentifiers($field) . ') ' - . ' REFERENCES ' . $this->db->escapeIdentifiers($this->db->getPrefix() . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; + $sql .= ",\n\t CONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) + . ' FOREIGN KEY (' . $this->db->escapeIdentifiers($field) . ') ' + . ' REFERENCES ' . $this->db->escapeIdentifiers($this->db->getPrefix() . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; - if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { - $sql .= ' ON DELETE ' . $fkey['onDelete']; - } + if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { + $sql .= ' ON DELETE ' . $fkey['onDelete']; + } - if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { - $sql .= ' ON UPDATE ' . $fkey['onUpdate']; - } + if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { + $sql .= ' ON UPDATE ' . $fkey['onUpdate']; } } diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 6e6a0a8fc88f..16432054d2e2 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -66,17 +66,14 @@ public function __construct(ToolbarConfig $config) /** * Returns all the data required by Debug Bar * - * @param float $startTime App start time + * @param float $startTime App start time + * @param IncomingRequest $request + * @param Response $response * * @return string JSON encoded data */ public function run(float $startTime, float $totalTime, RequestInterface $request, ResponseInterface $response): string { - /** - * @var IncomingRequest $request - * @var Response $response - */ - // Data items used within the view. $data['url'] = current_url(); $data['method'] = $request->getMethod(true); diff --git a/system/Debug/Toolbar/Collectors/Files.php b/system/Debug/Toolbar/Collectors/Files.php index d476154db1c3..d6aefd2c3fe9 100644 --- a/system/Debug/Toolbar/Collectors/Files.php +++ b/system/Debug/Toolbar/Collectors/Files.php @@ -45,7 +45,7 @@ class Files extends BaseCollector */ public function getTitleDetails(): string { - return '( ' . (int) count(get_included_files()) . ' )'; + return '( ' . count(get_included_files()) . ' )'; } /** diff --git a/system/Events/Events.php b/system/Events/Events.php index a0d9c7616451..ac08107459ca 100644 --- a/system/Events/Events.php +++ b/system/Events/Events.php @@ -71,9 +71,7 @@ public static function initialize() return; } - /** - * @var Modules - */ + /** @var Modules $config */ $config = config('Modules'); $events = APPPATH . 'Config' . DIRECTORY_SEPARATOR . 'Events.php'; $files = []; diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index bce502a3f4e9..9e3a0aa7913d 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -254,8 +254,6 @@ public function initialize(?string $uri = null) * Restores instance to its pre-initialized state. * Most useful for testing so the service can be * re-initialized to a different path. - * - * @return $this */ public function reset(): self { @@ -427,8 +425,6 @@ protected function processMethods() if (array_key_exists($method, $this->config->methods)) { $this->filters['before'] = array_merge($this->filters['before'], $this->config->methods[$method]); - - return; } } diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index f6eec4e80a4a..c7bdbb135354 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -997,9 +997,6 @@ public function resolveRelativeURI(string $uri) * Section 5.2 * * @see http://tools.ietf.org/html/rfc3986#section-5.2.3 - * - * @param URI $base - * @param URI $reference */ protected function mergePaths(self $base, self $reference): string { diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index dc175afe4e93..a1a51af11955 100755 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -304,10 +304,8 @@ function video($src, string $unsupportedMessage = '', string $attributes = '', a $video .= ">\n"; - if (! empty($tracks)) { - foreach ($tracks as $track) { - $video .= _space_indent() . $track . "\n"; - } + foreach ($tracks as $track) { + $video .= _space_indent() . $track . "\n"; } if (! empty($unsupportedMessage)) { @@ -352,10 +350,8 @@ function audio($src, string $unsupportedMessage = '', string $attributes = '', a $audio .= '>'; - if (! empty($tracks)) { - foreach ($tracks as $track) { - $audio .= "\n" . _space_indent() . $track; - } + foreach ($tracks as $track) { + $audio .= "\n" . _space_indent() . $track; } if (! empty($unsupportedMessage)) { @@ -388,10 +384,8 @@ function _media(string $name, array $types = [], string $unsupportedMessage = '' $media .= _space_indent() . $option . "\n"; } - if (! empty($tracks)) { - foreach ($tracks as $track) { - $media .= _space_indent() . $track . "\n"; - } + foreach ($tracks as $track) { + $media .= _space_indent() . $track . "\n"; } if (! empty($unsupportedMessage)) { diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 23f674be9eb3..5f0738421908 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -395,10 +395,8 @@ function word_wrap(string $str, int $charlim = 76): string } // Put our markers back - if (! empty($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); } // remove any trailing newline diff --git a/system/Log/Logger.php b/system/Log/Logger.php index cfceeb3f5449..cee971161f36 100644 --- a/system/Log/Logger.php +++ b/system/Log/Logger.php @@ -282,7 +282,7 @@ public function log($level, $message, array $context = []): bool } /** - * @var HandlerInterface + * @var HandlerInterface $handler */ $handler = $this->handlers[$className]; diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index a23f710f3c73..a653485633aa 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -363,8 +363,6 @@ public function getDetails(string $group = 'default'): array /** * Sets only allowed queries on pagination links. - * - * @return Pager */ public function only(array $queries): self { diff --git a/system/Pager/PagerRenderer.php b/system/Pager/PagerRenderer.php index e1f20a5492a6..8c70314dc99f 100644 --- a/system/Pager/PagerRenderer.php +++ b/system/Pager/PagerRenderer.php @@ -239,7 +239,7 @@ public function links(): array $uri = $this->segment === 0 ? $uri->addQuery($this->pageSelector, $i) : $uri->setSegment($this->segment, $i); $links[] = [ 'uri' => URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()), - 'title' => (int) $i, + 'title' => $i, 'active' => ($i === $this->current), ]; } @@ -260,8 +260,8 @@ protected function updatePages(?int $count = null) return; } - $this->first = $this->current - $count > 0 ? (int) ($this->current - $count) : 1; - $this->last = $this->current + $count <= $this->pageCount ? (int) ($this->current + $count) : (int) $this->pageCount; + $this->first = $this->current - $count > 0 ? $this->current - $count : 1; + $this->last = $this->current + $count <= $this->pageCount ? $this->current + $count : (int) $this->pageCount; } /** diff --git a/system/Router/RouteCollectionInterface.php b/system/Router/RouteCollectionInterface.php index 2a376f61ef32..da25077da0fb 100644 --- a/system/Router/RouteCollectionInterface.php +++ b/system/Router/RouteCollectionInterface.php @@ -92,8 +92,6 @@ public function setTranslateURIDashes(bool $value); * defined routes. * * If FALSE, will stop searching and do NO automatic routing. - * - * @return RouteCollectionInterface */ public function setAutoRoute(bool $value): self; @@ -105,8 +103,6 @@ public function setAutoRoute(bool $value): self; * This setting is passed to the Router class and handled there. * * @param callable|null $callable - * - * @return RouteCollectionInterface */ public function set404Override($callable = null): self; diff --git a/system/Router/Router.php b/system/Router/Router.php index aa29abebc56a..a5ccef2c2e3b 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -268,8 +268,6 @@ public function getMatchedRouteOptions() * it a blank. * * @param string $page - * - * @return $this */ public function setIndexPage($page): self { @@ -281,10 +279,6 @@ public function setIndexPage($page): self /** * Tells the system whether we should translate URI dashes or not * in the URI from a dash to an underscore. - * - * @param bool|false $val - * - * @return $this */ public function setTranslateURIDashes(bool $val = false): self { diff --git a/system/Security/Security.php b/system/Security/Security.php index eca76b483fcb..59a24a0cbd0f 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -125,7 +125,9 @@ class Security implements SecurityInterface */ public function __construct(App $config) { - /** @var SecurityConfig */ + /** + * @var SecurityConfig $security + */ $security = config('Security'); // Store CSRF-related configurations @@ -134,7 +136,9 @@ public function __construct(App $config) $this->regenerate = $security->regenerate ?? $config->CSRFRegenerate ?? $this->regenerate; $rawCookieName = $security->cookieName ?? $config->CSRFCookieName ?? $this->cookieName; - /** @var CookieConfig */ + /** + * @var CookieConfig $cookie + */ $cookie = config('Cookie'); $cookiePrefix = $cookie->prefix ?? $config->cookiePrefix; diff --git a/system/Session/Session.php b/system/Session/Session.php index 808e5fd65f49..7850fc534266 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -182,7 +182,9 @@ public function __construct(SessionHandlerInterface $driver, App $config) $this->cookieSecure = $config->cookieSecure ?? $this->cookieSecure; $this->cookieSameSite = $config->cookieSameSite ?? $this->cookieSameSite; - /** @var CookieConfig */ + /** + * @var CookieConfig $cookie + */ $cookie = config('Cookie'); $this->cookie = new Cookie($this->sessionCookieName, '', [ diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index 65fc10131d04..0fb013cb1820 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -233,8 +233,6 @@ public function getOverrides(): array * * @param array $overrides Array of [field => value] * @param bool $persist Whether these overrides should persist through the next operation - * - * @return $this */ public function setOverrides(array $overrides = [], $persist = true): self { @@ -259,8 +257,6 @@ public function getFormatters(): ?array * Set the formatters to use. Will attempt to autodetect if none are available. * * @param array|null $formatters Array of [field => formatter], or null to detect - * - * @return $this */ public function setFormatters(?array $formatters = null): self { @@ -277,8 +273,6 @@ public function setFormatters(?array $formatters = null): self /** * Try to identify the appropriate Faker formatter for each field. - * - * @return $this */ protected function detectFormatters(): self { diff --git a/system/Test/Mock/MockBuilder.php b/system/Test/Mock/MockBuilder.php index a47d76b0f561..63002436b4e4 100644 --- a/system/Test/Mock/MockBuilder.php +++ b/system/Test/Mock/MockBuilder.php @@ -12,12 +12,7 @@ namespace CodeIgniter\Test\Mock; use CodeIgniter\Database\BaseBuilder; -use CodeIgniter\Database\ConnectionInterface; class MockBuilder extends BaseBuilder { - public function __construct($tableName, ConnectionInterface &$db, ?array $options = null) - { - parent::__construct($tableName, $db, $options); - } } diff --git a/system/Throttle/Throttler.php b/system/Throttle/Throttler.php index fe0679a0217b..0bdf8a95522d 100644 --- a/system/Throttle/Throttler.php +++ b/system/Throttle/Throttler.php @@ -139,8 +139,6 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): /** * @param string $key The name of the bucket - * - * @return $this */ public function remove(string $key): self { diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 1336e9fb87f3..20f558e52be2 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -113,7 +113,7 @@ public function is_not_unique(?string $str, string $field, array $data): bool $row = $row->where($whereField, $whereValue); } - return (bool) ($row->get()->getRow() !== null); + return $row->get()->getRow() !== null; } /** @@ -158,7 +158,7 @@ public function is_unique(?string $str, string $field, array $data): bool $row = $row->where("{$ignoreField} !=", $ignoreValue); } - return (bool) ($row->get()->getRow() === null); + return $row->get()->getRow() === null; } /** diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index fd35469dd5ec..b63b7362a600 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -64,8 +64,8 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// } if ($this->request === null) { - $this->request = new MockIncomingRequest((object) $config, new URI($uri), null, new UserAgent()); - $this->response = new MockResponse((object) $config); + $this->request = new MockIncomingRequest($config, new URI($uri), null, new UserAgent()); + $this->response = new MockResponse($config); } // Insert headers into request. diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php index de912e4b5e84..ea5a095631e0 100644 --- a/tests/system/Cache/Handlers/FileHandlerTest.php +++ b/tests/system/Cache/Handlers/FileHandlerTest.php @@ -345,7 +345,7 @@ public function __construct() public function getFileInfoTest() { $tmpHandle = tmpfile(); - stream_get_meta_data($tmpHandle)['uri']; + stream_get_meta_data($tmpHandle); return $this->getFileInfo(stream_get_meta_data($tmpHandle)['uri'], [ 'name', diff --git a/tests/system/Cookie/CookieStoreTest.php b/tests/system/Cookie/CookieStoreTest.php index a73403fba6e1..2c588fb3391e 100644 --- a/tests/system/Cookie/CookieStoreTest.php +++ b/tests/system/Cookie/CookieStoreTest.php @@ -110,7 +110,7 @@ public function testCookieDispatching(): void $prod = $cookies['prod']->getOptions(); /** - * @var MockObject&CookieStore + * @var MockObject&CookieStore $store */ $store = $this->getMockBuilder(CookieStore::class) ->setConstructorArgs([$cookies]) diff --git a/tests/system/Database/Live/UpdateTest.php b/tests/system/Database/Live/UpdateTest.php index 665a7f675fe3..f047f16a7bfd 100644 --- a/tests/system/Database/Live/UpdateTest.php +++ b/tests/system/Database/Live/UpdateTest.php @@ -58,8 +58,6 @@ public function testUpdateSetsAllWithoutWhereAndLimit() // This DB doesn't support Where and Limit together // but we don't want it called a "Risky" test. $this->assertTrue(true); - - return; } } @@ -95,8 +93,6 @@ public function testUpdateWithWhereAndLimit() // This DB doesn't support Where and Limit together // but we don't want it called a "Risky" test. $this->assertTrue(true); - - return; } } diff --git a/tests/system/Events/EventsTest.php b/tests/system/Events/EventsTest.php index 65fd7df6365e..222722b1448d 100644 --- a/tests/system/Events/EventsTest.php +++ b/tests/system/Events/EventsTest.php @@ -48,7 +48,7 @@ protected function tearDown(): void public function testInitialize() { /** - * @var Modules + * @var Modules $config */ $config = config('Modules'); $config->aliases = []; diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 99d2bf7102bd..72deb09c2c4c 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -241,7 +241,7 @@ public function testGetNextURIUsesCurrentURI() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=3'); - $this->assertSame((string) $expected, $this->pager->getNextPageURI('foo')); + $this->assertSame($expected, $this->pager->getNextPageURI('foo')); } public function testGetNextURIReturnsNullOnLastPage() @@ -270,7 +270,7 @@ public function testGetPreviousURIUsesCurrentURI() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=1'); - $this->assertSame((string) $expected, $this->pager->getPreviousPageURI('foo')); + $this->assertSame($expected, $this->pager->getPreviousPageURI('foo')); } public function testGetNextURIReturnsNullOnFirstPage() @@ -292,7 +292,7 @@ public function testGetNextURIWithQueryStringUsesCurrentURI() $this->pager->store('foo', $_GET['page_foo'] - 1, 12, 70); - $this->assertSame((string) $expected, $this->pager->getNextPageURI('foo')); + $this->assertSame($expected, $this->pager->getNextPageURI('foo')); } public function testGetPreviousURIWithQueryStringUsesCurrentURI() @@ -306,7 +306,7 @@ public function testGetPreviousURIWithQueryStringUsesCurrentURI() $this->pager->store('foo', $_GET['page_foo'] + 1, 12, 70); - $this->assertSame((string) $expected, $this->pager->getPreviousPageURI('foo')); + $this->assertSame($expected, $this->pager->getPreviousPageURI('foo')); } public function testGetOnlyQueries() @@ -453,7 +453,7 @@ public function testBasedURI() $expected = current_url(true); $expected = (string) $expected->setQuery('page_foo=1'); - $this->assertSame((string) $expected, $this->pager->getPreviousPageURI('foo')); + $this->assertSame($expected, $this->pager->getPreviousPageURI('foo')); } public function testAccessPageMoreThanPageCountGetLastPage() diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index b6989b299db0..bb5afaacf515 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -180,9 +180,9 @@ public function testGetReturnsItemValueisZero() $session = $this->getInstance(); $session->start(); - $session->set('foo', (int) 0); + $session->set('foo', 0); - $this->assertSame((int) 0, $session->get('foo')); + $this->assertSame(0, $session->get('foo')); } public function testGetReturnsAllWithNoKeys() From 377eddb29b5c4220fee970a0c556ea44274f7460 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 17 Aug 2021 19:08:35 +0700 Subject: [PATCH 0127/2325] use single line @var --- system/Security/Security.php | 8 ++------ system/Session/Session.php | 4 +--- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index 59a24a0cbd0f..aa6cf6edabad 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -125,9 +125,7 @@ class Security implements SecurityInterface */ public function __construct(App $config) { - /** - * @var SecurityConfig $security - */ + /** @var SecurityConfig $security */ $security = config('Security'); // Store CSRF-related configurations @@ -136,9 +134,7 @@ public function __construct(App $config) $this->regenerate = $security->regenerate ?? $config->CSRFRegenerate ?? $this->regenerate; $rawCookieName = $security->cookieName ?? $config->CSRFCookieName ?? $this->cookieName; - /** - * @var CookieConfig $cookie - */ + /** @var CookieConfig $cookie */ $cookie = config('Cookie'); $cookiePrefix = $cookie->prefix ?? $config->cookiePrefix; diff --git a/system/Session/Session.php b/system/Session/Session.php index 7850fc534266..27ba502aea36 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -182,9 +182,7 @@ public function __construct(SessionHandlerInterface $driver, App $config) $this->cookieSecure = $config->cookieSecure ?? $this->cookieSecure; $this->cookieSameSite = $config->cookieSameSite ?? $this->cookieSameSite; - /** - * @var CookieConfig $cookie - */ + /** @var CookieConfig $cookie */ $cookie = config('Cookie'); $this->cookie = new Cookie($this->sessionCookieName, '', [ From 5c8d1ae2462cffbae0b604b8f5d71968896e0c22 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Wed, 18 Aug 2021 10:31:32 +0800 Subject: [PATCH 0128/2325] Make Cookie compatible with ArrayAccess --- system/Cookie/Cookie.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/system/Cookie/Cookie.php b/system/Cookie/Cookie.php index 3b8e62dd9fb3..150d42069949 100644 --- a/system/Cookie/Cookie.php +++ b/system/Cookie/Cookie.php @@ -17,6 +17,7 @@ use DateTimeInterface; use InvalidArgumentException; use LogicException; +use ReturnTypeWillChange; /** * A `Cookie` class represents an immutable HTTP cookie value object. @@ -562,11 +563,9 @@ public function withRaw(bool $raw = true) /** * Whether an offset exists. * - * @param string $offset - * - * @return bool + * @param mixed $offset */ - public function offsetExists($offset) + public function offsetExists($offset): bool { return $offset === 'expire' ? true : property_exists($this, $offset); } @@ -574,12 +573,13 @@ public function offsetExists($offset) /** * Offset to retrieve. * - * @param string $offset + * @param mixed $offset * * @throws InvalidArgumentException * * @return mixed */ + #[ReturnTypeWillChange] public function offsetGet($offset) { if (! $this->offsetExists($offset)) { @@ -592,12 +592,12 @@ public function offsetGet($offset) /** * Offset to set. * - * @param string $offset - * @param mixed $value + * @param mixed $offset + * @param mixed $value * * @throws LogicException */ - public function offsetSet($offset, $value) + public function offsetSet($offset, $value): void { throw new LogicException(sprintf('Cannot set values of properties of %s as it is immutable.', static::class)); } @@ -605,11 +605,11 @@ public function offsetSet($offset, $value) /** * Offset to unset. * - * @param string $offset + * @param mixed $offset * * @throws LogicException */ - public function offsetUnset($offset) + public function offsetUnset($offset): void { throw new LogicException(sprintf('Cannot unset values of properties of %s as it is immutable.', static::class)); } From d1ed808512a8695dc10f42c96856c8ed328c39cd Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Wed, 18 Aug 2021 10:33:33 +0800 Subject: [PATCH 0129/2325] Replace deprecated FILTER_SANITIZE_STRING --- system/Router/RouteCollection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index b3a3f8e75f56..e975a1ac86b9 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -246,7 +246,7 @@ public function addPlaceholder($placeholder, ?string $pattern = null): RouteColl */ public function setDefaultNamespace(string $value): RouteCollectionInterface { - $this->defaultNamespace = filter_var($value, FILTER_SANITIZE_STRING); + $this->defaultNamespace = esc(strip_tags($value)); $this->defaultNamespace = rtrim($this->defaultNamespace, '\\') . '\\'; return $this; @@ -258,7 +258,7 @@ public function setDefaultNamespace(string $value): RouteCollectionInterface */ public function setDefaultController(string $value): RouteCollectionInterface { - $this->defaultController = filter_var($value, FILTER_SANITIZE_STRING); + $this->defaultController = esc(strip_tags($value)); return $this; } @@ -269,7 +269,7 @@ public function setDefaultController(string $value): RouteCollectionInterface */ public function setDefaultMethod(string $value): RouteCollectionInterface { - $this->defaultMethod = filter_var($value, FILTER_SANITIZE_STRING); + $this->defaultMethod = esc(strip_tags($value)); return $this; } @@ -1090,7 +1090,7 @@ protected function create(string $verb, string $from, $to, ?array $options = nul $overwrite = false; $prefix = $this->group === null ? '' : $this->group . '/'; - $from = filter_var($prefix . $from, FILTER_SANITIZE_STRING); + $from = esc(strip_tags($prefix . $from)); // While we want to add a route within a group of '/', // it doesn't work with matching, so remove them... From eb11804cde7375641f437d63e45f235f3f084583 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Wed, 18 Aug 2021 11:04:16 +0800 Subject: [PATCH 0130/2325] Make CookieStore compatible with IteratorAggregate::getIterator --- system/Cookie/CookieStore.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Cookie/CookieStore.php b/system/Cookie/CookieStore.php index 8ef45c970f59..87dc472d1fe5 100644 --- a/system/Cookie/CookieStore.php +++ b/system/Cookie/CookieStore.php @@ -207,7 +207,7 @@ public function count(): int * * @return Traversable */ - public function getIterator() + public function getIterator(): Traversable { return new ArrayIterator($this->cookies); } From a4ff0e9525ef65e74d5fd3499fdaadae518e8e88 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 19 Aug 2021 22:59:20 +0800 Subject: [PATCH 0131/2325] Make the session handlers all compatible with SessionHandlerInterface (#5012) --- rector.php | 5 + system/Session/Handlers/ArrayHandler.php | 60 ++++---- system/Session/Handlers/BaseHandler.php | 6 +- system/Session/Handlers/DatabaseHandler.php | 101 ++++++------- system/Session/Handlers/FileHandler.php | 145 +++++++++---------- system/Session/Handlers/MemcachedHandler.php | 97 ++++++------- system/Session/Handlers/RedisHandler.php | 108 +++++++------- 7 files changed, 233 insertions(+), 289 deletions(-) diff --git a/rector.php b/rector.php index 7ed60ffb1382..a3db0f19c5ac 100644 --- a/rector.php +++ b/rector.php @@ -111,6 +111,11 @@ RecastingRemovalRector::class => [ __DIR__ . '/tests/system/Entity/EntityTest.php', ], + + // session handlers have the gc() method with underscored parameter `$max_lifetime` + UnderscoreToCamelCaseVariableNameRector::class => [ + __DIR__ . '/system/Session/Handlers', + ], ]); // auto import fully qualified class names diff --git a/system/Session/Handlers/ArrayHandler.php b/system/Session/Handlers/ArrayHandler.php index f3db062eb7fe..31951a788e65 100644 --- a/system/Session/Handlers/ArrayHandler.php +++ b/system/Session/Handlers/ArrayHandler.php @@ -11,7 +11,7 @@ namespace CodeIgniter\Session\Handlers; -use Exception; +use ReturnTypeWillChange; /** * Session handler using static array for storage. @@ -22,51 +22,43 @@ class ArrayHandler extends BaseHandler protected static $cache = []; /** - * Open + * Re-initialize existing session, or creates a new one. * - * Ensures we have an initialized database connection. - * - * @param string $savePath Path to session files' directory - * @param string $name Session cookie name - * - * @throws Exception + * @param string $path The path where to store/retrieve the session + * @param string $name The session name */ - public function open($savePath, $name): bool + public function open($path, $name): bool { return true; } /** - * Read + * Reads the session data from the session storage, and returns the results. * - * Reads session data and acquires a lock + * @param string $id The session ID * - * @param string $sessionID Session ID - * - * @return string Serialized session data + * @return false|string Returns an encoded string of the read data. + * If nothing was read, it must return false. */ - public function read($sessionID): string + #[ReturnTypeWillChange] + public function read($id) { return ''; } /** - * Write - * - * Writes (create / update) session data + * Writes the session data to the session storage. * - * @param string $sessionID Session ID - * @param string $sessionData Serialized session data + * @param string $id The session ID + * @param string $data The encoded session data */ - public function write($sessionID, $sessionData): bool + public function write($id, $data): bool { return true; } /** - * Close - * - * Releases locks and closes file descriptor. + * Closes the current session. */ public function close(): bool { @@ -74,26 +66,26 @@ public function close(): bool } /** - * Destroy - * - * Destroys the current session. + * Destroys a session * - * @param string $sessionID + * @param string $id The session ID being destroyed */ - public function destroy($sessionID): bool + public function destroy($id): bool { return true; } /** - * Garbage Collector + * Cleans up expired sessions. * - * Deletes expired sessions + * @param int $max_lifetime Sessions that have not updated + * for the last max_lifetime seconds will be removed. * - * @param int $maxlifetime Maximum lifetime of sessions + * @return false|int Returns the number of deleted sessions on success, or false on failure. */ - public function gc($maxlifetime): bool + #[ReturnTypeWillChange] + public function gc($max_lifetime) { - return true; + return 1; } } diff --git a/system/Session/Handlers/BaseHandler.php b/system/Session/Handlers/BaseHandler.php index e5663abc5f85..984b0fe7c3f6 100644 --- a/system/Session/Handlers/BaseHandler.php +++ b/system/Session/Handlers/BaseHandler.php @@ -100,9 +100,6 @@ abstract class BaseHandler implements SessionHandlerInterface */ protected $ipAddress; - /** - * Constructor - */ public function __construct(AppConfig $config, string $ipAddress) { $this->cookiePrefix = $config->cookiePrefix; @@ -155,12 +152,11 @@ protected function releaseLock(): bool } /** - * Fail - * * Drivers other than the 'files' one don't (need to) use the * session.save_path INI setting, but that leads to confusing * error messages emitted by PHP when open() or write() fail, * as the message contains session.save_path ... + * * To work around the problem, the drivers will call this method * so that the INI is set just in time for the error message to * be properly generated. diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index 01c127e1e125..18da544d2873 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -15,7 +15,7 @@ use CodeIgniter\Session\Exceptions\SessionException; use Config\App as AppConfig; use Config\Database; -use Exception; +use ReturnTypeWillChange; /** * Session handler using current Database for storage @@ -58,27 +58,24 @@ class DatabaseHandler extends BaseHandler protected $rowExists = false; /** - * Constructor + * @throws SessionException */ public function __construct(AppConfig $config, string $ipAddress) { parent::__construct($config, $ipAddress); - - // Determine Table $this->table = $config->sessionSavePath; if (empty($this->table)) { throw SessionException::forMissingDatabaseTable(); } - // Get DB Connection // @phpstan-ignore-next-line $this->DBGroup = $config->sessionDBGroup ?? config(Database::class)->defaultGroup; $this->db = Database::connect($this->DBGroup); - // Determine Database type $driver = strtolower(get_class($this->db)); + if (strpos($driver, 'mysql') !== false) { $this->platform = 'mysql'; } elseif (strpos($driver, 'postgre') !== false) { @@ -87,16 +84,12 @@ public function __construct(AppConfig $config, string $ipAddress) } /** - * Open - * - * Ensures we have an initialized database connection. - * - * @param string $savePath Path to session files' directory - * @param string $name Session cookie name + * Re-initialize existing session, or creates a new one. * - * @throws Exception + * @param string $path The path where to store/retrieve the session + * @param string $name The session name */ - public function open($savePath, $name): bool + public function open($path, $name): bool { if (empty($this->db->connID)) { $this->db->initialize(); @@ -106,30 +99,29 @@ public function open($savePath, $name): bool } /** - * Read + * Reads the session data from the session storage, and returns the results. * - * Reads session data and acquires a lock + * @param string $id The session ID * - * @param string $sessionID Session ID - * - * @return string Serialized session data + * @return false|string Returns an encoded string of the read data. + * If nothing was read, it must return false. */ - public function read($sessionID): string + #[ReturnTypeWillChange] + public function read($id) { - if ($this->lockSession($sessionID) === false) { + if ($this->lockSession($id) === false) { $this->fingerprint = md5(''); return ''; } - // Needed by write() to detect session_regenerate_id() calls if (! isset($this->sessionID)) { - $this->sessionID = $sessionID; + $this->sessionID = $id; } $builder = $this->db->table($this->table) ->select($this->platform === 'postgre' ? "encode(data, 'base64') AS data" : 'data') - ->where('id', $sessionID); + ->where('id', $id); if ($this->matchIP) { $builder = $builder->where('ip_address', $this->ipAddress); @@ -160,70 +152,63 @@ public function read($sessionID): string } /** - * Write - * - * Writes (create / update) session data + * Writes the session data to the session storage. * - * @param string $sessionID Session ID - * @param string $sessionData Serialized session data + * @param string $id The session ID + * @param string $data The encoded session data */ - public function write($sessionID, $sessionData): bool + public function write($id, $data): bool { if ($this->lock === false) { return $this->fail(); } - // Was the ID regenerated? - if ($sessionID !== $this->sessionID) { + if ($this->sessionID !== $id) { $this->rowExists = false; - $this->sessionID = $sessionID; + $this->sessionID = $id; } if ($this->rowExists === false) { $insertData = [ - 'id' => $sessionID, + 'id' => $id, 'ip_address' => $this->ipAddress, 'timestamp' => 'now()', - 'data' => $this->platform === 'postgre' ? '\x' . bin2hex($sessionData) : $sessionData, + 'data' => $this->platform === 'postgre' ? '\x' . bin2hex($data) : $data, ]; if (! $this->db->table($this->table)->insert($insertData)) { return $this->fail(); } - $this->fingerprint = md5($sessionData); + $this->fingerprint = md5($data); $this->rowExists = true; return true; } - $builder = $this->db->table($this->table)->where('id', $sessionID); + $builder = $this->db->table($this->table)->where('id', $id); if ($this->matchIP) { $builder = $builder->where('ip_address', $this->ipAddress); } - $updateData = [ - 'timestamp' => 'now()', - ]; + $updateData = ['timestamp' => 'now()']; - if ($this->fingerprint !== md5($sessionData)) { - $updateData['data'] = ($this->platform === 'postgre') ? '\x' . bin2hex($sessionData) : $sessionData; + if ($this->fingerprint !== md5($data)) { + $updateData['data'] = ($this->platform === 'postgre') ? '\x' . bin2hex($data) : $data; } if (! $builder->update($updateData)) { return $this->fail(); } - $this->fingerprint = md5($sessionData); + $this->fingerprint = md5($data); return true; } /** - * Close - * - * Releases locks and closes file descriptor. + * Closes the current session. */ public function close(): bool { @@ -231,16 +216,14 @@ public function close(): bool } /** - * Destroy - * - * Destroys the current session. + * Destroys a session * - * @param string $sessionID + * @param string $id The session ID being destroyed */ - public function destroy($sessionID): bool + public function destroy($id): bool { if ($this->lock) { - $builder = $this->db->table($this->table)->where('id', $sessionID); + $builder = $this->db->table($this->table)->where('id', $id); if ($this->matchIP) { $builder = $builder->where('ip_address', $this->ipAddress); @@ -261,18 +244,20 @@ public function destroy($sessionID): bool } /** - * Garbage Collector + * Cleans up expired sessions. * - * Deletes expired sessions + * @param int $max_lifetime Sessions that have not updated + * for the last max_lifetime seconds will be removed. * - * @param int $maxlifetime Maximum lifetime of sessions + * @return false|int Returns the number of deleted sessions on success, or false on failure. */ - public function gc($maxlifetime): bool + #[ReturnTypeWillChange] + public function gc($max_lifetime) { $separator = $this->platform === 'postgre' ? '\'' : ' '; - $interval = implode($separator, ['', "{$maxlifetime} second", '']); + $interval = implode($separator, ['', "{$max_lifetime} second", '']); - return $this->db->table($this->table)->delete("timestamp < now() - INTERVAL {$interval}") ? true : $this->fail(); + return $this->db->table($this->table)->delete("timestamp < now() - INTERVAL {$interval}") ? 1 : $this->fail(); } /** diff --git a/system/Session/Handlers/FileHandler.php b/system/Session/Handlers/FileHandler.php index 0f5653739dc3..9a6d2de7eb34 100644 --- a/system/Session/Handlers/FileHandler.php +++ b/system/Session/Handlers/FileHandler.php @@ -13,7 +13,7 @@ use CodeIgniter\Session\Exceptions\SessionException; use Config\App as AppConfig; -use Exception; +use ReturnTypeWillChange; /** * Session handler using file system for storage @@ -62,9 +62,6 @@ class FileHandler extends BaseHandler */ protected $sessionIDRegex = ''; - /** - * Constructor - */ public function __construct(AppConfig $config, string $ipAddress) { parent::__construct($config, $ipAddress); @@ -88,70 +85,67 @@ public function __construct(AppConfig $config, string $ipAddress) } /** - * Open + * Re-initialize existing session, or creates a new one. * - * Sanitizes the save_path directory. + * @param string $path The path where to store/retrieve the session + * @param string $name The session name * - * @param string $savePath Path to session files' directory - * @param string $name Session cookie name - * - * @throws Exception + * @throws SessionException */ - public function open($savePath, $name): bool + public function open($path, $name): bool { - if (! is_dir($savePath)) { - if (! mkdir($savePath, 0700, true)) { - throw SessionException::forInvalidSavePath($this->savePath); - } - } elseif (! is_writable($savePath)) { + if (! is_dir($path) && ! mkdir($path, 0700, true)) { + throw SessionException::forInvalidSavePath($this->savePath); + } + + if (! is_writable($path)) { throw SessionException::forWriteProtectedSavePath($this->savePath); } - $this->savePath = $savePath; - $this->filePath = $this->savePath . '/' - . $name // we'll use the session cookie name as a prefix to avoid collisions - . ($this->matchIP ? md5($this->ipAddress) : ''); + $this->savePath = $path; + + // we'll use the session name as prefix to avoid collisions + $this->filePath = $this->savePath . '/' . $name . ($this->matchIP ? md5($this->ipAddress) : ''); return true; } /** - * Read + * Reads the session data from the session storage, and returns the results. * - * Reads session data and acquires a lock + * @param string $id The session ID * - * @param string $sessionID Session ID - * - * @return bool|string Serialized session data + * @return false|string Returns an encoded string of the read data. + * If nothing was read, it must return false. */ - public function read($sessionID) + #[ReturnTypeWillChange] + public function read($id) { // This might seem weird, but PHP 5.6 introduced session_reset(), // which re-reads session data if ($this->fileHandle === null) { - $this->fileNew = ! is_file($this->filePath . $sessionID); + $this->fileNew = ! is_file($this->filePath . $id); - if (($this->fileHandle = fopen($this->filePath . $sessionID, 'c+b')) === false) { - $this->logger->error("Session: Unable to open file '" . $this->filePath . $sessionID . "'."); + if (($this->fileHandle = fopen($this->filePath . $id, 'c+b')) === false) { + $this->logger->error("Session: Unable to open file '" . $this->filePath . $id . "'."); return false; } if (flock($this->fileHandle, LOCK_EX) === false) { - $this->logger->error("Session: Unable to obtain lock for file '" . $this->filePath . $sessionID . "'."); + $this->logger->error("Session: Unable to obtain lock for file '" . $this->filePath . $id . "'."); fclose($this->fileHandle); $this->fileHandle = null; return false; } - // Needed by write() to detect session_regenerate_id() calls if (! isset($this->sessionID)) { - $this->sessionID = $sessionID; + $this->sessionID = $id; } if ($this->fileNew) { - chmod($this->filePath . $sessionID, 0600); + chmod($this->filePath . $id, 0600); $this->fingerprint = md5(''); return ''; @@ -160,43 +154,42 @@ public function read($sessionID) rewind($this->fileHandle); } - $sessionData = ''; - clearstatcache(); // Address https://github.com/codeigniter4/CodeIgniter4/issues/2056 + $data = ''; + $buffer = 0; + clearstatcache(); // Address https://github.com/codeigniter4/CodeIgniter4/issues/2056 - for ($read = 0, $length = filesize($this->filePath . $sessionID); $read < $length; $read += strlen($buffer)) { + for ($read = 0, $length = filesize($this->filePath . $id); $read < $length; $read += strlen($buffer)) { if (($buffer = fread($this->fileHandle, $length - $read)) === false) { break; } - $sessionData .= $buffer; + $data .= $buffer; } - $this->fingerprint = md5($sessionData); + $this->fingerprint = md5($data); - return $sessionData; + return $data; } /** - * Write - * - * Writes (create / update) session data + * Writes the session data to the session storage. * - * @param string $sessionID Session ID - * @param string $sessionData Serialized session data + * @param string $id The session ID + * @param string $data The encoded session data */ - public function write($sessionID, $sessionData): bool + public function write($id, $data): bool { // If the two IDs don't match, we have a session_regenerate_id() call - if ($sessionID !== $this->sessionID) { - $this->sessionID = $sessionID; + if ($id !== $this->sessionID) { + $this->sessionID = $id; } if (! is_resource($this->fileHandle)) { return false; } - if ($this->fingerprint === md5($sessionData)) { - return ($this->fileNew) ? true : touch($this->filePath . $sessionID); + if ($this->fingerprint === md5($data)) { + return ($this->fileNew) ? true : touch($this->filePath . $id); } if (! $this->fileNew) { @@ -204,32 +197,30 @@ public function write($sessionID, $sessionData): bool rewind($this->fileHandle); } - if (($length = strlen($sessionData)) > 0) { + if (($length = strlen($data)) > 0) { $result = null; for ($written = 0; $written < $length; $written += $result) { - if (($result = fwrite($this->fileHandle, substr($sessionData, $written))) === false) { + if (($result = fwrite($this->fileHandle, substr($data, $written))) === false) { break; } } if (! is_int($result)) { - $this->fingerprint = md5(substr($sessionData, 0, $written)); + $this->fingerprint = md5(substr($data, 0, $written)); $this->logger->error('Session: Unable to write data.'); return false; } } - $this->fingerprint = md5($sessionData); + $this->fingerprint = md5($data); return true; } /** - * Close - * - * Releases locks and closes file descriptor. + * Closes the current session. */ public function close(): bool { @@ -239,45 +230,45 @@ public function close(): bool $this->fileHandle = null; $this->fileNew = false; - - return true; } return true; } /** - * Destroy + * Destroys a session * - * Destroys the current session. - * - * @param string $sessionId Session ID + * @param string $id The session ID being destroyed */ - public function destroy($sessionId): bool + public function destroy($id): bool { if ($this->close()) { - return is_file($this->filePath . $sessionId) - ? (unlink($this->filePath . $sessionId) && $this->destroyCookie()) : true; + return is_file($this->filePath . $id) + ? (unlink($this->filePath . $id) && $this->destroyCookie()) + : true; } if ($this->filePath !== null) { clearstatcache(); - return is_file($this->filePath . $sessionId) - ? (unlink($this->filePath . $sessionId) && $this->destroyCookie()) : true; + return is_file($this->filePath . $id) + ? (unlink($this->filePath . $id) && $this->destroyCookie()) + : true; } return false; } /** - * Garbage Collector + * Cleans up expired sessions. * - * Deletes expired sessions + * @param int $max_lifetime Sessions that have not updated + * for the last max_lifetime seconds will be removed. * - * @param int $maxlifetime Maximum lifetime of sessions + * @return false|int Returns the number of deleted sessions on success, or false on failure. */ - public function gc($maxlifetime): bool + #[ReturnTypeWillChange] + public function gc($max_lifetime) { if (! is_dir($this->savePath) || ($directory = opendir($this->savePath)) === false) { $this->logger->debug("Session: Garbage collector couldn't list files under directory '" . $this->savePath . "'."); @@ -285,17 +276,17 @@ public function gc($maxlifetime): bool return false; } - $ts = time() - $maxlifetime; + $ts = time() - $max_lifetime; - $pattern = $this->matchIP === true - ? '[0-9a-f]{32}' - : ''; + $pattern = $this->matchIP === true ? '[0-9a-f]{32}' : ''; $pattern = sprintf( '#\A%s' . $pattern . $this->sessionIDRegex . '\z#', preg_quote($this->cookieName, '#') ); + $collected = 0; + while (($file = readdir($directory)) !== false) { // If the filename doesn't match this pattern, it's either not a session file or is not ours if (! preg_match($pattern, $file) @@ -307,11 +298,12 @@ public function gc($maxlifetime): bool } unlink($this->savePath . DIRECTORY_SEPARATOR . $file); + $collected++; } closedir($directory); - return true; + return $collected; } /** @@ -328,7 +320,6 @@ protected function configureSessionIDRegex() ini_set('session.sid_length', (string) $SIDLength); } - // Yes, 4,5,6 are the only known possible values as of 2016-10-27 switch ($bitsPerCharacter) { case 4: $this->sessionIDRegex = '[0-9a-f]'; diff --git a/system/Session/Handlers/MemcachedHandler.php b/system/Session/Handlers/MemcachedHandler.php index dab3e61d4b06..5e963bf5048a 100644 --- a/system/Session/Handlers/MemcachedHandler.php +++ b/system/Session/Handlers/MemcachedHandler.php @@ -14,6 +14,7 @@ use CodeIgniter\Session\Exceptions\SessionException; use Config\App as AppConfig; use Memcached; +use ReturnTypeWillChange; /** * Session handler using Memcache for persistence @@ -49,8 +50,6 @@ class MemcachedHandler extends BaseHandler protected $sessionExpiration = 7200; /** - * Constructor - * * @throws SessionException */ public function __construct(AppConfig $config, string $ipAddress) @@ -73,14 +72,12 @@ public function __construct(AppConfig $config, string $ipAddress) } /** - * Open - * - * Sanitizes save_path and initializes connections. + * Re-initialize existing session, or creates a new one. * - * @param string $savePath Server path(s) - * @param string $name Session cookie name, unused + * @param string $path The path where to store/retrieve the session + * @param string $name The session name */ - public function open($savePath, $name): bool + public function open($path, $name): bool { $this->memcached = new Memcached(); $this->memcached->setOption(Memcached::OPT_BINARY_PROTOCOL, true); // required for touch() usage @@ -91,8 +88,7 @@ public function open($savePath, $name): bool $serverList[] = $server['host'] . ':' . $server['port']; } - if (! preg_match_all('#,?([^,:]+)\:(\d{1,5})(?:\:(\d+))?#', $this->savePath, $matches, PREG_SET_ORDER) - ) { + if (! preg_match_all('#,?([^,:]+)\:(\d{1,5})(?:\:(\d+))?#', $this->savePath, $matches, PREG_SET_ORDER)) { $this->memcached = null; $this->logger->error('Session: Invalid Memcached save path format: ' . $this->savePath); @@ -124,60 +120,57 @@ public function open($savePath, $name): bool } /** - * Read - * - * Reads session data and acquires a lock + * Reads the session data from the session storage, and returns the results. * - * @param string $sessionID Session ID + * @param string $id The session ID * - * @return string Serialized session data + * @return false|string Returns an encoded string of the read data. + * If nothing was read, it must return false. */ - public function read($sessionID): string + #[ReturnTypeWillChange] + public function read($id) { - if (isset($this->memcached) && $this->lockSession($sessionID)) { - // Needed by write() to detect session_regenerate_id() calls + if (isset($this->memcached) && $this->lockSession($id)) { if (! isset($this->sessionID)) { - $this->sessionID = $sessionID; + $this->sessionID = $id; } - $sessionData = (string) $this->memcached->get($this->keyPrefix . $sessionID); - $this->fingerprint = md5($sessionData); + $data = (string) $this->memcached->get($this->keyPrefix . $id); + + $this->fingerprint = md5($data); - return $sessionData; + return $data; } return ''; } /** - * Write - * - * Writes (create / update) session data + * Writes the session data to the session storage. * - * @param string $sessionID Session ID - * @param string $sessionData Serialized session data + * @param string $id The session ID + * @param string $data The encoded session data */ - public function write($sessionID, $sessionData): bool + public function write($id, $data): bool { if (! isset($this->memcached)) { return false; } - // Was the ID regenerated? - if ($sessionID !== $this->sessionID) { - if (! $this->releaseLock() || ! $this->lockSession($sessionID)) { + if ($this->sessionID !== $id) { + if (! $this->releaseLock() || ! $this->lockSession($id)) { return false; } $this->fingerprint = md5(''); - $this->sessionID = $sessionID; + $this->sessionID = $id; } if (isset($this->lockKey)) { $this->memcached->replace($this->lockKey, time(), 300); - if ($this->fingerprint !== ($fingerprint = md5($sessionData))) { - if ($this->memcached->set($this->keyPrefix . $sessionID, $sessionData, $this->sessionExpiration)) { + if ($this->fingerprint !== ($fingerprint = md5($data))) { + if ($this->memcached->set($this->keyPrefix . $id, $data, $this->sessionExpiration)) { $this->fingerprint = $fingerprint; return true; @@ -186,16 +179,14 @@ public function write($sessionID, $sessionData): bool return false; } - return $this->memcached->touch($this->keyPrefix . $sessionID, $this->sessionExpiration); + return $this->memcached->touch($this->keyPrefix . $id, $this->sessionExpiration); } return false; } /** - * Close - * - * Releases locks and closes connection. + * Closes the current session. */ public function close(): bool { @@ -217,16 +208,14 @@ public function close(): bool } /** - * Destroy - * - * Destroys the current session. + * Destroys a session * - * @param string $sessionId Session ID + * @param string $id The session ID being destroyed */ - public function destroy($sessionId): bool + public function destroy($id): bool { if (isset($this->memcached, $this->lockKey)) { - $this->memcached->delete($this->keyPrefix . $sessionId); + $this->memcached->delete($this->keyPrefix . $id); return $this->destroyCookie(); } @@ -235,22 +224,21 @@ public function destroy($sessionId): bool } /** - * Garbage Collector + * Cleans up expired sessions. * - * Deletes expired sessions + * @param int $max_lifetime Sessions that have not updated + * for the last max_lifetime seconds will be removed. * - * @param int $maxlifetime Maximum lifetime of sessions + * @return false|int Returns the number of deleted sessions on success, or false on failure. */ - public function gc($maxlifetime): bool + #[ReturnTypeWillChange] + public function gc($max_lifetime) { - // Not necessary, Memcached takes care of that. - return true; + return 1; } /** - * Get lock - * - * Acquires an (emulated) lock. + * Acquires an emulated lock. * * @param string $sessionID Session ID */ @@ -260,7 +248,6 @@ protected function lockSession(string $sessionID): bool return $this->memcached->replace($this->lockKey, time(), 300); } - // 30 attempts to obtain a lock, in case another request already has it $lockKey = $this->keyPrefix . $sessionID . ':lock'; $attempt = 0; @@ -293,8 +280,6 @@ protected function lockSession(string $sessionID): bool } /** - * Release lock - * * Releases a previously acquired lock */ protected function releaseLock(): bool diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index c066813b7969..8ed7b8c052b8 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -13,9 +13,9 @@ use CodeIgniter\Session\Exceptions\SessionException; use Config\App as AppConfig; -use Exception; use Redis; use RedisException; +use ReturnTypeWillChange; /** * Session handler using Redis for persistence @@ -58,9 +58,7 @@ class RedisHandler extends BaseHandler protected $sessionExpiration = 7200; /** - * Constructor - * - * @throws Exception + * @throws SessionException */ public function __construct(AppConfig $config, string $ipAddress) { @@ -72,8 +70,8 @@ public function __construct(AppConfig $config, string $ipAddress) if (preg_match('#(?:tcp://)?([^:?]+)(?:\:(\d+))?(\?.+)?#', $this->savePath, $matches)) { if (! isset($matches[3])) { - $matches[3] = ''; - } // Just to avoid undefined index notices below + $matches[3] = ''; // Just to avoid undefined index notices below + } $this->savePath = [ 'host' => $matches[1], @@ -98,14 +96,12 @@ public function __construct(AppConfig $config, string $ipAddress) } /** - * Open + * Re-initialize existing session, or creates a new one. * - * Sanitizes save_path and initializes connection. - * - * @param string $savePath Server path - * @param string $name Session cookie name, unused + * @param string $path The path where to store/retrieve the session + * @param string $name The session name */ - public function open($savePath, $name): bool + public function open($path, $name): bool { if (empty($this->savePath)) { return false; @@ -129,62 +125,63 @@ public function open($savePath, $name): bool } /** - * Read + * Reads the session data from the session storage, and returns the results. * - * Reads session data and acquires a lock + * @param string $id The session ID * - * @param string $sessionID Session ID - * - * @return string Serialized session data + * @return false|string Returns an encoded string of the read data. + * If nothing was read, it must return false. */ - public function read($sessionID): string + #[ReturnTypeWillChange] + public function read($id) { - if (isset($this->redis) && $this->lockSession($sessionID)) { - // Needed by write() to detect session_regenerate_id() calls + if (isset($this->redis) && $this->lockSession($id)) { if (! isset($this->sessionID)) { - $this->sessionID = $sessionID; + $this->sessionID = ${$id}; } - $sessionData = $this->redis->get($this->keyPrefix . $sessionID); - is_string($sessionData) ? $this->keyExists = true : $sessionData = ''; + $data = $this->redis->get($this->keyPrefix . $id); + + if (is_string($data)) { + $this->keyExists = true; + } else { + $data = ''; + } - $this->fingerprint = md5($sessionData); + $this->fingerprint = md5($data); - return $sessionData; + return $data; } return ''; } /** - * Write + * Writes the session data to the session storage. * - * Writes (create / update) session data - * - * @param string $sessionID Session ID - * @param string $sessionData Serialized session data + * @param string $id The session ID + * @param string $data The encoded session data */ - public function write($sessionID, $sessionData): bool + public function write($id, $data): bool { if (! isset($this->redis)) { return false; } - // Was the ID regenerated? - if ($sessionID !== $this->sessionID) { - if (! $this->releaseLock() || ! $this->lockSession($sessionID)) { + if ($this->sessionID !== $id) { + if (! $this->releaseLock() || ! $this->lockSession($id)) { return false; } $this->keyExists = false; - $this->sessionID = $sessionID; + $this->sessionID = $id; } if (isset($this->lockKey)) { $this->redis->expire($this->lockKey, 300); - if ($this->fingerprint !== ($fingerprint = md5($sessionData)) || $this->keyExists === false) { - if ($this->redis->set($this->keyPrefix . $sessionID, $sessionData, $this->sessionExpiration)) { + if ($this->fingerprint !== ($fingerprint = md5($data)) || $this->keyExists === false) { + if ($this->redis->set($this->keyPrefix . $id, $data, $this->sessionExpiration)) { $this->fingerprint = $fingerprint; $this->keyExists = true; @@ -194,22 +191,21 @@ public function write($sessionID, $sessionData): bool return false; } - return $this->redis->expire($this->keyPrefix . $sessionID, $this->sessionExpiration); + return $this->redis->expire($this->keyPrefix . $id, $this->sessionExpiration); } return false; } /** - * Close - * - * Releases locks and closes connection. + * Closes the current session. */ public function close(): bool { if (isset($this->redis)) { try { $pingReply = $this->redis->ping(); + // @phpstan-ignore-next-line if (($pingReply === true) || ($pingReply === '+PONG')) { if (isset($this->lockKey)) { @@ -233,16 +229,14 @@ public function close(): bool } /** - * Destroy - * - * Destroys the current session. + * Destroys a session * - * @param string $sessionID + * @param string $id The session ID being destroyed */ - public function destroy($sessionID): bool + public function destroy($id): bool { if (isset($this->redis, $this->lockKey)) { - if (($result = $this->redis->del($this->keyPrefix . $sessionID)) !== 1) { + if (($result = $this->redis->del($this->keyPrefix . $id)) !== 1) { $this->logger->debug('Session: Redis::del() expected to return 1, got ' . var_export($result, true) . ' instead.'); } @@ -253,22 +247,21 @@ public function destroy($sessionID): bool } /** - * Garbage Collector + * Cleans up expired sessions. * - * Deletes expired sessions + * @param int $max_lifetime Sessions that have not updated + * for the last max_lifetime seconds will be removed. * - * @param int $maxlifetime Maximum lifetime of sessions + * @return false|int Returns the number of deleted sessions on success, or false on failure. */ - public function gc($maxlifetime): bool + #[ReturnTypeWillChange] + public function gc($max_lifetime) { - // Not necessary, Redis takes care of that. - return true; + return 1; } /** - * Get lock - * - * Acquires an (emulated) lock. + * Acquires an emulated lock. * * @param string $sessionID Session ID */ @@ -281,7 +274,6 @@ protected function lockSession(string $sessionID): bool return $this->redis->expire($this->lockKey, 300); } - // 30 attempts to obtain a lock, in case another request already has it $lockKey = $this->keyPrefix . $sessionID . ':lock'; $attempt = 0; @@ -318,8 +310,6 @@ protected function lockSession(string $sessionID): bool } /** - * Release lock - * * Releases a previously acquired lock */ protected function releaseLock(): bool From 9b4fbce55ee7d5bd7a517816d683cf6dd1192f54 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 20 Aug 2021 20:58:31 +0800 Subject: [PATCH 0132/2325] Make CITestStreamFilter compatible with php_user_filter (#5014) --- system/Test/Filters/CITestStreamFilter.php | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/system/Test/Filters/CITestStreamFilter.php b/system/Test/Filters/CITestStreamFilter.php index 39ab2f7ca444..46e895ab19b8 100644 --- a/system/Test/Filters/CITestStreamFilter.php +++ b/system/Test/Filters/CITestStreamFilter.php @@ -14,7 +14,6 @@ use php_user_filter; /** - * Class to extract an output snapshot. * Used to capture output during unit testing, so that it can * be used in assertions. */ @@ -28,16 +27,15 @@ class CITestStreamFilter extends php_user_filter public static $buffer = ''; /** - * Output filtering - catch it all. + * This method is called whenever data is read from or written to the + * attached stream (such as with fread() or fwrite()). * * @param resource $in * @param resource $out * @param int $consumed * @param bool $closing - * - * @return int */ - public function filter($in, $out, &$consumed, $closing) + public function filter($in, $out, &$consumed, $closing): int { while ($bucket = stream_bucket_make_writeable($in)) { static::$buffer .= $bucket->data; @@ -45,11 +43,8 @@ public function filter($in, $out, &$consumed, $closing) $consumed += $bucket->datalen; } - // @phpstan-ignore-next-line return PSFS_PASS_ON; } } -// @codeCoverageIgnoreStart -stream_filter_register('CITestStreamFilter', 'CodeIgniter\Test\Filters\CITestStreamFilter'); -// @codeCoverageIgnoreEnd +stream_filter_register('CITestStreamFilter', CITestStreamFilter::class); // @codeCoverageIgnore From d8b43eb25fc09f7c2da595703b8216cb19b5ee16 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 23 Aug 2021 23:54:58 +0000 Subject: [PATCH 0133/2325] Update rector/rector requirement from 0.11.48 to 0.11.49 (#5018) --- composer.json | 2 +- rector.php | 22 ++++++--------------- system/Common.php | 32 ++++++++++++++----------------- system/Test/DatabaseTestTrait.php | 10 ++++------ system/Test/FeatureTestCase.php | 6 ++---- 5 files changed, 27 insertions(+), 45 deletions(-) diff --git a/composer.json b/composer.json index 26fd890bf6bc..2287474c27de 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.48", + "rector/rector": "0.11.49", "symplify/package-builder": "^9.3" }, "suggest": { diff --git a/rector.php b/rector.php index a3db0f19c5ac..cbce74ea213d 100644 --- a/rector.php +++ b/rector.php @@ -30,11 +30,9 @@ use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPromotedPropertyRector; -use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector; -use Rector\DeadCode\Rector\Expression\RemoveDeadStmtRector; +use Rector\DeadCode\Rector\If_\RemoveUnusedNonEmptyArrayBeforeForeachRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; -use Rector\DeadCode\Rector\StaticCall\RemoveParentCallWithoutParentRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; use Rector\EarlyReturn\Rector\If_\ChangeIfElseValueAssignToEarlyReturnRector; use Rector\EarlyReturn\Rector\If_\RemoveAlwaysElseRector; @@ -78,9 +76,6 @@ // requires php 8 RemoveUnusedPromotedPropertyRector::class, - // currently buggy on call inside assign, wait for next release - RemoveParentCallWithoutParentRector::class, - // private method called via getPrivateMethodInvoker RemoveUnusedPrivateMethodRector::class => [ __DIR__ . '/system/Entity/Entity.php', @@ -92,21 +87,11 @@ __DIR__ . '/tests', ], - // currently buggy on class implements ArrayAccess, wait for next release - RemoveDeadStmtRector::class => [ - __DIR__ . '/tests/system/Cookie/CookieTest.php', - ], - // check on constant compare UnwrapFutureCompatibleIfPhpVersionRector::class => [ __DIR__ . '/system/CodeIgniter.php', ], - // check context ResponseTrait - RemoveUselessReturnTagRector::class => [ - __DIR__ . '/system/HTTP/MessageTrait.php', - ], - // casted to Entity via EntityTest->getCastEntity() RecastingRemovalRector::class => [ __DIR__ . '/tests/system/Entity/EntityTest.php', @@ -116,6 +101,11 @@ UnderscoreToCamelCaseVariableNameRector::class => [ __DIR__ . '/system/Session/Handlers', ], + + // check on $_SESSION + RemoveUnusedNonEmptyArrayBeforeForeachRector::class => [ + __DIR__ . '/system/Debug/Toolbar.php', + ], ]); // auto import fully qualified class names diff --git a/system/Common.php b/system/Common.php index 129a3374738e..19be6398a8e1 100644 --- a/system/Common.php +++ b/system/Common.php @@ -471,9 +471,9 @@ function force_https(int $duration = 31536000, ?RequestInterface $request = null $baseURL = config(App::class)->baseURL; if (strpos($baseURL, 'https://') === 0) { - $baseURL = (string) substr($baseURL, strlen('https://')); + $baseURL = substr($baseURL, strlen('https://')); } elseif (strpos($baseURL, 'http://') === 0) { - $baseURL = (string) substr($baseURL, strlen('http://')); + $baseURL = substr($baseURL, strlen('http://')); } $uri = URI::createURIString( @@ -601,18 +601,16 @@ function helper($filenames) else { $paths = $loader->search('Helpers/' . $filename); - if (! empty($paths)) { - foreach ($paths as $path) { - if (strpos($path, APPPATH) === 0) { - // @codeCoverageIgnoreStart - $appHelper = $path; - // @codeCoverageIgnoreEnd - } elseif (strpos($path, SYSTEMPATH) === 0) { - $systemHelper = $path; - } else { - $localIncludes[] = $path; - $loaded[] = $filename; - } + foreach ($paths as $path) { + if (strpos($path, APPPATH) === 0) { + // @codeCoverageIgnoreStart + $appHelper = $path; + // @codeCoverageIgnoreEnd + } elseif (strpos($path, SYSTEMPATH) === 0) { + $systemHelper = $path; + } else { + $localIncludes[] = $path; + $loaded[] = $filename; } } @@ -636,10 +634,8 @@ function helper($filenames) } // Now actually include all of the files - if (! empty($includes)) { - foreach ($includes as $path) { - include_once $path; - } + foreach ($includes as $path) { + include_once $path; } } } diff --git a/system/Test/DatabaseTestTrait.php b/system/Test/DatabaseTestTrait.php index 4ad164cd272d..d15a5fb44480 100644 --- a/system/Test/DatabaseTestTrait.php +++ b/system/Test/DatabaseTestTrait.php @@ -225,12 +225,10 @@ public static function resetMigrationSeedCount() */ protected function clearInsertCache() { - if (! empty($this->insertCache)) { - foreach ($this->insertCache as $row) { - $this->db->table($row[0]) - ->where($row[1]) - ->delete(); - } + foreach ($this->insertCache as $row) { + $this->db->table($row[0]) + ->where($row[1]) + ->delete(); } } diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index 1f188075e5cd..87423271cd63 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -326,10 +326,8 @@ protected function setupRequest(string $method, ?string $path = null): IncomingR */ protected function setupHeaders(IncomingRequest $request) { - if (! empty($this->headers)) { - foreach ($this->headers as $name => $value) { - $request->setHeader($name, $value); - } + foreach ($this->headers as $name => $value) { + $request->setHeader($name, $value); } return $request; From 4d0110fc151350bccc52438b04cc3c5bcc455ff9 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 26 Aug 2021 09:29:47 +0800 Subject: [PATCH 0134/2325] Make Time compatible with DateTime (#5022) --- system/I18n/Time.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/system/I18n/Time.php b/system/I18n/Time.php index 27d6ccc3ad5c..919a5a391534 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -21,10 +21,9 @@ use IntlCalendar; use IntlDateFormatter; use Locale; +use ReturnTypeWillChange; /** - * Class Time - * * A localized date/time package inspired * by Nesbot/Carbon and CakePHP/Chronos. * @@ -232,19 +231,20 @@ public static function create(?int $year = null, ?int $month = null, ?int $day = * * @param string $format * @param string $datetime - * @param DateTimeZone|string|null $timeZone + * @param DateTimeZone|string|null $timezone * * @throws Exception * * @return Time */ - public static function createFromFormat($format, $datetime, $timeZone = null) + #[ReturnTypeWillChange] + public static function createFromFormat($format, $datetime, $timezone = null) { if (! $date = parent::createFromFormat($format, $datetime)) { throw I18nException::forInvalidFormat($format); } - return new self($date->format('Y-m-d H:i:s'), $timeZone); + return new self($date->format('Y-m-d H:i:s'), $timezone); } /** @@ -679,6 +679,7 @@ protected function setValue(string $name, $value) * * @return Time */ + #[ReturnTypeWillChange] public function setTimezone($timezone) { $timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); @@ -695,6 +696,7 @@ public function setTimezone($timezone) * * @return Time */ + #[ReturnTypeWillChange] public function setTimestamp($timestamp) { $time = date('Y-m-d H:i:s', $timestamp); @@ -1181,7 +1183,7 @@ public function __isset($name): bool /** * This is called when we unserialize the Time object. */ - public function __wakeup() + public function __wakeup(): void { /** * Prior to unserialization, this is a string. From dae39bf75f9b087355baeeca6341ecd656e2a791 Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 26 Aug 2021 15:49:20 +0000 Subject: [PATCH 0135/2325] Apply PHP Copy/Paste Detector --- .github/workflows/test-phpcpd.yml | 43 +++++++++++ system/Database/SQLSRV/Builder.php | 120 +---------------------------- 2 files changed, 44 insertions(+), 119 deletions(-) create mode 100644 .github/workflows/test-phpcpd.yml diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml new file mode 100644 index 000000000000..fcc66f7d682c --- /dev/null +++ b/.github/workflows/test-phpcpd.yml @@ -0,0 +1,43 @@ +# When a PR is opened or a push is made, check code +# for duplication with PHP Copy/Paste Detector. +name: PHPCPD + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**' + - 'public/**' + - 'system/**' + - '.github/workflows/test-phpcpd.yml' + push: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**' + - 'public/**' + - 'system/**' + - '.github/workflows/test-phpcpd.yml' + +jobs: + build: + name: Duplicate Code Detection + runs-on: ubuntu-20.04 + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.0' + tools: phive + extensions: intl, json, mbstring, xml + + - name: Detect code duplication + run: | + sudo phive --no-progress install --global --trust-gpg-keys 4AA394086372C20A phpcpd + phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php app/ public/ system/ diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index 049f47a33fea..aaed5680dfc0 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -11,7 +11,6 @@ namespace CodeIgniter\Database\SQLSRV; -use Closure; use CodeIgniter\Database\BaseBuilder; use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Exceptions\DataException; @@ -93,57 +92,7 @@ protected function _truncate(string $table): string */ public function join(string $table, string $cond, string $type = '', ?bool $escape = null) { - if ($type !== '') { - $type = strtoupper(trim($type)); - - if (! in_array($type, $this->joinTypes, true)) { - $type = ''; - } else { - $type .= ' '; - } - } - - // Extract any aliases that might exist. We use this information - // in the protectIdentifiers to know whether to add a table prefix - $this->trackAliases($table); - - if (! is_bool($escape)) { - $escape = $this->db->protectIdentifiers; - } - - if (! $this->hasOperator($cond)) { - $cond = ' USING (' . ($escape ? $this->db->escapeIdentifiers($cond) : $cond) . ')'; - } elseif ($escape === false) { - $cond = ' ON ' . $cond; - } else { - // Split multiple conditions - if (preg_match_all('/\sAND\s|\sOR\s/i', $cond, $joints, PREG_OFFSET_CAPTURE)) { - $conditions = []; - $joints = $joints[0]; - array_unshift($joints, ['', 0]); - - for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--) { - $joints[$i][1] += strlen($joints[$i][0]); // offset - $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]); - $pos = $joints[$i][1] - strlen($joints[$i][0]); - $joints[$i] = $joints[$i][0]; - } - - ksort($conditions); - } else { - $conditions = [$cond]; - $joints = ['']; - } - - $cond = ' ON '; - - foreach ($conditions as $i => $condition) { - $operator = $this->getOperator($condition); - - $cond .= $joints[$i]; - $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; - } - } + parent::join($table, $cond, $type, $escape); // Do we want to escape the table name? if ($escape === true) { @@ -516,73 +465,6 @@ protected function compileSelect($selectOverride = false): string return $sql; } - /** - * WHERE, HAVING - * - * @param mixed $key - * @param mixed $value - * - * @return $this - */ - protected function whereHaving(string $qbKey, $key, $value = null, string $type = 'AND ', ?bool $escape = null) - { - if (! is_array($key)) { - $key = [$key => $value]; - } - - // If the escape value was not set will base it on the global setting - if (! is_bool($escape)) { - $escape = $this->db->protectIdentifiers; - } - - foreach ($key as $k => $v) { - $prefix = empty($this->{$qbKey}) ? $this->groupGetType('') : $this->groupGetType($type); - - if ($v !== null) { - $op = $this->getOperator($k, true); - - if (! empty($op)) { - $k = trim($k); - - end($op); - - $op = trim(current($op)); - - if (substr($k, -1 * strlen($op)) === $op) { - $k = rtrim(strrev(preg_replace(strrev('/' . $op . '/'), strrev(''), strrev($k), 1))); - } - } - - $bind = $this->setBind($k, $v, $escape); - - if (empty($op)) { - $k .= ' ='; - } else { - $k .= " {$op}"; - } - - if ($v instanceof Closure) { - $builder = $this->cleanClone(); - $v = '(' . str_replace("\n", ' ', $v($builder)->getCompiledSelect()) . ')'; - } else { - $v = " :{$bind}:"; - } - } elseif (! $this->hasOperator($k) && $qbKey !== 'QBHaving') { - // value appears not to have been set, assign the test to IS NULL - $k .= ' IS NULL'; - } elseif (preg_match('/\s*(!?=|<>|IS(?:\s+NOT)?)\s*$/i', $k, $match, PREG_OFFSET_CAPTURE)) { - $k = substr($k, 0, $match[0][1]) . ($match[1][0] === '=' ? ' IS NULL' : ' IS NOT NULL'); - } - - $this->{$qbKey}[] = [ - 'condition' => $prefix . $k . $v, - 'escape' => $escape, - ]; - } - - return $this; - } - /** * Compiles the select statement based on the other functions called * and runs the query From 4272b8ea5cb157e641fd482113797baa13a2f89b Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 27 Aug 2021 21:10:08 +0800 Subject: [PATCH 0136/2325] Update dependabot config (#5027) --- .github/dependabot.yml | 25 +++++++++++++++---------- .github/workflows/deploy-framework.yml | 8 ++++---- .github/workflows/test-phpstan.yml | 4 ++-- .github/workflows/test-phpunit.yml | 6 +++--- .github/workflows/test-rector.yml | 2 +- 5 files changed, 25 insertions(+), 20 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6532121074ad..d3afefe5c9fd 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,13 +1,18 @@ version: 2 + updates: -- package-ecosystem: composer - directory: "/" - schedule: - interval: daily - open-pull-requests-limit: 10 + - package-ecosystem: 'composer' + directory: '/' + schedule: + interval: 'daily' + open-pull-requests-limit: 10 -- package-ecosystem: "github-actions" - directory: "/" - schedule: - # Check for updates to GitHub Actions every weekday - interval: "daily" + - package-ecosystem: 'github-actions' + directory: '/' + schedule: + interval: 'daily' + ignore: + - dependency-name: '*' + update-types: + - 'version-update:semver-minor' + - 'version-update:semver-patch' diff --git a/.github/workflows/deploy-framework.yml b/.github/workflows/deploy-framework.yml index fff563878b2e..226cf242ed59 100644 --- a/.github/workflows/deploy-framework.yml +++ b/.github/workflows/deploy-framework.yml @@ -9,7 +9,7 @@ on: jobs: framework: name: Deploy to framework - if: (github.repository == 'codeigniter4/CodeIgniter4') + if: github.repository == 'codeigniter4/CodeIgniter4' runs-on: ubuntu-latest steps: - name: Identify @@ -36,7 +36,7 @@ jobs: run: ./source/.github/scripts/deploy-framework ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/framework ${GITHUB_REF##*/} - name: Release - uses: actions/github-script@v4.0.2 + uses: actions/github-script@v4 with: github-token: ${{secrets.ACCESS_TOKEN}} script: | @@ -54,7 +54,7 @@ jobs: appstarter: name: Deploy to appstarter - if: (github.repository == 'codeigniter4/CodeIgniter4') + if: github.repository == 'codeigniter4/CodeIgniter4' runs-on: ubuntu-latest steps: - name: Identify @@ -81,7 +81,7 @@ jobs: run: ./source/.github/scripts/deploy-appstarter ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/appstarter ${GITHUB_REF##*/} - name: Release - uses: actions/github-script@v4.0.2 + uses: actions/github-script@v4 with: github-token: ${{secrets.ACCESS_TOKEN}} script: | diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index 86b68b058ea1..0e59e3bf4e3a 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -54,7 +54,7 @@ jobs: run: mkdir -p ${{ steps.composer-cache.outputs.dir }} - name: Cache composer dependencies - uses: actions/cache@v2.1.5 + uses: actions/cache@v2 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} @@ -64,7 +64,7 @@ jobs: run: mkdir -p build/phpstan - name: Cache PHPStan result cache directory - uses: actions/cache@v2.1.5 + uses: actions/cache@v2 with: path: build/phpstan key: ${{ runner.os }}-phpstan-${{ github.sha }} diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 9b9da589720f..5dd68a65eac1 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -44,9 +44,9 @@ jobs: db-platforms: ['MySQLi', 'Postgre', 'SQLite3', 'SQLSRV'] mysql-versions: ['5.7'] include: - - php-versions: 7.4 + - php-versions: '7.4' db-platforms: MySQLi - mysql-versions: 8.0 + mysql-versions: '8.0' services: mysql: @@ -113,7 +113,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v2.1.5 + uses: actions/cache@v2 with: path: ${{ steps.composercache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/test-rector.yml b/.github/workflows/test-rector.yml index e1420c965f37..0d7262ceb4ea 100644 --- a/.github/workflows/test-rector.yml +++ b/.github/workflows/test-rector.yml @@ -58,7 +58,7 @@ jobs: run: mkdir -p ${{ steps.composer-cache.outputs.dir }} - name: Cache composer dependencies - uses: actions/cache@v2.1.5 + uses: actions/cache@v2 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} From 82d39def0bd386242855726b697f53a1f2d6e4b9 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 27 Aug 2021 21:11:49 +0800 Subject: [PATCH 0137/2325] Add `ReturnTypeWillChange` attribute to Entity (#5028) --- system/Entity/Entity.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 03f6327f8142..482d092912f4 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -27,6 +27,7 @@ use CodeIgniter\I18n\Time; use Exception; use JsonSerializable; +use ReturnTypeWillChange; /** * Entity encapsulation, for use with CodeIgniter\Model @@ -406,8 +407,9 @@ private function castAsJson($value, bool $asArray = false) /** * Support for json_encode() * - * @return array|mixed + * @return array */ + #[ReturnTypeWillChange] public function jsonSerialize() { return $this->toArray(); From 7be28cdfc31613c0adb10171bc4db6c7cf26c2b0 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 27 Aug 2021 21:13:05 +0800 Subject: [PATCH 0138/2325] Replace unused Entity private method (#5029) --- rector.php | 1 - system/Entity/Entity.php | 14 ---------- tests/system/Entity/EntityTest.php | 43 +++++++++++++++++------------- 3 files changed, 25 insertions(+), 33 deletions(-) diff --git a/rector.php b/rector.php index cbce74ea213d..552c6341cb0b 100644 --- a/rector.php +++ b/rector.php @@ -78,7 +78,6 @@ // private method called via getPrivateMethodInvoker RemoveUnusedPrivateMethodRector::class => [ - __DIR__ . '/system/Entity/Entity.php', __DIR__ . '/tests/system/Test/ReflectionHelperTest.php', ], diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 482d092912f4..7d44adf3e14c 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -390,20 +390,6 @@ protected function castAs($value, string $attribute, string $method = 'get') return $handlers[$type]::$method($value, $params); } - /** - * Cast as JSON - * - * @param mixed $value - * - * @throws CastException - * - * @return mixed - */ - private function castAsJson($value, bool $asArray = false) - { - return JsonCast::get($value, $asArray ? ['array'] : []); - } - /** * Support for json_encode() * diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 0928279ac514..69d0546510bd 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Entity; +use Closure; use CodeIgniter\Entity\Exceptions\CastException; use CodeIgniter\HTTP\URI; use CodeIgniter\I18n\Time; @@ -589,54 +590,60 @@ public function testCastAsJSONErrorUTF8() public function testCastAsJSONSyntaxError() { - $entity = new Entity(); - - $method = $this->getPrivateMethodInvoker($entity, 'castAsJson'); - $this->expectException(CastException::class); $this->expectExceptionMessage('Syntax error, malformed JSON'); - $method('{ this is bad string', true); + (Closure::bind(static function (string $value) { + $entity = new Entity(); + $entity->casts['dummy'] = 'json[array]'; + + return $entity->castAs($value, 'dummy'); + }, null, Entity::class))('{ this is bad string'); } public function testCastAsJSONAnotherErrorDepth() { - $entity = new Entity(); - - $method = $this->getPrivateMethodInvoker($entity, 'castAsJson'); - $this->expectException(CastException::class); $this->expectExceptionMessage('Maximum stack depth exceeded'); $string = '{' . str_repeat('"test":{', 513) . '"test":"value"' . str_repeat('}', 513) . '}'; - $method($string, true); + (Closure::bind(static function (string $value) { + $entity = new Entity(); + $entity->casts['dummy'] = 'json[array]'; + + return $entity->castAs($value, 'dummy'); + }, null, Entity::class))($string); } public function testCastAsJSONControlCharCheck() { - $entity = new Entity(); - $method = $this->getPrivateMethodInvoker($entity, 'castAsJson'); - $this->expectException(CastException::class); $this->expectExceptionMessage('Unexpected control character found'); $string = "{\n\t\"property1\": \"The quick brown fox\njumps over the lazy dog\",\n\t\"property2\":\"value2\"\n}"; - $method($string, true); + (Closure::bind(static function (string $value) { + $entity = new Entity(); + $entity->casts['dummy'] = 'json[array]'; + + return $entity->castAs($value, 'dummy'); + }, null, Entity::class))($string); } public function testCastAsJSONStateMismatch() { - $entity = new Entity(); - $method = $this->getPrivateMethodInvoker($entity, 'castAsJson'); - $this->expectException(CastException::class); $this->expectExceptionMessage('Underflow or the modes mismatch'); $string = '[{"name":"jack","product_id":"1234"]'; - $method($string, true); + (Closure::bind(static function (string $value) { + $entity = new Entity(); + $entity->casts['dummy'] = 'json[array]'; + + return $entity->castAs($value, 'dummy'); + }, null, Entity::class))($string); } public function testCastSetter() From d50f8ecf7b6b02af46535880099e4af4d70f2fd7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 27 Aug 2021 15:02:14 +0000 Subject: [PATCH 0139/2325] Update rector/rector requirement from 0.11.49 to 0.11.52 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.11.49...0.11.52) --- 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 2287474c27de..66a38a215e5c 100644 --- a/composer.json +++ b/composer.json @@ -23,7 +23,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.49", + "rector/rector": "0.11.52", "symplify/package-builder": "^9.3" }, "suggest": { From 60d5dc86c11501ac32ce6250d36cbbec0cbb95ba Mon Sep 17 00:00:00 2001 From: MGatner Date: Fri, 27 Aug 2021 18:39:15 +0000 Subject: [PATCH 0140/2325] Restore join code --- system/Database/SQLSRV/Builder.php | 52 +++++++++++++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index aaed5680dfc0..cda4fac8a825 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -92,7 +92,57 @@ protected function _truncate(string $table): string */ public function join(string $table, string $cond, string $type = '', ?bool $escape = null) { - parent::join($table, $cond, $type, $escape); + if ($type !== '') { + $type = strtoupper(trim($type)); + + if (! in_array($type, $this->joinTypes, true)) { + $type = ''; + } else { + $type .= ' '; + } + } + + // Extract any aliases that might exist. We use this information + // in the protectIdentifiers to know whether to add a table prefix + $this->trackAliases($table); + + if (! is_bool($escape)) { + $escape = $this->db->protectIdentifiers; + } + + if (! $this->hasOperator($cond)) { + $cond = ' USING (' . ($escape ? $this->db->escapeIdentifiers($cond) : $cond) . ')'; + } elseif ($escape === false) { + $cond = ' ON ' . $cond; + } else { + // Split multiple conditions + if (preg_match_all('/\sAND\s|\sOR\s/i', $cond, $joints, PREG_OFFSET_CAPTURE)) { + $conditions = []; + $joints = $joints[0]; + array_unshift($joints, ['', 0]); + + for ($i = count($joints) - 1, $pos = strlen($cond); $i >= 0; $i--) { + $joints[$i][1] += strlen($joints[$i][0]); // offset + $conditions[$i] = substr($cond, $joints[$i][1], $pos - $joints[$i][1]); + $pos = $joints[$i][1] - strlen($joints[$i][0]); + $joints[$i] = $joints[$i][0]; + } + + ksort($conditions); + } else { + $conditions = [$cond]; + $joints = ['']; + } + + $cond = ' ON '; + + foreach ($conditions as $i => $condition) { + $operator = $this->getOperator($condition); + + $cond .= $joints[$i]; + $cond .= preg_match('/(\(*)?([\[\]\w\.\'-]+)' . preg_quote($operator, '/') . '(.*)/i', $condition, $match) ? $match[1] . $this->db->protectIdentifiers($match[2]) . $operator . $this->db->protectIdentifiers($match[3]) : $condition; + } + } // Do we want to escape the table name? if ($escape === true) { From 3cbb61772f1e48779e91abc478111f993f416c9f Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 28 Aug 2021 09:33:43 +0700 Subject: [PATCH 0141/2325] clean up rector.php config skip --- rector.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rector.php b/rector.php index 552c6341cb0b..77b014df2559 100644 --- a/rector.php +++ b/rector.php @@ -30,7 +30,6 @@ use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPromotedPropertyRector; -use Rector\DeadCode\Rector\If_\RemoveUnusedNonEmptyArrayBeforeForeachRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; @@ -100,11 +99,6 @@ UnderscoreToCamelCaseVariableNameRector::class => [ __DIR__ . '/system/Session/Handlers', ], - - // check on $_SESSION - RemoveUnusedNonEmptyArrayBeforeForeachRector::class => [ - __DIR__ . '/system/Debug/Toolbar.php', - ], ]); // auto import fully qualified class names From c79a2cb3d880d3fc34f01aeca1024e406101c28f Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 29 Aug 2021 18:27:16 +0800 Subject: [PATCH 0142/2325] Fix broken apt installation --- .github/workflows/test-phpunit.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 5dd68a65eac1..35dc86f8b4d1 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -107,6 +107,7 @@ jobs: run: | sudo apt-get install --reinstall libgs9-common fonts-noto-mono libgs9:amd64 libijs-0.35:amd64 fonts-urw-base35 ghostscript poppler-data libjbig2dec0:amd64 gsfonts libopenjp2-7:amd64 fonts-droid-fallback ttf-dejavu-core sudo apt-get install -y imagemagick + sudo apt-get install --fix-broken - name: Get composer cache directory id: composercache From a63061769fb350a316e42a0b36a063e0fa8da7c7 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Mon, 30 Aug 2021 22:53:31 +0800 Subject: [PATCH 0143/2325] Make File compatible with SplFileInfo (#5040) --- system/Files/File.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/system/Files/File.php b/system/Files/File.php index 132822043f33..40d1247e7541 100644 --- a/system/Files/File.php +++ b/system/Files/File.php @@ -14,6 +14,7 @@ use CodeIgniter\Files\Exceptions\FileException; use CodeIgniter\Files\Exceptions\FileNotFoundException; use Config\Mimes; +use ReturnTypeWillChange; use SplFileInfo; /** @@ -29,8 +30,6 @@ class File extends SplFileInfo protected $size; /** - * Original MimeType - * * @var string|null */ protected $originalMimeType; @@ -38,6 +37,8 @@ class File extends SplFileInfo /** * Run our SplFileInfo constructor with an optional verification * that the path is really a file. + * + * @throws FileNotFoundException */ public function __construct(string $path, bool $checkFile = false) { @@ -55,8 +56,9 @@ public function __construct(string $path, bool $checkFile = false) * the file in the $_FILES array if available, as PHP calculates this based * on the actual size transmitted. * - * @return int The file size in bytes + * @return false|int The file size in bytes, or false on failure */ + #[ReturnTypeWillChange] public function getSize() { return $this->size ?? ($this->size = parent::getSize()); @@ -65,7 +67,7 @@ public function getSize() /** * Retrieve the file size by unit. * - * @return int|string + * @return false|int|string */ public function getSizeByUnit(string $unit = 'b') { From ffcf115daf1c7263245d2ccdda5ce2895c54ceba Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Mon, 30 Aug 2021 22:55:10 +0800 Subject: [PATCH 0144/2325] Update documentation code samples (#5039) --- env | 2 +- user_guide_src/source/cli/cli_commands.rst | 11 +- user_guide_src/source/cli/cli_library.rst | 9 +- user_guide_src/source/cli/cli_request.rst | 2 +- .../source/database/configuration.rst | 50 +++--- user_guide_src/source/database/connecting.rst | 2 +- user_guide_src/source/database/examples.rst | 12 +- user_guide_src/source/database/metadata.rst | 34 ++-- user_guide_src/source/database/queries.rst | 70 ++++---- .../source/database/query_builder.rst | 21 ++- user_guide_src/source/database/results.rst | 62 +++---- .../source/database/transactions.rst | 13 +- user_guide_src/source/dbmgmt/forge.rst | 72 ++++----- user_guide_src/source/dbmgmt/migration.rst | 17 +- .../source/extending/core_classes.rst | 5 +- user_guide_src/source/extending/events.rst | 4 +- .../source/general/common_functions.rst | 16 +- user_guide_src/source/general/errors.rst | 16 +- user_guide_src/source/general/helpers.rst | 7 +- user_guide_src/source/general/logging.rst | 10 +- user_guide_src/source/general/modules.rst | 3 +- .../source/helpers/array_helper.rst | 8 +- .../source/helpers/cookie_helper.rst | 2 +- user_guide_src/source/helpers/date_helper.rst | 2 +- .../source/helpers/filesystem_helper.rst | 45 +++--- user_guide_src/source/helpers/form_helper.rst | 44 ++--- user_guide_src/source/helpers/html_helper.rst | 43 +++-- .../source/helpers/inflector_helper.rst | 4 +- user_guide_src/source/helpers/text_helper.rst | 14 +- user_guide_src/source/helpers/url_helper.rst | 30 ++-- user_guide_src/source/helpers/xml_helper.rst | 2 +- .../source/incoming/content_negotiation.rst | 4 +- .../source/incoming/controllers.rst | 26 ++- user_guide_src/source/incoming/filters.rst | 9 +- .../source/incoming/incomingrequest.rst | 64 ++++---- user_guide_src/source/incoming/message.rst | 2 +- user_guide_src/source/incoming/request.rst | 21 ++- user_guide_src/source/incoming/routing.rst | 42 ++--- .../installation/upgrade_configuration.rst | 30 ++-- .../installation/upgrade_migrations.rst | 24 +-- user_guide_src/source/libraries/caching.rst | 15 +- .../source/libraries/curlrequest.rst | 29 ++-- user_guide_src/source/libraries/email.rst | 28 ++-- user_guide_src/source/libraries/files.rst | 14 +- user_guide_src/source/libraries/honeypot.rst | 18 +-- user_guide_src/source/libraries/images.rst | 4 +- .../source/libraries/pagination.rst | 6 +- user_guide_src/source/libraries/security.rst | 14 +- user_guide_src/source/libraries/sessions.rst | 40 ++--- user_guide_src/source/libraries/throttler.rst | 18 +-- user_guide_src/source/libraries/time.rst | 152 +++++++++--------- .../source/libraries/typography.rst | 2 +- .../source/libraries/uploaded_files.rst | 15 +- user_guide_src/source/libraries/uri.rst | 7 +- .../source/libraries/user_agent.rst | 58 +++---- .../source/libraries/validation.rst | 103 ++++++------ user_guide_src/source/models/entities.rst | 35 ++-- user_guide_src/source/models/model.rst | 47 +++--- .../source/outgoing/api_responses.rst | 9 +- .../source/outgoing/localization.rst | 6 +- user_guide_src/source/outgoing/response.rst | 12 +- user_guide_src/source/outgoing/table.rst | 31 ++-- .../source/outgoing/view_parser.rst | 58 +++---- user_guide_src/source/outgoing/views.rst | 10 +- user_guide_src/source/testing/benchmark.rst | 18 +-- user_guide_src/source/testing/database.rst | 8 +- user_guide_src/source/testing/debugging.rst | 10 +- user_guide_src/source/testing/feature.rst | 22 ++- user_guide_src/source/testing/overview.rst | 4 +- user_guide_src/source/testing/response.rst | 8 +- user_guide_src/source/tutorial/conclusion.rst | 2 +- .../source/tutorial/create_news_items.rst | 19 +-- .../source/tutorial/news_section.rst | 5 +- .../source/tutorial/static_pages.rst | 3 +- 74 files changed, 762 insertions(+), 922 deletions(-) diff --git a/env b/env index 1106ce46f932..38eabf203988 100644 --- a/env +++ b/env @@ -26,7 +26,7 @@ # app.sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler' # app.sessionCookieName = 'ci_session' # app.sessionExpiration = 7200 -# app.sessionSavePath = NULL +# app.sessionSavePath = null # app.sessionMatchIP = false # app.sessionTimeToUpdate = 300 # app.sessionRegenerateDestroy = false diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 65e0f89209fc..6f0fe21ee4bd 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -187,12 +187,9 @@ be familiar with when creating your own commands. It also has a :doc:`Logger showError($e); } @@ -208,8 +205,8 @@ be familiar with when creating your own commands. It also has a :doc:`Logger $value array output. The padding can be used to output a will formatted table in CLI:: $pad = $this->getPad($this->options, 6); - foreach ($this->options as $option => $description) - { + + foreach ($this->options as $option => $description) { CLI::write($tab . CLI::color(str_pad($option, $pad), 'green') . $description, 'yellow'); } diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 1697c8409358..d7ddc0993015 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -119,8 +119,7 @@ Instead it prints it to the screen wherever the cursor is currently. This allows the same line, from different calls. This is especially helpful when you want to show a status, do something, then print "Done" on the same line:: - for ($i = 0; $i <= 10; $i++) - { + for ($i = 0; $i <= 10; $i++) { CLI::print($i); } @@ -172,8 +171,7 @@ every line after the first line, so that you will have a crisp column edge on th // to determine the width of the left column $maxlen = max(array_map('strlen', $titles)); - for ($i=0; $i < count($titles); $i++) - { + for ($i = 0; $i < count($titles); $i++) { CLI::write( // Display the title on the left of the row $titles[$i] . ' ' . @@ -227,8 +225,7 @@ pass ``false`` as the first parameter and the progress bar will be removed. $totalSteps = count($tasks); $currStep = 1; - foreach ($tasks as $task) - { + foreach ($tasks as $task) { CLI::showProgress($currStep++, $totalSteps); $task->run(); } diff --git a/user_guide_src/source/cli/cli_request.rst b/user_guide_src/source/cli/cli_request.rst index 6932294aa2e0..0fa29f2735ab 100644 --- a/user_guide_src/source/cli/cli_request.rst +++ b/user_guide_src/source/cli/cli_request.rst @@ -37,7 +37,7 @@ Returns the value of a specific command line argument deemed to be an option:: // command line: php index.php users 21 profile --foo bar echo $request->getOption('foo'); // bar - echo $request->getOption('notthere'); // NULL + echo $request->getOption('notthere'); // null **getOptionString()** diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index 38be6c16efa5..53b2c3f932b0 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -22,14 +22,14 @@ prototype:: 'database' => 'database_name', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', - 'pConnect' => TRUE, - 'DBDebug' => TRUE, + 'pConnect' => true, + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', - 'encrypt' => FALSE, - 'compress' => FALSE, - 'strictOn' => FALSE, + 'encrypt' => false, + 'compress' => false, + 'strictOn' => false, 'failover' => [], ]; @@ -80,14 +80,14 @@ These failovers can be specified by setting the failover for a connection like t 'database' => '', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', - 'pConnect' => TRUE, - 'DBDebug' => TRUE, + 'pConnect' => true, + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', - 'encrypt' => FALSE, - 'compress' => FALSE, - 'strictOn' => FALSE + 'encrypt' => false, + 'compress' => false, + 'strictOn' => false, ], [ 'hostname' => 'localhost2', @@ -96,14 +96,14 @@ These failovers can be specified by setting the failover for a connection like t 'database' => '', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', - 'pConnect' => TRUE, - 'DBDebug' => TRUE, + 'pConnect' => true, + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', - 'encrypt' => FALSE, - 'compress' => FALSE, - 'strictOn' => FALSE + 'encrypt' => false, + 'compress' => false, + 'strictOn' => false, ] ]; @@ -123,14 +123,14 @@ example, to set up a "test" environment you would do this:: 'database' => 'database_name', 'DBDriver' => 'MySQLi', 'DBPrefix' => '', - 'pConnect' => TRUE, - 'DBDebug' => TRUE, + 'pConnect' => true, + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', - 'compress' => FALSE, - 'encrypt' => FALSE, - 'strictOn' => FALSE, + 'compress' => false, + 'encrypt' => false, + 'strictOn' => false, 'failover' => [] ); @@ -188,8 +188,8 @@ Explanation of Values: **DBPrefix** An optional table prefix which will added to the table name when running :doc:`Query Builder ` queries. This permits multiple CodeIgniter installations to share one database. -**pConnect** TRUE/FALSE (boolean) - Whether to use a persistent connection. -**DBDebug** TRUE/FALSE (boolean) - Whether database errors should be displayed. +**pConnect** true/false (boolean) - Whether to use a persistent connection. +**DBDebug** true/false (boolean) - Whether database errors should be displayed. **charset** The character set used in communicating with the database. **DBCollat** The character collation used in communicating with the database @@ -201,7 +201,7 @@ Explanation of Values: **schema** The database schema, default value varies by driver. Used by PostgreSQL and SQLSRV drivers. **encrypt** Whether or not to use an encrypted connection. - - 'sqlsrv' and 'pdo/sqlsrv' drivers accept TRUE/FALSE + - 'sqlsrv' and 'pdo/sqlsrv' drivers accept true/false - 'MySQLi' and 'pdo/mysql' drivers accept an array with the following options: - 'ssl_key' - Path to the private key file @@ -209,10 +209,10 @@ Explanation of Values: - 'ssl_ca' - Path to the certificate authority file - 'ssl_capath' - Path to a directory containing trusted CA certificates in PEM format - 'ssl_cipher' - List of *allowed* ciphers to be used for the encryption, separated by colons (':') - - 'ssl_verify' - TRUE/FALSE; Whether to verify the server certificate or not ('MySQLi' only) + - 'ssl_verify' - true/false; Whether to verify the server certificate or not ('MySQLi' only) **compress** Whether or not to use client compression (MySQL only). -**strictOn** TRUE/FALSE (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL +**strictOn** true/false (boolean) - Whether to force "Strict Mode" connections, good for ensuring strict SQL while developing an application. **port** The database port number. To use this value you have to add a line to the database config array. :: diff --git a/user_guide_src/source/database/connecting.rst b/user_guide_src/source/database/connecting.rst index 994f6537766c..65a3ed086d27 100644 --- a/user_guide_src/source/database/connecting.rst +++ b/user_guide_src/source/database/connecting.rst @@ -27,7 +27,7 @@ Available Parameters -------------------- #. The database group name, a string that must match the config class' property name. Default value is ``$config->defaultGroup``. -#. TRUE/FALSE (boolean). Whether to return the shared connection (see +#. true/false (boolean). Whether to return the shared connection (see Connecting to Multiple Databases below). Manually Connecting to a Database diff --git a/user_guide_src/source/database/examples.rst b/user_guide_src/source/database/examples.rst index 84358ac9963d..de41c39f1366 100644 --- a/user_guide_src/source/database/examples.rst +++ b/user_guide_src/source/database/examples.rst @@ -28,11 +28,10 @@ Standard Query With Multiple Results (Object Version) :: - $query = $db->query('SELECT name, title, email FROM my_table'); + $query = $db->query('SELECT name, title, email FROM my_table'); $results = $query->getResult(); - foreach ($results as $row) - { + foreach ($results as $row) { echo $row->title; echo $row->name; echo $row->email; @@ -51,8 +50,7 @@ Standard Query With Multiple Results (Array Version) $query = $db->query('SELECT name, title, email FROM my_table'); $results = $query->getResultArray(); - foreach ($results as $row) - { + foreach ($results as $row) { echo $row['title']; echo $row['name']; echo $row['email']; @@ -102,8 +100,7 @@ means of retrieving data:: $query = $db->table('table_name')->get(); - foreach ($query->getResult() as $row) - { + foreach ($query->getResult() as $row) { echo $row->title; } @@ -124,4 +121,3 @@ Query Builder Insert $db->table('mytable')->insert($data); // Produces: INSERT INTO mytable (title, name, date) VALUES ('{$title}', '{$name}', '{$date}') - diff --git a/user_guide_src/source/database/metadata.rst b/user_guide_src/source/database/metadata.rst index 60439f9d1a81..fd19a1aa35b5 100644 --- a/user_guide_src/source/database/metadata.rst +++ b/user_guide_src/source/database/metadata.rst @@ -22,8 +22,7 @@ you are currently connected to. Example:: $tables = $db->listTables(); - foreach ($tables as $table) - { + foreach ($tables as $table) { echo $table; } @@ -35,10 +34,9 @@ Determine If a Table Exists **$db->tableExists();** Sometimes it's helpful to know whether a particular table exists before -running an operation on it. Returns a boolean TRUE/FALSE. Usage example:: +running an operation on it. Returns a boolean true/false. Usage example:: - if ($db->tableExists('table_name')) - { + if ($db->tableExists('table_name')) { // some code... } @@ -60,8 +58,7 @@ two ways: $fields = $db->getFieldNames('table_name'); - foreach ($fields as $field) - { + foreach ($fields as $field) { echo $field; } @@ -70,8 +67,7 @@ calling the function from your query result object:: $query = $db->query('SELECT * FROM some_table'); - foreach ($query->getFieldNames() as $field) - { + foreach ($query->getFieldNames() as $field) { echo $field; } @@ -81,10 +77,9 @@ Determine If a Field is Present in a Table **$db->fieldExists()** Sometimes it's helpful to know whether a particular field exists before -performing an action. Returns a boolean TRUE/FALSE. Usage example:: +performing an action. Returns a boolean true/false. Usage example:: - if ($db->fieldExists('field_name', 'table_name')) - { + if ($db->fieldExists('field_name', 'table_name')) { // some code... } @@ -108,8 +103,7 @@ Usage example:: $fields = $db->getFieldData('table_name'); - foreach ($fields as $field) - { + foreach ($fields as $field) { echo $field->name; echo $field->type; echo $field->max_length; @@ -141,11 +135,10 @@ Usage example:: $keys = $db->getIndexData('table_name'); - foreach ($keys as $key) - { - echo $key->name; - echo $key->type; - echo $key->fields; // array of field names + foreach ($keys as $key) { + echo $key->name; + echo $key->type; + echo $key->fields; // array of field names } The key types may be unique to the database you are using. @@ -160,8 +153,7 @@ Usage example:: $keys = $db->getForeignKeyData('table_name'); - foreach ($keys as $key) - { + foreach ($keys as $key) { echo $key->constraint_name; echo $key->table_name; echo $key->column_name; diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst index 93a54f01d861..366b264cc45c 100644 --- a/user_guide_src/source/database/queries.rst +++ b/user_guide_src/source/database/queries.rst @@ -20,7 +20,7 @@ To submit a query, use the **query** function:: The ``query()`` function returns a database result **object** when "read" type queries are run which you can use to :doc:`show your results `. When "write" type queries are run it simply -returns TRUE or FALSE depending on success or failure. When retrieving +returns true or false depending on success or failure. When retrieving data you will typically assign the query to your own variable, like this:: @@ -36,19 +36,16 @@ compile bind data, or store your query for debugging. It simply lets you submit a query. Most users will rarely use this function. It returns whatever the database drivers "execute" function returns. -That typically is TRUE/FALSE on success or failure for write type queries +That typically is true/false on success or failure for write type queries such as INSERT, DELETE or UPDATE statements (which is what it really should be used for) and a resource/object on success for queries with fetchable results. :: - if ($db->simpleQuery('YOUR QUERY')) - { + if ($db->simpleQuery('YOUR QUERY')) { echo "Success!"; - } - else - { + } else { echo "Query failed!"; } @@ -94,9 +91,9 @@ identifier you can use:: This function will also add a table prefix to your table, assuming you have a prefix specified in your database config file. To enable the -prefixing set TRUE (boolean) via the second parameter:: +prefixing set true (boolean) via the second parameter:: - $db->protectIdentifiers('table_name', TRUE); + $db->protectIdentifiers('table_name', true); **************** Escaping Queries @@ -173,7 +170,7 @@ placeholders in the query:: $db->query($sql, [ 'id' => 3, 'status' => 'live', - 'name' => 'Rick' + 'name' => 'Rick', ]); .. note:: Each name in the query MUST be surrounded by colons. @@ -188,8 +185,7 @@ If you need to get the last error that has occurred, the ``error()`` method will return an array containing its code and message. Here's a quick example:: - if ( ! $db->simpleQuery('SELECT `example_field` FROM `example_table`')) - { + if ( ! $db->simpleQuery('SELECT `example_field` FROM `example_table`')) { $error = $db->error(); // Has keys 'code' and 'message' } @@ -214,14 +210,12 @@ a query object. Query objects are automatically generated by any of the "final" run a query. The query is not actually run, and the values don't matter since they're never applied, acting instead as placeholders. This returns a PreparedQuery object:: - $pQuery = $db->prepare(function($db) - { - return $db->table('user') - ->insert([ - 'name' => 'x', - 'email' => 'y', - 'country' => 'US' - ]); + $pQuery = $db->prepare(function ($db) { + return $db->table('user')->insert([ + 'name' => 'x', + 'email' => 'y', + 'country' => 'US' + ]); }); If you don't want to use the Query Builder you can create the Query object manually using question marks for @@ -229,8 +223,7 @@ value placeholders:: use CodeIgniter\Database\Query; - $pQuery = $db->prepare(function($db) - { + $pQuery = $db->prepare(function ($db) { $sql = "INSERT INTO user (name, email, country) VALUES (?, ?, ?)"; return (new Query($db))->setQuery($sql); @@ -241,8 +234,7 @@ array through in the second parameter:: use CodeIgniter\Database\Query; - $pQuery = $db->prepare(function($db) - { + $pQuery = $db->prepare(function ($db) { $sql = "INSERT INTO user (name, email, country) VALUES (?, ?, ?)"; return (new Query($db))->setQuery($sql); @@ -257,14 +249,12 @@ placeholders in the query. They must also be passed in the same order as the pla query:: // Prepare the Query - $pQuery = $db->prepare(function($db) - { - return $db->table('user') - ->insert([ - 'name' => 'x', - 'email' => 'y', - 'country' => 'US' - ]); + $pQuery = $db->prepare(function ($db) { + return $db->table('user')->insert([ + 'name' => 'x', + 'email' => 'y', + 'country' => 'US' + ]); }); // Collect the Data @@ -307,7 +297,7 @@ Working with Query Objects ************************** Internally, all queries are processed and stored as instances of -\CodeIgniter\Database\Query. This class is responsible for binding +``CodeIgniter\Database\Query``. This class is responsible for binding the parameters, otherwise preparing the query, and storing performance data about its query. @@ -317,7 +307,7 @@ When you just need to retrieve the last Query object, use the getLastQuery() method:: $query = $db->getLastQuery(); - echo (string)$query; + echo (string) $query; The Query Class =============== @@ -335,7 +325,7 @@ query that was sent to the database:: This same value can be retrieved by casting the Query object to a string:: - $sql = (string)$query; + $sql = (string) $query; **getOriginalQuery()** @@ -349,10 +339,9 @@ binds in it, or prefixes swapped out, etc:: If an error was encountered during the execution of this query this method will return true:: - if ($query->hasError()) - { - echo 'Code: '. $query->getErrorCode(); - echo 'Error: '. $query->getErrorMessage(); + if ($query->hasError()) { + echo 'Code: ' . $query->getErrorCode(); + echo 'Error: ' . $query->getErrorMessage(); } **isWriteType()** @@ -360,8 +349,7 @@ will return true:: Returns true if the query was determined to be a write-type query (i.e., INSERT, UPDATE, DELETE, etc):: - if ($query->isWriteType()) - { + if ($query->isWriteType()) { // ... do something } diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 62e3aa29b0c9..78c1b3731fd5 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -60,8 +60,7 @@ $query, which can be used to show the results:: $query = $builder->get(); - foreach ($query->getResult() as $row) - { + foreach ($query->getResult() as $row) { echo $row->title; } @@ -310,7 +309,7 @@ methods: :: - $builder->where('advance_amount <', function(BaseBuilder $builder) { + $builder->where('advance_amount <', function (BaseBuilder $builder) { return $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); }); // Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) @@ -341,7 +340,7 @@ You can use subqueries instead of an array of values. :: - $builder->whereIn('id', function(BaseBuilder $builder) { + $builder->whereIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); // Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) @@ -361,7 +360,7 @@ You can use subqueries instead of an array of values. :: - $builder->orWhereIn('id', function(BaseBuilder $builder) { + $builder->orWhereIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); @@ -382,7 +381,7 @@ You can use subqueries instead of an array of values. :: - $builder->whereNotIn('id', function(BaseBuilder $builder) { + $builder->whereNotIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); @@ -404,7 +403,7 @@ You can use subqueries instead of an array of values. :: - $builder->orWhereNotIn('id', function(BaseBuilder $builder) { + $builder->orWhereNotIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); @@ -545,7 +544,7 @@ You can use subqueries instead of an array of values. :: - $builder->havingIn('id', function(BaseBuilder $builder) { + $builder->havingIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); // Produces: HAVING "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) @@ -565,7 +564,7 @@ You can use subqueries instead of an array of values. :: - $builder->orHavingIn('id', function(BaseBuilder $builder) { + $builder->orHavingIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); @@ -586,7 +585,7 @@ You can use subqueries instead of an array of values. :: - $builder->havingNotIn('id', function(BaseBuilder $builder) { + $builder->havingNotIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); @@ -608,7 +607,7 @@ You can use subqueries instead of an array of values. :: - $builder->orHavingNotIn('id', function(BaseBuilder $builder) { + $builder->orHavingNotIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst index 79445da9e529..e3e573d5c460 100644 --- a/user_guide_src/source/database/results.rst +++ b/user_guide_src/source/database/results.rst @@ -20,8 +20,7 @@ loop, like this:: $query = $db->query("YOUR QUERY"); - foreach ($query->getResult() as $row) - { + foreach ($query->getResult() as $row) { echo $row->title; echo $row->name; echo $row->body; @@ -34,8 +33,7 @@ as an array of arrays:: $query = $db->query("YOUR QUERY"); - foreach ($query->getResult('array') as $row) - { + foreach ($query->getResult('array') as $row) { echo $row['title']; echo $row['name']; echo $row['body']; @@ -50,8 +48,7 @@ instantiate for each result object $query = $db->query("SELECT * FROM users;"); - foreach ($query->getResult('User') as $user) - { + foreach ($query->getResult('User') as $user) { echo $user->name; // access attributes echo $user->reverseName(); // or methods defined on the 'User' class } @@ -66,8 +63,7 @@ loop, like this:: $query = $db->query("YOUR QUERY"); - foreach ($query->getResultArray() as $row) - { + foreach ($query->getResultArray() as $row) { echo $row['title']; echo $row['name']; echo $row['body']; @@ -87,8 +83,7 @@ one row, it returns only the first row. The result is returned as an $row = $query->getRow(); - if (isset($row)) - { + if (isset($row)) { echo $row->title; echo $row->name; echo $row->body; @@ -117,8 +112,7 @@ Example:: $row = $query->getRowArray(); - if (isset($row)) - { + if (isset($row)) { echo $row['title']; echo $row['name']; echo $row['body']; @@ -159,8 +153,7 @@ it returns the current row and moves the internal data pointer ahead. $query = $db->query("YOUR QUERY"); - while ($row = $query->getUnbufferedRow()) - { + while ($row = $query->getUnbufferedRow()) { echo $row->title; echo $row->name; echo $row->body; @@ -201,16 +194,14 @@ Example:: public function __set($name, $value) { - if ($name === 'lastLogin') - { + if ($name === 'lastLogin') { $this->lastLogin = DateTime::createFromFormat('U', $value); } } public function __get($name) { - if (isset($this->$name)) - { + if (isset($this->$name)) { return $this->$name; } } @@ -231,8 +222,7 @@ Example:: $rows = $query->getCustomResultObject('User'); - foreach ($rows as $row) - { + foreach ($rows as $row) { echo $row->id; echo $row->email; echo $row->last_login('Y-m-d'); @@ -249,8 +239,7 @@ Example:: $row = $query->getCustomRowObject(0, 'User'); - if (isset($row)) - { + if (isset($row)) { echo $row->email; // access attributes echo $row->last_login('Y-m-d'); // access class methods } @@ -308,8 +297,7 @@ Example:: $query = $thisdb->query('SELECT title FROM my_table'); - foreach ($query->getResult() as $row) - { + foreach ($query->getResult() as $row) { echo $row->title; } @@ -327,7 +315,7 @@ This method sets the internal pointer for the next result row to be fetched. It is only useful in combination with ``getUnbufferedRow()``. It accepts a positive integer value, which defaults to 0 and returns -TRUE on success or FALSE on failure. +true on success or false on failure. :: @@ -335,7 +323,7 @@ TRUE on success or FALSE on failure. $query->dataSeek(5); // Skip the first 5 rows $row = $query->getUnbufferedRow(); -.. note:: Not all database drivers support this feature and will return FALSE. +.. note:: Not all database drivers support this feature and will return false. Most notably - you won't be able to use it with PDO. *************** @@ -388,7 +376,7 @@ Class Reference :param int $n: Index of the query results row to be returned :param string $type: Type of the requested result - array, object, or class name - :returns: The requested row or NULL if it doesn't exist + :returns: The requested row or null if it doesn't exist :rtype: mixed A wrapper for the ``getRowArray()``, ``getRowObject()`` and @@ -399,7 +387,7 @@ Class Reference .. php:method:: getUnbufferedRow([$type = 'object']) :param string $type: Type of the requested result - array, object, or class name - :returns: Next row from the result set or NULL if it doesn't exist + :returns: Next row from the result set or null if it doesn't exist :rtype: mixed Fetches the next result row and returns it in the @@ -410,7 +398,7 @@ Class Reference .. php:method:: getRowArray([$n = 0]) :param int $n: Index of the query results row to be returned - :returns: The requested row or NULL if it doesn't exist + :returns: The requested row or null if it doesn't exist :rtype: array Returns the requested result row as an associative array. @@ -420,7 +408,7 @@ Class Reference .. php:method:: getRowObject([$n = 0]) :param int $n: Index of the query results row to be returned - :returns: The requested row or NULL if it doesn't exist + :returns: The requested row or null if it doesn't exist :rtype: stdClass Returns the requested result row as an object of type @@ -432,7 +420,7 @@ Class Reference :param int $n: Index of the results row to return :param string $class_name: Class name for the resulting row - :returns: The requested row or NULL if it doesn't exist + :returns: The requested row or null if it doesn't exist :rtype: $type Returns the requested result row as an instance of the @@ -441,14 +429,14 @@ Class Reference .. php:method:: dataSeek([$n = 0]) :param int $n: Index of the results row to be returned next - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool Moves the internal results row pointer to the desired offset. Usage: see `Result Helper Methods`_. - .. php:method:: setRow($key[, $value = NULL]) + .. php:method:: setRow($key[, $value = null]) :param mixed $key: Column name or array of key/value pairs :param mixed $value: Value to assign to the column, $key is a single field name @@ -459,7 +447,7 @@ Class Reference .. php:method:: getNextRow([$type = 'object']) :param string $type: Type of the requested result - array, object, or class name - :returns: Next row of result set, or NULL if it doesn't exist + :returns: Next row of result set, or null if it doesn't exist :rtype: mixed Returns the next row from the result set. @@ -467,7 +455,7 @@ Class Reference .. php:method:: getPreviousRow([$type = 'object']) :param string $type: Type of the requested result - array, object, or class name - :returns: Previous row of result set, or NULL if it doesn't exist + :returns: Previous row of result set, or null if it doesn't exist :rtype: mixed Returns the previous row from the result set. @@ -475,7 +463,7 @@ Class Reference .. php:method:: getFirstRow([$type = 'object']) :param string $type: Type of the requested result - array, object, or class name - :returns: First row of result set, or NULL if it doesn't exist + :returns: First row of result set, or null if it doesn't exist :rtype: mixed Returns the first row from the result set. @@ -483,7 +471,7 @@ Class Reference .. php:method:: getLastRow([$type = 'object']) :param string $type: Type of the requested result - array, object, or class name - :returns: Last row of result set, or NULL if it doesn't exist + :returns: Last row of result set, or null if it doesn't exist :rtype: mixed Returns the last row from the result set. diff --git a/user_guide_src/source/database/transactions.rst b/user_guide_src/source/database/transactions.rst index 014b1f4ce8e5..a3c8ba9f9866 100644 --- a/user_guide_src/source/database/transactions.rst +++ b/user_guide_src/source/database/transactions.rst @@ -74,8 +74,7 @@ debugging is turned off, you can manage your own errors like this:: $this->db->query('ANOTHER QUERY...'); $this->db->transComplete(); - if ($this->db->transStatus() === FALSE) - { + if ($this->db->transStatus() === false) { // generate an error... or use the log_message() function to log your error } @@ -86,7 +85,6 @@ Transactions are enabled by default. If you would like to disable transactions y can do so using ``$this->db->transOff()``:: $this->db->transOff(); - $this->db->transStart(); $this->db->query('AN SQL QUERY...'); $this->db->transComplete(); @@ -100,7 +98,7 @@ Test Mode You can optionally put the transaction system into "test mode", which will cause your queries to be rolled back -- even if the queries produce a valid result. To use test mode simply set the first parameter in the -``$this->db->transStart()`` function to TRUE:: +``$this->db->transStart()`` function to true:: $this->db->transStart(true); // Query will be rolled back $this->db->query('AN SQL QUERY...'); @@ -117,12 +115,9 @@ If you would like to run transactions manually you can do so as follows:: $this->db->query('ANOTHER QUERY...'); $this->db->query('AND YET ANOTHER QUERY...'); - if ($this->db->transStatus() === FALSE) - { + if ($this->db->transStatus() === false) { $this->db->transRollback(); - } - else - { + } else { $this->db->transCommit(); } diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index 13ee31402ef6..aba92fc634b2 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -34,29 +34,27 @@ Creating and Dropping Databases **$forge->createDatabase('db_name')** Permits you to create the database specified in the first parameter. -Returns TRUE/FALSE based on success or failure:: +Returns true/false based on success or failure:: - if ($forge->createDatabase('my_db')) - { + if ($forge->createDatabase('my_db')) { echo 'Database created!'; } -An optional second parameter set to TRUE will add IF EXISTS statement +An optional second parameter set to true will add IF EXISTS statement or will check if a database exists before create it (depending on DBMS). :: - $forge->createDatabase('my_db', TRUE); + $forge->createDatabase('my_db', true); // gives CREATE DATABASE IF NOT EXISTS my_db // or will check if a database exists **$forge->dropDatabase('db_name')** Permits you to drop the database specified in the first parameter. -Returns TRUE/FALSE based on success or failure:: +Returns true/false based on success or failure:: - if ($forge->dropDatabase('my_db')) - { + if ($forge->dropDatabase('my_db')) { echo 'Database deleted!'; } @@ -115,8 +113,8 @@ Additionally, the following key/values can be used: - unsigned/true : to generate "UNSIGNED" in the field definition. - default/value : to generate a default value in the field definition. -- null/true : to generate "NULL" in the field definition. Without this, - the field will default to "NOT NULL". +- null/true : to generate "null" in the field definition. Without this, + the field will default to "NOT null". - auto_increment/true : generates an auto_increment flag on the field. Note that the field type must be a type that supports this, such as integer. @@ -191,8 +189,8 @@ Adding Keys Generally speaking, you'll want your table to have Keys. This is accomplished with $forge->addKey('field'). The optional second -parameter set to TRUE will make it a primary key and the third -parameter set to TRUE will make it a unique key. Note that addKey() +parameter set to true will make it a primary key and the third +parameter set to true will make it a unique key. Note that addKey() must be followed by a call to createTable(). Multiple column non-primary keys must be sent as an array. Sample output @@ -200,11 +198,11 @@ below is for MySQL. :: - $forge->addKey('blog_id', TRUE); + $forge->addKey('blog_id', true); // gives PRIMARY KEY `blog_id` (`blog_id`) - $forge->addKey('blog_id', TRUE); - $forge->addKey('site_id', TRUE); + $forge->addKey('blog_id', true); + $forge->addKey('site_id', true); // gives PRIMARY KEY `blog_id_site_id` (`blog_id`, `site_id`) $forge->addKey('blog_name'); @@ -213,7 +211,7 @@ below is for MySQL. $forge->addKey(['blog_name', 'blog_label']); // gives KEY `blog_name_blog_label` (`blog_name`, `blog_label`) - $forge->addKey(['blog_id', 'uri'], FALSE, TRUE); + $forge->addKey(['blog_id', 'uri'], false, true); // gives UNIQUE KEY `blog_id_uri` (`blog_id`, `uri`) To make code reading more objective it is also possible to add primary @@ -251,18 +249,18 @@ with $forge->createTable('table_name'); // gives CREATE TABLE table_name -An optional second parameter set to TRUE adds an "IF NOT EXISTS" clause +An optional second parameter set to true adds an "IF NOT EXISTS" clause into the definition :: - $forge->createTable('table_name', TRUE); + $forge->createTable('table_name', true); // gives CREATE TABLE IF NOT EXISTS table_name You could also pass optional table attributes, such as MySQL's ``ENGINE``:: $attributes = ['ENGINE' => 'InnoDB']; - $forge->createTable('table_name', FALSE, $attributes); + $forge->createTable('table_name', false, $attributes); // produces: CREATE TABLE `table_name` (...) ENGINE = InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci .. note:: Unless you specify the ``CHARACTER SET`` and/or ``COLLATE`` attributes, @@ -343,7 +341,7 @@ Examples:: // Will place the new column at the start of the table definition: $fields = [ - 'preferences' => ['type' => 'TEXT', 'first' => TRUE] + 'preferences' => ['type' => 'TEXT', 'first' => true] ]; Dropping Columns From a Table @@ -394,7 +392,7 @@ Class Reference :param string $table: Table name to add the column to :param array $field: Column definition(s) - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool Adds a column to a table. Usage: See `Adding a Column to a Table`_. @@ -407,11 +405,11 @@ Class Reference Adds a field to the set that will be used to create a table. Usage: See `Adding fields`_. - .. php:method:: addKey($key[, $primary = FALSE[, $unique = FALSE]]) + .. php:method:: addKey($key[, $primary = false[, $unique = false]]) :param mixed $key: Name of a key field or an array of fields - :param bool $primary: Set to TRUE if it should be a primary key or a regular one - :param bool $unique: Set to TRUE if it should be a unique key or a regular one + :param bool $primary: Set to true if it should be a primary key or a regular one + :param bool $unique: Set to true if it should be a unique key or a regular one :returns: \CodeIgniter\Database\Forge instance (method chaining) :rtype: \CodeIgniter\Database\Forge @@ -433,21 +431,21 @@ Class Reference Adds a unique key to the set that will be used to create a table. Usage: See `Adding Keys`_. - .. php:method:: createDatabase($dbName[, $ifNotExists = FALSE]) + .. php:method:: createDatabase($dbName[, $ifNotExists = false]) :param string $db_name: Name of the database to create - :param string $ifNotExists: Set to TRUE to add an 'IF NOT EXISTS' clause or check if database exists - :returns: TRUE on success, FALSE on failure + :param string $ifNotExists: Set to true to add an 'IF NOT EXISTS' clause or check if database exists + :returns: true on success, false on failure :rtype: bool Creates a new database. Usage: See `Creating and Dropping Databases`_. - .. php:method:: createTable($table[, $if_not_exists = FALSE[, array $attributes = []]]) + .. php:method:: createTable($table[, $if_not_exists = false[, array $attributes = []]]) :param string $table: Name of the table to create - :param string $if_not_exists: Set to TRUE to add an 'IF NOT EXISTS' clause + :param string $if_not_exists: Set to true to add an 'IF NOT EXISTS' clause :param string $attributes: An associative array of table attributes - :returns: Query object on success, FALSE on failure + :returns: Query object on success, false on failure :rtype: mixed Creates a new table. Usage: See `Creating a table`_. @@ -456,7 +454,7 @@ Class Reference :param string $table: Table name :param mixed $column_names: Comma-delimited string or an array of column names - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool Drops single or multiple columns from a table. Usage: See `Dropping Columns From a Table`_. @@ -464,16 +462,16 @@ Class Reference .. php:method:: dropDatabase($dbName) :param string $dbName: Name of the database to drop - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool Drops a database. Usage: See `Creating and Dropping Databases`_. - .. php:method:: dropTable($table_name[, $if_exists = FALSE]) + .. php:method:: dropTable($table_name[, $if_exists = false]) :param string $table: Name of the table to drop - :param string $if_exists: Set to TRUE to add an 'IF EXISTS' clause - :returns: TRUE on success, FALSE on failure + :param string $if_exists: Set to true to add an 'IF EXISTS' clause + :returns: true on success, false on failure :rtype: bool Drops a table. Usage: See `Dropping a table`_. @@ -482,7 +480,7 @@ Class Reference :param string $table: Table name :param array $field: Column definition(s) - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool Modifies a table column. Usage: See `Modifying a Column in a Table`_. @@ -491,7 +489,7 @@ Class Reference :param string $table: Current of the table :param string $new_table_name: New name of the table - :returns: Query object on success, FALSE on failure + :returns: Query object on success, false on failure :rtype: mixed Renames a table. Usage: See `Renaming a table`_. diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 031c01992e9c..9da3e2d3e9b3 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -174,12 +174,9 @@ to update the schema:: { $migrate = \Config\Services::migrations(); - try - { + try { $migrate->latest(); - } - catch (\Throwable $e) - { + } catch (\Throwable $e) { // Do something with the error here... } } @@ -321,8 +318,8 @@ Class Reference :returns: ``true`` on success, ``false`` on failure :rtype: bool - This forces a single file to migrate regardless of order or batches. Method "up" or "down" is detected based on whether it has already been migrated. - + This forces a single file to migrate regardless of order or batches. Method "up" or "down" is detected based on whether it has already been migrated. + .. note:: This method is recommended only for testing and could cause data consistency issues. .. php:method:: setNamespace($namespace) @@ -333,8 +330,7 @@ Class Reference Sets the namespace the library should look for migration files:: - $migration->setNamespace($namespace) - ->latest(); + $migration->setNamespace($namespace)->latest(); .. php:method:: setGroup($group) :param string $group: database group name. @@ -343,5 +339,4 @@ Class Reference Sets the group the library should look for migration files:: - $migration->setGroup($group) - ->latest(); + $migration->setGroup($group)->latest(); diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index 6f9a83d9d28c..6d7b0c9a3b64 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -64,8 +64,7 @@ Then you would modify the ``routes`` service to load your class instead:: public static function routes(bool $getShared = true) { - if ($getShared) - { + if ($getShared) { return static::getSharedInstance('routes'); } @@ -107,6 +106,8 @@ If you need to use a constructor in your class make sure you extend the parent c public function __construct() { parent::__construct(); + + // your code here } } diff --git a/user_guide_src/source/extending/events.rst b/user_guide_src/source/extending/events.rst index 1ee0e0150b94..f2190ee55473 100644 --- a/user_guide_src/source/extending/events.rst +++ b/user_guide_src/source/extending/events.rst @@ -42,7 +42,7 @@ In this example, whenever the **pre_controller** event is executed, an instance Events::on('pre_system', 'SomeClass::someMethod'); // Use a Closure - Events::on('pre_system', function(...$params) + Events::on('pre_system', function (...$params) { . . . }); @@ -81,7 +81,7 @@ given the arguments in the same order as defined:: \CodeIgniter\Events\Events::trigger('some_events', $foo, $bar, $baz); - Events::on('some_event', function($foo, $bar, $baz) { + Events::on('some_event', function ($foo, $bar, $baz) { ... }); diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index 5bbf71fccdea..8d006197bcfe 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -268,18 +268,18 @@ Miscellaneous Functions .. php:function:: function_usable ( $function_name ) :param string $function_name: Function to check for - :returns: TRUE if the function exists and is safe to call, FALSE otherwise. + :returns: true if the function exists and is safe to call, false otherwise. :rtype: bool .. php:function:: is_cli () - :returns: TRUE if the script is being executed from the command line or FALSE otherwise. + :returns: true if the script is being executed from the command line or false otherwise. :rtype: bool .. php:function:: is_really_writable ( $file ) :param string $file: The filename being checked. - :returns: TRUE if you can write to the file, FALSE otherwise. + :returns: true if you can write to the file, false otherwise. :rtype: bool .. php:function:: log_message ($level, $message [, $context]) @@ -287,7 +287,7 @@ Miscellaneous Functions :param string $level: The level of severity :param string $message: The message that is to be logged. :param array $context: An associative array of tags and their values that should be replaced in $message - :returns: TRUE if was logged successfully or FALSE if there was a problem logging it + :returns: true if was logged successfully or false if there was a problem logging it :rtype: bool Logs a message using the Log Handlers defined in **app/Config/Logger.php**. @@ -331,14 +331,14 @@ Miscellaneous Functions // Go to a named/reverse-routed URI return redirect('named_route'); -.. php:function:: remove_invisible_characters($str[, $urlEncoded = TRUE]) +.. php:function:: remove_invisible_characters($str[, $urlEncoded = true]) :param string $str: Input string :param bool $urlEncoded: Whether to remove URL-encoded characters as well :returns: Sanitized string :rtype: string - This function prevents inserting NULL characters between ASCII + This function prevents inserting null characters between ASCII characters, like Java\\0script. Example:: @@ -386,7 +386,7 @@ Miscellaneous Functions .. php:function:: slash_item ( $item ) :param string $item: Config item name - :returns: The configuration item or NULL if the item doesn't exist + :returns: The configuration item or null if the item doesn't exist :rtype: string|null Fetch a config file item with slash appended (if not empty) @@ -394,7 +394,7 @@ Miscellaneous Functions .. php:function:: stringify_attributes ( $attributes [, $js] ) :param mixed $attributes: string, array of key value pairs, or object - :param boolean $js: TRUE if values do not need quotes (Javascript-style) + :param boolean $js: true if values do not need quotes (Javascript-style) :returns: String containing the attribute key/value pairs, comma-separated :rtype: string diff --git a/user_guide_src/source/general/errors.rst b/user_guide_src/source/general/errors.rst index b02dce2d77d4..410e58236a8d 100644 --- a/user_guide_src/source/general/errors.rst +++ b/user_guide_src/source/general/errors.rst @@ -24,12 +24,9 @@ execution is then sent to the error handler which displays the appropriate error If you are calling a method that might throw an exception, you can catch that exception using a ``try/catch`` block:: - try - { + try { $user = $userModel->find($id); - } - catch (\Exception $e) - { + } catch (\Exception $e) { die($e->getMessage()); } @@ -40,16 +37,14 @@ In the example above, we catch any type of Exception. If we only want to watch f a ``UnknownFileException``, we can specify that in the catch parameter. Any other exceptions that are thrown and are not child classes of the caught exception will be passed on to the error handler:: - catch (\CodeIgniter\UnknownFileException $e) - { + catch (\CodeIgniter\UnknownFileException $e) { // do something here... } This can be handy for handling the error yourself, or for performing cleanup before the script ends. If you want the error handler to function as normal, you can throw a new exception within the catch block:: - catch (\CodeIgniter\UnknownFileException $e) - { + catch (\CodeIgniter\UnknownFileException $e) { // do something here... throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); @@ -98,8 +93,7 @@ This is used to signal a 404, Page Not Found error. When thrown, the system will If, in ``Config/Routes.php``, you have specified a 404 Override, that will be called instead of the standard 404 page:: - if (! $page = $pageModel->find($id)) - { + if (! $page = $pageModel->find($id)) { throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); } diff --git a/user_guide_src/source/general/helpers.rst b/user_guide_src/source/general/helpers.rst index 02dd4a017d20..65d63d942631 100644 --- a/user_guide_src/source/general/helpers.rst +++ b/user_guide_src/source/general/helpers.rst @@ -122,10 +122,8 @@ functions:: { $needle = is_array($needle) ? $needle : [$needle]; - foreach ($needle as $item) - { - if (in_array($item, $haystack)) - { + foreach ($needle as $item) { + if (in_array($item, $haystack, true)) { return true; } } @@ -137,6 +135,7 @@ functions:: function random_element($array) { shuffle($array); + return array_pop($array); } diff --git a/user_guide_src/source/general/logging.rst b/user_guide_src/source/general/logging.rst index 32953792a136..6a6ca1e49e0e 100644 --- a/user_guide_src/source/general/logging.rst +++ b/user_guide_src/source/general/logging.rst @@ -10,8 +10,7 @@ You can log information to the local log files by using the ``log_message()`` me the "level" of the error in the first parameter, indicating what type of message it is (debug, error, etc). The second parameter is the message itself:: - if ($some_var == '') - { + if ($some_var === '') { log_message('error', 'Some variable did not contain a value.'); } @@ -107,12 +106,9 @@ If you want to log an Exception or an Error, you can use the key of 'exception', Exception or Error itself. A string will be generated from that object containing the error message, the file name and line number. You must still provide the exception placeholder in the message:: - try - { + try { // Something throws error here - } - catch (\Exception $e) - { + } catch (\Exception $e) { log_message('error', '[ERROR] {exception}', ['exception' => $e]); } diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 35d72532670c..b744f30c0441 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -154,8 +154,7 @@ but must be specified within the Routes file itself:: To reduce the amount of typing needed here, the **group** routing feature is helpful:: - $routes->group('blog', ['namespace' => 'Acme\Blog\Controllers'], function($routes) - { + $routes->group('blog', ['namespace' => 'Acme\Blog\Controllers'], function ($routes) { $routes->get('/', 'Blog::index'); }); diff --git a/user_guide_src/source/helpers/array_helper.rst b/user_guide_src/source/helpers/array_helper.rst index 3ccdee76dd6d..2457790e4ad6 100644 --- a/user_guide_src/source/helpers/array_helper.rst +++ b/user_guide_src/source/helpers/array_helper.rst @@ -33,10 +33,10 @@ The following functions are available: $data = [ 'foo' => [ 'buzz' => [ - 'fizz' => 11 + 'fizz' => 11, ], 'bar' => [ - 'baz' => 23 + 'baz' => 23, ] ] ] @@ -61,10 +61,10 @@ The following functions are available: $data = [ 'foo' => [ - 'bar.baz' => 23 + 'bar.baz' => 23, ], 'foo.bar' => [ - 'baz' => 43 + 'baz' => 43, ], ]; diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 702598d0a0d5..4175bb2b99c4 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -42,7 +42,7 @@ The following functions are available: :param string $index: Cookie name :param bool $xss_clean: Whether to apply XSS filtering to the returned value - :returns: The cookie value or NULL if not found + :returns: The cookie value or null if not found :rtype: mixed This helper function gives you friendlier syntax to get browser diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst index 2c483668c067..0b7aeead3329 100644 --- a/user_guide_src/source/helpers/date_helper.rst +++ b/user_guide_src/source/helpers/date_helper.rst @@ -20,7 +20,7 @@ Available Functions The following functions are available: -.. php:function:: now([$timezone = NULL]) +.. php:function:: now([$timezone = null]) :param string $timezone: Timezone :returns: UNIX timestamp diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 5cfffae21f33..fc91a70f111e 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -22,7 +22,7 @@ Available Functions The following functions are available: -.. php:function:: directory_map($source_dir[, $directory_depth = 0[, $hidden = FALSE]]) +.. php:function:: directory_map($source_dir[, $directory_depth = 0[, $hidden = false]]) :param string $source_dir: Path to the source directory :param int $directory_depth: Depth of directories to traverse (0 = fully recursive, 1 = current dir, etc) @@ -46,7 +46,7 @@ The following functions are available: hidden directories will be skipped. To override this behavior, you may set a third parameter to true (boolean):: - $map = directory_map('./mydirectory/', FALSE, TRUE); + $map = directory_map('./mydirectory/', false, true); Each folder name will be an array index, while its contained files will be numerically indexed. Here is an example of a typical array:: @@ -91,12 +91,9 @@ The following functions are available: Example:: - try - {      + try {      directory_mirror($uploadedImages, FCPATH . 'images/'); - } - catch (Throwable $e) - {      + } catch (Throwable $e) {      echo 'Failed to export uploads!'; } @@ -107,7 +104,7 @@ The following functions are available: :param string $path: File path :param string $data: Data to write to file :param string $mode: ``fopen()`` mode - :returns: TRUE if the write was successful, FALSE in case of an error + :returns: true if the write was successful, false in case of an error :rtype: bool Writes data to the file specified in the path. If the file does not exist then the @@ -116,12 +113,10 @@ The following functions are available: Example:: $data = 'Some file data'; - if ( ! write_file('./path/to/file.php', $data)) - {      + + if ( ! write_file('./path/to/file.php', $data)) {      echo 'Unable to write the file'; - } - else - {      + } else {      echo 'File written!'; } @@ -142,13 +137,13 @@ The following functions are available: .. note:: This function acquires an exclusive lock on the file while writing to it. -.. php:function:: delete_files($path[, $delDir = FALSE[, $htdocs = FALSE[, $hidden = FALSE]]]) +.. php:function:: delete_files($path[, $delDir = false[, $htdocs = false[, $hidden = false]]]) :param string $path: Directory path :param bool $delDir: Whether to also delete directories :param bool $htdocs: Whether to skip deleting .htaccess and index page files :param bool $hidden: Whether to also delete hidden files (files beginning with a period) - :returns: TRUE on success, FALSE in case of an error + :returns: true on success, false in case of an error :rtype: bool Deletes ALL files contained in the supplied path. @@ -157,16 +152,16 @@ The following functions are available: delete_files('./path/to/directory/'); - If the second parameter is set to TRUE, any directories contained within the supplied + If the second parameter is set to true, any directories contained within the supplied root path will be deleted as well. Example:: - delete_files('./path/to/directory/', TRUE); + delete_files('./path/to/directory/', true); .. note:: The files must be writable or owned by the system in order to be deleted. -.. php:function:: get_filenames($source_dir[, $include_path = FALSE]) +.. php:function:: get_filenames($source_dir[, $include_path = false]) :param string $source_dir: Directory path :param bool|null $include_path: Whether to include the path as part of the filename; false for no path, null for the path relative to $source_dir, true for the full path @@ -192,7 +187,7 @@ The following functions are available: Reads the specified directory and builds an array containing the filenames, filesize, dates, and permissions. Sub-folders contained within the specified path are only read - if forced by sending the second parameter to FALSE, as this can be an intensive + if forced by sending the second parameter to false, as this can be an intensive operation. Example:: @@ -203,7 +198,7 @@ The following functions are available: :param string $file: File path :param array|string $returned_values: What type of info to return to be passed as array or comma separated string - :returns: An array containing info on the specified file or FALSE on failure + :returns: An array containing info on the specified file or false on failure :rtype: array Given a file and path, returns (optionally) the *name*, *path*, *size* and *date modified* @@ -252,7 +247,7 @@ The following functions are available: echo same_file($newFile, $oldFile) ? 'Same!' : 'Different!'; -.. php:function:: set_realpath($path[, $check_existence = FALSE]) +.. php:function:: set_realpath($path[, $check_existence = false]) :param string $path: Path :param bool $check_existence: Whether to check if the path actually exists @@ -269,12 +264,12 @@ The following functions are available: echo set_realpath($file); // Prints '/etc/php5/apache2/php.ini' $non_existent_file = '/path/to/non-exist-file.txt'; - echo set_realpath($non_existent_file, TRUE); // Shows an error, as the path cannot be resolved - echo set_realpath($non_existent_file, FALSE); // Prints '/path/to/non-exist-file.txt' + echo set_realpath($non_existent_file, true); // Shows an error, as the path cannot be resolved + echo set_realpath($non_existent_file, false); // Prints '/path/to/non-exist-file.txt' $directory = '/etc/php5'; echo set_realpath($directory); // Prints '/etc/php5/' $non_existent_directory = '/path/to/nowhere'; - echo set_realpath($non_existent_directory, TRUE); // Shows an error, as the path cannot be resolved - echo set_realpath($non_existent_directory, FALSE); // Prints '/path/to/nowhere' + echo set_realpath($non_existent_directory, true); // Shows an error, as the path cannot be resolved + echo set_realpath($non_existent_directory, false); // Prints '/path/to/nowhere' diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index f9b37070a652..f54b1166a05e 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -151,7 +151,7 @@ The following functions are available: $data = [ 'name' => 'John Doe', 'email' => 'john@example.com', - 'url' => 'http://example.com' + 'url' => 'http://example.com', ]; echo form_hidden($data); @@ -169,7 +169,7 @@ The following functions are available: $data = [ 'name' => 'John Doe', 'email' => 'john@example.com', - 'url' => 'http://example.com' + 'url' => 'http://example.com', ]; echo form_hidden('my_array', $data); @@ -189,7 +189,7 @@ The following functions are available: 'name' => 'email', 'id' => 'hiddenemail', 'value' => 'john@example.com', - 'class' => 'hiddenemail' + 'class' => 'hiddenemail', ]; echo form_input($data); @@ -223,7 +223,7 @@ The following functions are available: 'value' => 'johndoe', 'maxlength' => '100', 'size' => '50', - 'style' => 'width:50%' + 'style' => 'width:50%', ]; echo form_input($data); @@ -237,12 +237,12 @@ The following functions are available: If you would like your form to contain some additional data, like JavaScript, you can pass it as a string in the third parameter:: - $js = 'onClick="some_function()"'; + $js = 'onClick="some_function ()"'; echo form_input('username', 'johndoe', $js); Or you can pass it as an array:: - $js = ['onClick' => 'some_function();']; + $js = ['onClick' => 'some_function ();']; echo form_input('username', 'johndoe', $js); To support the expanded range of HTML5 input fields, you can pass an input type in as the fourth parameter:: @@ -442,7 +442,7 @@ The following functions are available: echo form_fieldset_close($string); // Would produce: -.. php:function:: form_checkbox([$data = ''[, $value = ''[, $checked = FALSE[, $extra = '']]]]) +.. php:function:: form_checkbox([$data = ''[, $value = ''[, $checked = false[, $extra = '']]]]) :param array $data: Field attributes data :param string $value: Field value @@ -453,10 +453,10 @@ The following functions are available: Lets you generate a checkbox field. Simple example:: - echo form_checkbox('newsletter', 'accept', TRUE); + echo form_checkbox('newsletter', 'accept', true); // Would produce: - The third parameter contains a boolean TRUE/FALSE to determine whether + The third parameter contains a boolean true/false to determine whether the box should be checked or not. Similar to the other form functions in this helper, you can also pass an @@ -466,7 +466,7 @@ The following functions are available: 'name' => 'newsletter', 'id' => 'newsletter', 'value' => 'accept', - 'checked' => TRUE, + 'checked' => true, 'style' => 'margin:10px' ]; @@ -478,14 +478,14 @@ The following functions are available: fourth parameter:: $js = 'onClick="some_function()"'; - echo form_checkbox('newsletter', 'accept', TRUE, $js); + echo form_checkbox('newsletter', 'accept', true, $js); Or you can pass it as an array:: $js = ['onClick' => 'some_function();']; - echo form_checkbox('newsletter', 'accept', TRUE, $js); + echo form_checkbox('newsletter', 'accept', true, $js); -.. php:function:: form_radio([$data = ''[, $value = ''[, $checked = FALSE[, $extra = '']]]]) +.. php:function:: form_radio([$data = ''[, $value = ''[, $checked = false[, $extra = '']]]]) :param array $data: Field attributes data :param string $value: Field value @@ -573,7 +573,7 @@ The following functions are available: 'id' => 'button', 'value' => 'true', 'type' => 'reset', - 'content' => 'Reset' + 'content' => 'Reset', ]; echo form_button($data); @@ -599,7 +599,7 @@ The following functions are available: echo form_close($string); // Would produce: -.. php:function:: set_value($field[, $default = ''[, $html_escape = TRUE]]) +.. php:function:: set_value($field[, $default = ''[, $html_escape = true]]) :param string $field: Field name :param string $default: Default value @@ -620,7 +620,7 @@ The following functions are available: The above form will show "0" when loaded for the first time. -.. php:function:: set_select($field[, $value = ''[, $default = FALSE]]) +.. php:function:: set_select($field[, $value = ''[, $default = false]]) :param string $field: Field name :param string $value: Value to check for @@ -633,17 +633,17 @@ The following functions are available: The first parameter must contain the name of the select menu, the second parameter must contain the value of each item, and the third (optional) - parameter lets you set an item as the default (use boolean TRUE/FALSE). + parameter lets you set an item as the default (use boolean true/false). Example:: -.. php:function:: set_checkbox($field[, $value = ''[, $default = FALSE]]) +.. php:function:: set_checkbox($field[, $value = ''[, $default = false]]) :param string $field: Field name :param string $value: Value to check for @@ -655,14 +655,14 @@ The following functions are available: The first parameter must contain the name of the checkbox, the second parameter must contain its value, and the third (optional) parameter - lets you set an item as the default (use boolean TRUE/FALSE). + lets you set an item as the default (use boolean true/false). Example:: /> /> -.. php:function:: set_radio($field[, $value = ''[, $default = FALSE]]) +.. php:function:: set_radio($field[, $value = ''[, $default = false]]) :param string $field: Field name :param string $value: Value to check for @@ -675,7 +675,7 @@ The following functions are available: Example:: - /> + /> /> .. note:: If you are using the Form Validation class, you must always specify diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst index 72a9ed9640a9..a477b9cbd311 100755 --- a/user_guide_src/source/helpers/html_helper.rst +++ b/user_guide_src/source/helpers/html_helper.rst @@ -59,7 +59,7 @@ The following functions are available: 'width' => '200', 'height' => '200', 'title' => 'That was quite a night', - 'rel' => 'lightbox' + 'rel' => 'lightbox', ]; img($imageProperties); @@ -126,7 +126,7 @@ The following functions are available: 'href' => 'css/printer.css', 'rel' => 'stylesheet', 'type' => 'text/css', - 'media' => 'print' + 'media' => 'print', ]; echo link_tag($link); @@ -171,12 +171,12 @@ The following functions are available: 'red', 'blue', 'green', - 'yellow' + 'yellow', ]; $attributes = [ 'class' => 'boldlist', - 'id' => 'mylist' + 'id' => 'mylist', ]; echo ul($list, $attributes); @@ -196,14 +196,14 @@ The following functions are available: $attributes = [ 'class' => 'boldlist', - 'id' => 'mylist' + 'id' => 'mylist', ]; $list = [ 'colors' => [ 'red', 'blue', - 'green' + 'green', ], 'shapes' => [ 'round', @@ -211,8 +211,8 @@ The following functions are available: 'circles' => [ 'ellipse', 'oval', - 'sphere' - ] + 'sphere', + ], ], 'moods' => [ 'happy', @@ -220,11 +220,11 @@ The following functions are available: 'defeated' => [ 'dejected', 'disheartened', - 'depressed' + 'depressed', ], 'annoyed', 'cross', - 'angry' + 'angry', ] ] ]; @@ -300,30 +300,26 @@ The following functions are available: Permits you to generate HTML video element from simple or source arrays. Example:: - $tracks = - [ + $tracks = [ track('subtitles_no.vtt', 'subtitles', 'no', 'Norwegian No'), track('subtitles_yes.vtt', 'subtitles', 'yes', 'Norwegian Yes') ]; echo video('test.mp4', 'Your browser does not support the video tag.', 'controls'); - echo video - ( + echo video( 'http://www.codeigniter.com/test.mp4', 'Your browser does not support the video tag.', 'controls', $tracks ); - echo video - ( - [ - source('movie.mp4', 'video/mp4', 'class="test"'), - source('movie.ogg', 'video/ogg'), - source('movie.mov', 'video/quicktime'), - source('movie.ogv', 'video/ogv; codecs=dirac, speex') - ], + echo video([ + source('movie.mp4', 'video/mp4', 'class="test"'), + source('movie.ogg', 'video/ogg'), + source('movie.mov', 'video/quicktime'), + source('movie.ogv', 'video/ogv; codecs=dirac, speex') + ], 'Your browser does not support the video tag.', 'class="test" controls', $tracks @@ -408,8 +404,7 @@ The following functions are available: echo object('movie.swf', 'application/x-shockwave-flash', 'class="test"'); - echo object - ( + echo object( 'movie.swf', 'application/x-shockwave-flash', 'class="test"', diff --git a/user_guide_src/source/helpers/inflector_helper.rst b/user_guide_src/source/helpers/inflector_helper.rst index f006869d0625..fdc70a4cd92d 100755 --- a/user_guide_src/source/helpers/inflector_helper.rst +++ b/user_guide_src/source/helpers/inflector_helper.rst @@ -105,12 +105,12 @@ The following functions are available: .. php:function:: is_pluralizable($word) :param string $word: Input string - :returns: TRUE if the word is countable or FALSE if not + :returns: true if the word is countable or false if not :rtype: bool Checks if the given word has a plural version. Example:: - is_pluralizable('equipment'); // Returns FALSE + is_pluralizable('equipment'); // Returns false .. php:function:: dasherize($string) diff --git a/user_guide_src/source/helpers/text_helper.rst b/user_guide_src/source/helpers/text_helper.rst index 4e45620b253d..6b875e3d7e36 100755 --- a/user_guide_src/source/helpers/text_helper.rst +++ b/user_guide_src/source/helpers/text_helper.rst @@ -72,8 +72,7 @@ The following functions are available: Allows two or more items to be alternated between, when cycling through a loop. Example:: - for ($i = 0; $i < 10; $i++) - {      + for ($i = 0; $i < 10; $i++) {      echo alternator('string one', 'string two'); } @@ -82,8 +81,7 @@ The following functions are available: :: - for ($i = 0; $i < 10; $i++) - {      + for ($i = 0; $i < 10; $i++) {      echo alternator('one', 'two', 'three', 'four', 'five'); } @@ -132,7 +130,7 @@ The following functions are available: and handle string inputs. This however makes it just an alias for ``stripslashes()``. -.. php:function:: reduce_multiples($str[, $character = ''[, $trim = FALSE]]) +.. php:function:: reduce_multiples($str[, $character = ''[, $trim = false]]) :param string $str: Text to search in :param string $character: Character to reduce @@ -146,11 +144,11 @@ The following functions are available: $string = "Fred, Bill,, Joe, Jimmy"; $string = reduce_multiples($string, ","); // results in "Fred, Bill, Joe, Jimmy" - If the third parameter is set to TRUE it will remove occurrences of the + If the third parameter is set to true it will remove occurrences of the character at the beginning and the end of the string. Example:: $string = ",Fred, Bill,, Joe, Jimmy,"; - $string = reduce_multiples($string, ", ", TRUE); // results in "Fred, Bill, Joe, Jimmy" + $string = reduce_multiples($string, ", ", true); // results in "Fred, Bill, Joe, Jimmy" .. php:function:: quotes_to_entities($str) @@ -234,7 +232,7 @@ The following functions are available: $string = ascii_to_entities($string); -.. php:function:: entities_to_ascii($str[, $all = TRUE]) +.. php:function:: entities_to_ascii($str[, $all = true]) :param string $str: Input string :param bool $all: Whether to convert unsafe entities as well diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst index 1c1ca5866ef8..16cd6e4534df 100644 --- a/user_guide_src/source/helpers/url_helper.rst +++ b/user_guide_src/source/helpers/url_helper.rst @@ -17,7 +17,7 @@ Available Functions The following functions are available: -.. php:function:: site_url([$uri = ''[, $protocol = NULL[, $altConfig = NULL]]]) +.. php:function:: site_url([$uri = ''[, $protocol = null[, $altConfig = null]]]) :param mixed $uri: URI string or array of URI segments :param string $protocol: Protocol, e.g., 'http' or 'https' @@ -51,7 +51,7 @@ The following functions are available: different site than yours, which contains different configuration preferences. We use this for unit testing the framework itself. -.. php:function:: base_url([$uri = ''[, $protocol = NULL]]) +.. php:function:: base_url([$uri = ''[, $protocol = null]]) :param mixed $uri: URI string or array of URI segments :param string $protocol: Protocol, e.g., 'http' or 'https' @@ -127,13 +127,13 @@ The following functions are available: /blog/comments/123 Or with the optional relative parameter:: - + app.baseURL = http://some-site.com/subfolder/ uri_string(); // "/subfolder/blog/comments/123" uri_string(true); // "blog/comments/123" -.. php:function:: index_page([$altConfig = NULL]) +.. php:function:: index_page([$altConfig = null]) :param \\Config\\App $altConfig: Alternate configuration to use :returns: 'index_page' value @@ -149,7 +149,7 @@ The following functions are available: different site than yours, which contains different configuration preferences. We use this for unit testing the framework itself. -.. php:function:: anchor([$uri = ''[, $title = ''[, $attributes = ''[, $altConfig = NULL]]]]) +.. php:function:: anchor([$uri = ''[, $title = ''[, $attributes = ''[, $altConfig = null]]]]) :param mixed $uri: URI string or array of URI segments :param string $title: Anchor title @@ -194,7 +194,7 @@ The following functions are available: .. note:: Attributes passed into the anchor function are automatically escaped to protected against XSS attacks. -.. php:function:: anchor_popup([$uri = ''[, $title = ''[, $attributes = FALSE[, $altConfig = NULL]]]]) +.. php:function:: anchor_popup([$uri = ''[, $title = ''[, $attributes = false[, $altConfig = null]]]]) :param string $uri: URI string :param string $title: Anchor title @@ -219,7 +219,7 @@ The following functions are available: 'resizable'   => 'yes', 'screenx' => 0, 'screeny' => 0, - 'window_name' => '_blank' + 'window_name' => '_blank', ]; echo anchor_popup('news/local/123', 'Click Me!', $atts); @@ -277,7 +277,7 @@ The following functions are available: version of the *mailto* tag using ordinal numbers written with JavaScript to help prevent the e-mail address from being harvested by spam bots. -.. php:function:: auto_link($str[, $type = 'both'[, $popup = FALSE]]) +.. php:function:: auto_link($str[, $type = 'both'[, $popup = false]]) :param string $str: Input string :param string $type: Link type ('email', 'url' or 'both') @@ -304,13 +304,13 @@ The following functions are available: $string = auto_link($string, 'email'); The third parameter determines whether links are shown in a new window. - The value can be TRUE or FALSE (boolean):: + The value can be true or false (boolean):: - $string = auto_link($string, 'both', TRUE); + $string = auto_link($string, 'both', true); .. note:: The only URLs recognized are those that start with "www." or with "://". -.. php:function:: url_title($str[, $separator = '-'[, $lowercase = FALSE]]) +.. php:function:: url_title($str[, $separator = '-'[, $lowercase = false]]) :param string $str: Input string :param string $separator: Word separator (usually '-' or '_') @@ -336,15 +336,15 @@ The following functions are available: // Produces: Whats_wrong_with_CSS The third parameter determines whether or not lowercase characters are - forced. By default they are not. Options are boolean TRUE/FALSE. + forced. By default they are not. Options are boolean true/false. Example:: $title = "What's wrong with CSS?"; - $url_title = url_title($title, '-', TRUE); + $url_title = url_title($title, '-', true); // Produces: whats-wrong-with-css -.. php:function:: mb_url_title($str[, $separator = '-'[, $lowercase = FALSE]]) +.. php:function:: mb_url_title($str[, $separator = '-'[, $lowercase = false]]) :param string $str: Input string :param string $separator: Word separator (usually '-' or '_') @@ -358,7 +358,7 @@ The following functions are available: .. php:function:: prep_url([$str = ''[, $secure = false]]) :param string $str: URL string - :param boolean $secure: TRUE for https:// + :param boolean $secure: true for https:// :returns: Protocol-prefixed URL string :rtype: string diff --git a/user_guide_src/source/helpers/xml_helper.rst b/user_guide_src/source/helpers/xml_helper.rst index 72d4b7c5c7a9..4f7ff453384a 100644 --- a/user_guide_src/source/helpers/xml_helper.rst +++ b/user_guide_src/source/helpers/xml_helper.rst @@ -22,7 +22,7 @@ Available Functions The following functions are available: -.. php:function:: xml_convert($str[, $protect_all = FALSE]) +.. php:function:: xml_convert($str[, $protect_all = false]) :param string $str: the text string to convert :param bool $protect_all: Whether to protect all content that looks like a potential entity instead of just numbered entities, e.g., &foo; diff --git a/user_guide_src/source/incoming/content_negotiation.rst b/user_guide_src/source/incoming/content_negotiation.rst index 0b95b51f9a8c..11940b82092a 100644 --- a/user_guide_src/source/incoming/content_negotiation.rst +++ b/user_guide_src/source/incoming/content_negotiation.rst @@ -52,7 +52,7 @@ be able to return data as raw HTML, JSON, or XML. This list should be provided i $supported = [ 'application/json', 'text/html', - 'application/xml' + 'application/xml', ]; $format = $request->negotiate('media', $supported); @@ -84,7 +84,7 @@ and German you would do something like:: $supported = [ 'en', - 'de' + 'de', ]; $lang = $request->negotiate('language', $supported); diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 8270b1c0701a..49075fc84500 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -224,12 +224,9 @@ be passed as a parameter to the ``_remap()`` method:: public function _remap($method) { - if ($method === 'some_method') - { + if ($method === 'some_method') { return $this->$method(); - } - else - { + } else { return $this->default_method(); } } @@ -242,10 +239,11 @@ Example:: public function _remap($method, ...$params) { $method = 'process_'.$method; - if (method_exists($this, $method)) - { + + if (method_exists($this, $method)) { return $this->$method(...$params); } + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); } @@ -321,8 +319,7 @@ An instance of the :doc:`Logger <../general/logging>` class is available as a cl A convenience method for forcing a method to be accessed via HTTPS is available within all controllers:: - if (! $this->request->isSecure()) - { + if (! $this->request->isSecure()) { $this->forceHTTPS(); } @@ -330,9 +327,8 @@ By default, and in modern browsers that support the HTTP Strict Transport Securi call should force the browser to convert non-HTTPS calls to HTTPS calls for one year. You can modify this by passing the duration (in seconds) as the first parameter:: - if (! $this->request->isSecure()) - { - $this->forceHTTPS(31536000); // one year + if (! $this->request->isSecure()) { + $this->forceHTTPS(31536000); // one year } .. note:: A number of :doc:`time-based constants ` are always available for you to use, including YEAR, MONTH, and more. @@ -367,8 +363,7 @@ rule and message array formats, as well as available rules.:: if (! $this->validate([ 'email' => "required|is_unique[users.email,id,{$userID}]", 'name' => 'required|alpha_numeric_spaces' - ])) - { + ])) { return view('users/update', [ 'errors' => $this->validator->getErrors() ]); @@ -382,8 +377,7 @@ the $rules array with the name of the group as defined in ``Config\Validation.ph public function updateUser(int $userID) { - if (! $this->validate('userRules')) - { + if (! $this->validate('userRules')) { return view('users/update', [ 'errors' => $this->validator->getErrors() ]); diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index ce7ddcbc582b..a95333516503 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -67,8 +67,7 @@ This is typically used to perform redirects, like in this example:: { $auth = service('auth'); - if (! $auth->isLoggedIn()) - { + if (! $auth->isLoggedIn()) { return redirect()->to(site_url('login')); } } @@ -128,7 +127,7 @@ run on every request. Filters can be specified by adding their alias to either t 'before' => [ 'csrf', ], - 'after' => [], + 'after' => [], ]; There are times where you want to apply a filter to almost every request, but have a few that should be left alone. @@ -140,7 +139,7 @@ an array with the 'except' key and a uri to match as the value alongside the ali 'before' => [ 'csrf' => ['except' => 'api/*'], ], - 'after' => [], + 'after' => [], ]; Any place you can use a URI in the filter settings, you can use a regular expression or, like in this example, use @@ -152,7 +151,7 @@ URI's you can use an array of URI patterns:: 'before' => [ 'csrf' => ['except' => ['foo/*', 'bar/*']], ], - 'after' => [], + 'after' => [], ]; $methods diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 968872c9f218..50b152d5dd14 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -25,8 +25,7 @@ An instance of the request class already populated for you if the current class { public function index() { - if ($this->request->isAJAX()) - { + if ($this->request->isAJAX()) { // ... } } @@ -63,19 +62,17 @@ A request could be of several types, including an AJAX request or a request from be checked with the ``isAJAX()`` and ``isCLI()`` methods:: // Check for AJAX request. - if ($request->isAJAX()) - { + if ($request->isAJAX()) { // ... } // Check for CLI Request - if ($request->isCLI()) - { + if ($request->isCLI()) { // ... } -.. note:: The ``isAJAX()`` method depends on the ``X-Requested-With`` header, - which in some cases is not sent by default in XHR requests via JavaScript (i.e., fetch). +.. note:: The ``isAJAX()`` method depends on the ``X-Requested-With`` header, + which in some cases is not sent by default in XHR requests via JavaScript (i.e., fetch). See the :doc:`AJAX Requests ` section on how to avoid this problem. You can check the HTTP method that this request represents with the ``method()`` method:: @@ -91,8 +88,7 @@ uppercase version by wrapping the call in ``str_to_upper()``:: You can also check if the request was made through and HTTPS connection with the ``isSecure()`` method:: - if (! $request->isSecure()) - { + if (! $request->isSecure()) { force_https(); } @@ -106,7 +102,7 @@ will return null if the item doesn't exist, and you can have the data filtered. use data without having to test whether an item exists first. In other words, normally you might do something like this:: - $something = isset($_POST['foo']) ? $_POST['foo'] : NULL; + $something = isset($_POST['foo']) ? $_POST['foo'] : null; With CodeIgniter’s built in methods you can simply do this:: @@ -236,8 +232,7 @@ specified header object in a case-insensitive manner if it exists. If not, then You can always use ``hasHeader()`` to see if the header existed in this request:: - if ($request->hasHeader('DNT')) - { + if ($request->hasHeader('DNT')) { // Don't track something... } @@ -298,8 +293,7 @@ and uses best practices to minimize any security risks. $files = $request->getFiles(); // Grab the file by name given in HTML form - if ($files->hasFile('uploadedFile')) - { + if ($files->hasFile('uploadedFile')) { $file = $files->getFile('uploadedfile'); // Generate a new secure name @@ -308,9 +302,9 @@ and uses best practices to minimize any security risks. // Move the file to it's new home $file->move('/path/to/dir', $name); - echo $file->getSize('mb'); // 1.23 - echo $file->getExtension(); // jpg - echo $file->getType(); // image/jpg + echo $file->getSize('mb'); // 1.23 + echo $file->getExtension(); // jpg + echo $file->getType(); // image/jpg } You can retrieve a single file uploaded on its own, based on the filename given in the HTML file input:: @@ -386,9 +380,9 @@ The methods provided by the parent classes that are available are: .. php:method:: getVar([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be found + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. :returns: $_REQUEST if no parameters supplied, otherwise the REQUEST value if found, or null if not :rtype: mixed|null @@ -411,7 +405,7 @@ The methods provided by the parent classes that are available are: first parameter to null while setting the second parameter to the filter you want to use:: - $request->getVar(null, FILTER_SANITIZE_STRING); + $request->getVar(null, FILTER_SANITIZE_STRING); // returns all POST items with string sanitation To return an array of multiple POST parameters, pass all the required keys as an array:: @@ -426,9 +420,9 @@ The methods provided by the parent classes that are available are: .. php:method:: getGet([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. :returns: $_GET if no parameters supplied, otherwise the GET value if found, or null if not :rtype: mixed|null @@ -438,9 +432,9 @@ The methods provided by the parent classes that are available are: .. php:method:: getPost([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. :returns: $_POST if no parameters supplied, otherwise the POST value if found, or null if not :rtype: mixed|null @@ -450,9 +444,9 @@ The methods provided by the parent classes that are available are: .. php:method:: getPostGet([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. :returns: $_POST if no parameters supplied, otherwise the POST value if found, or null if not :rtype: mixed|null @@ -466,9 +460,9 @@ The methods provided by the parent classes that are available are: .. php:method:: getGetPost([$index = null[, $filter = null[, $flags = null]]]) :param string $index: The name of the variable/key to look for. - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. :returns: $_POST if no parameters supplied, otherwise the POST value if found, or null if not :rtype: mixed|null @@ -483,9 +477,9 @@ The methods provided by the parent classes that are available are: :noindex: :param mixed $index: COOKIE name - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. :returns: $_COOKIE if no parameters supplied, otherwise the COOKIE value if found or null if not :rtype: mixed @@ -507,11 +501,11 @@ The methods provided by the parent classes that are available are: :noindex: :param mixed $index: Value name - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. - :param int $flags: Flags to apply. A list of flags can be found + :param int $flags: Flags to apply. A list of flags can be found `here `__. - :returns: $_SERVER item value if found, NULL if not + :returns: $_SERVER item value if found, null if not :rtype: mixed This method is identical to the ``getPost()``, ``getGet()`` and ``getCookie()`` @@ -527,7 +521,7 @@ The methods provided by the parent classes that are available are: .. php:method:: getUserAgent([$filter = null]) - :param int $filter: The type of filter to apply. A list of filters can be + :param int $filter: The type of filter to apply. A list of filters can be found `here `__. :returns: The User Agent string, as found in the SERVER data, or null if not found. :rtype: mixed diff --git a/user_guide_src/source/incoming/message.rst b/user_guide_src/source/incoming/message.rst index 91ebd2ae789c..317f7823b8d2 100644 --- a/user_guide_src/source/incoming/message.rst +++ b/user_guide_src/source/incoming/message.rst @@ -123,7 +123,7 @@ Class Reference .. php:method:: hasHeader($name) :param string $name: The name of the header you want to see if it exists. - :returns: Returns TRUE if it exists, FALSE otherwise. + :returns: Returns true if it exists, false otherwise. :rtype: bool .. php:method:: getHeaderLine($name) diff --git a/user_guide_src/source/incoming/request.rst b/user_guide_src/source/incoming/request.rst index 7c4df0d5309b..1fdbce30d5ee 100644 --- a/user_guide_src/source/incoming/request.rst +++ b/user_guide_src/source/incoming/request.rst @@ -1,5 +1,5 @@ Request Class -**************************************************** +************* The request class is an object-oriented representation of an HTTP request. This is meant to work for both incoming, such as a request to the application from a browser, and outgoing requests, @@ -11,7 +11,7 @@ See the documentation for the :doc:`IncomingRequest Class ` for more usage details. Class Reference -============================================================ +=============== .. php:class:: CodeIgniter\\HTTP\\Request @@ -46,19 +46,16 @@ Class Reference :: - if ( ! $request->isValidIP($ip)) - { + if ( ! $request->isValidIP($ip)) { echo 'Not Valid'; - } - else - { + } else { echo 'Valid'; } Accepts an optional second string parameter of 'ipv4' or 'ipv6' to specify an IP format. The default checks for both formats. - .. php:method:: getMethod([$upper = FALSE]) + .. php:method:: getMethod([$upper = false]) .. important:: Use of the ``$upper`` parameter is deprecated. @@ -70,8 +67,8 @@ Class Reference in uppercase or lowercase. :: - echo $request->getMethod(TRUE); // Outputs: POST - echo $request->getMethod(FALSE); // Outputs: post + echo $request->getMethod(true); // Outputs: POST + echo $request->getMethod(false); // Outputs: post echo $request->getMethod(); // Outputs: post .. php:method:: setMethod($method) @@ -85,7 +82,7 @@ Class Reference :param mixed $index: Value name :param int $filter: The type of filter to apply. A list of filters can be found `here `__. :param int|array $flags: Flags to apply. A list of flags can be found `here `__. - :returns: $_SERVER item value if found, NULL if not + :returns: $_SERVER item value if found, null if not :rtype: mixed This method is identical to the ``post()``, ``get()`` and ``cookie()`` methods from the @@ -104,7 +101,7 @@ Class Reference :param mixed $index: Value name :param int $filter: The type of filter to apply. A list of filters can be found `here `__. :param int|array $flags: Flags to apply. A list of flags can be found `here `__. - :returns: $_ENV item value if found, NULL if not + :returns: $_ENV item value if found, null if not :rtype: mixed This method is identical to the ``post()``, ``get()`` and ``cookie()`` methods from the diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 6b8c194d67d1..d03d59ddf263 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -103,7 +103,7 @@ Note that a single ``(:any)`` will match multiple segments in the URL if present $routes->add('product/(:any)', 'Catalog::productLookup/$1'); -will match product/123, product/123/456, product/123/456/789 and so on. The implementation in the +will match product/123, product/123/456, product/123/456/789 and so on. The implementation in the Controller should take into account the maximum parameters:: public function productLookup($seg1 = false, $seg2 = false, $seg3 = false) { @@ -112,7 +112,7 @@ Controller should take into account the maximum parameters:: echo $seg3; // false in first and second, 789 in third } -If matching multiple segments is not the intended behavior, ``(:segment)`` should be used when defining the +If matching multiple segments is not the intended behavior, ``(:segment)`` should be used when defining the routes. With the examples URLs from above:: $routes->add('product/(:segment)', 'Catalog::productLookup/$1'); @@ -171,9 +171,9 @@ You can use an anonymous function, or Closure, as the destination that a route m executed when the user visits that URI. This is handy for quickly executing small tasks, or even just showing a simple view:: - $routes->add('feed', function() - { + $routes->add('feed', function () { $rss = new RSSFeeder(); + return $rss->feed('general'); }); @@ -185,7 +185,7 @@ the ``map()`` method. Instead of calling the ``add()`` method for each route tha define an array of routes and then pass it as the first parameter to the ``map()`` method:: $routes = []; - $routes['product/(:num)'] = 'Catalog::productLookupById'; + $routes['product/(:num)'] = 'Catalog::productLookupById'; $routes['product/(:alphanum)'] = 'Catalog::productLookupByName'; $collection->map($routes); @@ -216,8 +216,7 @@ You can group your routes under a common name with the ``group()`` method. The g appears prior to the routes defined inside of the group. This allows you to reduce the typing needed to build out an extensive set of routes that all share the opening string, like when building an admin area:: - $routes->group('admin', function($routes) - { + $routes->group('admin', function ($routes) { $routes->add('users', 'Admin\Users::index'); $routes->add('blog', 'Admin\Blog::index'); }); @@ -226,8 +225,7 @@ This would prefix the 'users' and 'blog" URIs with "admin", handling URLs like ` If you need to assign options to a group, like a `namespace <#assigning-namespace>`_, do it before the callback:: - $routes->group('api', ['namespace' => 'App\API\v1'], function($routes) - { + $routes->group('api', ['namespace' => 'App\API\v1'], function ($routes) { $routes->resource('users'); }); @@ -236,8 +234,7 @@ This would handle a resource route to the ``App\API\v1\Users`` controller with t You can also use a specific `filter `_ for a group of routes. This will always run the filter before or after the controller. This is especially handy during authentication or api logging:: - $routes->group('api', ['filter' => 'api-auth'], function($routes) - { + $routes->group('api', ['filter' => 'api-auth'], function ($routes) { $routes->resource('users'); }); @@ -245,21 +242,18 @@ The value for the filter must match one of the aliases defined within ``app/Conf It is possible to nest groups within groups for finer organization if you need it:: - $routes->group('admin', function($routes) - { - $routes->group('users', function($routes) - { + $routes->group('admin', function ($routes) { + $routes->group('users', function ($routes) { $routes->add('list', 'Admin\Users::list'); }); - }); -This would handle the URL at ``admin/users/list``. Note that options passed to the outer ``group()`` (for example +This would handle the URL at ``admin/users/list``. Note that options passed to the outer ``group()`` (for example ``namespace`` and ``filter``) are not merged with the inner ``group()`` options. -At some point, you may want to group routes for the purpose of applying filters or other route -config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass -an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the +At some point, you may want to group routes for the purpose of applying filters or other route +config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass +an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the given route config options. Environment Restrictions @@ -270,8 +264,7 @@ tools that only the developer can use on their local machines that are not reach This can be done with the ``environment()`` method. The first parameter is the name of the environment. Any routes defined within this closure are only accessible from the given environment:: - $routes->environment('development', function($routes) - { + $routes->environment('development', function ($routes) { $routes->add('builder', 'Tools\Builder::index'); }); @@ -354,7 +347,7 @@ can modify the generated routes, or further restrict them. The ``$options`` arra $routes->match(['get', 'put'], 'from', 'to', $options); $routes->resource('photos', $options); $routes->map($array, $options); - $routes->group('name', $options, function()); + $routes->group('name', $options, function ()); Applying Filters ---------------- @@ -545,7 +538,7 @@ a valid class/method pair, just like you would show in any route, or a Closure:: $routes->set404Override('App\Errors::show404'); // Will display a custom view - $routes->set404Override(function() + $routes->set404Override(function () { echo view('my_errors/not_found.html'); }); @@ -563,4 +556,3 @@ For an example of use lowering the priority see :ref:`priority`:: // to disable $routes->setPrioritize(false); - diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index 18908f7a72c2..de8eee5c53c5 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -22,16 +22,16 @@ What has been changed Upgrade Guide ============= -1. You have to change the values in the default CI4 config files according to the +1. You have to change the values in the default CI4 config files according to the changes in the CI3 files. The config names are pretty much the same as in CI3. -2. If you are using custom config files in your CI3 project you have to create those - files as new php classes in your CI4 project in ``app/Config/``. These classes +2. If you are using custom config files in your CI3 project you have to create those + files as new php classes in your CI4 project in ``app/Config/``. These classes should be in the ``Config`` namespace and should extend ``CodeIgniter\Config\BaseConfig``. -3. Once you have created all custom config classes, you have to copy the variables +3. Once you have created all custom config classes, you have to copy the variables from the CI3 config into the new CI4 config class as public class properties. -4. Now, you have to change the config fetching syntax everywhere you fetch config - values. The CI3 syntax is something like ``$this->config->item('item_name');``. - You have to change this into ``config('MyConfigFile')->item_name;``. Alternatively, +4. Now, you have to change the config fetching syntax everywhere you fetch config + values. The CI3 syntax is something like ``$this->config->item('item_name');``. + You have to change this into ``config('MyConfigFile')->item_name;``. Alternatively, you can use the object-oriented approach: ``CodeIgniter\Config\Config::get('MyConfigFile')->item_name;`` Code Example @@ -54,14 +54,14 @@ Codeigniter Version 4.x Path: ``app/Config``:: - array( 'type' => 'INT', 'constraint' => 5, - 'unsigned' => TRUE, - 'auto_increment' => TRUE, + 'unsigned' => true, + 'auto_increment' => true, ), 'blog_title' => array( 'type' => 'VARCHAR', @@ -66,10 +66,10 @@ Path: ``application/migrations``:: ), 'blog_description' => array( 'type' => 'TEXT', - 'null' => TRUE, + 'null' => true, ), )); - $this->dbforge->add_key('blog_id', TRUE); + $this->dbforge->add_key('blog_id', true); $this->dbforge->create_table('blog'); } @@ -96,18 +96,18 @@ Path: ``app/Database/Migrations``:: { $this->forge->addField([ 'blog_id' => [ - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true, + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => true, + 'auto_increment' => true, ], 'blog_title' => [ - 'type' => 'VARCHAR', - 'constraint' => '100', + 'type' => 'VARCHAR', + 'constraint' => '100', ], 'blog_description' => [ - 'type' => 'TEXT', - 'null' => true, + 'type' => 'TEXT', + 'null' => true, ], ]); $this->forge->addKey('blog_id', true); diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst index 87d213839f5f..6f373e9aafa4 100644 --- a/user_guide_src/source/libraries/caching.rst +++ b/user_guide_src/source/libraries/caching.rst @@ -19,8 +19,7 @@ The following example shows a common usage pattern within your controllers. :: - if (! $foo = cache('foo')) - { + if (! $foo = cache('foo')) { echo 'Saving to the cache!
'; $foo = 'foobarbaz!'; @@ -93,7 +92,7 @@ Class Reference :rtype: mixed This method will attempt to fetch an item from the cache store. If the - item does not exist, the method will return NULL. + item does not exist, the method will return null. Example:: @@ -106,7 +105,7 @@ Class Reference :param Closure $callback: Callback to invoke when the cache item returns null :returns: The value of the cache item :rtype: mixed - + Gets an item from the cache. If ``null`` was returned, this will invoke the callback and save the result. Either way, this will return the value. @@ -136,7 +135,7 @@ Class Reference :rtype: bool This method will delete a specific item from the cache store. If item - deletion fails, the method will return FALSE. + deletion fails, the method will return false. Example:: @@ -174,7 +173,7 @@ Class Reference Example:: // 'iterator' has a value of 2 - $cache->increment('iterator'); // 'iterator' is now 3 + $cache->increment('iterator'); // 'iterator' is now 3 $cache->increment('iterator', 3); // 'iterator' is now 6 .. php:method:: decrement($key[, $offset = 1]): mixed @@ -189,7 +188,7 @@ Class Reference Example:: // 'iterator' has a value of 6 - $cache->decrement('iterator'); // 'iterator' is now 5 + $cache->decrement('iterator'); // 'iterator' is now 5 $cache->decrement('iterator', 2); // 'iterator' is now 3 .. php:method:: clean() @@ -198,7 +197,7 @@ Class Reference :rtype: bool This method will 'clean' the entire cache. If the deletion of the - cache files fails, the method will return FALSE. + cache files fails, the method will return false. Example:: diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index 6b5d15dea487..08dc0c0a41c9 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -34,7 +34,7 @@ The options are described later in this document:: $options = [ 'baseURI' => 'http://example.com/api/v1/', - 'timeout' => 3 + 'timeout' => 3, ]; $client = \Config\Services::curlrequest($options); @@ -67,7 +67,7 @@ a Response instance to you. This takes the HTTP method, the url and an array of $client = \Config\Services::curlrequest(); $response = $client->request('GET', 'https://api.github.com/user', [ - 'auth' => ['user', 'pass'] + 'auth' => ['user', 'pass'], ]); Since the response is an instance of ``CodeIgniter\HTTP\Response`` you have all of the normal information @@ -97,7 +97,7 @@ set a base URI, and then make all requests with that client using relative URLs. when working with APIs:: $client = \Config\Services::curlrequest([ - 'baseURI' => 'https://example.com/api/v1/' + 'baseURI' => 'https://example.com/api/v1/', ]); // GET http:example.com/api/v1/photos @@ -130,8 +130,8 @@ methods. The most commonly used methods let you determine the response itself. You can get the status code and reason phrase of the response:: - $code = $response->getStatusCode(); // 200 - $reason = $response->getReason(); // OK + $code = $response->getStatusCode(); // 200 + $reason = $response->getReason(); // OK You can retrieve headers from the response:: @@ -139,8 +139,7 @@ You can retrieve headers from the response:: echo $response->getHeaderLine('Content-Type'); // Get all headers - foreach ($response->getHeaders() as $name => $value) - { + foreach ($response->getHeaders() as $name => $value) { echo $name .': '. $response->getHeaderLine($name) ."\n"; } @@ -151,8 +150,7 @@ The body can be retrieved using the ``getBody()`` method:: The body is the raw body provided by the remote getServer. If the content type requires formatting, you will need to ensure that your script handles that:: - if (strpos($response->getHeader('content-type'), 'application/json') !== false) - { + if (strpos($response->getHeader('content-type'), 'application/json') !== false) { $body = json_decode($body); } @@ -208,8 +206,7 @@ body There are two ways to set the body of the request for request types that support them, like PUT, OR POST. The first way is to use the ``setBody()`` method:: - $client->setBody($body) - ->request('put', 'http://example.com'); + $client->setBody($body) ->request('put', 'http://example.com'); The second method is by passing a ``body`` option in. This is provided to maintain Guzzle API compatibility, and functions the exact same way as the previous example. The value must be a string:: @@ -275,8 +272,8 @@ if it's not already set:: $client->request('POST', '/post', [ 'form_params' => [ 'foo' => 'bar', - 'baz' => ['hi', 'there'] - ] + 'baz' => ['hi', 'there'], + ], ]); .. note:: ``form_params`` cannot be used with the ``multipart`` option. You will need to use one or the other. @@ -294,8 +291,8 @@ representing the header field values:: 'headers' => [ 'User-Agent' => 'testing/1.0', 'Accept' => 'application/json', - 'X-Foo' => ['Bar', 'Baz'] - ] + 'X-Foo' => ['Bar', 'Baz'], + ], ]); If headers are passed into the constructor they are treated as default values that will be overridden later by any @@ -337,7 +334,7 @@ has been disabled. Any files that you want to send must be passed as instances o $post_data = [ 'foo' => 'bar', - 'userfile' => new \CURLFile('/path/to/file.txt') + 'userfile' => new \CURLFile('/path/to/file.txt'), ]; .. note:: ``multipart`` cannot be used with the ``form_params`` option. You can only use one or the other. Use diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index f92be8500db6..55604ad6bbee 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -128,24 +128,24 @@ Preference Default Value Options Descript **SMTPPort** 25 None SMTP Port. (If set to 465, TLS will be used for the connection regardless of SMTPCrypto setting.) **SMTPTimeout** 5 None SMTP Timeout (in seconds). -**SMTPKeepAlive** FALSE TRUE or FALSE (boolean) Enable persistent SMTP connections. +**SMTPKeepAlive** false true or false (boolean) Enable persistent SMTP connections. **SMTPCrypto** No Default tls or ssl SMTP Encryption. Setting this to "ssl" will create a secure channel to the server using SSL and "tls" will issue a ``STARTTLS`` command to the server. Connection on port 465 should set this to blank. -**wordWrap** TRUE TRUE or FALSE (boolean) Enable word-wrap. +**wordWrap** true true or false (boolean) Enable word-wrap. **wrapChars** 76 Character count to wrap at. **mailType** text text or html Type of mail. If you send HTML email you must send it as a complete web page. Make sure you don't have any relative links or relative image paths otherwise they will not work. **charset** utf-8 Character set (utf-8, iso-8859-1, etc.). -**validate** TRUE TRUE or FALSE (boolean) Whether to validate the email address. +**validate** true true or false (boolean) Whether to validate the email address. **priority** 3 1, 2, 3, 4, 5 Email Priority. 1 = highest. 5 = lowest. 3 = normal. **CRLF** \\n "\\r\\n" or "\\n" or "\\r" Newline character. (Use "\\r\\n" to comply with RFC 822). **newline** \\n "\\r\\n" or "\\n" or "\\r" Newline character. (Use "\\r\\n" to comply with RFC 822). -**BCCBatchMode** FALSE TRUE or FALSE (boolean) Enable BCC Batch Mode. +**BCCBatchMode** false true or false (boolean) Enable BCC Batch Mode. **BCCBatchSize** 200 None Number of emails in each BCC batch. -**DSN** FALSE TRUE or FALSE (boolean) Enable notify message from server +**DSN** false true or false (boolean) Enable notify message from server =================== ====================== ============================ ======================================================================= Overriding Word Wrapping @@ -320,7 +320,7 @@ Class Reference $email->send(); } - If you set the parameter to TRUE any attachments will be cleared as + If you set the parameter to true any attachments will be cleared as well:: $email->clear(true); @@ -328,10 +328,10 @@ Class Reference .. php:method:: send($autoClear = true) :param bool $autoClear: Whether to clear message data automatically - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool - The e-mail sending method. Returns boolean TRUE or FALSE based on + The e-mail sending method. Returns boolean true or false based on success or failure, enabling it to be used conditionally:: if (! $email->send()) @@ -340,7 +340,7 @@ Class Reference } This method will automatically clear all parameters if the request was - successful. To stop this behaviour pass FALSE:: + successful. To stop this behaviour pass false:: if ($email->send(false)) { @@ -352,7 +352,7 @@ Class Reference .. note:: If ``BCCBatchMode`` is enabled, and there are more than ``BCCBatchSize`` recipients, this method will always return - boolean ``TRUE``. + boolean ``true``. .. php:method:: attach($filename[, $disposition = ''[, $newname = null[, $mime = '']]]) @@ -395,7 +395,7 @@ Class Reference .. php:method:: setAttachmentCID($filename) :param string $filename: Existing attachment filename - :returns: Attachment Content-ID or FALSE if not found + :returns: Attachment Content-ID or false if not found :rtype: string Sets and returns an attachment's Content-ID, which enables your to embed an inline @@ -404,8 +404,8 @@ Class Reference $filename = '/img/photo1.jpg'; $email->attach($filename); - foreach ($list as $address) - { + + foreach ($list as $address) { $email->setTo($address); $cid = $email->setAttachmentCID($filename); $email->setMessage('photo1'); @@ -428,7 +428,7 @@ Class Reference Example:: - // You need to pass FALSE while sending in order for the email data + // You need to pass false while sending in order for the email data // to not be cleared - if that happens, printDebugger() would have // nothing to output. $email->send(false); diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index e6482642d698..9b29767d4d19 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -36,12 +36,10 @@ Once you have an instance, you have the full power of the SplFileInfo class at t echo $file->getPerms(); // Write CSV rows to it. - if ($file->isWritable()) - { + if ($file->isWritable()) { $csv = $file->openFile('w'); - foreach ($rows as $row) - { + foreach ($rows as $row) { $csv->fputcsv($row); } } @@ -63,16 +61,16 @@ method. This is especially useful to rename files when moving it so that the fil Returns the size of the uploaded file in bytes:: - $size = $file->getSize(); // 256901 + $size = $file->getSize(); // 256901 **getSizeByUnit()** Returns the size of the uploaded file default in bytes. You can pass in either 'kb' or 'mb' as the first parameter to get the results in kilobytes or megabytes, respectively:: - $bytes = $file->getSizeByUnit(); // 256901 - $kilobytes = $file->getSizeByUnit('kb'); // 250.880 - $megabytes = $file->getSizeByUnit('mb'); // 0.245 + $bytes = $file->getSizeByUnit(); // 256901 + $kilobytes = $file->getSizeByUnit('kb'); // 250.880 + $megabytes = $file->getSizeByUnit('mb'); // 0.245 **getMimeType()** diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index ec780ea2218b..959a2278178e 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -18,15 +18,15 @@ To enable a Honeypot, changes have to be made to the ``app/Config/Filters.php``. from the ``$globals`` array, like...:: public $globals = [ - 'before' => [ - 'honeypot' - // 'csrf', - ], - 'after' => [ - 'toolbar', - 'honeypot' - ] - ]; + 'before' => [ + 'honeypot' + // 'csrf', + ], + 'after' => [ + 'toolbar', + 'honeypot', + ], + ]; A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``. If it is not suitable, make your own at ``app/Filters/Honeypot.php``, diff --git a/user_guide_src/source/libraries/images.rst b/user_guide_src/source/libraries/images.rst index 7dc782c15902..d22f3eba9af6 100644 --- a/user_guide_src/source/libraries/images.rst +++ b/user_guide_src/source/libraries/images.rst @@ -135,9 +135,7 @@ error upon failure, like this:: ->withFile('/path/to/image/mypic.jpg') ->fit(100, 100, 'center') ->save('/path/to/image/mypic_thumb.jpg'); - } - catch (CodeIgniter\Images\ImageException $e) - { + } catch (CodeIgniter\Images\ImageException $e) { echo $e->getMessage(); } diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index c575579d2169..dc5b605c8d72 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -90,7 +90,7 @@ methods to keep the data separate:: $data = [ 'users' => $userModel->paginate(10, 'group1'), 'pages' => $pageModel->paginate(15, 'group2'), - 'pager' => $userModel->pager + 'pager' => $userModel->pager, ]; echo view('users/index', $data); @@ -189,7 +189,7 @@ that is used by editing **app/Config/Pager.php**:: public $templates = [ 'default_full' => 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple' + 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', ]; This setting stores the alias and :doc:`namespaced view paths ` for the view that @@ -304,7 +304,7 @@ title, which is just the number, and a boolean that tells whether the link is th $link = [ 'active' => false, 'uri' => 'http://example.com/foo?page=2', - 'title' => 1 + 'title' => 1, ]; In the code presented for the standard pagination structure, the methods ``getPrevious()`` and ``getNext()`` are used to obtain the links to the previous and next pagination groups respectively. diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index b52b7aafeb21..0e4d540dd899 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -28,9 +28,9 @@ and enabling the `csrf` filter globally:: public $globals = [ 'before' => [ - //'honeypot' - 'csrf' - ] + // 'honeypot', + 'csrf', + ], ]; Select URIs can be whitelisted from CSRF protection (for example API @@ -39,16 +39,16 @@ by adding them as exceptions in the filter:: public $globals = [ 'before' => [ - 'csrf' => ['except' => ['api/record/save']] - ] + 'csrf' => ['except' => ['api/record/save']], + ], ]; Regular expressions are also supported (case-insensitive):: public $globals = [ 'before' => [ - 'csrf' => ['except' => ['api/record/[0-9]+']] - ] + 'csrf' => ['except' => ['api/record/[0-9]+']], + ], ]; If you use the :doc:`form helper <../helpers/form_helper>`, then diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 2020430012aa..ac4a20719b8c 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -145,7 +145,7 @@ variable, you will do this:: $name = $session->get('name'); -.. note:: The ``get()`` method returns NULL if the item you are trying +.. note:: The ``get()`` method returns null if the item you are trying to access does not exist. If you want to retrieve all of the existing userdata, you can simply @@ -180,7 +180,7 @@ an example:: $newdata = [ 'username' => 'johndoe', 'email' => 'johndoe@some-site.com', - 'logged_in' => TRUE + 'logged_in' => true, ]; $session->set($newdata); @@ -193,8 +193,8 @@ supports this syntax:: If you want to verify that a session value exists, simply check with ``isset()``:: - // returns FALSE if the 'some_name' item doesn't exist or is NULL, - // TRUE otherwise: + // returns false if the 'some_name' item doesn't exist or is null, + // true otherwise: isset($_SESSION['some_name']) Or you can call ``has()``:: @@ -287,7 +287,7 @@ Or to get an array with all flashdata, simply omit the key parameter:: $session->getFlashdata(); -.. note:: The ``getFlashdata()`` method returns NULL if the item cannot be +.. note:: The ``getFlashdata()`` method returns null if the item cannot be found. If you find that you need to preserve a flashdata variable through an @@ -325,7 +325,7 @@ you want them all to have the same expiry time or not:: // will do so after only 240 seconds $session->markAsTempdata([ 'item' => 300, - 'item2' => 240 + 'item2' => 240, ]); To add tempdata:: @@ -339,8 +339,8 @@ Or alternatively, using the ``setTempdata()`` method:: You can also pass an array to ``setTempdata()``:: - $tempdata = ['newuser' => TRUE, 'message' => 'Thanks for joining!']; - $session->setTempdata($tempdata, NULL, $expire); + $tempdata = ['newuser' => true, 'message' => 'Thanks for joining!']; + $session->setTempdata($tempdata, null, $expire); .. note:: If the expiration is omitted or set to 0, the default time-to-live value of 300 seconds (or 5 minutes) will be used. @@ -363,7 +363,7 @@ And of course, if you want to retrieve all existing tempdata:: $session->getTempdata(); -.. note:: The ``getTempdata()`` method returns NULL if the item cannot be +.. note:: The ``getTempdata()`` method returns null if the item cannot be found. If you need to remove a tempdata value before it expires, you can directly @@ -441,14 +441,14 @@ Preference Default Opti **sessionCookieName** ci_session [A-Za-z\_-] characters only The name used for the session cookie. **sessionExpiration** 7200 (2 hours) Time in seconds (integer) The number of seconds you would like the session to last. If you would like a non-expiring session (until browser is closed) set the value to zero: 0 -**sessionSavePath** NULL None Specifies the storage location, depends on the driver being used. -**sessionMatchIP** FALSE TRUE/FALSE (boolean) Whether to validate the user's IP address when reading the session cookie. +**sessionSavePath** null None Specifies the storage location, depends on the driver being used. +**sessionMatchIP** false true/false (boolean) Whether to validate the user's IP address when reading the session cookie. Note that some ISPs dynamically changes the IP, so if you want a non-expiring session you - will likely set this to FALSE. + will likely set this to false. **sessionTimeToUpdate** 300 Time in seconds (integer) This option controls how often the session class will regenerate itself and create a new session ID. Setting it to 0 will disable session ID regeneration. -**sessionRegenerateDestroy** FALSE TRUE/FALSE (boolean) Whether to destroy session data associated with the old session ID when auto-regenerating - the session ID. When set to FALSE, the data will be later deleted by the garbage collector. +**sessionRegenerateDestroy** false true/false (boolean) Whether to destroy session data associated with the old session ID when auto-regenerating + the session ID. When set to false, the data will be later deleted by the garbage collector. ============================== ============================================ ================================================= ============================================================================================ .. note:: As a last resort, the Session library will try to fetch PHP's @@ -579,10 +579,10 @@ And then of course, create the database table ... For MySQL:: CREATE TABLE IF NOT EXISTS `ci_sessions` ( - `id` varchar(128) NOT NULL, - `ip_address` varchar(45) NOT NULL, - `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL, - `data` blob NOT NULL, + `id` varchar(128) NOT null, + `ip_address` varchar(45) NOT null, + `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP NOT null, + `data` blob NOT null, KEY `ci_sessions_timestamp` (`timestamp`) ); @@ -600,10 +600,10 @@ For PostgreSQL:: You will also need to add a PRIMARY KEY **depending on your 'sessionMatchIP' setting**. The examples below work both on MySQL and PostgreSQL:: - // When sessionMatchIP = TRUE + // When sessionMatchIP = true ALTER TABLE ci_sessions ADD PRIMARY KEY (id, ip_address); - // When sessionMatchIP = FALSE + // When sessionMatchIP = false ALTER TABLE ci_sessions ADD PRIMARY KEY (id); // To drop a previously created primary key (use when changing the setting) diff --git a/user_guide_src/source/libraries/throttler.rst b/user_guide_src/source/libraries/throttler.rst index cdefb935ba1d..22d7829899cd 100644 --- a/user_guide_src/source/libraries/throttler.rst +++ b/user_guide_src/source/libraries/throttler.rst @@ -67,8 +67,7 @@ along the lines of:: * This is a demo implementation of using the Throttler class * to implement rate limiting for your application. * - * @param RequestInterface|\CodeIgniter\HTTP\IncomingRequest $request - * @param array|null $arguments + * @param array|null $arguments * * @return mixed */ @@ -79,8 +78,7 @@ along the lines of:: // Restrict an IP address to no more // than 1 request per second across the // entire site. - if ($throttler->check($request->getIPAddress(), 60, MINUTE) === false) - { + if ($throttler->check($request->getIPAddress(), 60, MINUTE) === false) { return Services::response()->setStatusCode(429); } } @@ -88,9 +86,7 @@ along the lines of:: /** * We don't have anything to do here. * - * @param RequestInterface|\CodeIgniter\HTTP\IncomingRequest $request - * @param ResponseInterface|\CodeIgniter\HTTP\Response $response - * @param array|null $arguments + * @param array|null $arguments * * @return mixed */ @@ -116,13 +112,13 @@ filter:: public $aliases = [ ... - 'throttle' => \App\Filters\Throttle::class + 'throttle' => \App\Filters\Throttle::class, ]; Next, we assign it to all POST requests made on the site:: public $methods = [ - 'post' => ['throttle', 'CSRF'] + 'post' => ['throttle', 'CSRF'], ]; And that's all there is to it. Now all POST requests made on the site will have to be rate limited. @@ -137,7 +133,7 @@ Class Reference :param int $capacity: The number of tokens the bucket holds :param int $seconds: The number of seconds it takes for a bucket to completely fill :param int $cost: The number of tokens that are spent on this action - :returns: TRUE if action can be performed, FALSE if not + :returns: true if action can be performed, false if not :rtype: bool Checks to see if there are any tokens left within the bucket, or if too many have @@ -149,7 +145,7 @@ Class Reference :returns: The number of seconds until another token should be available. :rtype: integer - After ``check()`` has been run and returned FALSE, this method can be used + After ``check()`` has been run and returned false, this method can be used to determine the time until a new token should be available and the action can be tried again. In this case, the minimum enforced wait time is one second. diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index d964892eb91c..12f3a9f38e7e 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -85,8 +85,8 @@ Given separate inputs for **year**, **month**, and **day**, will return a new in are not provided, it will use the current value to fill it in. Accepts strings for the timezone and locale in the fourth and fifth parameters:: - $today = Time::createFromDate(); // Uses current year, month, and day - $anniversary = Time::createFromDate(2018); // Uses current month and day + $today = Time::createFromDate(); // Uses current year, month, and day + $anniversary = Time::createFromDate(2018); // Uses current month and day $date = Time::createFromDate(2018, 3, 15, 'America/Chicago', 'en_US'); createFromTime() @@ -96,8 +96,8 @@ Like **createFromDate** except it is only concerned with the **hours**, **minute current day for the date portion of the Time instance. Accepts strings for the timezone and locale in the fourth and fifth parameters:: - $lunch = Time::createFromTime(11, 30) // 11:30 am today - $dinner = Time::createFromTime(18, 00, 00) // 6:00 pm today + $lunch = Time::createFromTime(11, 30); // 11:30 am today + $dinner = Time::createFromTime(18, 00, 00); // 6:00 pm today $time = Time::createFromTime($hour, $minutes, $seconds, $timezone, $locale); create() @@ -160,7 +160,7 @@ A full listing of values can be found `here toLocalizedString('MMM d, yyyy'); // March 9, 2016 + echo $time->toLocalizedString('MMM d, yyyy'); // March 9, 2016 toDateTimeString() ------------------ @@ -169,7 +169,7 @@ This is the first of three helper methods to work with the IntlDateFormatter wit This will return a string formatted as you would commonly use for datetime columns in a database (Y-m-d H:i:s):: $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toDateTimeString(); // 2016-03-09 12:00:00 + echo $time->toDateTimeString(); // 2016-03-09 12:00:00 toDateString() -------------- @@ -177,7 +177,7 @@ toDateString() Displays just the date portion of the Time:: $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toDateString(); // 2016-03-09 + echo $time->toDateString(); // 2016-03-09 toTimeString() -------------- @@ -185,7 +185,7 @@ toTimeString() Displays just the time portion of the value:: $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toTimeString(); // 12:00:00 + echo $time->toTimeString(); // 12:00:00 humanize() ---------- @@ -197,7 +197,7 @@ human readable format that is geared towards being easily understood. It can cre // Assume current time is: March 10, 2017 (America/Chicago) $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->humanize(); // 1 year ago + echo $time->humanize(); // 1 year ago The exact time displayed is determined in the following manner: @@ -234,37 +234,37 @@ The following basic getters exist:: $time = Time::parse('August 12, 2016 4:15:23pm'); - echo $time->getYear(); // 2016 - echo $time->getMonth(); // 8 - echo $time->getDay(); // 12 - echo $time->getHour(); // 16 - echo $time->getMinute(); // 15 - echo $time->getSecond(); // 23 + echo $time->getYear(); // 2016 + echo $time->getMonth(); // 8 + echo $time->getDay(); // 12 + echo $time->getHour(); // 16 + echo $time->getMinute(); // 15 + echo $time->getSecond(); // 23 - echo $time->year; // 2016 - echo $time->month; // 8 - echo $time->day; // 12 - echo $time->hour; // 16 - echo $time->minute; // 15 - echo $time->second; // 23 + echo $time->year; // 2016 + echo $time->month; // 8 + echo $time->day; // 12 + echo $time->hour; // 16 + echo $time->minute; // 15 + echo $time->second; // 23 In addition to these, a number of methods exist to provide additional information about the date:: $time = Time::parse('August 12, 2016 4:15:23pm'); - echo $time->getDayOfWeek(); // 6 - but may vary based on locale's starting day of the week - echo $time->getDayOfYear(); // 225 - echo $time->getWeekOfMonth(); // 2 - echo $time->getWeekOfYear(); // 33 - echo $time->getTimestamp(); // 1471018523 - UNIX timestamp - echo $time->getQuarter(); // 3 + echo $time->getDayOfWeek(); // 6 - but may vary based on locale's starting day of the week + echo $time->getDayOfYear(); // 225 + echo $time->getWeekOfMonth(); // 2 + echo $time->getWeekOfYear(); // 33 + echo $time->getTimestamp(); // 1471018523 - UNIX timestamp + echo $time->getQuarter(); // 3 - echo $time->dayOfWeek; // 6 - echo $time->dayOfYear; // 225 - echo $time->weekOfMonth; // 2 - echo $time->weekOfYear; // 33 - echo $time->timestamp; // 1471018523 - echo $time->quarter; // 3 + echo $time->dayOfWeek; // 6 + echo $time->dayOfYear; // 225 + echo $time->weekOfMonth; // 2 + echo $time->weekOfYear; // 33 + echo $time->timestamp; // 1471018523 + echo $time->quarter; // 3 getAge() -------- @@ -274,32 +274,32 @@ the age of someone based on their birthday:: $time = Time::parse('5 years ago'); - echo $time->getAge(); // 5 - echo $time->age; // 5 + echo $time->getAge(); // 5 + echo $time->age; // 5 getDST() -------- Returns boolean true/false based on whether the Time instance is currently observing Daylight Savings Time:: - echo Time::createFromDate(2012, 1, 1)->getDst(); // false - echo Time::createFromDate(2012, 9, 1)->dst; // true + echo Time::createFromDate(2012, 1, 1)->getDst(); // false + echo Time::createFromDate(2012, 9, 1)->dst; // true getLocal() ---------- Returns boolean true if the Time instance is in the same timezone as the application is currently running in:: - echo Time::now()->getLocal(); // true - echo Time::now('Europe/London'); // false + echo Time::now()->getLocal(); // true + echo Time::now('Europe/London'); // false getUtc() -------- Returns boolean true if the Time instance is in UTC time:: - echo Time::now('America/Chicago')->getUtc(); // false - echo Time::now('UTC')->utc; // true + echo Time::now('America/Chicago')->getUtc(); // false + echo Time::now('UTC')->utc; // true getTimezone() ------------- @@ -318,8 +318,8 @@ getTimezoneName() Returns the full `timezone string `__ of the Time instance:: - echo Time::now('America/Chicago')->getTimezoneName(); // America/Chicago - echo Time::now('Europe/London')->timezoneName; // Europe/London + echo Time::now('America/Chicago')->getTimezoneName(); // America/Chicago + echo Time::now('Europe/London')->timezoneName; // Europe/London Setters ======= @@ -334,11 +334,11 @@ thrown. :: $time = $time->setYear(2017); - $time = $time->setMonthNumber(4); // April + $time = $time->setMonthNumber(4); // April $time = $time->setMonthLongName('April'); - $time = $time->setMonthShortName('Feb'); // February + $time = $time->setMonthShortName('Feb'); // February $time = $time->setDay(25); - $time = $time->setHour(14); // 2:00 pm + $time = $time->setHour(14); // 2:00 pm $time = $time->setMinute(30); $time = $time->setSecond(54); @@ -348,13 +348,13 @@ setTimezone() Converts the time from it's current timezone into the new one:: $time = Time::parse('13 May 2020 10:00', 'America/Chicago'); - $time2 = $time->setTimezone('Europe/London'); // Returns new instance converted to new timezone + $time2 = $time->setTimezone('Europe/London'); // Returns new instance converted to new timezone - echo $time->getTimezoneName(); // American/Chicago - echo $time2->getTimezoneName(); // Europe/London + echo $time->getTimezoneName(); // American/Chicago + echo $time2->getTimezoneName(); // Europe/London - echo $time->toDateTimeString(); // 2020-05-13 10:00:00 - echo $time2->toDateTimeString(); // 2020-05-13 18:00:00 + echo $time->toDateTimeString(); // 2020-05-13 10:00:00 + echo $time2->toDateTimeString(); // 2020-05-13 18:00:00 setTimestamp() -------------- @@ -364,8 +364,8 @@ Returns a new instance with the date set to the new timestamp:: $time = Time::parse('May 10, 2017', 'America/Chicago'); $time2 = $time->setTimestamp(strtotime('April 1, 2017')); - echo $time->toDateTimeString(); // 2017-05-10 00:00:00 - echo $time2->toDateTimeString(); // 2017-04-01 00:00:00 + echo $time->toDateTimeString(); // 2017-05-10 00:00:00 + echo $time2->toDateTimeString(); // 2017-04-01 00:00:00 Modifying the Value =================== @@ -405,13 +405,13 @@ that way:: $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); $time2 = Time::parse('January 11, 2017 03:50:00', 'Europe/London'); - $time1->equals($time2); // true + $time1->equals($time2); // true The value being tested against can be a Time instance, a DateTime instance, or a string with the full date time in a manner that a new DateTime instance can understand. When passing a string as the first parameter, you can pass a timezone string in as the second parameter. If no timezone is given, the system default will be used:: - $time1->equals('January 11, 2017 03:50:00', 'Europe/London'); // true + $time1->equals('January 11, 2017 03:50:00', 'Europe/London'); // true sameAs() -------- @@ -423,7 +423,7 @@ all identical:: $time2 = Time::parse('January 11, 2017 03:50:00', 'Europe/London'); $time1->sameAs($time2); // false - $time2->sameAs('January 10, 2017 21:50:00', 'America/Chicago'); // true + $time2->sameAs('January 10, 2017 21:50:00', 'America/Chicago'); // true isBefore() ---------- @@ -434,14 +434,14 @@ both times:: $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); $time2 = Time::parse('January 11, 2017 03:50:00', 'America/Chicago'); - $time1->isBefore($time2); // true - $time2->isBefore($time1); // false + $time1->isBefore($time2); // true + $time2->isBefore($time1); // false The value being tested against can be a Time instance, a DateTime instance, or a string with the full date time in a manner that a new DateTime instance can understand. When passing a string as the first parameter, you can pass a timezone string in as the second parameter. If no timezone is given, the system default will be used:: - $time1->isBefore('March 15, 2013', 'America/Chicago'); // false + $time1->isBefore('March 15, 2013', 'America/Chicago'); // false isAfter() --------- @@ -451,8 +451,8 @@ Works exactly the same as **isBefore()** except checks if the time is after the $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); $time2 = Time::parse('January 11, 2017 03:50:00', 'America/Chicago'); - $time1->isAfter($time2); // false - $time2->isAfter($time1); // true + $time1->isAfter($time2); // false + $time2->isAfter($time1); // true Viewing Differences =================== @@ -476,23 +476,23 @@ the original time:: $diff = $current->difference($test); - echo $diff->getYears(); // -7 - echo $diff->getMonths(); // -84 - echo $diff->getWeeks(); // -365 - echo $diff->getDays(); // -2557 - echo $diff->getHours(); // -61368 - echo $diff->getMinutes(); // -3682080 - echo $diff->getSeconds(); // -220924800 + echo $diff->getYears(); // -7 + echo $diff->getMonths(); // -84 + echo $diff->getWeeks(); // -365 + echo $diff->getDays(); // -2557 + echo $diff->getHours(); // -61368 + echo $diff->getMinutes(); // -3682080 + echo $diff->getSeconds(); // -220924800 You can use either **getX()** methods, or access the calculate values as if they were properties:: - echo $diff->years; // -7 - echo $diff->months; // -84 - echo $diff->weeks; // -365 - echo $diff->days; // -2557 - echo $diff->hours; // -61368 - echo $diff->minutes; // -3682080 - echo $diff->seconds; // -220924800 + echo $diff->years; // -7 + echo $diff->months; // -84 + echo $diff->weeks; // -365 + echo $diff->days; // -2557 + echo $diff->hours; // -61368 + echo $diff->minutes; // -3682080 + echo $diff->seconds; // -220924800 humanize() ---------- @@ -506,7 +506,7 @@ human readable format that is geared towards being easily understood. It can cre $diff = $current->difference($test) - echo $diff->humanize(); // 1 year ago + echo $diff->humanize(); // 1 year ago The exact time displayed is determined in the following manner: diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst index 7d53f61f820e..e449c6371148 100644 --- a/user_guide_src/source/libraries/typography.rst +++ b/user_guide_src/source/libraries/typography.rst @@ -26,7 +26,7 @@ The following functions are available: **autoTypography()** -.. php:function:: autoTypography($str[, $reduce_linebreaks = FALSE]) +.. php:function:: autoTypography($str[, $reduce_linebreaks = false]) :param string $str: Input string :param bool $reduce_linebreaks: Whether to reduce multiple instances of double newlines to two diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 3e76fb74c905..c4067f3e8eb6 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -110,11 +110,10 @@ In controller:: { foreach($imagefile['images'] as $img) { - if ($img->isValid() && ! $img->hasMoved()) - { - $newName = $img->getRandomName(); - $img->move(WRITEPATH.'uploads', $newName); - } + if ($img->isValid() && ! $img->hasMoved()) { + $newName = $img->getRandomName(); + $img->move(WRITEPATH.'uploads', $newName); + } } } @@ -155,8 +154,7 @@ Verify A File You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method:: - if (! $file->isValid()) - { + if (! $file->isValid()) { throw new \RuntimeException($file->getErrorString().'('.$file->getError().')'); } @@ -230,8 +228,7 @@ By default, the original filename was used. You can specify a new filename by pa Once the file has been removed the temporary file is deleted. You can check if a file has been moved already with the ``hasMoved()`` method, which returns a boolean:: - if ($file->isValid() && ! $file->hasMoved()) - { + if ($file->isValid() && ! $file->hasMoved()) { $file->move($path); } diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst index 649685db71ec..e8b7c0cefd57 100644 --- a/user_guide_src/source/libraries/uri.rst +++ b/user_guide_src/source/libraries/uri.rst @@ -211,8 +211,8 @@ you can use the ``stripQuery()`` and ``keepQuery()`` methods to change the actua // Leaves just the 'foo' variable $uri->keepQuery('foo'); -.. note:: By default ``setQuery()`` and ``setQueryArray()`` methods uses native ``parse_str()`` function to prepare data. - If you want to use more liberal rules (which allow key names to contain dots), you can use a special method +.. note:: By default ``setQuery()`` and ``setQueryArray()`` methods uses native ``parse_str()`` function to prepare data. + If you want to use more liberal rules (which allow key names to contain dots), you can use a special method ``useRawQueryString()`` beforehand. Fragment @@ -238,8 +238,7 @@ what the values of the segments are. The segments start at 1 being the furthest // URI = http://example.com/users/15/profile // Prints '15' - if ($uri->getSegment(1) == 'users') - { + if ($uri->getSegment(1) == 'users') { echo $uri->getSegment(2); } diff --git a/user_guide_src/source/libraries/user_agent.rst b/user_guide_src/source/libraries/user_agent.rst index e1d0d155b3af..f8cf92f72064 100644 --- a/user_guide_src/source/libraries/user_agent.rst +++ b/user_guide_src/source/libraries/user_agent.rst @@ -39,20 +39,13 @@ is available:: $agent = $this->request->getUserAgent(); - if ($agent->isBrowser()) - { + if ($agent->isBrowser()) { $currentAgent = $agent->getBrowser().' '.$agent->getVersion(); - } - elseif ($agent->isRobot()) - { + } elseif ($agent->isRobot()) { $currentAgent = $this->agent->robot(); - } - elseif ($agent->isMobile()) - { + } elseif ($agent->isMobile()) { $currentAgent = $agent->getMobile(); - } - else - { + } else { $currentAgent = 'Unidentified User Agent'; } @@ -66,21 +59,18 @@ Class Reference .. php:class:: CodeIgniter\\HTTP\\UserAgent - .. php:method:: isBrowser([$key = NULL]) + .. php:method:: isBrowser([$key = null]) :param string $key: Optional browser name - :returns: TRUE if the user agent is a (specified) browser, FALSE if not + :returns: true if the user agent is a (specified) browser, false if not :rtype: bool - Returns TRUE/FALSE (boolean) if the user agent is a known web browser. + Returns true/false (boolean) if the user agent is a known web browser. :: - if ($agent->isBrowser('Safari')) - { + if ($agent->isBrowser('Safari')) { echo 'You are using Safari.'; - } - elseif ($agent->isBrowser()) - { + } elseif ($agent->isBrowser()) { echo 'You are using a browser.'; } @@ -88,35 +78,30 @@ Class Reference You can find this list in **app/Config/UserAgents.php** if you want to add new browsers or change the strings. - .. php:method:: isMobile([$key = NULL]) + .. php:method:: isMobile([$key = null]) :param string $key: Optional mobile device name - :returns: TRUE if the user agent is a (specified) mobile device, FALSE if not + :returns: true if the user agent is a (specified) mobile device, false if not :rtype: bool - Returns TRUE/FALSE (boolean) if the user agent is a known mobile device. + Returns true/false (boolean) if the user agent is a known mobile device. :: - if ($agent->isMobile('iphone')) - { + if ($agent->isMobile('iphone')) { echo view('iphone/home'); - } - elseif ($agent->isMobile()) - { + } elseif ($agent->isMobile()) { echo view('mobile/home'); - } - else - { + } else { echo view('web/home'); } - .. php:method:: isRobot([$key = NULL]) + .. php:method:: isRobot([$key = null]) :param string $key: Optional robot name - :returns: TRUE if the user agent is a (specified) robot, FALSE if not + :returns: true if the user agent is a (specified) robot, false if not :rtype: bool - Returns TRUE/FALSE (boolean) if the user agent is a known robot. + Returns true/false (boolean) if the user agent is a known robot. .. note:: The user agent library only contains the most common robot definitions. It is not a complete list of bots. There are hundreds of them so searching for each one would not be very efficient. If you find that some bots @@ -125,10 +110,10 @@ Class Reference .. php:method:: isReferral() - :returns: TRUE if the user agent is a referral, FALSE if not + :returns: true if the user agent is a referral, false if not :rtype: bool - Returns TRUE/FALSE (boolean) if the user agent was referred from another site. + Returns true/false (boolean) if the user agent was referred from another site. .. php:method:: getBrowser() @@ -172,8 +157,7 @@ Class Reference The referrer, if the user agent was referred from another site. Typically you'll test for this as follows:: - if ($agent->isReferral()) - { + if ($agent->isReferral()) { echo $agent->referrer(); } diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index ddfcf406f260..940a95953819 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -132,14 +132,11 @@ this code and save it to your **app/Controllers/** folder:: { helper(['form', 'url']); - if (! $this->validate([])) - { + if (! $this->validate([])) { echo view('Signup', [ 'validation' => $this->validator, ]); - } - else - { + } else { echo view('Success'); } } @@ -227,14 +224,14 @@ Like, ``setRule()``, but accepts an array of field names and their rules:: $validation->setRules([ 'username' => 'required', - 'password' => 'required|min_length[10]' + 'password' => 'required|min_length[10]', ]); To give a labeled error message you can set up as:: $validation->setRules([ 'username' => ['label' => 'Username', 'rules' => 'required'], - 'password' => ['label' => 'Password', 'rules' => 'required|min_length[10]'] + 'password' => ['label' => 'Password', 'rules' => 'required|min_length[10]'], ]); withRequest() @@ -245,8 +242,7 @@ data that was input from an HTTP Request. If desired, you can pass an instance o current Request object and it will take all of the input data and set it as the data to be validated:: - $validation->withRequest($this->request) - ->run(); + $validation->withRequest($this->request)->run(); Working with Validation ************************************************ @@ -262,29 +258,29 @@ easily validate your data:: 'name' => 'Joe Smith', 'friends' => [ [ - 'name' => 'Fred Flinstone' + 'name' => 'Fred Flinstone', ], [ - 'name' => 'Wilma' - ] + 'name' => 'Wilma', + ], ] ] // Joe Smith $validation->setRules([ - 'contacts.name' => 'required' + 'contacts.name' => 'required', ]); // Fred Flintsone & Wilma $validation->setRules([ - 'contacts.friends.name' => 'required' + 'contacts.friends.name' => 'required', ]); You can use the '*' wildcard symbol to match any one level of the array:: // Fred Flintsone & Wilma $validation->setRules([ - 'contacts.*.name' => 'required' + 'contacts.*.name' => 'required', ]); "dot array syntax" can also be useful when you have single dimension array data. @@ -294,11 +290,11 @@ For example, data returned by multi select dropdown:: 'user_ids' => [ 1, 2, - 3 + 3, ] // Rule $validation->setRules([ - 'user_ids.*' => 'required' + 'user_ids.*' => 'required', ]); Validate 1 Value @@ -331,7 +327,7 @@ rules. As shown earlier, the validation array will have this prototype:: 'username' => 'required', 'password' => 'required', 'pass_confirm' => 'required|matches[password]', - 'email' => 'required|valid_email' + 'email' => 'required|valid_email', ]; } @@ -349,7 +345,7 @@ be used for any errors when this group is used:: 'username' => 'required', 'password' => 'required', 'pass_confirm' => 'required|matches[password]', - 'email' => 'required|valid_email' + 'email' => 'required|valid_email', ]; public $signup_errors = [ @@ -357,8 +353,8 @@ be used for any errors when this group is used:: 'required' => 'You must choose a username.', ], 'email' => [ - 'valid_email' => 'Please check the Email field. It does not appear to be valid.' - ] + 'valid_email' => 'Please check the Email field. It does not appear to be valid.', + ], ]; } @@ -370,14 +366,14 @@ Or pass all settings in an array:: 'username' => [ 'rules' => 'required', 'errors' => [ - 'required' => 'You must choose a Username.' - ] + 'required' => 'You must choose a Username.', + ], ], 'email' => [ 'rules' => 'required|valid_email', 'errors' => [ - 'valid_email' => 'Please check the Email field. It does not appear to be valid.' - ] + 'valid_email' => 'Please check the Email field. It does not appear to be valid.', + ], ], ]; } @@ -411,10 +407,11 @@ rules after one another, you might need to call ``$validation->reset()`` before errors from previous run. Be aware that ``reset()`` will invalidate any data, rule or custom error you previously set, so ``setRules()``, ``setRuleGroup()`` etc. need to be repeated:: - for ($userAccounts as $user) { + foreach ($userAccounts as $user) { $validation->reset(); $validation->setRules($userAccountRules); - if (!$validation->run($user)) { + + if (! $validation->run($user)) { // handle validation errors } } @@ -428,7 +425,7 @@ the name of the field (or array key) that was passed in as $data surrounded by c replaced by the **value** of the matched incoming field. An example should clarify this:: $validation->setRules([ - 'email' => 'required|valid_email|is_unique[users.email,id,{id}]' + 'email' => 'required|valid_email|is_unique[users.email,id,{id}]', ]); In this set of rules, it states that the email address should be unique in the database, except for the row @@ -436,13 +433,13 @@ that has an id matching the placeholder's value. Assuming that the form POST dat $_POST = [ 'id' => 4, - 'email' => 'foo@example.com' + 'email' => 'foo@example.com', ]; then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule:: $validation->setRules([ - 'email' => 'required|valid_email|is_unique[users.email,id,4]' + 'email' => 'required|valid_email|is_unique[users.email,id,4]', ]); So it will ignore the row in the database that has ``id=4`` when it verifies the email is unique. @@ -482,8 +479,8 @@ As the last parameter:: 'required' => 'All accounts must have usernames provided', ], 'password' => [ - 'min_length' => 'Your password is too short. You want to get hacked?' - ] + 'min_length' => 'Your password is too short. You want to get hacked?', + ], ] ); @@ -494,15 +491,15 @@ Or as a labeled style:: 'label' => 'Username', 'rules' => 'required|is_unique[users.username]', 'errors' => [ - 'required' => 'All accounts must have {field} provided' - ] + 'required' => 'All accounts must have {field} provided', + ], ], 'password' => [ 'label' => 'Password', 'rules' => 'required|min_length[10]', 'errors' => [ - 'min_length' => 'Your {field} is too short. You want to get hacked?' - ] + 'min_length' => 'Your {field} is too short. You want to get hacked?', + ], ] ] ); @@ -529,16 +526,16 @@ We can simply use the language lines defined in this file, like this:: 'label' => 'Rules.username', 'rules' => 'required|is_unique[users.username]', 'errors' => [ - 'required' => 'Rules.username.required' - ] + 'required' => 'Rules.username.required', + ], ], 'password' => [ 'label' => 'Rules.password', 'rules' => 'required|min_length[10]', 'errors' => [ - 'min_length' => 'Rules.password.min_length' - ] - ] + 'min_length' => 'Rules.password.min_length', + ], + ], ] ); @@ -572,8 +569,7 @@ Check If Error Exists You can check to see if an error exists with the ``hasError()`` method. The only parameter is the field name:: - if ($validation->hasError('username')) - { + if ($validation->hasError('username')) { echo $validation->getError('username'); } @@ -623,7 +619,7 @@ short alias they can be referenced by. If we were to add our example file from a public $templates = [ 'list' => 'CodeIgniter\Validation\Views\list', 'single' => 'CodeIgniter\Validation\Views\single', - 'my_list' => '_errors_list' + 'my_list' => '_errors_list', ]; Specifying the Template @@ -667,7 +663,7 @@ a boolean true or false value signifying true if it passed the test or false if { public function even(string $str): bool { - return (int)$str % 2 == 0; + return (int) $str % 2 == 0; } } @@ -677,9 +673,9 @@ second parameter:: public function even(string $str, string &$error = null): bool { - if ((int)$str % 2 != 0) - { + if ((int) $str % 2 !== 0) { $error = lang('myerrors.evenError'); + return false; } @@ -689,7 +685,7 @@ second parameter:: Your new custom rule could now be used just like any other rule:: $this->validate($request, [ - 'foo' => 'required|even' + 'foo' => 'required|even', ]); Allowing Parameters @@ -708,8 +704,7 @@ for rules like ``require_with`` that needs to check the value of another submitt // search field is present or not. $present = $this->required($str ?? ''); - if ($present) - { + if ($present) { return true; } @@ -718,10 +713,8 @@ for rules like ``require_with`` that needs to check the value of another submitt // as $fields is the lis $requiredFields = []; - foreach ($fields as $field) - { - if (array_key_exists($field, $data)) - { + foreach ($fields as $field) { + if (array_key_exists($field, $data)) { $requiredFields[] = $field; } } @@ -887,7 +880,7 @@ file upload related rules:: // In the controller $this->validate([ - 'avatar' => 'uploaded[avatar]|max_size[avatar,1024]' + 'avatar' => 'uploaded[avatar]|max_size[avatar,1024]', ]); ======================= ========== ============================================= =================================================== diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 0d8ae47377bc..247c0fdce0e3 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -68,7 +68,7 @@ Create the model first at **app/Models/UserModel.php** so that we can interact w { protected $table = 'users'; protected $allowedFields = [ - 'username', 'email', 'password' + 'username', 'email', 'password', ]; protected $returnType = 'App\Entities\User'; protected $useTimestamps = true; @@ -93,10 +93,11 @@ Now that all of the pieces are in place, you would work with the Entity class as // Updating unset($user->username); - if (! isset($user->username) - { + + if (! isset($user->username) { $user->username = 'something new'; } + $userModel->save($user); // Create @@ -160,7 +161,7 @@ the attributes directly, allowing you to enforce any business logic or data conv Here's an updated User entity to provide some examples of how this could be used:: null, - 'name' => null, // Represents a username + 'name' => null, // Represents a username 'email' => null, 'password' => null, 'created_at' => null, @@ -257,7 +258,7 @@ property from ``$name`` to ``$full_name``, but that would require changes throug simply map the ``full_name`` column in the database to the ``$name`` property, and be done with the Entity changes:: null, - 'name' => null, // Represents a username + 'name' => null, // Represents a username 'email' => null, 'password' => null, 'created_at' => null, @@ -301,7 +302,7 @@ of helpful methods in an immutable, localized way. You can define which properties are automatically converted by adding the name to the **options['dates']** array:: 'boolean', + 'is_banned' => 'boolean', 'is_banned_nullable' => '?boolean', ]; } @@ -367,7 +368,7 @@ Unlike the rest of the data types that you can cast properties into, the: the value whenever the property is set:: hasChanged(); // true + $user->hasChanged(); // true diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index f2b852432298..8326f6e84bcc 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -172,7 +172,7 @@ is used with methods like ``find()`` to know what column to match the specified **$useAutoIncrement** Specifies if the table uses an auto-increment feature for ``$primaryKey``. If set to ``false`` -then you are responsible for providing primary key value for every record in the table. This +then you are responsible for providing primary key value for every record in the table. This feature may be handy when we want to implement 1:1 relation or use UUIDs for our model. .. note:: If you set ``$useAutoIncrement`` to ``false`` then make sure to set your primary @@ -321,7 +321,7 @@ Returns the first row in the result set. This is best used in combination with t **withDeleted()** -If $useSoftDeletes is true, then the find* methods will not return any rows where 'deleted_at IS NOT NULL'. +If $useSoftDeletes is true, then the find* methods will not return any rows where 'deleted_at IS NOT null'. To temporarily override this, you can use the withDeleted() method prior to calling the find* method. :: @@ -329,16 +329,14 @@ To temporarily override this, you can use the withDeleted() method prior to call $activeUsers = $userModel->findAll(); // Gets all rows - $allUsers = $userModel->withDeleted() - ->findAll(); + $allUsers = $userModel->withDeleted()->findAll(); **onlyDeleted()** Whereas withDeleted() will return both deleted and not-deleted rows, this method modifies the next find* methods to return only soft deleted rows:: - $deletedUsers = $userModel->onlyDeleted() - ->findAll(); + $deletedUsers = $userModel->onlyDeleted()->findAll(); Saving Data ----------- @@ -351,7 +349,7 @@ the array's values are the values to save for that key:: $data = [ 'username' => 'darth', - 'email' => 'd.vader@theempire.com' + 'email' => 'd.vader@theempire.com', ]; $userModel->insert($data); @@ -364,7 +362,7 @@ of the columns in a $table, while the array's values are the values to save for $data = [ 'username' => 'darth', - 'email' => 'd.vader@theempire.com' + 'email' => 'd.vader@theempire.com', ]; $userModel->update($id, $data); @@ -372,7 +370,7 @@ of the columns in a $table, while the array's values are the values to save for Multiple records may be updated with a single call by passing an array of primary keys as the first parameter:: $data = [ - 'active' => 1 + 'active' => 1, ]; $userModel->update([1, 2, 3], $data); @@ -396,7 +394,7 @@ automatically, based on whether it finds an array key matching the $primaryKey v // Does an insert() $data = [ 'username' => 'darth', - 'email' => 'd.vader@theempire.com' + 'email' => 'd.vader@theempire.com', ]; $userModel->save($data); @@ -405,7 +403,7 @@ automatically, based on whether it finds an array key matching the $primaryKey v $data = [ 'id' => 3, 'username' => 'darth', - 'email' => 'd.vader@theempire.com' + 'email' => 'd.vader@theempire.com', ]; $userModel->save($data); @@ -427,16 +425,14 @@ simplest, they might look like this:: public function __get($key) { - if (property_exists($this, $key)) - { + if (property_exists($this, $key)) { return $this->$key; } } public function __set($key, $value) { - if (property_exists($this, $key)) - { + if (property_exists($this, $key)) { $this->$key = $value; } } @@ -514,13 +510,13 @@ be applied. If you have custom error message that you want to use, place them in 'username' => 'required|alpha_numeric_space|min_length[3]', 'email' => 'required|valid_email|is_unique[users.email]', 'password' => 'required|min_length[8]', - 'pass_confirm' => 'required_with[password]|matches[password]' + 'pass_confirm' => 'required_with[password]|matches[password]', ]; protected $validationMessages = [ 'email' => [ - 'is_unique' => 'Sorry. That email has already been taken. Please choose another.' - ] + 'is_unique' => 'Sorry. That email has already been taken. Please choose another.', + ], ]; } @@ -537,7 +533,7 @@ The other way to set the validation rules to fields by functions, $fieldName = 'username'; $fieldRules = 'required|alpha_numeric_space|min_length[3]'; - + $model->setValidationRule($fieldName, $fieldRules); .. php:function:: setValidationRules($validationRules) @@ -751,8 +747,7 @@ parameter is a Closure that will be called for each row of data. This is best used during cronjobs, data exports, or other large tasks. :: - $userModel->chunk(100, function ($data) - { + $userModel->chunk(100, function ($data) { // do something. // $data is a single row of data. }); @@ -804,7 +799,7 @@ Additionally, each model may allow (default) or deny callbacks class-wide by set You may also change this setting temporarily for a single model call sing the ``allowCallbacks()`` method:: $model->allowCallbacks(false)->find(1); // No callbacks triggered - $model->find(1); // Callbacks subject to original property value + $model->find(1); // Callbacks subject to original property value Event Parameters ---------------- @@ -854,13 +849,15 @@ boolean, ``returnData``:: protected function checkCache(array $data) { // Check if the requested item is already in our cache - if (isset($data['id']) && $item = $this->getCachedItem($data['id']])) - { + if (isset($data['id']) && $item = $this->getCachedItem($data['id']])) { $data['data'] = $item; $data['returnData'] = true; return $data; - // ... + } + + // ... + } Manual Model Creation ===================== diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index 8d570144cf4c..4758fe4f02bb 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -85,7 +85,7 @@ format both XML and JSON responses:: public $supportedResponseFormats = [ 'application/json', - 'application/xml' + 'application/xml', ]; This is the array that is used during :doc:`Content Negotiation ` to determine which @@ -98,7 +98,7 @@ support both JSON and XML:: public $formatters = [ 'application/json' => \CodeIgniter\Format\JSONFormatter::class, - 'application/xml' => \CodeIgniter\Format\XMLFormatter::class + 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, ]; So, if your request asks for JSON formatted data in an **Accept** header, the data array you pass any of the @@ -167,8 +167,8 @@ Class Reference 'code' => '321a', 'messages' => [ 'Error message 1', - 'Error message 2' - ] + 'Error message 2', + ], ]; .. php:method:: respondCreated($data = null[, string $message = '']) @@ -317,4 +317,3 @@ Class Reference :: return $this->failServerError('Server error.'); - diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 20287bfba2ad..97d3fbdf6d5e 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -125,7 +125,7 @@ It also support nested definition:: 'language_key' => [ 'nested' => [ - 'key' => 'The actual message to be shown.' + 'key' => 'The actual message to be shown.', ], ], @@ -278,8 +278,8 @@ Language files also allow nested arrays to make working with lists, etc... easie 'Grapes', 'Lemons', 'Oranges', - 'Strawberries' - ] + 'Strawberries', + ], ]; // Displays "Apples, Bananas, Grapes, Lemons, Oranges, Strawberries" diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index e48a5af6cd08..060e2cd28291 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -37,7 +37,7 @@ You can set format an array into either JSON or XML and set the content type hea $data = [ 'success' => true, - 'id' => 123 + 'id' => 123, ]; return $this->response->setJSON($data); @@ -80,10 +80,10 @@ to your computer. This sets the appropriate headers to make it happen. The first parameter is the **name you want the downloaded file to be named**, the second parameter is the file data. -If you set the second parameter to NULL and ``$filename`` is an existing, readable +If you set the second parameter to null and ``$filename`` is an existing, readable file path, then its content will be read instead. -If you set the third parameter to boolean TRUE, then the actual file MIME type +If you set the third parameter to boolean true, then the actual file MIME type (based on the filename extension) will be sent, so that if your browser has a handler for that type - it can use it. @@ -394,7 +394,7 @@ The methods provided by the parent class that are available are: followed by the response body. For the main application response, you do not need to call this as it is handled automatically by CodeIgniter. - .. php:method:: setCookie($name = ''[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = FALSE[, $httponly = FALSE[, $samesite = null]]]]]]]]) + .. php:method:: setCookie($name = ''[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = false[, $httponly = false[, $samesite = null]]]]]]]]) :param mixed $name: Cookie name or an array of parameters :param string $value: Cookie value @@ -423,8 +423,8 @@ The methods provided by the parent class that are available are: 'domain' => '.some-domain.com', 'path' => '/', 'prefix' => 'myprefix_', - 'secure' => TRUE, - 'httponly' => FALSE, + 'secure' => true, + 'httponly' => false, 'samesite' => 'Lax' ]; diff --git a/user_guide_src/source/outgoing/table.rst b/user_guide_src/source/outgoing/table.rst index 781788491ddf..334658d08380 100644 --- a/user_guide_src/source/outgoing/table.rst +++ b/user_guide_src/source/outgoing/table.rst @@ -136,7 +136,7 @@ example, only the table opening tag is being changed:: ]; $table->setTemplate($template); - + You can also set defaults for these by passing an array of template settings to the Table constructor.:: @@ -153,7 +153,7 @@ Class Reference .. php:class:: Table - .. attribute:: $function = NULL + .. attribute:: $function = null Allows you to specify a native PHP function or a valid function array object to be applied to all cell data. :: @@ -170,7 +170,7 @@ Class Reference Fred<strong>Blue</strong>Small - .. php:method:: generate([$tableData = NULL]) + .. php:method:: generate([$tableData = null]) :param mixed $tableData: Data to populate the table rows with :returns: HTML table @@ -213,7 +213,7 @@ Class Reference $table->setFooting(['Subtotal', $subtotal, $notes]); - .. php:method:: addRow([$args = array()[, ...]]) + .. php:method:: addRow([$args = [] [, ...]]) :param mixed $args: An array or multiple strings containing the row values :returns: Table instance (method chaining) @@ -267,16 +267,16 @@ Class Reference .. php:method:: setTemplate($template) :param array $template: An associative array containing template values - :returns: TRUE on success, FALSE on failure + :returns: true on success, false on failure :rtype: bool Permits you to set your template. You can submit a full or partial template. :: $template = [ - 'table_open' => '' + 'table_open' => '
' ]; - + $table->setTemplate($template); .. php:method:: setEmpty($value) @@ -304,21 +304,20 @@ Class Reference $table = new \CodeIgniter\View\Table(); - $table->setCaption('Preferences') - ->setHeading('Name', 'Color', 'Size') - ->addRow('Fred', 'Blue', 'Small') - ->addRow('Mary', 'Red', 'Large') - ->addRow('John', 'Green', 'Medium'); + ->setHeading('Name', 'Color', 'Size') + ->addRow('Fred', 'Blue', 'Small') + ->addRow('Mary', 'Red', 'Large') + ->addRow('John', 'Green', 'Medium'); echo $table->generate(); $table->clear(); $table->setCaption('Shipping') - ->setHeading('Name', 'Day', 'Delivery') - ->addRow('Fred', 'Wednesday', 'Express') - ->addRow('Mary', 'Monday', 'Air') - ->addRow('John', 'Saturday', 'Overnight'); + ->setHeading('Name', 'Day', 'Delivery') + ->addRow('Fred', 'Wednesday', 'Express') + ->addRow('Mary', 'Monday', 'Air') + ->addRow('John', 'Saturday', 'Overnight'); echo $table->generate(); diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 6ba136e11536..37c20c82e11e 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -89,7 +89,7 @@ like this:: $data = [ 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading' + 'blog_heading' => 'My Blog Heading', ]; echo $parser->setData($data) @@ -194,8 +194,8 @@ corresponding to your variable pair data. Consider this example:: ['title' => 'Title 2', 'body' => 'Body 2'], ['title' => 'Title 3', 'body' => 'Body 3'], ['title' => 'Title 4', 'body' => 'Body 4'], - ['title' => 'Title 5', 'body' => 'Body 5'] - ] + ['title' => 'Title 5', 'body' => 'Body 5'], + ], ]; echo $parser->setData($data) @@ -214,11 +214,11 @@ method:: $data = [ 'blog_title' => 'My Blog Title', 'blog_heading' => 'My Blog Heading', - 'blog_entries' => $query->getResultArray() + 'blog_entries' => $query->getResultArray(), ]; echo $parser->setData($data) - ->render('blog_template'); + ->render('blog_template'); If the array you are trying to loop over contains objects instead of arrays, the parser will first look for an ``asArray`` method on the object. If it exists, @@ -240,12 +240,13 @@ an associative array of values, like a record from a database:: 'blog_title' => 'My Blog Title', 'blog_heading' => 'My Blog Heading', 'blog_entry' => [ - 'title' => 'Title 1', 'body' => 'Body 1' - ] + 'title' => 'Title 1', + 'body' => 'Body 1', + ], ]; echo $parser->setData($data) - ->render('blog_template'); + ->render('blog_template'); The value for the pseudo-variable ``blog_entry`` is an associative array. The key/value pairs defined inside it will be exposed inside @@ -292,7 +293,7 @@ The following example is not impacted by cascading:: $data = [ 'name' => 'George', - 'location' => [ 'city' => 'Red City', 'planet' => 'Mars' ] + 'location' => ['city' => 'Red City', 'planet' => 'Mars'], ]; echo $parser->setData($data)->renderString($template); @@ -304,7 +305,7 @@ This example gives different results, depending on cascading:: $data = [ 'name' => 'George', - 'location' => [ 'city' => 'Red City', 'planet' => 'Mars' ] + 'location' => ['city' => 'Red City', 'planet' => 'Mars'], ]; echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]); @@ -540,7 +541,7 @@ used within the template file. The value is any valid PHP callable, including st public $plugins = [ 'foo' => '\Some\Class::methodName', - 'bar' => function($str, array $params=[]) { + 'bar' => function ($str, array $params=[]) { return $str; }, ]; @@ -553,7 +554,7 @@ Any closures that are being used must be defined in the config file's constructo public function __construct() { - $this->plugins['bar'] = function(array $params=[]) { + $this->plugins['bar'] = function (array $params=[]) { return $params[0] ?? ''; }; @@ -605,10 +606,10 @@ template, the original pseudo-variable is shown in the result:: $data = [ 'title' => 'Mr', 'firstname' => 'John', - 'lastname' => 'Doe' + 'lastname' => 'Doe', ]; echo $parser->setData($data) - ->renderString($template); + ->renderString($template); // Result: Hello, John {initials} Doe @@ -623,11 +624,11 @@ pair tag, but the closing variable pair tag is not rendered properly:: 'lastname' => 'Doe', 'titles' => [ ['degree' => 'BSc'], - ['degree' => 'PhD'] - ] + ['degree' => 'PhD'], + ], ]; echo $parser->setData($data) - ->renderString($template); + ->renderString($template); // Result: Hello, John Doe (Mr{degree} {/degrees}) @@ -652,7 +653,7 @@ An example with the iteration controlled in the view:: ] ]; echo $parser->setData($data) - ->renderString($template); + ->renderString($template); Result:: @@ -671,17 +672,16 @@ using a view fragment:: ['title' => 'Second Link', 'link' => '/second'], ]; - foreach ($data1 as $menuItem) - { + foreach ($data1 as $menuItem),{ $temp .= $parser->setData($menuItem)->renderString($template1); } $template2 = '
    {menuitems}
'; $data = [ - 'menuitems' => $temp + 'menuitems' => $temp, ]; echo $parser->setData($data) - ->renderString($template2); + ->renderString($template2); Result:: @@ -710,12 +710,12 @@ Class Reference Options supported: - - ``cache`` - the time in seconds, to save a view's results - - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath - - ``cascadeData`` - true if the data pairs in effect when a nested or loop substitution occurs should be propagated - - ``saveData`` - true if the view data parameter should be retained for subsequent calls - - ``leftDelimiter`` - the left delimiter to use in pseudo-variable syntax - - ``rightDelimiter`` - the right delimiter to use in pseudo-variable syntax + - ``cache`` - the time in seconds, to save a view's results + - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath + - ``cascadeData`` - true if the data pairs in effect when a nested or loop substitution occurs should be propagated + - ``saveData`` - true if the view data parameter should be retained for subsequent calls + - ``leftDelimiter`` - the left delimiter to use in pseudo-variable syntax + - ``rightDelimiter`` - the right delimiter to use in pseudo-variable syntax Any conditional substitutions are performed first, then remaining substitutions are performed for each data pair. @@ -770,6 +770,6 @@ Class Reference :returns: The Renderer, for method chaining :rtype: CodeIgniter\\View\\RendererInterface. - Over-ride the substitution field delimiters:: + Override the substitution field delimiters:: $renderer->setDelimiters('[',']'); diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 97485ba84774..0ea2001fe724 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -80,7 +80,7 @@ content view, and a footer view. That might look something like this:: public function index() { $data = [ - 'page_title' => 'Your title' + 'page_title' => 'Your title', ]; echo view('header'); @@ -137,7 +137,7 @@ Here's an example:: $data = [ 'title' => 'My title', 'heading' => 'My Heading', - 'message' => 'My Message' + 'message' => 'My Message', ]; echo view('blogview', $data); @@ -181,7 +181,7 @@ into the `$option` array in the third parameter. $data = [ 'title' => 'My title', 'heading' => 'My Heading', - 'message' => 'My Message' + 'message' => 'My Message', ]; echo view('blogview', $data, ['saveData' => true]); @@ -208,8 +208,8 @@ Here’s a simple example. Add this to your controller:: { $data = [ 'todo_list' => ['Clean House', 'Call Mom', 'Run Errands'], - 'title' => "My Real Title", - 'heading' => "My Real Heading" + 'title' => 'My Real Title', + 'heading' => 'My Real Heading', ]; echo view('blogview', $data); diff --git a/user_guide_src/source/testing/benchmark.rst b/user_guide_src/source/testing/benchmark.rst index 3f2a760d9428..780dcfe8ac08 100644 --- a/user_guide_src/source/testing/benchmark.rst +++ b/user_guide_src/source/testing/benchmark.rst @@ -57,7 +57,7 @@ This returns an array of benchmark information, including start, end, and durati 'render view' => [ 'start' => 1234567890, 'end' => 1345678920, - 'duration' => 15.4315 // number of seconds + 'duration' => 15.4315, // number of seconds ] ] @@ -97,18 +97,14 @@ this test by. The second parameter is the Closure, itself:: $iterator = new \CodeIgniter\Benchmark\Iterator(); // Add a new task - $iterator->add('single_concat', function() - { - $str = 'Some basic'.'little'.'string concatenation test.'; - } - ); + $iterator->add('single_concat', function () { + $str = 'Some basic'.'little'.'string concatenation test.'; + }); // Add another task - $iterator->add('double', function($a='little') - { - $str = "Some basic {$little} string test."; - } - ); + $iterator->add('double', function ($a = 'little') { + $str = "Some basic {$little} string test."; + }); Running the Tasks ================= diff --git a/user_guide_src/source/testing/database.rst b/user_guide_src/source/testing/database.rst index 31f96b5bb565..86b91537917e 100644 --- a/user_guide_src/source/testing/database.rst +++ b/user_guide_src/source/testing/database.rst @@ -163,7 +163,7 @@ Asserts that a row with criteria matching the key/value pairs in ``$criteria`` D $criteria = [ 'email' => 'joe@example.com', - 'active' => 1 + 'active' => 1, ]; $this->dontSeeInDatabase('users', $criteria); @@ -174,7 +174,7 @@ Asserts that a row with criteria matching the key/value pairs in ``$criteria`` D $criteria = [ 'email' => 'joe@example.com', - 'active' => 1 + 'active' => 1, ]; $this->seeInDatabase('users', $criteria); @@ -194,7 +194,7 @@ array with the data to insert into the table. $data = [ 'email' => 'joe@example.com', - 'name' => 'Joe Cool' + 'name' => 'Joe Cool', ]; $this->hasInDatabase('users', $data); @@ -204,6 +204,6 @@ Asserts that a number of matching rows are found in the database that match ``$c :: $criteria = [ - 'active' => 1 + 'active' => 1, ]; $this->seeNumRecords(2, 'users', $criteria); diff --git a/user_guide_src/source/testing/debugging.rst b/user_guide_src/source/testing/debugging.rst index afeb9deaade6..6149ceac9a54 100644 --- a/user_guide_src/source/testing/debugging.rst +++ b/user_guide_src/source/testing/debugging.rst @@ -79,7 +79,7 @@ the **app/Config/Toolbar.php** configuration file:: \CodeIgniter\Debug\Toolbar\Collectors\Database::class, \CodeIgniter\Debug\Toolbar\Collectors\Logs::class, \CodeIgniter\Debug\Toolbar\Collectors\Views::class, - \CodeIgniter\Debug\Toolbar\Collectors\Cache::class, + \CodeIgniter\Debug\Toolbar\Collectors\Cache::class, \CodeIgniter\Debug\Toolbar\Collectors\Files::class, \CodeIgniter\Debug\Toolbar\Collectors\Routes::class, \CodeIgniter\Debug\Toolbar\Collectors\Events::class, @@ -182,7 +182,7 @@ it to sort it correctly and display the correct information. The inner arrays mu 'name' => '', // Name displayed on the left of the timeline 'component' => '', // Name of the Component listed in the middle of timeline 'start' => 0.00, // start time, like microtime(true) - 'duration' => 0.00 // duration, like mircrotime(true) - microtime(true) + 'duration' => 0.00, // duration, like mircrotime(true) - microtime(true) ]; Providing Vars @@ -199,10 +199,10 @@ outer array's key is the name of the section on the Vars tab:: $data = [ 'section 1' => [ 'foo' => 'bar', - 'bar' => 'baz' + 'bar' => 'baz', ], 'section 2' => [ 'foo' => 'bar', - 'bar' => 'baz' - ] + 'bar' => 'baz', + ], ]; diff --git a/user_guide_src/source/testing/feature.rst b/user_guide_src/source/testing/feature.rst index 6abc1ff228ce..6ec786c67079 100644 --- a/user_guide_src/source/testing/feature.rst +++ b/user_guide_src/source/testing/feature.rst @@ -61,7 +61,7 @@ populated, while a **post** request would have the **$_POST** array populated. // Submit a form $result = $this->call('post', 'contact'), [ - 'name' => 'Fred Flintstone', + 'name' => 'Fred Flintstone', 'email' => 'flintyfred@example.com' ]); @@ -83,11 +83,10 @@ You can use a custom collection of routes by passing an array of "routes" into t override any existing routes in the system:: $routes = [ - [ 'get', 'users', 'UserController::list' ] - ]; + ['get', 'users', 'UserController::list'], + ]; - $result = $this->withRoutes($routes) - ->get('users'); + $result = $this->withRoutes($routes)->get('users'); Each of the "routes" is a 3 element array containing the HTTP verb (or "add" for all), the URI to match, and the routing destination. @@ -102,11 +101,10 @@ that the current values of ``$_SESSION`` should be used. This is handy for testi :: $values = [ - 'logged_in' => 123 + 'logged_in' => 123, ]; - $result = $this->withSession($values) - ->get('admin'); + $result = $this->withSession($values)->get('admin'); // Or... @@ -121,7 +119,7 @@ You can set header values with the ``withHeaders()`` method. This takes an array passed as a header into the call.:: $headers = [ - 'CONTENT_TYPE' => 'application/json' + 'CONTENT_TYPE' => 'application/json', ]; $result = $this->withHeaders($headers)->post('users'); @@ -132,8 +130,7 @@ Bypassing Events Events are handy to use in your application, but can be problematic during testing. Especially events that are used to send out emails. You can tell the system to skip any event handling with the ``skipEvents()`` method:: - $result = $this->skipEvents() - ->post('users', $userInfo); + $result = $this->skipEvents()->post('users', $userInfo); Formatting The Request ----------------------- @@ -145,8 +142,7 @@ This is useful when testing JSON or XML API's so that you can set the request in :: // If your feature test contains this: - $result = $this->withBodyFormat('json') - ->post('users', $userInfo); + $result = $this->withBodyFormat('json')->post('users', $userInfo); // Your controller can then get the parameters passed in with: $userInfo = $this->request->getJson(); diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index e19403542a6e..28e99b9b4bbc 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -195,7 +195,7 @@ Ensure that something you expected to be logged actually was:: Ensure that an event you expected to be triggered actually was:: - Events::on('foo', function($arg) use(&$result) { + Events::on('foo', function ($arg) use(&$result) { $result = $arg; }); @@ -384,5 +384,5 @@ An example demonstrating this inside one of your test cases:: { CLI::write('first.'); $expected = "first.\n"; - $this->assertEquals($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, CITestStreamFilter::$buffer); } diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index a5cc1749f58d..4152feff03d1 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -40,8 +40,7 @@ Returns a boolean true/false based on whether the response is perceived to be "o a response status code in the 200 or 300's. :: - if ($result->isOK()) - { + if ($result->isOK()) { ... } @@ -57,8 +56,7 @@ This assertion simply uses the **isOK()** method to test a response. **assertNot Returns a boolean true/false based on whether the response is a redirected response. :: - if ($result->isRedirect()) - { + if ($result->isRedirect()) { ... } @@ -314,7 +312,7 @@ Asserts that $fragment is found within the JSON response. It does not need to ma // Response body is this: [ - 'config' => ['key-a', 'key-b'] + 'config' => ['key-a', 'key-b'], ] // Is true diff --git a/user_guide_src/source/tutorial/conclusion.rst b/user_guide_src/source/tutorial/conclusion.rst index 613b56b7e24f..afb38465904b 100644 --- a/user_guide_src/source/tutorial/conclusion.rst +++ b/user_guide_src/source/tutorial/conclusion.rst @@ -1,5 +1,5 @@ Conclusion -############################################################################### +########## This tutorial did not cover all of the things you might expect of a full-fledged content management system, but it introduced you to the diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index d7a1ed8b321e..6b8dd53bd458 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -1,5 +1,5 @@ Create news items -############################################################################### +################# You now know how you can read data from a database using CodeIgniter, but you haven't written any information to the database yet. In this section, @@ -7,7 +7,7 @@ you'll expand your news controller and model created earlier to include this functionality. Create a form -------------------------------------------------------- +------------- To input data into the database, you need to create a form where you can input the information to be stored. This means you'll be needing a form @@ -50,21 +50,18 @@ validation <../libraries/validation>` library to do this. $model = new NewsModel(); if ($this->request->getMethod() === 'post' && $this->validate([ - 'title' => 'required|min_length[3]|max_length[255]', - 'body' => 'required', - ])) - { + 'title' => 'required|min_length[3]|max_length[255]', + 'body' => 'required', + ])) { $model->save([ 'title' => $this->request->getPost('title'), - 'slug' => url_title($this->request->getPost('title'), '-', TRUE), + 'slug' => url_title($this->request->getPost('title'), '-', true), 'body' => $this->request->getPost('body'), ]); echo view('news/success'); - - } - else - { + + } else { echo view('templates/header', ['title' => 'Create a news item']); echo view('news/create'); echo view('templates/footer'); diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index 3ee34cfa1ba8..054b030e61e9 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -107,8 +107,7 @@ following code to your model. public function getNews($slug = false) { - if ($slug === false) - { + if ($slug === false) { return $this->findAll(); } @@ -243,7 +242,7 @@ add some code to the controller and create a new view. Go back to the :: - public function view($slug = NULL) + public function view($slug = null) { $model = new NewsModel(); diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index a68a7e9d249a..54dfdce6a369 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -129,8 +129,7 @@ in the ``Pages`` controller created above: public function view($page = 'home') { - if ( ! is_file(APPPATH.'/Views/pages/'.$page.'.php')) - { + if ( ! is_file(APPPATH.'/Views/pages/'.$page.'.php')) { // Whoops, we don't have a page for that! throw new \CodeIgniter\Exceptions\PageNotFoundException($page); } From b24b48345144715df038dd14f8a188e43a1122ec Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 31 Aug 2021 13:52:11 +0700 Subject: [PATCH 0145/2325] [Rector] Apply Rector: FixClassCaseSensitivityNameRector --- rector.php | 2 ++ .../system/Cache/Handlers/PredisHandlerTest.php | 4 ++-- tests/system/Config/DotEnvTest.php | 16 ++++++++-------- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/rector.php b/rector.php index 77b014df2559..054ed3ea09ad 100644 --- a/rector.php +++ b/rector.php @@ -20,6 +20,7 @@ use Rector\CodeQuality\Rector\If_\ShortenElseIfRector; use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector; use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector; +use Rector\CodeQuality\Rector\Name\FixClassCaseSensitivityNameRector; use Rector\CodeQuality\Rector\Return_\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\Ternary\UnnecessaryTernaryExpressionRector; use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector; @@ -135,4 +136,5 @@ $services->set(RemoveExtraParametersRector::class); $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); + $services->set(FixClassCaseSensitivityNameRector::class); }; diff --git a/tests/system/Cache/Handlers/PredisHandlerTest.php b/tests/system/Cache/Handlers/PredisHandlerTest.php index 22106c6c09aa..df6dfdbfbaef 100644 --- a/tests/system/Cache/Handlers/PredisHandlerTest.php +++ b/tests/system/Cache/Handlers/PredisHandlerTest.php @@ -62,10 +62,10 @@ public function testNew() public function testDestruct() { - $this->PredisHandler = new PRedisHandler($this->config); + $this->PredisHandler = new PredisHandler($this->config); $this->PredisHandler->initialize(); - $this->assertInstanceOf(PRedisHandler::class, $this->PredisHandler); + $this->assertInstanceOf(PredisHandler::class, $this->PredisHandler); } /** diff --git a/tests/system/Config/DotEnvTest.php b/tests/system/Config/DotEnvTest.php index 9943d20d3a73..dbdb1c1c6743 100644 --- a/tests/system/Config/DotEnvTest.php +++ b/tests/system/Config/DotEnvTest.php @@ -123,7 +123,7 @@ public function testLoadsUnreadableFile() public function testQuotedDotenvLoadsEnvironmentVars() { - $dotenv = new Dotenv($this->fixturesFolder, 'quoted.env'); + $dotenv = new DotEnv($this->fixturesFolder, 'quoted.env'); $dotenv->load(); $this->assertSame('bar', getenv('QFOO')); $this->assertSame('baz', getenv('QBAR')); @@ -138,13 +138,13 @@ public function testSpacedValuesWithoutQuotesThrowsException() $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('.env values containing spaces must be surrounded by quotes.'); - $dotenv = new Dotenv($this->fixturesFolder, 'spaced-wrong.env'); + $dotenv = new DotEnv($this->fixturesFolder, 'spaced-wrong.env'); $dotenv->load(); } public function testLoadsServerGlobals() { - $dotenv = new Dotenv($this->fixturesFolder, '.env'); + $dotenv = new DotEnv($this->fixturesFolder, '.env'); $dotenv->load(); $this->assertSame('bar', $_SERVER['FOO']); @@ -155,7 +155,7 @@ public function testLoadsServerGlobals() public function testNamespacedVariables() { - $dotenv = new Dotenv($this->fixturesFolder, '.env'); + $dotenv = new DotEnv($this->fixturesFolder, '.env'); $dotenv->load(); $this->assertSame('complex', $_SERVER['SimpleConfig.simple.name']); @@ -164,7 +164,7 @@ public function testNamespacedVariables() public function testLoadsGetServerVar() { $_SERVER['SER_VAR'] = 'TT'; - $dotenv = new Dotenv($this->fixturesFolder, 'nested.env'); + $dotenv = new DotEnv($this->fixturesFolder, 'nested.env'); $dotenv->load(); $this->assertSame('TT', $_ENV['NVAR7']); @@ -172,7 +172,7 @@ public function testLoadsGetServerVar() public function testLoadsEnvGlobals() { - $dotenv = new Dotenv($this->fixturesFolder); + $dotenv = new DotEnv($this->fixturesFolder); $dotenv->load(); $this->assertSame('bar', $_ENV['FOO']); $this->assertSame('baz', $_ENV['BAR']); @@ -182,7 +182,7 @@ public function testLoadsEnvGlobals() public function testNestedEnvironmentVars() { - $dotenv = new Dotenv($this->fixturesFolder, 'nested.env'); + $dotenv = new DotEnv($this->fixturesFolder, 'nested.env'); $dotenv->load(); $this->assertSame('{$NVAR1} {$NVAR2}', $_ENV['NVAR3']); // not resolved $this->assertSame('Hello World!', $_ENV['NVAR4']); @@ -192,7 +192,7 @@ public function testNestedEnvironmentVars() public function testDotenvAllowsSpecialCharacters() { - $dotenv = new Dotenv($this->fixturesFolder, 'specialchars.env'); + $dotenv = new DotEnv($this->fixturesFolder, 'specialchars.env'); $dotenv->load(); $this->assertSame('$a6^C7k%zs+e^.jvjXk', getenv('SPVAR1')); $this->assertSame('?BUty3koaV3%GA*hMAwH}B', getenv('SPVAR2')); From ab580bae7197fc04467d8269745850e0cfbb00bf Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Tue, 31 Aug 2021 12:33:14 +0200 Subject: [PATCH 0146/2325] Fix key casting in form_dropdown helper. (#5035) --- system/Helpers/form_helper.php | 6 +++++- tests/system/Helpers/FormHelperTest.php | 28 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/system/Helpers/form_helper.php b/system/Helpers/form_helper.php index bb4f6cd8060f..e33ec2e89137 100644 --- a/system/Helpers/form_helper.php +++ b/system/Helpers/form_helper.php @@ -298,7 +298,7 @@ function form_dropdown($data = '', $options = [], $selected = [], $extra = ''): } } - // standardize selected as strings, like the option keys will be. + // Standardize selected as strings, like the option keys will be foreach ($selected as $key => $item) { $selected[$key] = (string) $item; } @@ -308,6 +308,7 @@ function form_dropdown($data = '', $options = [], $selected = [], $extra = ''): $form = '\n + EOH; + $this->assertSame($expected, form_dropdown('cars', $options, $selected)); + } + public function testFormDropdownInferred() { $options = [ From cca4660e54acad5e77820a218bc0b4a1d16cebca Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Tue, 31 Aug 2021 20:40:48 +0800 Subject: [PATCH 0147/2325] Bump to php-cs-fixer v3.1 (#5045) --- tests/system/API/ResponseTraitTest.php | 4 ++-- tests/system/ControllerTest.php | 4 ++-- tests/system/Database/Live/GetTest.php | 2 +- tests/system/Database/Migrations/MigrationTest.php | 2 +- tests/system/Entity/EntityTest.php | 14 +++++++------- tests/system/Events/EventsTest.php | 2 +- tests/system/Models/GeneralModelTest.php | 4 ++-- tests/system/Models/InsertModelTest.php | 4 ++-- tests/system/Models/SaveModelTest.php | 6 +++--- tests/system/Models/UpdateModelTest.php | 6 +++--- tests/system/View/ParserTest.php | 4 ++-- utils/PhpCsFixer/CodeIgniter4.php | 7 ++++--- 12 files changed, 30 insertions(+), 29 deletions(-) diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index b63b7362a600..958be5434689 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -82,7 +82,7 @@ protected function makeController(array $userConfig = [], string $uri = 'http:// } // Create the controller class finally. - $controller = new class($this->request, $this->response, $this->formatter) { + $controller = new class ($this->request, $this->response, $this->formatter) { use ResponseTrait; protected $request; @@ -524,7 +524,7 @@ public function testFormatByRequestNegotiateIfFormatIsNotJsonOrXML() $request = new MockIncomingRequest($config, new URI($config->baseURL), null, new UserAgent()); $response = new MockResponse($config); - $controller = new class($request, $response) { + $controller = new class ($request, $response) { use ResponseTrait; protected $request; diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index d10a9038089c..3d7c205eec0b 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -85,7 +85,7 @@ public function testConstructorHTTPS() $original = $_SERVER; $_SERVER = ['HTTPS' => 'on']; // make sure we can instantiate one - $this->controller = new class() extends Controller { + $this->controller = new class () extends Controller { protected $forceHTTPS = 1; }; $this->controller->initController($this->request, $this->response, $this->logger); @@ -169,7 +169,7 @@ public function testValidateWithStringRulesFoundUseMessagesParameter() public function testHelpers() { - $this->controller = new class() extends Controller { + $this->controller = new class () extends Controller { protected $helpers = [ 'cookie', 'text', diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index 16424c252d29..a2f1aa4f9b89 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -227,7 +227,7 @@ public function testGetRowWithReturnType() public function testGetRowWithCustomReturnType() { - $testClass = new class() {}; + $testClass = new class () {}; $user = $this->db->table('user')->get()->getRow(0, get_class($testClass)); diff --git a/tests/system/Database/Migrations/MigrationTest.php b/tests/system/Database/Migrations/MigrationTest.php index 5f89716279a2..1c1561044be0 100644 --- a/tests/system/Database/Migrations/MigrationTest.php +++ b/tests/system/Database/Migrations/MigrationTest.php @@ -29,7 +29,7 @@ protected function setUp(): void public function testDBGroup() { - $migration = new class() extends Migration { + $migration = new class () extends Migration { protected $DBGroup = 'tests'; public function up() diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 69d0546510bd..c995f5d7c191 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -762,7 +762,7 @@ public function testAsArraySwapped() public function testToArraySkipAttributesWithUnderscoreInFirstCharacter() { - $entity = new class() extends Entity { + $entity = new class () extends Entity { protected $attributes = [ '_foo' => null, 'bar' => null, @@ -923,7 +923,7 @@ public function testJsonSerializableEntity() protected function getEntity() { - return new class() extends Entity { + return new class () extends Entity { protected $attributes = [ 'foo' => null, 'bar' => null, @@ -963,7 +963,7 @@ public function getFakeBar() protected function getMappedEntity() { - return new class() extends Entity { + return new class () extends Entity { protected $attributes = [ 'foo' => null, 'simple' => null, @@ -994,7 +994,7 @@ protected function getSimple() protected function getSwappedEntity() { - return new class() extends Entity { + return new class () extends Entity { protected $attributes = [ 'foo' => 'foo', 'bar' => 'bar', @@ -1015,7 +1015,7 @@ protected function getSwappedEntity() protected function getCastEntity($data = null): Entity { - return new class($data) extends Entity { + return new class ($data) extends Entity { protected $attributes = [ 'first' => null, 'second' => null, @@ -1074,7 +1074,7 @@ public function setSeventh($seventh) protected function getCastNullableEntity() { - return new class() extends Entity { + return new class () extends Entity { protected $attributes = [ 'string_null' => null, 'string_empty' => null, @@ -1104,7 +1104,7 @@ protected function getCastNullableEntity() protected function getCustomCastEntity() { - return new class() extends Entity { + return new class () extends Entity { protected $attributes = [ 'first' => null, 'second' => null, diff --git a/tests/system/Events/EventsTest.php b/tests/system/Events/EventsTest.php index 222722b1448d..bb3b3e87a827 100644 --- a/tests/system/Events/EventsTest.php +++ b/tests/system/Events/EventsTest.php @@ -280,7 +280,7 @@ public function testHandleEventCallableInternalFunc() public function testHandleEventCallableClass() { - $box = new class() { + $box = new class () { public $logged; public function hold(string $value) diff --git a/tests/system/Models/GeneralModelTest.php b/tests/system/Models/GeneralModelTest.php index a896764290b2..cc41c453603b 100644 --- a/tests/system/Models/GeneralModelTest.php +++ b/tests/system/Models/GeneralModelTest.php @@ -104,7 +104,7 @@ public function testSetAllowedFields(): void 'updated_at', ]; - $model = new class() extends Model { + $model = new class () extends Model { protected $allowedFields = [ 'id', 'created_at', @@ -147,7 +147,7 @@ public function testBuilderWithParameterIgnoresShared(): void public function testInitialize(): void { - $model = new class() extends Model { + $model = new class () extends Model { /** * @var bool */ diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 93a47999d45f..38b86eb67e30 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -157,7 +157,7 @@ public function testInsertResultFail(): void public function testInsertBatchNewEntityWithDateTime(): void { - $entity = new class() extends Entity { + $entity = new class () extends Entity { protected $id; protected $name; protected $email; @@ -215,7 +215,7 @@ public function testInsertEntityWithNoDataExceptionNoAllowedData(): void { $this->createModel(UserModel::class); - $entity = new class() extends Entity { + $entity = new class () extends Entity { protected $id; protected $name; protected $email; diff --git a/tests/system/Models/SaveModelTest.php b/tests/system/Models/SaveModelTest.php index 59963c3e4946..17f56a4cb88c 100644 --- a/tests/system/Models/SaveModelTest.php +++ b/tests/system/Models/SaveModelTest.php @@ -208,7 +208,7 @@ public function testEmptySaveData(): void public function testSaveNewEntityWithDateTime(): void { - $entity = new class() extends Entity { + $entity = new class () extends Entity { protected $id; protected $name; protected $email; @@ -242,7 +242,7 @@ public function testSaveNewEntityWithDateTime(): void public function testSaveNewEntityWithDate(): void { - $entity = new class() extends Entity { + $entity = new class () extends Entity { protected $id; protected $name; protected $created_at; @@ -258,7 +258,7 @@ public function testSaveNewEntityWithDate(): void ]; }; - $testModel = new class() extends Model { + $testModel = new class () extends Model { protected $table = 'empty'; protected $allowedFields = [ 'name', diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 50847b620c8a..619028a748aa 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -158,7 +158,7 @@ public function testUpdateBatchValidationFail(): void public function testUpdateBatchWithEntity(): void { - $entity1 = new class() extends Entity { + $entity1 = new class () extends Entity { protected $id; protected $name; protected $email; @@ -178,7 +178,7 @@ public function testUpdateBatchWithEntity(): void ]; }; - $entity2 = new class() extends Entity { + $entity2 = new class () extends Entity { protected $id; protected $name; protected $email; @@ -307,7 +307,7 @@ public function testUpdateWithEntityNoAllowedFields(): void { $this->createModel(UserModel::class); - $entity = new class() extends Entity { + $entity = new class () extends Entity { protected $id; protected $name; protected $email; diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index 547d9b549d0f..a7a97f00c51a 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -262,7 +262,7 @@ public function testParseLoopObjectProperties() public function testParseLoopEntityProperties() { - $power = new class() extends Entity { + $power = new class () extends Entity { public $foo = 'bar'; protected $bar = 'baz'; @@ -292,7 +292,7 @@ public function toArray(bool $onlyChanged = false, bool $cast = true, bool $recu public function testParseLoopEntityObjectProperties() { - $power = new class() extends Entity { + $power = new class () extends Entity { protected $attributes = [ 'foo' => 'bar', 'bar' => 'baz', diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php index 4a5643ec923d..05e83b544270 100644 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ b/utils/PhpCsFixer/CodeIgniter4.php @@ -73,8 +73,6 @@ public function __construct() 'cast_spaces' => ['space' => 'single'], 'class_attributes_separation' => [ 'elements' => [ - // 'const' => 'one_if_phpdoc', // @todo Enable in php-cs-fixer v3.1 - // 'property' => 'one_if_phpdoc', // @todo Enable in php-cs-fixer v3.1 'method' => 'one', ], ], @@ -82,8 +80,8 @@ public function __construct() 'multi_line_extends_each_single_line' => true, 'single_item_single_line' => true, 'single_line' => true, + 'space_before_parenthesis' => true, ], - 'class_keyword_remove' => false, 'clean_namespace' => true, 'combine_consecutive_issets' => true, 'combine_consecutive_unsets' => true, @@ -103,6 +101,7 @@ public function __construct() 'constant_case' => ['case' => 'lower'], 'date_time_immutable' => false, 'declare_equal_normalize' => ['space' => 'none'], + 'declare_parentheses' => true, 'declare_strict_types' => false, 'dir_constant' => true, 'doctrine_annotation_array_assignment' => false, @@ -115,6 +114,7 @@ public function __construct() 'shorten_simple_statements_only' => false, ], 'elseif' => true, + 'empty_loop_body' => ['style' => 'braces'], 'encoding' => true, 'ereg_to_preg' => true, 'error_suppression' => [ @@ -519,6 +519,7 @@ public function __construct() 'elements' => ['arrays'], ], 'trim_array_spaces' => true, + 'types_spaces' => ['space' => 'none'], 'unary_operator_spaces' => true, 'use_arrow_functions' => false, // requires PHP7.4+ 'visibility_required' => ['elements' => ['const', 'method', 'property']], From 4ab9d66b530ec798f2b06a551a2cab8797161f5d Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 2 Sep 2021 12:32:07 +0800 Subject: [PATCH 0148/2325] Switch to official coding standard (#5038) * Switch to official coding standard * Update .no-header.php-cs-fixer.dist.php Co-authored-by: Abdul Malik Ikhsan --- .github/workflows/test-phpunit.yml | 2 +- .no-header.php-cs-fixer.dist.php | 16 +- .php-cs-fixer.dist.php | 13 +- admin/framework/composer.json | 5 +- app/Config/Services.php | 19 +- composer.json | 5 +- system/Database/BaseConnection.php | 2 +- system/Email/Email.php | 4 +- system/Session/Session.php | 2 +- system/Test/Mock/MockIncomingRequest.php | 5 - system/Typography/Typography.php | 4 +- tests/system/CLI/CLITest.php | 17 +- .../system/Cache/Handlers/FileHandlerTest.php | 4 +- tests/system/Config/ServicesTest.php | 11 - tests/system/I18n/TimeTest.php | 13 - tests/system/Test/TestCaseTest.php | 10 - utils/PhpCsFixer/CodeIgniter4.php | 540 ------------------ .../Comment/SpaceAfterCommentStartFixer.php | 95 --- 18 files changed, 48 insertions(+), 719 deletions(-) delete mode 100644 utils/PhpCsFixer/CodeIgniter4.php delete mode 100644 utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 35dc86f8b4d1..c093190233cb 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -123,7 +123,7 @@ jobs: - name: Install dependencies run: | composer update --ansi --no-interaction - composer remove --ansi --dev --unused -W rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config + composer remove --ansi --dev --unused -W rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config codeigniter/coding-standard php -r 'file_put_contents("vendor/laminas/laminas-zendframework-bridge/src/autoload.php", "");' env: COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php index 8f7eb0a71cf1..acfdbf48e1b7 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.no-header.php-cs-fixer.dist.php @@ -11,10 +11,11 @@ * the LICENSE file that was distributed with this source code. */ +use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; +use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; +use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; -use Utils\PhpCsFixer\CodeIgniter4; -use Utils\PhpCsFixer\Fixer\Comment\SpaceAfterCommentStartFixer; $finder = Finder::create() ->files() @@ -22,18 +23,17 @@ __DIR__ . '/admin', __DIR__ . '/app', __DIR__ . '/public', - ]); + ]) + ->notName('#Logger\.php$#'); $overrides = []; $options = [ 'cacheFile' => 'build/.no-header.php-cs-fixer.cache', 'finder' => $finder, - 'customFixers' => [ - new SpaceAfterCommentStartFixer(), - ], - 'customRules' => [ - 'CodeIgniter4/space_after_comment_start' => true, + 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), + 'customRules' => [ + SpaceAfterCommentStartFixer::name() => true, ], ]; diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 95478343a53a..f362a830f99e 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -11,10 +11,11 @@ * the LICENSE file that was distributed with this source code. */ +use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; +use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; +use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; -use Utils\PhpCsFixer\CodeIgniter4; -use Utils\PhpCsFixer\Fixer\Comment\SpaceAfterCommentStartFixer; $finder = Finder::create() ->files() @@ -37,11 +38,9 @@ $options = [ 'cacheFile' => 'build/.php-cs-fixer.cache', 'finder' => $finder, - 'customFixers' => [ - new SpaceAfterCommentStartFixer(), - ], - 'customRules' => [ - 'CodeIgniter4/space_after_comment_start' => true, + 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), + 'customRules' => [ + SpaceAfterCommentStartFixer::name() => true, ], ]; diff --git a/admin/framework/composer.json b/admin/framework/composer.json index d65d30bdbed5..6e3852d2af79 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -15,10 +15,11 @@ "psr/log": "^1.1" }, "require-dev": { + "codeigniter/coding-standard": "^1.1", "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "^3.0", + "friendsofphp/php-cs-fixer": "^3.1", "mikey179/vfsstream": "^1.6", - "nexusphp/cs-config": "^3.1", + "nexusphp/cs-config": "^3.3", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1" }, diff --git a/app/Config/Services.php b/app/Config/Services.php index 946be65a11c2..df7c8ad08600 100644 --- a/app/Config/Services.php +++ b/app/Config/Services.php @@ -19,13 +19,14 @@ */ class Services extends BaseService { - // public static function example($getShared = true) - // { - // if ($getShared) - // { - // return static::getSharedInstance('example'); - // } - // - // return new \CodeIgniter\Example(); - // } + /* + * public static function example($getShared = true) + * { + * if ($getShared) { + * return static::getSharedInstance('example'); + * } + * + * return new \CodeIgniter\Example(); + * } + */ } diff --git a/composer.json b/composer.json index 66a38a215e5c..7b9d50b8e620 100644 --- a/composer.json +++ b/composer.json @@ -15,10 +15,11 @@ "psr/log": "^1.1" }, "require-dev": { + "codeigniter/coding-standard": "^1.1", "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "^3.0", + "friendsofphp/php-cs-fixer": "^3.1", "mikey179/vfsstream": "^1.6", - "nexusphp/cs-config": "^3.1", + "nexusphp/cs-config": "^3.3", "nexusphp/tachycardia": "^1.0", "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index c7bec269c472..70bde67b6d50 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1004,7 +1004,7 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro // we have nothing more to do other than escape the item // // NOTE: The ! empty() condition prevents this method - // from breaking when QB isn't enabled. + // from breaking when QB isn't enabled. if (! empty($this->aliasedTables) && in_array($parts[0], $this->aliasedTables, true)) { if ($protectIdentifiers === true) { foreach ($parts as $key => $val) { diff --git a/system/Email/Email.php b/system/Email/Email.php index c07f79d80df6..966c08e6f830 100644 --- a/system/Email/Email.php +++ b/system/Email/Email.php @@ -1459,8 +1459,8 @@ protected function prepQEncoding($str) if ($this->charset === 'UTF-8') { // Note: We used to have mb_encode_mimeheader() as the first choice - // here, but it turned out to be buggy and unreliable. DO NOT - // re-add it! -- Narf + // here, but it turned out to be buggy and unreliable. DO NOT + // re-add it! -- Narf if (extension_loaded('iconv')) { $output = @iconv_mime_encode('', $str, [ 'scheme' => 'Q', diff --git a/system/Session/Session.php b/system/Session/Session.php index 27ba502aea36..5fc1bda6005e 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -565,7 +565,7 @@ public function __set(string $key, $value) public function __get(string $key) { // Note: Keep this order the same, just in case somebody wants to - // use 'session_id' as a session data key, for whatever reason + // use 'session_id' as a session data key, for whatever reason if (isset($_SESSION[$key])) { return $_SESSION[$key]; } diff --git a/system/Test/Mock/MockIncomingRequest.php b/system/Test/Mock/MockIncomingRequest.php index 522965f46998..05c9587d4170 100644 --- a/system/Test/Mock/MockIncomingRequest.php +++ b/system/Test/Mock/MockIncomingRequest.php @@ -15,11 +15,6 @@ class MockIncomingRequest extends IncomingRequest { - // public function populateHeaders() - // { - // // Don't do anything... force the tester to manually set the headers they want. - // } - protected function detectURI($protocol, $baseURL) { // Do nothing... diff --git a/system/Typography/Typography.php b/system/Typography/Typography.php index 9ad2dd3914c8..a5ecebd69ddc 100644 --- a/system/Typography/Typography.php +++ b/system/Typography/Typography.php @@ -155,12 +155,12 @@ public function autoTypography(string $str, bool $reduceLinebreaks = false): str continue; } - // Force a newline to make sure end tags get processed by _format_newlines() + // Force a newline to make sure end tags get processed by _format_newlines() if ($i === $c) { $chunks[$i] .= "\n"; } - // Convert Newlines into

and
tags + // Convert Newlines into

and
tags $str .= $this->formatNewLines($chunks[$i]); } diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 51dbe3611684..68008ccc1e4d 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -75,14 +75,15 @@ public function testWait() // The problem: if the block below is enabled, the phpunit tests // go catatonic when it is executed, presumably because of // the CLI::input() waiting for a key press - // // test the press any key to continue... - // stream_filter_register('CLITestKeyboardFilter', 'CodeIgniter\CLI\CLITestKeyboardFilter'); - // $spoofer = stream_filter_append(STDIN, 'CLITestKeyboardFilter'); - // $time = time(); - // CLITestKeyboardFilter::$spoofed = ' '; - // CLI::wait(0); - // stream_filter_remove($spoofer); - // $this->assertEquals(0, time() - $time); + // + // // test the press any key to continue... + // stream_filter_register('CLITestKeyboardFilter', 'CodeIgniter\CLI\CLITestKeyboardFilter'); + // $spoofer = stream_filter_append(STDIN, 'CLITestKeyboardFilter'); + // $time = time(); + // CLITestKeyboardFilter::$spoofed = ' '; + // CLI::wait(0); + // stream_filter_remove($spoofer); + // $this->assertEquals(0, time() - $time); } public function testIsWindows() diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php index ea5a095631e0..bfd379ae9d8f 100644 --- a/tests/system/Cache/Handlers/FileHandlerTest.php +++ b/tests/system/Cache/Handlers/FileHandlerTest.php @@ -221,8 +221,8 @@ public function testDecrement() $this->fileHandler->save(self::$key1, 10); $this->fileHandler->save(self::$key2, 'value'); - // Line following commented out to force the cache to add a zero entry for key3 - // $this->fileHandler->save(self::$key3, 0); + // Line following commented out to force the cache to add a zero entry for key3 + // $this->fileHandler->save(self::$key3, 0); $this->assertSame(9, $this->fileHandler->decrement(self::$key1, 1)); $this->assertFalse($this->fileHandler->decrement(self::$key2, 1)); diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php index 44d65b1ebfc7..6733ee06fff6 100644 --- a/tests/system/Config/ServicesTest.php +++ b/tests/system/Config/ServicesTest.php @@ -147,17 +147,6 @@ public function testNewImage() $this->assertInstanceOf(ImageHandlerInterface::class, $actual); } - // public function testNewMigrationRunner() - // { - // //FIXME - docs aren't clear about setting this up to just make sure that the service - // // returns a MigrationRunner - // $config = new \Config\Migrations(); - // $db = new \CodeIgniter\Database\MockConnection([]); - // $this->expectException('InvalidArgumentException'); - // $actual = Services::migrations($config, $db); - // $this->assertInstanceOf(\CodeIgniter\Database\MigrationRunner::class, $actual); - // } - // public function testNewNegotiatorWithNullConfig() { $actual = Services::negotiator(null); diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 70b5ca05fbd7..2da8e5accbf3 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -643,19 +643,6 @@ public function testToFormattedDateString() $this->assertSame('May 10, 2017', $time->toFormattedDateString()); } - /** - * Unfortunately, ubuntu 14.04 (on TravisCI) fails this test and - * shows a numeric version of the month instead of the textual version. - * Confirmed on CentOS 7 as well. - * Example: format 'MMM' for November returns 'M02' instead of 'Nov' - * Not sure what the fix is just yet.... - */ - // public function testToFormattedDateString() - // { - // $time = Time::parse('February 10, 2017', 'America/Chicago'); - // $this->assertEquals('Feb 10, 2017', $time->toFormattedDateString()); - // } - public function testToTimeString() { $time = Time::parse('January 10, 2017 13:20:33', 'America/Chicago'); diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index a2c798d21cc6..5db2832fa12d 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -22,15 +22,6 @@ */ final class TestCaseTest extends CIUnitTestCase { - // protected function tearDown(): void - // { - // $buffer = ob_clean(); - // if (ob_get_level() > 0) - // { - // ob_end_clean(); - // } - // } - // public function testGetPrivatePropertyWithObject() { $obj = new __TestForReflectionHelper(); @@ -86,7 +77,6 @@ public function testPHPUnitHeadersEmitted() $response->send(); ob_end_clean(); - // Did PHPunit do its thing? $this->assertHeaderEmitted('Content-type: text/html;'); $this->assertHeaderNotEmitted('Set-Cookie: foo=bar;'); } diff --git a/utils/PhpCsFixer/CodeIgniter4.php b/utils/PhpCsFixer/CodeIgniter4.php deleted file mode 100644 index 05e83b544270..000000000000 --- a/utils/PhpCsFixer/CodeIgniter4.php +++ /dev/null @@ -1,540 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace Utils\PhpCsFixer; - -use Nexus\CsConfig\Ruleset\AbstractRuleset; - -/** - * Defines the ruleset used for the CodeIgniter4 organization. - * - * @internal - */ -final class CodeIgniter4 extends AbstractRuleset -{ - public function __construct() - { - $this->name = 'CodeIgniter4 Revised Coding Standards'; - - $this->rules = [ - 'align_multiline_comment' => ['comment_type' => 'phpdocs_only'], - 'array_indentation' => true, - 'array_push' => true, - 'array_syntax' => ['syntax' => 'short'], - 'backtick_to_shell_exec' => true, - 'binary_operator_spaces' => [ - 'default' => 'single_space', - 'operators' => [ - '=' => 'align_single_space_minimal', - '=>' => 'align_single_space_minimal', - '||' => 'align_single_space_minimal', - '.=' => 'align_single_space_minimal', - ], - ], - 'blank_line_after_namespace' => true, - 'blank_line_after_opening_tag' => true, - 'blank_line_before_statement' => [ - 'statements' => [ - 'case', - 'continue', - 'declare', - 'default', - 'do', - 'exit', - 'for', - 'foreach', - 'goto', - 'return', - 'switch', - 'throw', - 'try', - 'while', - 'yield', - 'yield_from', - ], - ], - 'braces' => [ - 'allow_single_line_anonymous_class_with_empty_body' => true, - 'allow_single_line_closure' => true, - 'position_after_anonymous_constructs' => 'same', - 'position_after_control_structures' => 'same', - 'position_after_functions_and_oop_constructs' => 'next', - ], - 'cast_spaces' => ['space' => 'single'], - 'class_attributes_separation' => [ - 'elements' => [ - 'method' => 'one', - ], - ], - 'class_definition' => [ - 'multi_line_extends_each_single_line' => true, - 'single_item_single_line' => true, - 'single_line' => true, - 'space_before_parenthesis' => true, - ], - 'clean_namespace' => true, - 'combine_consecutive_issets' => true, - 'combine_consecutive_unsets' => true, - 'combine_nested_dirname' => true, - 'comment_to_phpdoc' => [ - 'ignored_tags' => [ - 'todo', - 'codeCoverageIgnore', - 'codeCoverageIgnoreStart', - 'codeCoverageIgnoreEnd', - 'phpstan-ignore-line', - 'phpstan-ignore-next-line', - ], - ], - 'compact_nullable_typehint' => true, - 'concat_space' => ['spacing' => 'one'], - 'constant_case' => ['case' => 'lower'], - 'date_time_immutable' => false, - 'declare_equal_normalize' => ['space' => 'none'], - 'declare_parentheses' => true, - 'declare_strict_types' => false, - 'dir_constant' => true, - 'doctrine_annotation_array_assignment' => false, - 'doctrine_annotation_braces' => false, - 'doctrine_annotation_indentation' => false, - 'doctrine_annotation_spaces' => false, - 'echo_tag_syntax' => [ - 'format' => 'short', - 'long_function' => 'echo', - 'shorten_simple_statements_only' => false, - ], - 'elseif' => true, - 'empty_loop_body' => ['style' => 'braces'], - 'encoding' => true, - 'ereg_to_preg' => true, - 'error_suppression' => [ - 'mute_deprecation_error' => true, - 'noise_remaining_usages' => false, - 'noise_remaining_usages_exclude' => [], - ], - 'escape_implicit_backslashes' => [ - 'double_quoted' => true, - 'heredoc_syntax' => true, - 'single_quoted' => false, - ], - 'explicit_indirect_variable' => true, - 'explicit_string_variable' => true, - 'final_class' => false, - 'final_internal_class' => [ - 'annotation_exclude' => ['@no-final'], - 'annotation_include' => ['@internal'], - 'consider_absent_docblock_as_internal_class' => false, - ], - 'final_public_method_for_abstract_class' => false, - 'fopen_flag_order' => true, - 'fopen_flags' => ['b_mode' => true], - 'full_opening_tag' => true, - 'fully_qualified_strict_types' => true, - 'function_declaration' => ['closure_function_spacing' => 'one'], - 'function_to_constant' => [ - 'functions' => [ - 'get_called_class', - 'get_class', - 'get_class_this', - 'php_sapi_name', - 'phpversion', - 'pi', - ], - ], - 'function_typehint_space' => true, - 'general_phpdoc_annotation_remove' => [ - 'annotations' => [ - 'author', - 'package', - 'subpackage', - ], - ], - 'general_phpdoc_tag_rename' => [ - 'case_sensitive' => false, - 'fix_annotation' => true, - 'fix_inline' => true, - 'replacements' => ['inheritDocs' => 'inheritDoc'], - ], - 'global_namespace_import' => false, - 'group_import' => false, - 'header_comment' => false, // false by default - 'heredoc_indentation' => ['indentation' => 'start_plus_one'], - 'heredoc_to_nowdoc' => true, - 'implode_call' => true, - 'include' => true, - 'increment_style' => ['style' => 'post'], - 'indentation_type' => true, - 'is_null' => true, - 'lambda_not_used_import' => true, - 'line_ending' => true, - 'linebreak_after_opening_tag' => true, - 'list_syntax' => ['syntax' => 'short'], - 'logical_operators' => true, - 'lowercase_cast' => true, - 'lowercase_keywords' => true, - 'lowercase_static_reference' => true, - 'magic_constant_casing' => true, - 'magic_method_casing' => true, - 'mb_str_functions' => false, - 'method_argument_space' => [ - 'after_heredoc' => false, - 'keep_multiple_spaces_after_comma' => false, - 'on_multiline' => 'ensure_fully_multiline', - ], - 'method_chaining_indentation' => true, - 'modernize_types_casting' => true, - 'multiline_comment_opening_closing' => true, - 'multiline_whitespace_before_semicolons' => ['strategy' => 'no_multi_line'], - 'native_constant_invocation' => false, - 'native_function_casing' => true, - 'native_function_invocation' => false, - 'native_function_type_declaration_casing' => true, - 'new_with_braces' => true, - 'no_alias_functions' => ['sets' => ['@all']], - 'no_alias_language_construct_call' => true, - 'no_alternative_syntax' => false, - 'no_binary_string' => true, - 'no_blank_lines_after_class_opening' => true, - 'no_blank_lines_after_phpdoc' => true, - 'no_blank_lines_before_namespace' => false, // conflicts with `single_blank_line_before_namespace` - 'no_break_comment' => ['comment_text' => 'no break'], - 'no_closing_tag' => true, - 'no_empty_comment' => true, - 'no_empty_phpdoc' => true, - 'no_empty_statement' => true, - 'no_extra_blank_lines' => ['tokens' => ['extra']], - 'no_homoglyph_names' => true, - 'no_leading_import_slash' => true, - 'no_leading_namespace_whitespace' => true, - 'no_mixed_echo_print' => ['use' => 'echo'], - 'no_multiline_whitespace_around_double_arrow' => true, - 'no_null_property_initialization' => true, - 'no_php4_constructor' => true, - 'no_short_bool_cast' => true, - 'no_singleline_whitespace_before_semicolons' => true, - 'no_spaces_after_function_name' => true, - 'no_spaces_around_offset' => ['positions' => ['inside', 'outside']], - 'no_spaces_inside_parenthesis' => true, - 'no_superfluous_elseif' => true, - 'no_superfluous_phpdoc_tags' => [ - 'allow_mixed' => true, - 'allow_unused_params' => true, - 'remove_inheritdoc' => false, - ], - 'no_trailing_comma_in_list_call' => true, - 'no_trailing_comma_in_singleline_array' => true, - 'no_trailing_whitespace' => true, - 'no_trailing_whitespace_in_comment' => true, - 'no_trailing_whitespace_in_string' => true, - 'no_unneeded_control_parentheses' => [ - 'statements' => [ - 'break', - 'clone', - 'continue', - 'echo_print', - 'return', - 'switch_case', - 'yield', - ], - ], - 'no_unneeded_curly_braces' => ['namespaces' => true], - 'no_unneeded_final_method' => ['private_methods' => true], - 'no_unreachable_default_argument_value' => true, - 'no_unset_cast' => true, - 'no_unset_on_property' => false, - 'no_unused_imports' => true, - 'no_useless_else' => true, - 'no_useless_return' => true, - 'no_useless_sprintf' => true, - 'no_whitespace_before_comma_in_array' => ['after_heredoc' => true], - 'no_whitespace_in_blank_line' => true, - 'non_printable_character' => ['use_escape_sequences_in_strings' => true], - 'normalize_index_brace' => true, - 'not_operator_with_space' => false, - 'not_operator_with_successor_space' => true, - 'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => true], - 'object_operator_without_whitespace' => true, - 'operator_linebreak' => ['only_booleans' => true, 'position' => 'beginning'], - 'ordered_class_elements' => false, - 'ordered_imports' => [ - 'sort_algorithm' => 'alpha', - 'imports_order' => ['class', 'function', 'const'], - ], - 'ordered_interfaces' => false, - 'ordered_traits' => false, - 'php_unit_construct' => [ - 'assertions' => [ - 'assertSame', - 'assertEquals', - 'assertNotEquals', - 'assertNotSame', - ], - ], - 'php_unit_dedicate_assert' => ['target' => 'newest'], - 'php_unit_dedicate_assert_internal_type' => ['target' => 'newest'], - 'php_unit_expectation' => ['target' => 'newest'], - 'php_unit_fqcn_annotation' => true, - 'php_unit_internal_class' => ['types' => ['normal', 'final']], - 'php_unit_method_casing' => ['case' => 'camel_case'], - 'php_unit_mock' => ['target' => 'newest'], - 'php_unit_mock_short_will_return' => true, - 'php_unit_namespaced' => ['target' => 'newest'], - 'php_unit_no_expectation_annotation' => [ - 'target' => 'newest', - 'use_class_const' => true, - ], - 'php_unit_set_up_tear_down_visibility' => true, - 'php_unit_size_class' => false, - 'php_unit_strict' => [ - 'assertions' => [ - 'assertAttributeEquals', - 'assertAttributeNotEquals', - 'assertEquals', - 'assertNotEquals', - ], - ], - 'php_unit_test_annotation' => ['style' => 'prefix'], - 'php_unit_test_case_static_method_calls' => [ - 'call_type' => 'this', - 'methods' => [], - ], - 'php_unit_test_class_requires_covers' => false, - 'phpdoc_add_missing_param_annotation' => ['only_untyped' => true], - 'phpdoc_align' => [ - 'align' => 'vertical', - 'tags' => [ - 'method', - 'param', - 'property', - 'return', - 'throws', - 'type', - 'var', - ], - ], - 'phpdoc_annotation_without_dot' => false, - 'phpdoc_indent' => true, - 'phpdoc_inline_tag_normalizer' => [ - 'tags' => [ - 'example', - 'id', - 'internal', - 'inheritdoc', - 'inheritdocs', - 'link', - 'source', - 'toc', - 'tutorial', - ], - ], - 'phpdoc_line_span' => [ - 'const' => 'multi', - 'method' => 'multi', - 'property' => 'multi', - ], - 'phpdoc_no_access' => true, - 'phpdoc_no_alias_tag' => [ - 'replacements' => [ - 'property-read' => 'property', - 'property-write' => 'property', - 'type' => 'var', - 'link' => 'see', - ], - ], - 'phpdoc_no_empty_return' => false, - 'phpdoc_no_package' => true, - 'phpdoc_no_useless_inheritdoc' => true, - 'phpdoc_order' => true, - 'phpdoc_order_by_value' => [ - 'annotations' => [ - 'author', - 'covers', - 'coversNothing', - 'dataProvider', - 'depends', - 'group', - 'internal', - 'method', - 'property', - 'property-read', - 'property-write', - 'requires', - 'throws', - 'uses', - ], - ], - 'phpdoc_return_self_reference' => [ - 'replacements' => [ - 'this' => '$this', - '@this' => '$this', - '$self' => 'self', - '@self' => 'self', - '$static' => 'static', - '@static' => 'static', - ], - ], - 'phpdoc_scalar' => [ - 'types' => [ - 'boolean', - 'callback', - 'double', - 'integer', - 'real', - 'str', - ], - ], - 'phpdoc_separation' => true, - 'phpdoc_single_line_var_spacing' => true, - 'phpdoc_summary' => false, - 'phpdoc_tag_casing' => ['tags' => ['inheritDoc']], - 'phpdoc_tag_type' => ['tags' => ['inheritDoc' => 'inline']], - 'phpdoc_to_comment' => false, - 'phpdoc_to_param_type' => false, - 'phpdoc_to_property_type' => false, - 'phpdoc_to_return_type' => false, - 'phpdoc_trim' => true, - 'phpdoc_trim_consecutive_blank_line_separation' => true, - 'phpdoc_types' => ['groups' => ['simple', 'alias', 'meta']], - 'phpdoc_types_order' => [ - 'null_adjustment' => 'always_last', - 'sort_algorithm' => 'alpha', - ], - 'phpdoc_var_annotation_correct_order' => true, - 'phpdoc_var_without_name' => true, - 'pow_to_exponentiation' => true, - 'protected_to_private' => true, - 'psr_autoloading' => ['dir' => null], - 'random_api_migration' => [ - 'replacements' => [ - 'getrandmax' => 'mt_getrandmax', - 'rand' => 'mt_rand', - 'srand' => 'mt_srand', - ], - ], - 'regular_callable_call' => true, - 'return_assignment' => true, - 'return_type_declaration' => ['space_before' => 'none'], - 'self_accessor' => false, - 'self_static_accessor' => true, - 'semicolon_after_instruction' => false, - 'set_type_to_cast' => true, - 'short_scalar_cast' => true, - 'simple_to_complex_string_variable' => true, - 'simplified_if_return' => true, - 'simplified_null_return' => false, - 'single_blank_line_at_eof' => true, - 'single_blank_line_before_namespace' => true, - 'single_class_element_per_statement' => ['elements' => ['const', 'property']], - 'single_import_per_statement' => true, - 'single_line_after_imports' => true, - 'single_line_comment_style' => ['comment_types' => ['asterisk', 'hash']], - 'single_line_throw' => false, - 'single_quote' => ['strings_containing_single_quote_chars' => false], - 'single_space_after_construct' => [ - 'constructs' => [ - 'abstract', - 'as', - 'attribute', - 'break', - 'case', - 'catch', - 'class', - 'clone', - 'comment', - 'const', - 'const_import', - 'continue', - 'do', - 'echo', - 'else', - 'elseif', - 'extends', - 'final', - 'finally', - 'for', - 'foreach', - 'function', - 'function_import', - 'global', - 'goto', - 'if', - 'implements', - 'include', - 'include_once', - 'instanceof', - 'insteadof', - 'interface', - 'match', - 'named_argument', - 'new', - 'open_tag_with_echo', - 'php_doc', - 'php_open', - 'print', - 'private', - 'protected', - 'public', - 'require', - 'require_once', - 'return', - 'static', - 'throw', - 'trait', - 'try', - 'use', - 'use_lambda', - 'use_trait', - 'var', - 'while', - 'yield', - 'yield_from', - ], - ], - 'single_trait_insert_per_statement' => true, - 'space_after_semicolon' => ['remove_in_empty_for_expressions' => true], - 'standardize_increment' => true, - 'standardize_not_equals' => true, - 'static_lambda' => true, - 'strict_comparison' => true, - 'strict_param' => true, - 'string_line_ending' => true, - 'switch_case_semicolon_to_colon' => true, - 'switch_case_space' => true, - 'switch_continue_to_break' => true, - 'ternary_operator_spaces' => true, - 'ternary_to_elvis_operator' => true, - 'ternary_to_null_coalescing' => true, - 'trailing_comma_in_multiline' => [ - 'after_heredoc' => true, - 'elements' => ['arrays'], - ], - 'trim_array_spaces' => true, - 'types_spaces' => ['space' => 'none'], - 'unary_operator_spaces' => true, - 'use_arrow_functions' => false, // requires PHP7.4+ - 'visibility_required' => ['elements' => ['const', 'method', 'property']], - 'void_return' => false, // changes method signature - 'whitespace_after_comma_in_array' => true, - 'yoda_style' => [ - 'equal' => false, - 'identical' => null, - 'less_and_greater' => false, - 'always_move_variable' => false, - ], - ]; - - $this->requiredPHPVersion = 70300; - - $this->autoActivateIsRiskyAllowed = true; - } -} diff --git a/utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php b/utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php deleted file mode 100644 index d7322c32d308..000000000000 --- a/utils/PhpCsFixer/Fixer/Comment/SpaceAfterCommentStartFixer.php +++ /dev/null @@ -1,95 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace Utils\PhpCsFixer\Fixer\Comment; - -use PhpCsFixer\AbstractFixer; -use PhpCsFixer\FixerDefinition\CodeSample; -use PhpCsFixer\FixerDefinition\FixerDefinition; -use PhpCsFixer\FixerDefinition\FixerDefinitionInterface; -use PhpCsFixer\Preg; -use PhpCsFixer\Tokenizer\Token; -use PhpCsFixer\Tokenizer\Tokens; -use SplFileInfo; - -/** - * @internal - */ -final class SpaceAfterCommentStartFixer extends AbstractFixer -{ - /** - * {@inheritDoc} - */ - public function getName(): string - { - return 'CodeIgniter4/' . parent::getName(); - } - - /** - * {@inheritDoc} - */ - public function getDefinition(): FixerDefinitionInterface - { - return new FixerDefinition( - 'There should be a single whitespace after the comment start', - [new CodeSample("isTokenKindFound(T_COMMENT); - } - - /** - * {@inheritDoc} - * - * Must run after NoEmptyCommentFixer - */ - public function getPriority(): int - { - return 3; - } - - /** - * {@inheritDoc} - */ - protected function applyFix(SplFileInfo $file, Tokens $tokens): void - { - for ($index = 1, $count = $tokens->count(); $index < $count; $index++) { - /** @var Token $token */ - $token = $tokens[$index]; - - if (! $token->isGivenKind(T_COMMENT)) { - continue; - } - - $comment = $token->getContent(); - - if (substr($comment, 0, 2) !== '//') { - continue; - } - - if (Preg::match('/^\/\/(?!\s+)(.+)/', $comment, $matches) !== 1) { - continue; - } - - if (Preg::match('/\-+/', $matches[1]) === 1 || Preg::match('/\=+/', $matches[1]) === 1) { - continue; - } - - $tokens[$index] = new Token([T_COMMENT, '// ' . $matches[1]]); - } - } -} From b855bca99b0c374643f6626a97686e0dee5a2c4a Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Fri, 3 Sep 2021 20:57:36 +0800 Subject: [PATCH 0149/2325] Apply NoCodeSeparatorCommentFixer --- .no-header.php-cs-fixer.dist.php | 2 ++ .php-cs-fixer.dist.php | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php index acfdbf48e1b7..12acddb81087 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.no-header.php-cs-fixer.dist.php @@ -13,6 +13,7 @@ use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; +use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; @@ -33,6 +34,7 @@ 'finder' => $finder, 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ + NoCodeSeparatorCommentFixer::name() => true, SpaceAfterCommentStartFixer::name() => true, ], ]; diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index f362a830f99e..3c9e05fe3b74 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -13,6 +13,7 @@ use CodeIgniter\CodingStandard\CodeIgniter4; use Nexus\CsConfig\Factory; +use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; use Nexus\CsConfig\FixerGenerator; use PhpCsFixer\Finder; @@ -40,6 +41,7 @@ 'finder' => $finder, 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ + NoCodeSeparatorCommentFixer::name() => true, SpaceAfterCommentStartFixer::name() => true, ], ]; From 1cbdeac15c34e7bb85a70906324cb2195edba452 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Sat, 4 Sep 2021 22:19:17 +0800 Subject: [PATCH 0150/2325] Fixes and enhancements to Exceptions --- system/Debug/Exceptions.php | 101 ++++++++++++-------------- tests/system/Debug/ExceptionsTest.php | 53 ++++++++++++-- 2 files changed, 91 insertions(+), 63 deletions(-) diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 5950148984ef..04556c5c4f20 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -19,7 +19,6 @@ use Config\Paths; use ErrorException; use Throwable; -use function error_reporting; /** * Exceptions manager @@ -64,17 +63,11 @@ class Exceptions */ protected $response; - /** - * Constructor. - */ public function __construct(ExceptionsConfig $config, IncomingRequest $request, Response $response) { $this->ob_level = ob_get_level(); - $this->viewPath = rtrim($config->errorViewPath, '\\/ ') . DIRECTORY_SEPARATOR; - - $this->config = $config; - + $this->config = $config; $this->request = $request; $this->response = $response; } @@ -82,17 +75,13 @@ public function __construct(ExceptionsConfig $config, IncomingRequest $request, /** * Responsible for registering the error, exception and shutdown * handling of our application. + * + * @codeCoverageIgnore */ public function initialize() { - // Set the Exception Handler set_exception_handler([$this, 'exceptionHandler']); - - // Set the Error Handler set_error_handler([$this, 'errorHandler']); - - // Set the handler for shutdown to catch Parse errors - // Do we need this in PHP7? register_shutdown_function([$this, 'shutdownHandler']); } @@ -105,12 +94,8 @@ public function initialize() */ public function exceptionHandler(Throwable $exception) { - [ - $statusCode, - $exitCode, - ] = $this->determineCodes($exception); + [$statusCode, $exitCode] = $this->determineCodes($exception); - // Log it if ($this->config->log === true && ! in_array($statusCode, $this->config->ignoreCodes, true)) { log_message('critical', $exception->getMessage() . "\n{trace}", [ 'trace' => $exception->getTraceAsString(), @@ -119,8 +104,7 @@ public function exceptionHandler(Throwable $exception) if (! is_cli()) { $this->response->setStatusCode($statusCode); - $header = "HTTP/{$this->request->getProtocolVersion()} {$this->response->getStatusCode()} {$this->response->getReason()}"; - header($header, true, $statusCode); + header(sprintf('HTTP/%s %s %s', $this->request->getProtocolVersion(), $this->response->getStatusCode(), $this->response->getReasonPhrase()), true, $statusCode); if (strpos($this->request->getHeaderLine('accept'), 'text/html') === false) { $this->respond(ENVIRONMENT === 'development' ? $this->collectVars($exception, $statusCode) : '', $statusCode)->send(); @@ -142,6 +126,8 @@ public function exceptionHandler(Throwable $exception) * This seems to be primarily when a user triggers it with trigger_error(). * * @throws ErrorException + * + * @codeCoverageIgnore */ public function errorHandler(int $severity, string $message, ?string $file = null, ?int $line = null) { @@ -149,24 +135,27 @@ public function errorHandler(int $severity, string $message, ?string $file = nul return; } - // Convert it to an exception and pass it along. throw new ErrorException($message, 0, $severity, $file, $line); } /** * Checks to see if any errors have happened during shutdown that * need to be caught and handle them. + * + * @codeCoverageIgnore */ public function shutdownHandler() { $error = error_get_last(); - // If we've got an error that hasn't been displayed, then convert - // it to an Exception and use the Exception handler to display it - // to the user. - // Fatal Error? - if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE], true)) { - $this->exceptionHandler(new ErrorException($error['message'], $error['type'], 0, $error['file'], $error['line'])); + if ($error === null) { + return; + } + + ['type' => $type, 'message' => $message, 'file' => $file, 'line' => $line] = $error; + + if (in_array($type, [E_ERROR, E_CORE_ERROR, E_COMPILE_ERROR, E_PARSE], true)) { + $this->exceptionHandler(new ErrorException($message, $type, 0, $file, $line)); } } @@ -222,20 +211,25 @@ protected function render(Throwable $exception, int $statusCode) $viewFile = $altPath . $altView; } - // Prepare the vars - $vars = $this->collectVars($exception, $statusCode); - extract($vars); + if (! isset($viewFile)) { + echo 'The error view files were not found. Cannot render exception trace.'; + + exit(1); + } - // Render it if (ob_get_level() > $this->ob_level + 1) { ob_end_clean(); } - ob_start(); - include $viewFile; // @phpstan-ignore-line - $buffer = ob_get_contents(); - ob_end_clean(); - echo $buffer; + echo(function () use ($exception, $statusCode, $viewFile): string { + $vars = $this->collectVars($exception, $statusCode); + extract($vars, EXTR_SKIP); + + ob_start(); + include $viewFile; + + return ob_get_clean(); + })(); } /** @@ -244,7 +238,8 @@ protected function render(Throwable $exception, int $statusCode) protected function collectVars(Throwable $exception, int $statusCode): array { $trace = $exception->getTrace(); - if (! empty($this->config->sensitiveDataInTrace)) { + + if ($this->config->sensitiveDataInTrace !== []) { $this->maskSensitiveData($trace, $this->config->sensitiveDataInTrace); } @@ -279,11 +274,11 @@ protected function maskSensitiveData(&$trace, array $keysToMask, string $path = } } - if (! is_iterable($trace) && is_object($trace)) { + if (is_object($trace)) { $trace = get_object_vars($trace); } - if (is_iterable($trace)) { + if (is_array($trace)) { foreach ($trace as $pathKey => $subarray) { $this->maskSensitiveData($subarray, $keysToMask, $path . '/' . $pathKey); } @@ -298,19 +293,18 @@ protected function determineCodes(Throwable $exception): array $statusCode = abs($exception->getCode()); if ($statusCode < 100 || $statusCode > 599) { - $exitStatus = $statusCode + EXIT__AUTO_MIN; // 9 is EXIT__AUTO_MIN - if ($exitStatus > EXIT__AUTO_MAX) { // 125 is EXIT__AUTO_MAX - $exitStatus = EXIT_ERROR; // EXIT_ERROR + $exitStatus = $statusCode + EXIT__AUTO_MIN; + + if ($exitStatus > EXIT__AUTO_MAX) { + $exitStatus = EXIT_ERROR; } + $statusCode = 500; } else { - $exitStatus = 1; // EXIT_ERROR + $exitStatus = EXIT_ERROR; } - return [ - $statusCode ?: 500, - $exitStatus, - ]; + return [$statusCode, $exitStatus]; } //-------------------------------------------------------------------- @@ -318,8 +312,6 @@ protected function determineCodes(Throwable $exception): array //-------------------------------------------------------------------- /** - * Clean Path - * * This makes nicer looking paths for the error output. */ public static function cleanPath(string $file): string @@ -354,6 +346,7 @@ public static function describeMemory(int $bytes): string if ($bytes < 1024) { return $bytes . 'B'; } + if ($bytes < 1048576) { return round($bytes / 1024, 2) . 'KB'; } @@ -390,18 +383,16 @@ public static function highlightFile(string $file, int $lineNumber, int $lines = $source = str_replace(["\r\n", "\r"], "\n", $source); $source = explode("\n", highlight_string($source, true)); $source = str_replace('
', "\n", $source[1]); - $source = explode("\n", str_replace("\r\n", "\n", $source)); // Get just the part to show - $start = $lineNumber - (int) round($lines / 2); - $start = $start < 0 ? 0 : $start; + $start = max($lineNumber - (int) round($lines / 2), 0); // Get just the lines we need to display, while keeping line numbers... $source = array_splice($source, $start, $lines, true); // @phpstan-ignore-line // Used to format the line number in the source - $format = '% ' . strlen(sprintf('%s', $start + $lines)) . 'd'; + $format = '% ' . strlen((string) ($start + $lines)) . 'd'; $out = ''; // Because the highlighting may have an uneven number @@ -412,11 +403,11 @@ public static function highlightFile(string $file, int $lineNumber, int $lines = foreach ($source as $n => $row) { $spans += substr_count($row, ']+>#', $row, $tags); + $out .= sprintf( "{$format} %s\n%s", $n + $start + 1, diff --git a/tests/system/Debug/ExceptionsTest.php b/tests/system/Debug/ExceptionsTest.php index 115ae335c5e1..9bfcbb93c08b 100644 --- a/tests/system/Debug/ExceptionsTest.php +++ b/tests/system/Debug/ExceptionsTest.php @@ -11,27 +11,64 @@ namespace CodeIgniter\Debug; +use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\ReflectionHelper; +use Config\Exceptions as ExceptionsConfig; use Config\Services; +use RuntimeException; /** * @internal */ final class ExceptionsTest extends CIUnitTestCase { - public function testNew() + use ReflectionHelper; + + /** + * @var Exceptions + */ + private $exception; + + protected function setUp(): void { - $actual = new Exceptions(new \Config\Exceptions(), Services::request(), Services::response()); - $this->assertInstanceOf(Exceptions::class, $actual); + $this->exception = new Exceptions(new ExceptionsConfig(), Services::request(), Services::response()); + } + + public function testDetermineViews(): void + { + $determineView = $this->getPrivateMethodInvoker($this->exception, 'determineView'); + + $this->assertSame('error_404.php', $determineView(PageNotFoundException::forControllerNotFound('Foo', 'bar'), '')); + $this->assertSame('error_exception.php', $determineView(new RuntimeException('Exception'), '')); + $this->assertSame('error_404.php', $determineView(new RuntimeException('foo', 404), 'app/Views/errors/cli')); + } + + public function testCollectVars(): void + { + $vars = $this->getPrivateMethodInvoker($this->exception, 'collectVars')(new RuntimeException('This.'), 404); + + $this->assertIsArray($vars); + $this->assertCount(7, $vars); + + foreach (['title', 'type', 'code', 'message', 'file', 'line', 'trace'] as $key) { + $this->assertArrayHasKey($key, $vars); + } + } + + public function testDetermineCodes(): void + { + $determineCodes = $this->getPrivateMethodInvoker($this->exception, 'determineCodes'); + + $this->assertSame([500, 9], $determineCodes(new RuntimeException('This.'))); + $this->assertSame([500, 1], $determineCodes(new RuntimeException('That.', 600))); + $this->assertSame([404, 1], $determineCodes(new RuntimeException('There.', 404))); } /** * @dataProvider dirtyPathsProvider - * - * @param mixed $file - * @param mixed $expected */ - public function testCleanPaths($file, $expected) + public function testCleanPaths(string $file, string $expected): void { $this->assertSame($expected, Exceptions::cleanPath($file)); } @@ -40,7 +77,7 @@ public function dirtyPathsProvider() { $ds = DIRECTORY_SEPARATOR; - return [ + yield from [ [ APPPATH . 'Config' . $ds . 'App.php', 'APPPATH' . $ds . 'Config' . $ds . 'App.php', From a355c3bf40c9cc82f618d9a0aea5373be3692415 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Sat, 4 Sep 2021 22:20:36 +0800 Subject: [PATCH 0151/2325] Add entry to changelog for initial PHP 8.1 changes --- user_guide_src/source/changelogs/v4.1.4.rst | 67 +++++++++++++-------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.4.rst b/user_guide_src/source/changelogs/v4.1.4.rst index f5f7fb7d33b9..daca6b616294 100644 --- a/user_guide_src/source/changelogs/v4.1.4.rst +++ b/user_guide_src/source/changelogs/v4.1.4.rst @@ -7,28 +7,45 @@ Release Date: Not released Breaking Changes: -The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: - -* CodeIgniter4\Database\MySQLi\Connection::execute() -* CodeIgniter4\Database\MySQLi\Connection::_fieldData() -* CodeIgniter4\Database\MySQLi\Connection::_indexData() -* CodeIgniter4\Database\MySQLi\Connection::_foreignKeyData() -* CodeIgniter4\Database\Postgre\Builder::_like_statement() -* CodeIgniter4\Database\Postgre\Connection::execute() -* CodeIgniter4\Database\Postgre\Connection::_fieldData() -* CodeIgniter4\Database\Postgre\Connection::_indexData() -* CodeIgniter4\Database\Postgre\Connection::_foreignKeyData() -* CodeIgniter4\Database\SQLSRV\Connection::execute() -* CodeIgniter4\Database\SQLSRV\Connection::_fieldData() -* CodeIgniter4\Database\SQLSRV\Connection::_indexData() -* CodeIgniter4\Database\SQLSRV\Connection::_foreignKeyData() -* CodeIgniter4\Database\SQLite3\Connection::execute() -* CodeIgniter4\Database\SQLite3\Connection::_fieldData() -* CodeIgniter4\Database\SQLite3\Connection::_indexData() -* CodeIgniter4\Database\SQLite3\Connection::_foreignKeyData() -* CodeIgniter4\Images\Handlers\GDHandler::_flatten() -* CodeIgniter4\Images\Handlers\GDHandler::_flip() -* CodeIgniter4\Images\Handlers\ImageMagickHandler::_flatten() -* CodeIgniter4\Images\Handlers\ImageMagickHandler::_flip() -* CodeIgniter4\Test\Mock\MockIncomingRequest::detectURI() -* CodeIgniter4\Test\Mock\MockSecurity.php::sendCookie() +- The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: + +* ``CodeIgniter\Database\MySQLi\Connection::execute()`` +* ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` +* ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` +* ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` +* ``CodeIgniter\Database\Postgre\Connection::execute()`` +* ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` +* ``CodeIgniter\Database\Postgre\Connection::_indexData()`` +* ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::execute()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\SQLite3\Connection::execute()`` +* ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` +* ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` +* ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` +* ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` +* ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` +* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` +* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` +* ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` +* ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` + +- To be compatible with the strict inheritance checks of PHP 8.1, the following method signatures were added return types to match their parents' signatures whenever possible: + +* ``CodeIgniter\Cookie\Cookie::offsetExists()`` +* ``CodeIgniter\Cookie\Cookie::offsetSet()`` +* ``CodeIgniter\Cookie\Cookie::offsetUnset()`` +* ``CodeIgniter\Cookie\CookieStore::getIterator()`` +* ``CodeIgniter\I18n\Time::__wakeup()`` +* ``CodeIgniter\Test\Filters\CITestStreamFilter::filter()`` + +- Related to the strict inheritance checks of PHP 8.1, the following session handlers implementing ``SessionHandlerInterface`` have their public methods modified to match the interface: + +* ``CodeIgniter\Session\Handlers\ArrayHandler`` +* ``CodeIgniter\Session\Handlers\DatabaseHandler`` +* ``CodeIgniter\Session\Handlers\FileHandler`` +* ``CodeIgniter\Session\Handlers\MemcachedHandler`` +* ``CodeIgniter\Session\Handlers\RedisHandler`` From 8207b2f3f2bdddbb9e99813053303f210ad68d5c Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Sun, 5 Sep 2021 20:05:46 +0800 Subject: [PATCH 0152/2325] Fix entity name generation when bundled in model --- system/Commands/Generators/ModelGenerator.php | 22 ++++--- .../Commands/Generators/Views/entity.tpl.php | 6 +- .../Commands/Generators/Views/model.tpl.php | 46 +++++++-------- tests/system/Commands/ModelGeneratorTest.php | 57 ++++++++++++++----- 4 files changed, 80 insertions(+), 51 deletions(-) diff --git a/system/Commands/Generators/ModelGenerator.php b/system/Commands/Generators/ModelGenerator.php index 1ad8a75e1f8c..b4b7ffcda2ca 100644 --- a/system/Commands/Generators/ModelGenerator.php +++ b/system/Commands/Generators/ModelGenerator.php @@ -92,14 +92,17 @@ public function run(array $params) protected function prepare(string $class): string { $table = $this->getOption('table'); - $DBGroup = $this->getOption('dbgroup'); + $dbGroup = $this->getOption('dbgroup'); $return = $this->getOption('return'); - $baseClass = strtolower(str_replace(trim(implode('\\', array_slice(explode('\\', $class), 0, -1)), '\\') . '\\', '', $class)); - $baseClass = strpos($baseClass, 'model') ? str_replace('model', '', $baseClass) : $baseClass; + $baseClass = class_basename($class); - $table = is_string($table) ? $table : plural($baseClass); - $DBGroup = is_string($DBGroup) ? $DBGroup : 'default'; + if (preg_match('/^(\S+)Model$/i', $baseClass, $match) === 1) { + $baseClass = $match[1]; + } + + $table = is_string($table) ? $table : plural(strtolower($baseClass)); + $dbGroup = is_string($dbGroup) ? $dbGroup : 'default'; $return = is_string($return) ? $return : 'array'; if (! in_array($return, ['array', 'object', 'entity'], true)) { @@ -112,17 +115,20 @@ protected function prepare(string $class): string if ($return === 'entity') { $return = str_replace('Models', 'Entities', $class); - if ($pos = strpos($return, 'Model')) { - $return = substr($return, 0, $pos); + if (preg_match('/^(\S+)Model$/i', $return, $match) === 1) { + $return = $match[1]; if ($this->getOption('suffix')) { $return .= 'Entity'; } } + $return = '\\' . trim($return, '\\') . '::class'; $this->call('make:entity', array_merge([$baseClass], $this->params)); + } else { + $return = "'{$return}'"; } - return $this->parseTemplate($class, ['{table}', '{DBGroup}', '{return}'], [$table, $DBGroup, $return]); + return $this->parseTemplate($class, ['{table}', '{dbGroup}', '{return}'], [$table, $dbGroup, $return]); } } diff --git a/system/Commands/Generators/Views/entity.tpl.php b/system/Commands/Generators/Views/entity.tpl.php index 6623e2f14bbb..c74c776f4ad3 100644 --- a/system/Commands/Generators/Views/entity.tpl.php +++ b/system/Commands/Generators/Views/entity.tpl.php @@ -7,10 +7,6 @@ class {class} extends Entity { protected $datamap = []; - protected $dates = [ - 'created_at', - 'updated_at', - 'deleted_at', - ]; + protected $dates = ['created_at', 'updated_at', 'deleted_at']; protected $casts = []; } diff --git a/system/Commands/Generators/Views/model.tpl.php b/system/Commands/Generators/Views/model.tpl.php index 088ecb7e1161..5fc5ed9ba428 100644 --- a/system/Commands/Generators/Views/model.tpl.php +++ b/system/Commands/Generators/Views/model.tpl.php @@ -6,22 +6,22 @@ class {class} extends Model { - protected $DBGroup = '{DBGroup}'; - protected $table = '{table}'; - protected $primaryKey = 'id'; - protected $useAutoIncrement = true; - protected $insertID = 0; - protected $returnType = '{return}'; - protected $useSoftDeletes = false; - protected $protectFields = true; - protected $allowedFields = []; + protected $DBGroup = '{dbGroup}'; + protected $table = '{table}'; + protected $primaryKey = 'id'; + protected $useAutoIncrement = true; + protected $insertID = 0; + protected $returnType = {return}; + protected $useSoftDeletes = false; + protected $protectFields = true; + protected $allowedFields = []; // Dates - protected $useTimestamps = false; - protected $dateFormat = 'datetime'; - protected $createdField = 'created_at'; - protected $updatedField = 'updated_at'; - protected $deletedField = 'deleted_at'; + protected $useTimestamps = false; + protected $dateFormat = 'datetime'; + protected $createdField = 'created_at'; + protected $updatedField = 'updated_at'; + protected $deletedField = 'deleted_at'; // Validation protected $validationRules = []; @@ -30,13 +30,13 @@ class {class} extends Model protected $cleanValidationRules = true; // Callbacks - protected $allowCallbacks = true; - protected $beforeInsert = []; - protected $afterInsert = []; - protected $beforeUpdate = []; - protected $afterUpdate = []; - protected $beforeFind = []; - protected $afterFind = []; - protected $beforeDelete = []; - protected $afterDelete = []; + protected $allowCallbacks = true; + protected $beforeInsert = []; + protected $afterInsert = []; + protected $beforeUpdate = []; + protected $afterUpdate = []; + protected $beforeFind = []; + protected $afterFind = []; + protected $beforeDelete = []; + protected $afterDelete = []; } diff --git a/tests/system/Commands/ModelGeneratorTest.php b/tests/system/Commands/ModelGeneratorTest.php index 68e001103fb5..2d00460c53ee 100644 --- a/tests/system/Commands/ModelGeneratorTest.php +++ b/tests/system/Commands/ModelGeneratorTest.php @@ -19,10 +19,11 @@ */ final class ModelGeneratorTest extends CIUnitTestCase { - protected $streamFilter; + private $streamFilter; protected function setUp(): void { + parent::setUp(); CITestStreamFilter::$buffer = ''; $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); @@ -31,16 +32,18 @@ protected function setUp(): void protected function tearDown(): void { + parent::tearDown(); stream_filter_remove($this->streamFilter); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); + if (is_file($file)) { unlink($file); } } - protected function getFileContent(string $filepath): string + private function getFileContent(string $filepath): string { if (! is_file($filepath)) { return ''; @@ -51,14 +54,14 @@ protected function getFileContent(string $filepath): string public function testGenerateModel() { - command('make:model user -table users'); + command('make:model user --table users'); $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); $this->assertStringContainsString('extends Model', $this->getFileContent($file)); - $this->assertStringContainsString('protected $table = \'users\';', $this->getFileContent($file)); - $this->assertStringContainsString('protected $DBGroup = \'default\';', $this->getFileContent($file)); - $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $table = \'users\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $DBGroup = \'default\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); } public function testGenerateModelWithOptionTable() @@ -67,7 +70,7 @@ public function testGenerateModelWithOptionTable() $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $file = APPPATH . 'Models/Cars.php'; $this->assertFileExists($file); - $this->assertStringContainsString('protected $table = \'utilisateur\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $table = \'utilisateur\';', $this->getFileContent($file)); } public function testGenerateModelWithOptionDBGroup() @@ -76,43 +79,48 @@ public function testGenerateModelWithOptionDBGroup() $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); - $this->assertStringContainsString('protected $DBGroup = \'testing\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $DBGroup = \'testing\';', $this->getFileContent($file)); } public function testGenerateModelWithOptionReturnArray() { - command('make:model user -return array'); + command('make:model user --return array'); $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); - $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); } public function testGenerateModelWithOptionReturnObject() { - command('make:model user -return object'); + command('make:model user --return object'); $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); - $this->assertStringContainsString('protected $returnType = \'object\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $returnType = \'object\';', $this->getFileContent($file)); } public function testGenerateModelWithOptionReturnEntity() { - command('make:model user -return entity'); + command('make:model user --return entity'); $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); - $this->assertStringContainsString('protected $returnType = \'App\Entities\User\';', $this->getFileContent($file)); + $this->assertStringContainsString('protected $returnType = \App\Entities\User::class;', $this->getFileContent($file)); + if (is_file($file)) { unlink($file); } + $file = APPPATH . 'Entities/User.php'; $this->assertFileExists($file); $dir = dirname($file); + if (is_file($file)) { unlink($file); } + if (is_dir($dir)) { rmdir($dir); } @@ -120,13 +128,32 @@ public function testGenerateModelWithOptionReturnEntity() public function testGenerateModelWithOptionSuffix() { - command('make:model user -suffix -return entity'); + command('make:model user --suffix --return entity'); $model = APPPATH . 'Models/UserModel.php'; $entity = APPPATH . 'Entities/UserEntity.php'; $this->assertFileExists($model); $this->assertFileExists($entity); + + unlink($model); + unlink($entity); + rmdir(dirname($entity)); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5050 + */ + public function testGenerateModelWithSuffixAndMixedPascalCasedName() + { + command('make:model MyTable --suffix --return entity'); + + $model = APPPATH . 'Models/MyTableModel.php'; + $entity = APPPATH . 'Entities/MyTableEntity.php'; + + $this->assertFileExists($model); + $this->assertFileExists($entity); + unlink($model); unlink($entity); rmdir(dirname($entity)); From f4bb2657125e5d10ec5c2b43e55a764f5da4b02f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Sep 2021 11:08:46 +0900 Subject: [PATCH 0153/2325] docs: fix indentation of the list --- user_guide_src/source/changelogs/v4.1.4.rst | 68 ++++++++++----------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.4.rst b/user_guide_src/source/changelogs/v4.1.4.rst index daca6b616294..79b9b881fd82 100644 --- a/user_guide_src/source/changelogs/v4.1.4.rst +++ b/user_guide_src/source/changelogs/v4.1.4.rst @@ -9,43 +9,43 @@ Breaking Changes: - The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: -* ``CodeIgniter\Database\MySQLi\Connection::execute()`` -* ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` -* ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` -* ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` -* ``CodeIgniter\Database\Postgre\Connection::execute()`` -* ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` -* ``CodeIgniter\Database\Postgre\Connection::_indexData()`` -* ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::execute()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\SQLite3\Connection::execute()`` -* ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` -* ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` -* ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` -* ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` -* ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` -* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` -* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` -* ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` -* ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` + * ``CodeIgniter\Database\MySQLi\Connection::execute()`` + * ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` + * ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` + * ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` + * ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` + * ``CodeIgniter\Database\Postgre\Connection::execute()`` + * ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` + * ``CodeIgniter\Database\Postgre\Connection::_indexData()`` + * ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` + * ``CodeIgniter\Database\SQLSRV\Connection::execute()`` + * ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` + * ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` + * ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` + * ``CodeIgniter\Database\SQLite3\Connection::execute()`` + * ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` + * ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` + * ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` + * ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` + * ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` + * ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` + * ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` + * ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` + * ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` - To be compatible with the strict inheritance checks of PHP 8.1, the following method signatures were added return types to match their parents' signatures whenever possible: -* ``CodeIgniter\Cookie\Cookie::offsetExists()`` -* ``CodeIgniter\Cookie\Cookie::offsetSet()`` -* ``CodeIgniter\Cookie\Cookie::offsetUnset()`` -* ``CodeIgniter\Cookie\CookieStore::getIterator()`` -* ``CodeIgniter\I18n\Time::__wakeup()`` -* ``CodeIgniter\Test\Filters\CITestStreamFilter::filter()`` + * ``CodeIgniter\Cookie\Cookie::offsetExists()`` + * ``CodeIgniter\Cookie\Cookie::offsetSet()`` + * ``CodeIgniter\Cookie\Cookie::offsetUnset()`` + * ``CodeIgniter\Cookie\CookieStore::getIterator()`` + * ``CodeIgniter\I18n\Time::__wakeup()`` + * ``CodeIgniter\Test\Filters\CITestStreamFilter::filter()`` - Related to the strict inheritance checks of PHP 8.1, the following session handlers implementing ``SessionHandlerInterface`` have their public methods modified to match the interface: -* ``CodeIgniter\Session\Handlers\ArrayHandler`` -* ``CodeIgniter\Session\Handlers\DatabaseHandler`` -* ``CodeIgniter\Session\Handlers\FileHandler`` -* ``CodeIgniter\Session\Handlers\MemcachedHandler`` -* ``CodeIgniter\Session\Handlers\RedisHandler`` + * ``CodeIgniter\Session\Handlers\ArrayHandler`` + * ``CodeIgniter\Session\Handlers\DatabaseHandler`` + * ``CodeIgniter\Session\Handlers\FileHandler`` + * ``CodeIgniter\Session\Handlers\MemcachedHandler`` + * ``CodeIgniter\Session\Handlers\RedisHandler`` From 0ae2594f9d7651e1fe442383a823e56fc29caeb4 Mon Sep 17 00:00:00 2001 From: MGatner Date: Mon, 6 Sep 2021 15:09:53 +0000 Subject: [PATCH 0154/2325] Prep for 4.1.4 release --- CHANGELOG.md | 7 ++ system/CodeIgniter.php | 2 +- user_guide_src/source/changelogs/v4.1.4.rst | 51 +++++----- user_guide_src/source/conf.py | 2 +- .../source/installation/upgrade_414.rst | 95 +++++++++++++++++++ .../source/installation/upgrading.rst | 1 + 6 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 user_guide_src/source/installation/upgrade_414.rst diff --git a/CHANGELOG.md b/CHANGELOG.md index 24249162d792..74513d243589 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [v4.1.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.4) (2021-09-06) + +This release focuses on code style. All changes (except those noted below) are cosmetic to bring the code in line with the new +[CodeIgniter Coding Standard](https://github.com/CodeIgniter/coding-standard) (based on PSR-12). + +*Note: Full changelog forthcoming.* + ## [v4.1.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.3) (2021-06-06) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.2...v4.1.3) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 7034f710b8ac..4350876bd3a2 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -44,7 +44,7 @@ class CodeIgniter /** * The current version of CodeIgniter Framework */ - public const CI_VERSION = '4.1.3'; + public const CI_VERSION = '4.1.4'; private const MIN_PHP_VERSION = '7.3'; diff --git a/user_guide_src/source/changelogs/v4.1.4.rst b/user_guide_src/source/changelogs/v4.1.4.rst index f5f7fb7d33b9..4ce8aa41587e 100644 --- a/user_guide_src/source/changelogs/v4.1.4.rst +++ b/user_guide_src/source/changelogs/v4.1.4.rst @@ -1,34 +1,37 @@ Version 4.1.4 ============= -Release Date: Not released +Release Date: September 6, 2021 **4.1.4 release of CodeIgniter4** +This release focuses on code style. All changes (except those noted below) are cosmetic to bring the code in line with the new +`CodeIgniter Coding Standard `_ (based on PSR-12). + Breaking Changes: The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: -* CodeIgniter4\Database\MySQLi\Connection::execute() -* CodeIgniter4\Database\MySQLi\Connection::_fieldData() -* CodeIgniter4\Database\MySQLi\Connection::_indexData() -* CodeIgniter4\Database\MySQLi\Connection::_foreignKeyData() -* CodeIgniter4\Database\Postgre\Builder::_like_statement() -* CodeIgniter4\Database\Postgre\Connection::execute() -* CodeIgniter4\Database\Postgre\Connection::_fieldData() -* CodeIgniter4\Database\Postgre\Connection::_indexData() -* CodeIgniter4\Database\Postgre\Connection::_foreignKeyData() -* CodeIgniter4\Database\SQLSRV\Connection::execute() -* CodeIgniter4\Database\SQLSRV\Connection::_fieldData() -* CodeIgniter4\Database\SQLSRV\Connection::_indexData() -* CodeIgniter4\Database\SQLSRV\Connection::_foreignKeyData() -* CodeIgniter4\Database\SQLite3\Connection::execute() -* CodeIgniter4\Database\SQLite3\Connection::_fieldData() -* CodeIgniter4\Database\SQLite3\Connection::_indexData() -* CodeIgniter4\Database\SQLite3\Connection::_foreignKeyData() -* CodeIgniter4\Images\Handlers\GDHandler::_flatten() -* CodeIgniter4\Images\Handlers\GDHandler::_flip() -* CodeIgniter4\Images\Handlers\ImageMagickHandler::_flatten() -* CodeIgniter4\Images\Handlers\ImageMagickHandler::_flip() -* CodeIgniter4\Test\Mock\MockIncomingRequest::detectURI() -* CodeIgniter4\Test\Mock\MockSecurity.php::sendCookie() +* CodeIgniter\Database\MySQLi\Connection::execute() +* CodeIgniter\Database\MySQLi\Connection::_fieldData() +* CodeIgniter\Database\MySQLi\Connection::_indexData() +* CodeIgniter\Database\MySQLi\Connection::_foreignKeyData() +* CodeIgniter\Database\Postgre\Builder::_like_statement() +* CodeIgniter\Database\Postgre\Connection::execute() +* CodeIgniter\Database\Postgre\Connection::_fieldData() +* CodeIgniter\Database\Postgre\Connection::_indexData() +* CodeIgniter\Database\Postgre\Connection::_foreignKeyData() +* CodeIgniter\Database\SQLSRV\Connection::execute() +* CodeIgniter\Database\SQLSRV\Connection::_fieldData() +* CodeIgniter\Database\SQLSRV\Connection::_indexData() +* CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData() +* CodeIgniter\Database\SQLite3\Connection::execute() +* CodeIgniter\Database\SQLite3\Connection::_fieldData() +* CodeIgniter\Database\SQLite3\Connection::_indexData() +* CodeIgniter\Database\SQLite3\Connection::_foreignKeyData() +* CodeIgniter\Images\Handlers\GDHandler::_flatten() +* CodeIgniter\Images\Handlers\GDHandler::_flip() +* CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten() +* CodeIgniter\Images\Handlers\ImageMagickHandler::_flip() +* CodeIgniter\Test\Mock\MockIncomingRequest::detectURI() +* CodeIgniter\Test\Mock\MockSecurity.php::sendCookie() diff --git a/user_guide_src/source/conf.py b/user_guide_src/source/conf.py index 63fd4dcf46bc..f341ddfc25c4 100644 --- a/user_guide_src/source/conf.py +++ b/user_guide_src/source/conf.py @@ -24,7 +24,7 @@ version = '4.1' # The full version, including alpha/beta/rc tags. -release = '4.1.3' +release = '4.1.4' # -- General configuration --------------------------------------------------- diff --git a/user_guide_src/source/installation/upgrade_414.rst b/user_guide_src/source/installation/upgrade_414.rst new file mode 100644 index 000000000000..8f84809fb664 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_414.rst @@ -0,0 +1,95 @@ +############################# +Upgrading from 4.1.3 to 4.1.4 +############################# + +This release focuses on code style. All changes (except those noted below) are cosmetic to bring the code in line with the new +`CodeIgniter Coding Standard `_ (based on PSR-12). + +**Method Scope** + +The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses. +If you relied on any of these methods being public (highly unlikely) adjust your code accordingly:: + +* ``CodeIgniter\Database\MySQLi\Connection::execute()`` +* ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` +* ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` +* ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` +* ``CodeIgniter\Database\Postgre\Connection::execute()`` +* ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` +* ``CodeIgniter\Database\Postgre\Connection::_indexData()`` +* ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::execute()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\SQLite3\Connection::execute()`` +* ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` +* ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` +* ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` +* ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` +* ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` +* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` +* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` +* ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` +* ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` + + +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 +--------------- + +The following files received significant changes (including deprecations or visual adjustments) +and it is recommended that you merge the updated versions with your application: + +* ``app/Config/App.php`` +* ``app/Config/Autoload.php`` +* ``app/Config/Cookie.php`` +* ``app/Config/Events.php`` +* ``app/Config/Exceptions.php`` +* ``app/Config/Security.php`` +* ``app/Views/errors/html/*`` +* ``env`` +* ``spark`` + +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 affect on the runtime: + +* ``app/Config/App.php`` +* ``app/Config/Autoload.php`` +* ``app/Config/ContentSecurityPolicy.php`` +* ``app/Config/Cookie.php`` +* ``app/Config/Events.php`` +* ``app/Config/Exceptions.php`` +* ``app/Config/Logger.php`` +* ``app/Config/Mimes.php`` +* ``app/Config/Modules.php`` +* ``app/Config/Security.php`` +* ``app/Controllers/BaseController.php`` +* ``app/Views/errors/html/debug.css`` +* ``app/Views/errors/html/error_404.php`` +* ``app/Views/errors/html/error_exception.php`` +* ``app/Views/welcome_message.php`` +* ``composer.json`` +* ``contributing/guidelines.rst`` +* ``env`` +* ``phpstan.neon.dist`` +* ``phpunit.xml.dist`` +* ``public/.htaccess`` +* ``public/index.php`` +* ``rector.php`` +* ``spark`` diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 333f0a0f8e66..64696e691dc7 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -8,6 +8,7 @@ upgrading from. .. toctree:: :titlesonly: + Upgrading from 4.1.3 to 4.1.4 Upgrading from 4.1.2 to 4.1.3 Upgrading from 4.1.1 to 4.1.2 Upgrading from 4.0.5 to 4.1.0 or 4.1.1 From 62bf3abfd36d4aafa9a3200ac890eb66a15af0f4 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Sat, 4 Sep 2021 22:20:36 +0800 Subject: [PATCH 0155/2325] Add entry to changelog for initial PHP 8.1 changes --- user_guide_src/source/changelogs/v4.1.4.rst | 67 +++++++++++++-------- 1 file changed, 42 insertions(+), 25 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.4.rst b/user_guide_src/source/changelogs/v4.1.4.rst index 4ce8aa41587e..14c7a99e5e62 100644 --- a/user_guide_src/source/changelogs/v4.1.4.rst +++ b/user_guide_src/source/changelogs/v4.1.4.rst @@ -10,28 +10,45 @@ This release focuses on code style. All changes (except those noted below) are c Breaking Changes: -The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: - -* CodeIgniter\Database\MySQLi\Connection::execute() -* CodeIgniter\Database\MySQLi\Connection::_fieldData() -* CodeIgniter\Database\MySQLi\Connection::_indexData() -* CodeIgniter\Database\MySQLi\Connection::_foreignKeyData() -* CodeIgniter\Database\Postgre\Builder::_like_statement() -* CodeIgniter\Database\Postgre\Connection::execute() -* CodeIgniter\Database\Postgre\Connection::_fieldData() -* CodeIgniter\Database\Postgre\Connection::_indexData() -* CodeIgniter\Database\Postgre\Connection::_foreignKeyData() -* CodeIgniter\Database\SQLSRV\Connection::execute() -* CodeIgniter\Database\SQLSRV\Connection::_fieldData() -* CodeIgniter\Database\SQLSRV\Connection::_indexData() -* CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData() -* CodeIgniter\Database\SQLite3\Connection::execute() -* CodeIgniter\Database\SQLite3\Connection::_fieldData() -* CodeIgniter\Database\SQLite3\Connection::_indexData() -* CodeIgniter\Database\SQLite3\Connection::_foreignKeyData() -* CodeIgniter\Images\Handlers\GDHandler::_flatten() -* CodeIgniter\Images\Handlers\GDHandler::_flip() -* CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten() -* CodeIgniter\Images\Handlers\ImageMagickHandler::_flip() -* CodeIgniter\Test\Mock\MockIncomingRequest::detectURI() -* CodeIgniter\Test\Mock\MockSecurity.php::sendCookie() +- The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: + +* ``CodeIgniter\Database\MySQLi\Connection::execute()`` +* ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` +* ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` +* ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` +* ``CodeIgniter\Database\Postgre\Connection::execute()`` +* ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` +* ``CodeIgniter\Database\Postgre\Connection::_indexData()`` +* ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::execute()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` +* ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` +* ``CodeIgniter\Database\SQLite3\Connection::execute()`` +* ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` +* ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` +* ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` +* ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` +* ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` +* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` +* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` +* ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` +* ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` + +- To be compatible with the strict inheritance checks of PHP 8.1, the following method signatures were added return types to match their parents' signatures whenever possible: + +* ``CodeIgniter\Cookie\Cookie::offsetExists()`` +* ``CodeIgniter\Cookie\Cookie::offsetSet()`` +* ``CodeIgniter\Cookie\Cookie::offsetUnset()`` +* ``CodeIgniter\Cookie\CookieStore::getIterator()`` +* ``CodeIgniter\I18n\Time::__wakeup()`` +* ``CodeIgniter\Test\Filters\CITestStreamFilter::filter()`` + +- Related to the strict inheritance checks of PHP 8.1, the following session handlers implementing ``SessionHandlerInterface`` have their public methods modified to match the interface: + +* ``CodeIgniter\Session\Handlers\ArrayHandler`` +* ``CodeIgniter\Session\Handlers\DatabaseHandler`` +* ``CodeIgniter\Session\Handlers\FileHandler`` +* ``CodeIgniter\Session\Handlers\MemcachedHandler`` +* ``CodeIgniter\Session\Handlers\RedisHandler`` From 26b7a909c0733de105a1b2a13d7f5199de9f30c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Sep 2021 11:08:46 +0900 Subject: [PATCH 0156/2325] docs: fix indentation of the list --- user_guide_src/source/changelogs/v4.1.4.rst | 68 ++++++++++----------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.4.rst b/user_guide_src/source/changelogs/v4.1.4.rst index 14c7a99e5e62..58cfe82b61ac 100644 --- a/user_guide_src/source/changelogs/v4.1.4.rst +++ b/user_guide_src/source/changelogs/v4.1.4.rst @@ -12,43 +12,43 @@ Breaking Changes: - The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses: -* ``CodeIgniter\Database\MySQLi\Connection::execute()`` -* ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` -* ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` -* ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` -* ``CodeIgniter\Database\Postgre\Connection::execute()`` -* ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` -* ``CodeIgniter\Database\Postgre\Connection::_indexData()`` -* ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::execute()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` -* ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` -* ``CodeIgniter\Database\SQLite3\Connection::execute()`` -* ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` -* ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` -* ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` -* ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` -* ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` -* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` -* ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` -* ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` -* ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` + * ``CodeIgniter\Database\MySQLi\Connection::execute()`` + * ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` + * ``CodeIgniter\Database\MySQLi\Connection::_indexData()`` + * ``CodeIgniter\Database\MySQLi\Connection::_foreignKeyData()`` + * ``CodeIgniter\Database\Postgre\Builder::_like_statement()`` + * ``CodeIgniter\Database\Postgre\Connection::execute()`` + * ``CodeIgniter\Database\Postgre\Connection::_fieldData()`` + * ``CodeIgniter\Database\Postgre\Connection::_indexData()`` + * ``CodeIgniter\Database\Postgre\Connection::_foreignKeyData()`` + * ``CodeIgniter\Database\SQLSRV\Connection::execute()`` + * ``CodeIgniter\Database\SQLSRV\Connection::_fieldData()`` + * ``CodeIgniter\Database\SQLSRV\Connection::_indexData()`` + * ``CodeIgniter\Database\SQLSRV\Connection::_foreignKeyData()`` + * ``CodeIgniter\Database\SQLite3\Connection::execute()`` + * ``CodeIgniter\Database\SQLite3\Connection::_fieldData()`` + * ``CodeIgniter\Database\SQLite3\Connection::_indexData()`` + * ``CodeIgniter\Database\SQLite3\Connection::_foreignKeyData()`` + * ``CodeIgniter\Images\Handlers\GDHandler::_flatten()`` + * ``CodeIgniter\Images\Handlers\GDHandler::_flip()`` + * ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flatten()`` + * ``CodeIgniter\Images\Handlers\ImageMagickHandler::_flip()`` + * ``CodeIgniter\Test\Mock\MockIncomingRequest::detectURI()`` + * ``CodeIgniter\Test\Mock\MockSecurity.php::sendCookie()`` - To be compatible with the strict inheritance checks of PHP 8.1, the following method signatures were added return types to match their parents' signatures whenever possible: -* ``CodeIgniter\Cookie\Cookie::offsetExists()`` -* ``CodeIgniter\Cookie\Cookie::offsetSet()`` -* ``CodeIgniter\Cookie\Cookie::offsetUnset()`` -* ``CodeIgniter\Cookie\CookieStore::getIterator()`` -* ``CodeIgniter\I18n\Time::__wakeup()`` -* ``CodeIgniter\Test\Filters\CITestStreamFilter::filter()`` + * ``CodeIgniter\Cookie\Cookie::offsetExists()`` + * ``CodeIgniter\Cookie\Cookie::offsetSet()`` + * ``CodeIgniter\Cookie\Cookie::offsetUnset()`` + * ``CodeIgniter\Cookie\CookieStore::getIterator()`` + * ``CodeIgniter\I18n\Time::__wakeup()`` + * ``CodeIgniter\Test\Filters\CITestStreamFilter::filter()`` - Related to the strict inheritance checks of PHP 8.1, the following session handlers implementing ``SessionHandlerInterface`` have their public methods modified to match the interface: -* ``CodeIgniter\Session\Handlers\ArrayHandler`` -* ``CodeIgniter\Session\Handlers\DatabaseHandler`` -* ``CodeIgniter\Session\Handlers\FileHandler`` -* ``CodeIgniter\Session\Handlers\MemcachedHandler`` -* ``CodeIgniter\Session\Handlers\RedisHandler`` + * ``CodeIgniter\Session\Handlers\ArrayHandler`` + * ``CodeIgniter\Session\Handlers\DatabaseHandler`` + * ``CodeIgniter\Session\Handlers\FileHandler`` + * ``CodeIgniter\Session\Handlers\MemcachedHandler`` + * ``CodeIgniter\Session\Handlers\RedisHandler`` From f1cdeff536a12d903f38a5f39ad84fa9dd55f5ae Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 7 Sep 2021 01:51:29 +0000 Subject: [PATCH 0157/2325] Replace pasted content --- .../source/installation/upgrade_414.rst | 58 +------------------ 1 file changed, 3 insertions(+), 55 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_414.rst b/user_guide_src/source/installation/upgrade_414.rst index 8f84809fb664..613823132351 100644 --- a/user_guide_src/source/installation/upgrade_414.rst +++ b/user_guide_src/source/installation/upgrade_414.rst @@ -38,58 +38,6 @@ If you relied on any of these methods being public (highly unlikely) adjust your 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 ---------------- - -The following files received significant changes (including deprecations or visual adjustments) -and it is recommended that you merge the updated versions with your application: - -* ``app/Config/App.php`` -* ``app/Config/Autoload.php`` -* ``app/Config/Cookie.php`` -* ``app/Config/Events.php`` -* ``app/Config/Exceptions.php`` -* ``app/Config/Security.php`` -* ``app/Views/errors/html/*`` -* ``env`` -* ``spark`` - -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 affect on the runtime: - -* ``app/Config/App.php`` -* ``app/Config/Autoload.php`` -* ``app/Config/ContentSecurityPolicy.php`` -* ``app/Config/Cookie.php`` -* ``app/Config/Events.php`` -* ``app/Config/Exceptions.php`` -* ``app/Config/Logger.php`` -* ``app/Config/Mimes.php`` -* ``app/Config/Modules.php`` -* ``app/Config/Security.php`` -* ``app/Controllers/BaseController.php`` -* ``app/Views/errors/html/debug.css`` -* ``app/Views/errors/html/error_404.php`` -* ``app/Views/errors/html/error_exception.php`` -* ``app/Views/welcome_message.php`` -* ``composer.json`` -* ``contributing/guidelines.rst`` -* ``env`` -* ``phpstan.neon.dist`` -* ``phpunit.xml.dist`` -* ``public/.htaccess`` -* ``public/index.php`` -* ``rector.php`` -* ``spark`` +All files in the project space were reformatted with the new coding style. This will not affect +existing code but you may want to apply the updated coding style to your own projects to keep +them in line with the framework's version of these files. From 09609d5ab050e89d26dac6e93a465a27aff66254 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Sun, 13 Jun 2021 23:37:10 -0500 Subject: [PATCH 0158/2325] New mock() test helper and expanded MockCache with assertions. --- system/Cache/CacheFactory.php | 18 ++++- system/Exceptions/TestException.php | 25 ++++++ system/Helpers/test_helper.php | 32 +++++++- system/Language/en/Test.php | 15 ++++ system/Test/Mock/MockCache.php | 98 +++++++++++++++++------ tests/system/Cache/CacheMockTest.php | 46 +++++++++++ user_guide_src/source/testing/index.rst | 3 +- user_guide_src/source/testing/mocking.rst | 53 ++++++++++++ 8 files changed, 260 insertions(+), 30 deletions(-) create mode 100644 system/Exceptions/TestException.php create mode 100644 system/Language/en/Test.php create mode 100644 tests/system/Cache/CacheMockTest.php create mode 100644 user_guide_src/source/testing/mocking.rst diff --git a/system/Cache/CacheFactory.php b/system/Cache/CacheFactory.php index 720fae0e4c6c..875dcd3f7bcd 100644 --- a/system/Cache/CacheFactory.php +++ b/system/Cache/CacheFactory.php @@ -13,6 +13,7 @@ use CodeIgniter\Cache\Exceptions\CacheException; use CodeIgniter\Exceptions\CriticalError; +use CodeIgniter\Test\Mock\MockCache; use Config\Cache; /** @@ -20,6 +21,20 @@ */ class CacheFactory { + /** + * The class to use when mocking + * + * @var string + */ + public static $mockClass = MockCache::class; + + /** + * The service to inject the mock as + * + * @var string + */ + public static $mockServiceName = 'cache'; + /** * Attempts to create the desired cache handler, based upon the * @@ -42,14 +57,12 @@ public static function getHandler(Cache $config, ?string $handler = null, ?strin throw CacheException::forHandlerNotFound(); } - // Get an instance of our handler. $adapter = new $config->validHandlers[$handler]($config); if (! $adapter->isSupported()) { $adapter = new $config->validHandlers[$backup]($config); if (! $adapter->isSupported()) { - // Log stuff here, don't throw exception. No need to raise a fuss. // Fall back to the dummy adapter. $adapter = new $config->validHandlers['dummy'](); } @@ -60,7 +73,6 @@ public static function getHandler(Cache $config, ?string $handler = null, ?strin try { $adapter->initialize(); } catch (CriticalError $e) { - // log the fact that an exception occurred as well what handler we are resorting to log_message('critical', $e->getMessage() . ' Resorting to using ' . $backup . ' handler.'); // get the next best cache handler (or dummy if the $backup also fails) diff --git a/system/Exceptions/TestException.php b/system/Exceptions/TestException.php new file mode 100644 index 000000000000..a1c4c51cf814 --- /dev/null +++ b/system/Exceptions/TestException.php @@ -0,0 +1,25 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Exceptions; + +/** + * Exception for automatic logging. + */ +class TestException extends CriticalError +{ + use DebugTraceableTrait; + + public static function forInvalidMockClass(string $name) + { + return new static(lang('Test.invalidMockClass', [$name])); + } +} diff --git a/system/Helpers/test_helper.php b/system/Helpers/test_helper.php index e20054ab6893..a73446a0ac5f 100644 --- a/system/Helpers/test_helper.php +++ b/system/Helpers/test_helper.php @@ -9,8 +9,10 @@ * the LICENSE file that was distributed with this source code. */ +use CodeIgniter\Exceptions\TestException; use CodeIgniter\Model; use CodeIgniter\Test\Fabricator; +use Config\Services; // CodeIgniter Test Helpers @@ -20,16 +22,14 @@ * * @param Model|object|string $model Instance or name of the model * @param array|null $overrides Overriding data to pass to Fabricator::setOverrides() - * @param mixed $persist + * @param bool $persist * * @return array|object */ function fake($model, ?array $overrides = null, $persist = true) { - // Get a model-appropriate Fabricator instance $fabricator = new Fabricator($model); - // Set overriding data, if necessary if ($overrides) { $fabricator->setOverrides($overrides); } @@ -41,3 +41,29 @@ function fake($model, ?array $overrides = null, $persist = true) return $fabricator->make(); } } + +if (! function_exists('mock')) { + /** + * Used within our test suite to mock certain system tools. + * All tools using this MUST use the MockableTrait + * + * @param string $className Fully qualified class name + */ + function mock(string $className) + { + $mockClass = $className::$mockClass; + $mockService = $className::$mockServiceName; + + if (empty($mockClass) || ! class_exists($mockClass)) { + throw TestException::forInvalidMockClass($mockClass); + } + + $mock = new $mockClass(); + + if (! empty($mockService)) { + Services::injectMock($mockService, $mock); + } + + return $mock; + } +} diff --git a/system/Language/en/Test.php b/system/Language/en/Test.php new file mode 100644 index 000000000000..a3f5d7ef6f02 --- /dev/null +++ b/system/Language/en/Test.php @@ -0,0 +1,15 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +// Testing language settings +return [ + 'invalidMockClass' => '{0} is not a valid Mock class', +]; diff --git a/system/Test/Mock/MockCache.php b/system/Test/Mock/MockCache.php index e6bc200fdd1f..a2b1c12cd68f 100644 --- a/system/Test/Mock/MockCache.php +++ b/system/Test/Mock/MockCache.php @@ -14,6 +14,7 @@ use Closure; use CodeIgniter\Cache\CacheInterface; use CodeIgniter\Cache\Handlers\BaseHandler; +use PHPUnit\Framework\Assert; class MockCache extends BaseHandler implements CacheInterface { @@ -31,6 +32,13 @@ class MockCache extends BaseHandler implements CacheInterface */ protected $expirations = []; + /** + * If true, will not cache any data. + * + * @var bool + */ + protected $bypass = false; + /** * Takes care of any handler-specific setup that must be done. */ @@ -49,16 +57,12 @@ public function get(string $key) { $key = static::validateKey($key, $this->prefix); - return $this->cache[$key] ?? null; + return array_key_exists($key, $this->cache) ? $this->cache[$key] : null; } /** * Get an item from the cache, or execute the given Closure and store the result. * - * @param string $key Cache item name - * @param int $ttl Time to live - * @param Closure $callback Callback return value - * * @return mixed */ public function remember(string $key, int $ttl, Closure $callback) @@ -89,6 +93,10 @@ public function remember(string $key, int $ttl, Closure $callback) */ public function save(string $key, $value, int $ttl = 60, bool $raw = false) { + if ($this->bypass) { + return false; + } + $key = static::validateKey($key, $this->prefix); $this->cache[$key] = $value; @@ -100,8 +108,6 @@ public function save(string $key, $value, int $ttl = 60, bool $raw = false) /** * Deletes a specific item from the cache store. * - * @param string $key Cache item name - * * @return bool */ public function delete(string $key) @@ -120,8 +126,6 @@ public function delete(string $key) /** * Deletes items from the cache store matching a given pattern. * - * @param string $pattern Cache items glob-style pattern - * * @return int */ public function deleteMatching(string $pattern) @@ -141,9 +145,6 @@ public function deleteMatching(string $pattern) /** * Performs atomic incrementation of a raw stored value. * - * @param string $key Cache ID - * @param int $offset Step/value to increase by - * * @return bool */ public function increment(string $key, int $offset = 1) @@ -163,9 +164,6 @@ public function increment(string $key, int $offset = 1) /** * Performs atomic decrementation of a raw stored value. * - * @param string $key Cache ID - * @param int $offset Step/value to increase by - * * @return bool */ public function decrement(string $key, int $offset = 1) @@ -212,10 +210,7 @@ public function getCacheInfo() /** * Returns detailed information about the specific item in the cache. * - * @param string $key Cache item name. - * - * @return array|null - * Returns null if the item does not exist, otherwise array + * @return array|null Returns null if the item does not exist, otherwise array * with at least the 'expire' key for absolute epoch expiry (or null). */ public function getMetaData(string $key) @@ -230,16 +225,73 @@ public function getMetaData(string $key) return null; } - return [ - 'expire' => $this->expirations[$key], - ]; + return ['expire' => $this->expirations[$key]]; } /** - * Determines if the driver is supported on this system. + * Determine if the driver is supported on this system. */ public function isSupported(): bool { return true; } + + //-------------------------------------------------------------------- + // Test Helpers + //-------------------------------------------------------------------- + + /** + * Instructs the class to ignore all + * requests to cache an item, and always "miss" + * when checked for existing data. + * + * @return $this + */ + public function bypass(bool $bypass = true) + { + $this->clean(); + $this->bypass = $bypass; + + return $this; + } + + //-------------------------------------------------------------------- + // Additional Assertions + //-------------------------------------------------------------------- + + /** + * Asserts that the cache has an item named $key. + * The value is not checked since storing false or null + * values is valid. + */ + public function assertHas(string $key) + { + Assert::assertNotNull($this->get($key), "The cache does not have an item named: `{$key}`"); + } + + /** + * Asserts that the cache has an item named $key with a value matching $value. + * + * @param mixed $value + */ + public function assertHasValue(string $key, $value = null) + { + $item = $this->get($key); + + // Let assertHas handle throwing the error for consistency + // if the key is not found + if (empty($item)) { + $this->assertHas($key); + } + + Assert::assertEquals($value, $this->get($key), "The cached item `{$key}` does not equal match expectation. Found: " . print_r($value, true)); + } + + /** + * Asserts that the cache does NOT have an item named $key. + */ + public function assertMissing(string $key) + { + Assert::assertFalse(array_key_exists($key, $this->cache), "The cached item named `{$key}` exists."); + } } diff --git a/tests/system/Cache/CacheMockTest.php b/tests/system/Cache/CacheMockTest.php new file mode 100644 index 000000000000..860623478693 --- /dev/null +++ b/tests/system/Cache/CacheMockTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Cache; + +use CodeIgniter\Cache\Handlers\BaseHandler; +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\Mock\MockCache; + +/** + * @internal + */ +final class CacheMockTest extends CIUnitTestCase +{ + public function testMockReturnsMockCacheClass() + { + $this->assertInstanceOf(BaseHandler::class, service('cache')); + + $mock = mock(CacheFactory::class); + $this->assertInstanceOf(MockCache::class, $mock); + $this->assertInstanceOf(MockCache::class, service('cache')); + } + + public function testMockCaching() + { + $mock = mock(CacheFactory::class); + + // Ensure it stores the value normally + $mock->save('foo', 'bar'); + $mock->assertHas('foo'); + $mock->assertHasValue('foo', 'bar'); + + // Try it again with bypass on + $mock->bypass(); + $mock->save('foo', 'bar'); + $mock->assertMissing('foo'); + } +} diff --git a/user_guide_src/source/testing/index.rst b/user_guide_src/source/testing/index.rst index 878cc9918355..949a68b99b51 100644 --- a/user_guide_src/source/testing/index.rst +++ b/user_guide_src/source/testing/index.rst @@ -2,7 +2,7 @@ Testing ####### -CodeIgniter ships with a number of tools to help you test and debug your application thoroughly. +CodeIgniter ships with a number of tools to help you test and debug your application thoroughly. The following sections should get you quickly testing your applications. .. toctree:: @@ -16,3 +16,4 @@ The following sections should get you quickly testing your applications. response benchmark debugging + Mocking diff --git a/user_guide_src/source/testing/mocking.rst b/user_guide_src/source/testing/mocking.rst new file mode 100644 index 000000000000..ea0a30922dd4 --- /dev/null +++ b/user_guide_src/source/testing/mocking.rst @@ -0,0 +1,53 @@ +###################### +Mocking System Classes +###################### + +Several classes within the framework provide mocked versions of the classes that can be used during testing. These classes +can take the place of the normal class during test execution, often providing additional assertions to test that actions +have taken place (or not taken place) during the execution of the test. This might be checking data gets cached correctly, +emails were sent correctly, etc. + +.. contents:: + :local: + :depth: 1 + +Cache +===== + +You can mock the cache with the ``mock()`` method, using the ``CacheFactory`` as its only parameter. +:: + + $mock = mock(CodeIgniter\Cache\CacheFactory::class); + +While this returns an instance of ``CodeIgniter\Test\Mock\MockCache`` that you can use directly, it also inserts the +mock into the Service class, so any calls within your code to ``service('cache')`` or ``Config\Services::cache()`` will +use the mocked class within its place. + +When using this in more than one test method within a single file you should call either the ``clean()`` or ``bypass()`` +methods during the test ``setUp()`` to ensure a clean slate when your tests run. + +Additional Methods +------------------ + +You can instruct the mocked cache handler to never do any caching with the ``bypass()`` method. This will emulate +using the dummy handler and ensures that your test does not rely on cached data for your tests. +:: + + $mock = mock(CodeIgniter\Cache\CacheFactory::class); + // Never cache any items during this test. + $mock->bypass(); + +Available Assertions +-------------------- + +The following new assertions are available on the mocked class for using during testing: +:: + + $mock = mock(CodeIgniter\Cache\CacheFactory::class); + + // Assert that a cached item named $key exists + $mock->assertHas($key); + // Assert that a cached item named $key exists with a value of $value + $mock->assertHasValue($key, $value); + // Assert that a cached item named $key does NOT exist + $mock->assertMissing($key); From 8710e3ed949661e96fe089a94c1776317ab6bb21 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Wed, 16 Jun 2021 22:30:50 -0500 Subject: [PATCH 0159/2325] Updated assert to assertArrayNotHasKey per suggestion. --- system/Test/Mock/MockCache.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Test/Mock/MockCache.php b/system/Test/Mock/MockCache.php index a2b1c12cd68f..ebdacccbbef5 100644 --- a/system/Test/Mock/MockCache.php +++ b/system/Test/Mock/MockCache.php @@ -284,7 +284,7 @@ public function assertHasValue(string $key, $value = null) $this->assertHas($key); } - Assert::assertEquals($value, $this->get($key), "The cached item `{$key}` does not equal match expectation. Found: " . print_r($value, true)); + Assert::assertSame($value, $this->get($key), "The cached item `{$key}` does not equal match expectation. Found: " . print_r($value, true)); } /** @@ -292,6 +292,6 @@ public function assertHasValue(string $key, $value = null) */ public function assertMissing(string $key) { - Assert::assertFalse(array_key_exists($key, $this->cache), "The cached item named `{$key}` exists."); + Assert::assertArrayNotHasKey($key, $this->cache, "The cached item named `{$key}` exists."); } } From d2e9a64b00d0bdb83fd8cac259a3f374d606b896 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 14 Jun 2021 08:13:52 -0500 Subject: [PATCH 0160/2325] Update system/Helpers/test_helper.php Co-authored-by: MGatner --- system/Helpers/test_helper.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system/Helpers/test_helper.php b/system/Helpers/test_helper.php index a73446a0ac5f..fe6b06794ccd 100644 --- a/system/Helpers/test_helper.php +++ b/system/Helpers/test_helper.php @@ -45,14 +45,13 @@ function fake($model, ?array $overrides = null, $persist = true) if (! function_exists('mock')) { /** * Used within our test suite to mock certain system tools. - * All tools using this MUST use the MockableTrait * * @param string $className Fully qualified class name */ function mock(string $className) { $mockClass = $className::$mockClass; - $mockService = $className::$mockServiceName; + $mockService = $className::$mockServiceName ?? ''; if (empty($mockClass) || ! class_exists($mockClass)) { throw TestException::forInvalidMockClass($mockClass); From 0a2b74b2ecaa3802f3009a0df826499eaefce76a Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Mon, 14 Jun 2021 08:17:05 -0500 Subject: [PATCH 0161/2325] Update user_guide_src/source/testing/mocking.rst Co-authored-by: MGatner --- user_guide_src/source/testing/mocking.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/testing/mocking.rst b/user_guide_src/source/testing/mocking.rst index ea0a30922dd4..03b464cf6570 100644 --- a/user_guide_src/source/testing/mocking.rst +++ b/user_guide_src/source/testing/mocking.rst @@ -2,7 +2,7 @@ Mocking System Classes ###################### -Several classes within the framework provide mocked versions of the classes that can be used during testing. These classes +Several components within the framework provide mocked versions of their classes that can be used during testing. These classes can take the place of the normal class during test execution, often providing additional assertions to test that actions have taken place (or not taken place) during the execution of the test. This might be checking data gets cached correctly, emails were sent correctly, etc. From 944152fe130554a1529d8070bb2ec285975519aa Mon Sep 17 00:00:00 2001 From: MGatner Date: Sun, 23 May 2021 19:09:49 +0000 Subject: [PATCH 0162/2325] Add Publisher --- system/Language/en/Publisher.php | 17 + .../Exceptions/PublisherException.php | 32 + system/Publisher/Publisher.php | 713 ++++++++++++++++++ tests/_support/Publishers/TestPublisher.php | 16 + 4 files changed, 778 insertions(+) create mode 100644 system/Language/en/Publisher.php create mode 100644 system/Publisher/Exceptions/PublisherException.php create mode 100644 system/Publisher/Publisher.php create mode 100644 tests/_support/Publishers/TestPublisher.php diff --git a/system/Language/en/Publisher.php b/system/Language/en/Publisher.php new file mode 100644 index 000000000000..ada599074efe --- /dev/null +++ b/system/Language/en/Publisher.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +// Publisher language settings +return [ + 'expectedFile' => 'Publisher::{0} expects a valid file.', + 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', + 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', +]; diff --git a/system/Publisher/Exceptions/PublisherException.php b/system/Publisher/Exceptions/PublisherException.php new file mode 100644 index 000000000000..23a4b54d3e57 --- /dev/null +++ b/system/Publisher/Exceptions/PublisherException.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CodeIgniter\Publisher\Exceptions; + +use CodeIgniter\Exceptions\FrameworkException; + +class PublisherException extends FrameworkException +{ + public static function forExpectedDirectory(string $caller) + { + return new static(lang('Publisher.expectedDirectory', [$caller])); + } + + public static function forExpectedFile(string $caller) + { + return new static(lang('Publisher.expectedFile', [$caller])); + } + + public static function forCollision(string $from, string $to) + { + return new static(lang('Publisher.collision', [filetype($to), $from, $to])); + } +} diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php new file mode 100644 index 000000000000..8f599d3292b6 --- /dev/null +++ b/system/Publisher/Publisher.php @@ -0,0 +1,713 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CodeIgniter\Publisher; + +use CodeIgniter\Autoloader\FileLocator; +use CodeIgniter\Files\File; +use CodeIgniter\HTTP\URI; +use CodeIgniter\Publisher\Exceptions\PublisherException; +use Throwable; + +/** + * Publisher Class + * + * Publishers read in file paths from a variety + * of sources and copy the files out to different + * destinations. + * This class acts both as a base for individual + * publication directives as well as the mode of + * discovery for said instances. + * In this class a "file" is a full path to a + * verified file while a "path" is relative to + * to its source or destination and may indicate + * either a file or directory fo unconfirmed + * existence. + * Class failures throw a PublisherException, + * but some underlying methods may percolate + * different exceptions, like FileException, + * FileNotFoundException, InvalidArgumentException. + * Write operations will catch all errors in the + * file-specific $errors property to minimize + * impact of partial batch operations. + */ +class Publisher +{ + /** + * Array of discovered Publishers. + * + * @var array + */ + private static $discovered = []; + + /** + * Directory to use for methods + * that need temporary storage. + * Created on-the-fly as needed. + * + * @var string|null + */ + private $scratch; + + /** + * The current list of files. + * + * @var string[] + */ + private $files = []; + + /** + * Exceptions for specific files + * from the last write operation. + * + * @var array + */ + private $errors = []; + + /** + * Base path to use for the source. + * + * @var string + */ + protected $source = ROOTPATH; + + /** + * Base path to use for the destination. + * + * @var string + */ + protected $destination = FCPATH; + + /** + * Discovers and returns all Publishers + * in the specified namespace directory. + * + * @return self[] + */ + public static function discover($directory = 'Publishers'): array + { + if (isset(self::$discovered[$directory])) + { + return self::$discovered[$directory]; + } + self::$discovered[$directory] = []; + + /** @var FileLocator $locator */ + $locator = service('locator'); + + if ([] === $files = $locator->listFiles($directory)) + { + return []; + } + + // Loop over each file checking to see if it is a Primer + foreach ($files as $file) + { + $className = $locator->findQualifiedNameFromPath($file); + + if (is_string($className) && class_exists($className) && is_a($className, self::class, true)) + { + self::$discovered[$directory][] = new $className(); + } + } + sort(self::$discovered[$directory]); + + return self::$discovered[$directory]; + } + + //-------------------------------------------------------------------- + + /** + * Resolves a full path and verifies + * it is an actual directory. + * + * @param string $directory + * + * @return string + */ + private static function resolveDirectory(string $directory): string + { + if (! is_dir($directory = set_realpath($directory))) + { + $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; + throw PublisherException::forExpectedDirectory($caller['function']); + } + + return $directory; + } + + /** + * Resolves a full path and verifies + * it is an actual file. + * + * @param string $file + * + * @return string + */ + private static function resolveFile(string $file): string + { + if (! is_file($file = set_realpath($file))) + { + $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; + throw PublisherException::forExpectedFile($caller['function']); + } + + return $file; + } + + //-------------------------------------------------------------------- + + /** + * Filters an array of files, removing files not + * part of the given directory (recursive). + * + * @param string[] $files + * @param string $directory + * + * @return string[] + */ + private static function filterFiles(array $files, string $directory): array + { + $directory = self::resolveDirectory($directory); + + return array_filter($files, function ($value) use ($directory) { + return strpos($value, $directory) === 0; + }); + } + + /** + * Returns any files whose basename matches + * the given pattern. + * + * @param string[] $files + * @param string $pattern Regex or pseudo-regex string + * + * @return string[] + */ + private static function matchFiles(array $files, string $pattern) + { + // Convert pseudo-regex into their true form + if (@preg_match($pattern, null) === false) // @phpstan-ignore-line + { + $pattern = str_replace( + ['#', '.', '*', '?'], + ['\#', '\.', '.*', '.'], + $pattern + ); + $pattern = "#{$pattern}#"; + } + + return array_filter($files, function ($value) use ($pattern) { + return (bool) preg_match($pattern, basename($value)); + }); + } + + //-------------------------------------------------------------------- + + /** + * Removes a directory and all its files + * and subdirectories. + * + * @param string $directory + * + * @return void + */ + private static function wipeDirectory(string $directory) + { + if (is_dir($directory)) + { + // Try a few times in case of lingering locks + $attempts = 10; + while ((bool) $attempts && ! delete_files($directory, true, false, true)) + { + $attempts--; + usleep(100000); // .1s + } + + @rmdir($directory); + } + } + + /** + * Copies a file with directory creation + * and identical file awareness. + * Intentionally allows errors. + * + * @param string $from + * @param string $to + * @param bool $replace + * + * @return void + * + * @throws PublisherException For unresolvable collisions + */ + private static function safeCopyFile(string $from, string $to, bool $replace): void + { + // Check for an existing file + if (file_exists($to)) + { + // If not replacing or if files are identical then consider successful + if (! $replace || same_file($from, $to)) + { + return; + } + + // If it is a directory then do not try to remove it + if (is_dir($to)) + { + throw PublisherException::forCollision($from, $to); + } + + // Try to remove anything else + unlink($to); + } + + // Allow copy() to throw errors + copy($from, $to); + } + + //-------------------------------------------------------------------- + + /** + * Loads the helper and verifies the + * source and destination directories. + * + * @param string|null $source + * @param string|null $destination + */ + public function __construct(string $source = null, string $destination = null) + { + helper(['filesystem']); + + $this->source = self::resolveDirectory($source ?? $this->source); + $this->destination = self::resolveDirectory($destination ?? $this->destination); + } + + /** + * Cleans up any temporary files + * in the scratch space. + */ + public function __destruct() + { + if (isset($this->scratch)) + { + self::wipeDirectory($this->scratch); + + $this->scratch = null; + } + } + + /** + * Reads in file sources and copies out + * the files to their destinations. + * This method should be reimplemented by + * child classes intended for discovery. + * + * @return void + */ + public function publish() + { + } + + //-------------------------------------------------------------------- + + /** + * Returns the temporary workspace, + * creating it if necessary. + * + * @return string + */ + protected function getScratch(): string + { + if (is_null($this->scratch)) + { + $this->scratch = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . DIRECTORY_SEPARATOR; + mkdir($this->scratch, 0700); + } + + return $this->scratch; + } + + /** + * Returns any errors from the last + * write operation. + * + * @return array + */ + public function getErrors(): array + { + return $this->errors; + } + + /** + * Optimizes and returns the + * current file list. + * + * @return string[] + */ + public function getFiles(): array + { + $this->files = array_unique($this->files, SORT_STRING); + sort($this->files, SORT_STRING); + + return $this->files; + } + + /** + * Sets the file list directly. + * Files are still subject to verification. + * This works as a "reset" method with []. + * + * @param string[] $files A new file list to use + * + * @return $this + */ + public function setFiles(array $files) + { + $this->files = []; + + return $this->addFiles($files); + } + + //-------------------------------------------------------------------- + + /** + * Verifies and adds files to the list. + * + * @param string[] $files + * + * @return $this + */ + public function addFiles(array $files) + { + foreach ($files as $file) + { + $this->addFile($file); + } + + return $this; + } + + /** + * Verifies and adds a single file + * to the file list. + * + * @param string $file + * + * @return $this + */ + public function addFile(string $file) + { + $this->files[] = self::resolveFile($file); + + return $this; + } + + /** + * Removes files from the list. + * + * @param string[] $files + * + * @return $this + */ + public function removeFiles(array $files) + { + $this->files = array_diff($this->files, $files); + + return $this; + } + + /** + * Removes a single file from the list. + * + * @param string $file + * + * @return $this + */ + public function removeFile(string $file) + { + return $this->removeFiles([$file]); + } + + //-------------------------------------------------------------------- + + /** + * Verifies and adds files from each + * directory to the list. + * + * @param string[] $directories + * @param bool $recursive + * + * @return $this + */ + public function addDirectories(array $directories, bool $recursive = false) + { + foreach ($directories as $directory) + { + $this->addDirectory($directory, $recursive); + } + + return $this; + } + + /** + * Verifies and adds all files + * from a directory. + * + * @param string $directory + * @param bool $recursive + * + * @return $this + */ + public function addDirectory(string $directory, bool $recursive = false) + { + $directory = self::resolveDirectory($directory); + + // Map the directory to depth 2 to so directories become arrays + foreach (directory_map($directory, 2, true) as $key => $path) + { + if (is_string($path)) + { + $this->addFile($directory . $path); + } + elseif ($recursive && is_array($path)) + { + $this->addDirectory($directory . $key, true); + } + } + + return $this; + } + + //-------------------------------------------------------------------- + + /** + * Verifies and adds paths to the list. + * + * @param string[] $paths + * @param bool $recursive + * + * @return $this + */ + public function addPaths(array $paths, bool $recursive = true) + { + foreach ($paths as $path) + { + $this->addPath($path, $recursive); + } + + return $this; + } + + /** + * Adds a single path to the file list. + * + * @param string $path + * @param bool $recursive + * + * @return $this + */ + public function addPath(string $path, bool $recursive = true) + { + $full = $this->source . $path; + + // Test for a directory + try + { + $directory = self::resolveDirectory($full); + } + catch (PublisherException $e) + { + return $this->addFile($full); + } + + return $this->addDirectory($full, $recursive); + } + + //-------------------------------------------------------------------- + + /** + * Downloads and stages files from + * an array of URIs. + * + * @param string[] $uris + * + * @return $this + */ + public function addUris(array $uris) + { + foreach ($uris as $uri) + { + $this->addUri($uri); + } + + return $this; + } + + /** + * Downloads a file from the URI + * and adds it to the file list. + * + * @param string $uri Because HTTP\URI is stringable it will still be accepted + * + * @return $this + */ + public function addUri(string $uri) + { + // Figure out a good filename (using URI strips queries and fragments) + $file = $this->getScratch() . basename((new URI($uri))->getPath()); + + // Get the content and write it to the scratch space + $response = service('curlrequest')->get($uri); + write_file($file, $response->getBody()); + + return $this->addFile($file); + } + + //-------------------------------------------------------------------- + + /** + * Removes any files from the list that match + * the supplied pattern (within the optional scope). + * + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope A directory to limit the scope + * + * @return $this + */ + public function removePattern(string $pattern, string $scope = null) + { + if ($pattern === '') + { + return $this; + } + + // Start with all files or those in scope + $files = is_null($scope) + ? $this->files + : self::filterFiles($this->files, $scope); + + // Remove any files that match the pattern + return $this->removeFiles(self::matchFiles($files, $pattern)); + } + + /** + * Keeps only the files from the list that match + * the supplied pattern (within the optional scope). + * + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope A directory to limit the scope + * + * @return $this + */ + public function retainPattern(string $pattern, string $scope = null) + { + if ($pattern === '') + { + return $this; + } + + // Start with all files or those in scope + $files = is_null($scope) + ? $this->files + : self::filterFiles($this->files, $scope); + + // Match the pattern within the scoped files + $matched = self::matchFiles($files, $pattern); + + // ... and remove their inverse + return $this->removeFiles(array_diff($files, $matched)); + } + + //-------------------------------------------------------------------- + + /** + * Removes the destination and all its files and folders. + * + * @return $this + */ + public function wipe() + { + self::wipeDirectory($this->destination); + + return $this; + } + + //-------------------------------------------------------------------- + + /** + * Copies all files into the destination. + * Does not create directory structure. + * + * @param bool $replace Whether to overwrite existing files. + * + * @return boolean Whether all files were copied successfully + */ + public function copy(bool $replace = true): bool + { + $this->errors = []; + + foreach ($this->getFiles() as $file) + { + $to = $this->destination . basename($file); + + try + { + self::safeCopyFile($file, $to, $replace); + } + catch (Throwable $e) + { + $this->errors[$file] = $e; + } + } + + return $this->errors === []; + } + + /** + * Merges all files into the destination. + * Creates a mirrored directory structure + * only for files from source. + * + * @param bool $replace Whether to overwrite existing files. + * + * @return boolean Whether all files were copied successfully + */ + public function merge(bool $replace = true): bool + { + $this->errors = []; + + // Get the file from source for special handling + $sourced = self::matchFiles($this->getFiles(), $this->source); + + // Handle everything else with a flat copy + $this->files = array_diff($this->files, $sourced); + $this->copy($replace); + + // Copy each sourced file to its relative destination + foreach ($sourced as $file) + { + // Resolve the destination path + $to = $this->destination . substr($file, strlen($this->source)); + + try + { + self::safeCopyFile($file, $to, $replace); + } + catch (Throwable $e) + { + $this->errors[$file] = $e; + } + } + + return $this->errors === []; + } +} diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php new file mode 100644 index 000000000000..8ef30ca90024 --- /dev/null +++ b/tests/_support/Publishers/TestPublisher.php @@ -0,0 +1,16 @@ +downloadFromUrls($urls)->mergeToDirectory(FCPATH . 'assets'); + } +} From b2a16e9d402ab80aaa73150ffff2ee47d5a3e8da Mon Sep 17 00:00:00 2001 From: MGatner Date: Mon, 24 May 2021 01:10:02 +0000 Subject: [PATCH 0163/2325] Add tests --- system/Publisher/Publisher.php | 18 +- tests/system/Publisher/PublisherInputTest.php | 472 ++++++++++++++++++ .../system/Publisher/PublisherOutputTest.php | 202 ++++++++ .../system/Publisher/PublisherSupportTest.php | 199 ++++++++ 4 files changed, 887 insertions(+), 4 deletions(-) create mode 100644 tests/system/Publisher/PublisherInputTest.php create mode 100644 tests/system/Publisher/PublisherOutputTest.php create mode 100644 tests/system/Publisher/PublisherSupportTest.php diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 8f599d3292b6..d7f797e00312 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -108,8 +108,8 @@ public static function discover($directory = 'Publishers'): array return []; } - // Loop over each file checking to see if it is a Primer - foreach ($files as $file) + // Loop over each file checking to see if it is a Publisher + foreach (array_unique($files) as $file) { $className = $locator->findQualifiedNameFromPath($file); @@ -228,8 +228,10 @@ private static function wipeDirectory(string $directory) $attempts = 10; while ((bool) $attempts && ! delete_files($directory, true, false, true)) { + // @codeCoverageIgnoreStart $attempts--; usleep(100000); // .1s + // @codeCoverageIgnoreEnd } @rmdir($directory); @@ -270,6 +272,13 @@ private static function safeCopyFile(string $from, string $to, bool $replace): v unlink($to); } + // Make sure the directory exists + $directory = pathinfo($to, PATHINFO_DIRNAME); + if (! is_dir($directory)) + { + mkdir($directory, 0775, true); + } + // Allow copy() to throw errors copy($from, $to); } @@ -311,10 +320,11 @@ public function __destruct() * This method should be reimplemented by * child classes intended for discovery. * - * @return void + * @return bool */ public function publish() { + return $this->addPath('/')->merge(true); } //-------------------------------------------------------------------- @@ -686,7 +696,7 @@ public function merge(bool $replace = true): bool $this->errors = []; // Get the file from source for special handling - $sourced = self::matchFiles($this->getFiles(), $this->source); + $sourced = self::filterFiles($this->getFiles(), $this->source); // Handle everything else with a flat copy $this->files = array_diff($this->files, $sourced); diff --git a/tests/system/Publisher/PublisherInputTest.php b/tests/system/Publisher/PublisherInputTest.php new file mode 100644 index 000000000000..553a92b14c53 --- /dev/null +++ b/tests/system/Publisher/PublisherInputTest.php @@ -0,0 +1,472 @@ +assertSame([], $this->getPrivateProperty($publisher, 'files')); + + $publisher->addFile($this->file); + $this->assertSame([$this->file], $this->getPrivateProperty($publisher, 'files')); + } + + public function testAddFileMissing() + { + $publisher = new Publisher(); + + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.expectedFile', ['addFile'])); + + $publisher->addFile('TheHillsAreAlive.bmp'); + } + + public function testAddFileDirectory() + { + $publisher = new Publisher(); + + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.expectedFile', ['addFile'])); + + $publisher->addFile($this->directory); + } + + public function testAddFiles() + { + $publisher = new Publisher(); + $files = [ + $this->file, + $this->file, + ]; + + $publisher->addFiles($files); + $this->assertSame($files, $this->getPrivateProperty($publisher, 'files')); + } + + //-------------------------------------------------------------------- + + public function testGetFiles() + { + $publisher = new Publisher(); + $publisher->addFile($this->file); + + $this->assertSame([$this->file], $publisher->getFiles()); + } + + public function testGetFilesSorts() + { + $publisher = new Publisher(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $publisher->addFiles($files); + + $this->assertSame(array_reverse($files), $publisher->getFiles()); + } + + public function testGetFilesUniques() + { + $publisher = new Publisher(); + $files = [ + $this->file, + $this->file, + ]; + + $publisher->addFiles($files); + $this->assertSame([$this->file], $publisher->getFiles()); + } + + public function testSetFiles() + { + $publisher = new Publisher(); + + $publisher->setFiles([$this->file]); + $this->assertSame([$this->file], $publisher->getFiles()); + } + + public function testSetFilesInvalid() + { + $publisher = new Publisher(); + + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.expectedFile', ['addFile'])); + + $publisher->setFiles(['flerb']); + } + + //-------------------------------------------------------------------- + + public function testRemoveFile() + { + $publisher = new Publisher(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $publisher->addFiles($files); + + $publisher->removeFile($this->file); + + $this->assertSame([$this->directory . 'apple.php'], $publisher->getFiles()); + } + + public function testRemoveFiles() + { + $publisher = new Publisher(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $publisher->addFiles($files); + + $publisher->removeFiles($files); + + $this->assertSame([], $publisher->getFiles()); + } + + //-------------------------------------------------------------------- + + public function testAddDirectoryInvalid() + { + $publisher = new Publisher(); + + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.expectedDirectory', ['addDirectory'])); + + $publisher->addDirectory($this->file); + } + + public function testAddDirectory() + { + $publisher = new Publisher(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $publisher->addDirectory($this->directory); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testAddDirectoryRecursive() + { + $publisher = new Publisher(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testAddDirectories() + { + $publisher = new Publisher(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->addDirectories([ + $this->directory, + SUPPORTPATH . 'Files/baker', + ]); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testAddDirectoriesRecursive() + { + $publisher = new Publisher(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; + + $publisher->addDirectories([ + SUPPORTPATH . 'Files', + SUPPORTPATH . 'Log', + ], true); + + $this->assertSame($expected, $publisher->getFiles()); + } + + //-------------------------------------------------------------------- + + public function testAddPathFile() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $publisher->addPath('baker/banana.php'); + + $this->assertSame([$this->file], $publisher->getFiles()); + } + + public function testAddPathFileRecursiveDoesNothing() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $publisher->addPath('baker/banana.php', true); + + $this->assertSame([$this->file], $publisher->getFiles()); + } + + public function testAddPathDirectory() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $publisher->addPath('able'); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testAddPathDirectoryRecursive() + { + $publisher = new Publisher(SUPPORTPATH); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->addPath('Files'); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testAddPaths() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->addPaths([ + 'able', + 'baker/banana.php', + ]); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testAddPathsRecursive() + { + $publisher = new Publisher(SUPPORTPATH); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; + + $publisher->addPaths([ + 'Files', + 'Log', + ], true); + + $this->assertSame($expected, $publisher->getFiles()); + } + + //-------------------------------------------------------------------- + + public function testAddUri() + { + $publisher = new Publisher(); + $publisher->addUri('https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/composer.json'); + + $scratch = $this->getPrivateProperty($publisher, 'scratch'); + + $this->assertSame([$scratch . 'composer.json'], $publisher->getFiles()); + } + + public function testAddUris() + { + $publisher = new Publisher(); + $publisher->addUris([ + 'https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/LICENSE', + 'https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/composer.json', + ]); + + $scratch = $this->getPrivateProperty($publisher, 'scratch'); + + $this->assertSame([$scratch . 'LICENSE', $scratch . 'composer.json'], $publisher->getFiles()); + } + + //-------------------------------------------------------------------- + + public function testRemovePatternEmpty() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $files = $publisher->getFiles(); + + $publisher->removePattern(''); + + $this->assertSame($files, $publisher->getFiles()); + } + + public function testRemovePatternRegex() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'apple.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->removePattern('#[a-z]+_.*#'); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testRemovePatternPseudo() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'apple.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->removePattern('*_*.php'); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testRemovePatternScope() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->removePattern('*.php', $this->directory); + + $this->assertSame($expected, $publisher->getFiles()); + } + + //-------------------------------------------------------------------- + + public function testRetainPatternEmpty() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $files = $publisher->getFiles(); + + $publisher->retainPattern(''); + + $this->assertSame($files, $publisher->getFiles()); + } + + public function testRetainPatternRegex() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $publisher->retainPattern('#[a-z]+_.*#'); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testRetainPatternPseudo() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'fig_3.php', + ]; + + $publisher->retainPattern('*_?.php'); + + $this->assertSame($expected, $publisher->getFiles()); + } + + public function testRetainPatternScope() + { + $publisher = new Publisher(); + $publisher->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'fig_3.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->retainPattern('*_?.php', $this->directory); + + $this->assertSame($expected, $publisher->getFiles()); + } +} diff --git a/tests/system/Publisher/PublisherOutputTest.php b/tests/system/Publisher/PublisherOutputTest.php new file mode 100644 index 000000000000..5183d188d6b9 --- /dev/null +++ b/tests/system/Publisher/PublisherOutputTest.php @@ -0,0 +1,202 @@ +structure = [ + 'able' => [ + 'apple.php' => 'Once upon a midnight dreary', + 'bazam' => 'While I pondered weak and weary', + ], + 'boo' => [ + 'far' => 'Upon a tome of long-forgotten lore', + 'faz' => 'There came a tapping up on the door', + ], + 'AnEmptyFolder' => [], + 'simpleFile' => 'A tap-tap-tapping upon my door', + '.hidden' => 'There is no spoon', + ]; + + $this->root = vfsStream::setup('root', null, $this->structure); + } + + //-------------------------------------------------------------------- + + public function testCopy() + { + $publisher = new Publisher($this->directory, $this->root->url()); + $publisher->addFile($this->file); + + $this->assertFileDoesNotExist($this->root->url() . '/banana.php'); + + $result = $publisher->copy(false); + + $this->assertTrue($result); + $this->assertFileExists($this->root->url() . '/banana.php'); + } + + public function testCopyReplace() + { + $file = $this->directory . 'apple.php'; + $publisher = new Publisher($this->directory, $this->root->url() . '/able'); + $publisher->addFile($file); + + $this->assertFileExists($this->root->url() . '/able/apple.php'); + $this->assertFalse(same_file($file, $this->root->url() . '/able/apple.php')); + + $result = $publisher->copy(true); + + $this->assertTrue($result); + $this->assertTrue(same_file($file, $this->root->url() . '/able/apple.php')); + } + + public function testCopyIgnoresSame() + { + $publisher = new Publisher($this->directory, $this->root->url()); + $publisher->addFile($this->file); + + copy($this->file, $this->root->url() . '/banana.php'); + + $result = $publisher->copy(false); + $this->assertTrue($result); + + $result = $publisher->copy(true); + $this->assertTrue($result); + } + + public function testCopyIgnoresCollision() + { + $publisher = new Publisher($this->directory, $this->root->url()); + + mkdir($this->root->url() . '/banana.php'); + + $result = $publisher->addFile($this->file)->copy(false); + $errors = $publisher->getErrors(); + + $this->assertTrue($result); + $this->assertSame([], $errors); + } + + public function testCopyCollides() + { + $publisher = new Publisher($this->directory, $this->root->url()); + $expected = lang('Publisher.collision', ['dir', $this->file, $this->root->url() . '/banana.php']); + + mkdir($this->root->url() . '/banana.php'); + + $result = $publisher->addFile($this->file)->copy(true); + $errors = $publisher->getErrors(); + + $this->assertFalse($result); + $this->assertCount(1, $errors); + $this->assertSame([$this->file], array_keys($errors)); + $this->assertSame($expected, $errors[$this->file]->getMessage()); + } + + //-------------------------------------------------------------------- + + public function testMerge() + { + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + + $this->assertFileDoesNotExist($this->root->url() . '/able/fig_3.php'); + $this->assertDirectoryDoesNotExist($this->root->url() . '/baker'); + + $result = $publisher->addPath('/')->merge(false); + + $this->assertTrue($result); + $this->assertFileExists($this->root->url() . '/able/fig_3.php'); + $this->assertDirectoryExists($this->root->url() . '/baker'); + } + + public function testMergeReplace() + { + $this->assertFalse(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + + $result = $publisher->addPath('/')->merge(true); + + $this->assertTrue($result); + $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + } + + public function testMergeCollides() + { + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + $expected = lang('Publisher.collision', ['dir', $this->directory . 'fig_3.php', $this->root->url() . '/able/fig_3.php']); + + mkdir($this->root->url() . '/able/fig_3.php'); + + $result = $publisher->addPath('/')->merge(true); + $errors = $publisher->getErrors(); + + $this->assertFalse($result); + $this->assertCount(1, $errors); + $this->assertSame([$this->directory . 'fig_3.php'], array_keys($errors)); + $this->assertSame($expected, $errors[$this->directory . 'fig_3.php']->getMessage()); + } + + //-------------------------------------------------------------------- + + public function testPublish() + { + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + + $result = $publisher->publish(); + + $this->assertTrue($result); + $this->assertFileExists($this->root->url() . '/able/fig_3.php'); + $this->assertDirectoryExists($this->root->url() . '/baker'); + $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + } +} diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php new file mode 100644 index 000000000000..5592c02fc4ca --- /dev/null +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -0,0 +1,199 @@ +assertCount(1, $result); + $this->assertInstanceOf(TestPublisher::class, $result[0]); + } + + public function testDiscoverNothing() + { + $result = Publisher::discover('Nothing'); + + $this->assertSame([], $result); + } + + public function testDiscoverStores() + { + $publisher = Publisher::discover()[0]; + $publisher->addFile($this->file); + + $result = Publisher::discover(); + $this->assertSame($publisher, $result[0]); + $this->assertSame([$this->file], $result[0]->getFiles()); + } + + //-------------------------------------------------------------------- + + public function testResolveDirectoryDirectory() + { + $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveDirectory'); + + $this->assertSame($this->directory, $method($this->directory)); + } + + public function testResolveDirectoryFile() + { + $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveDirectory'); + + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.expectedDirectory', ['invokeArgs'])); + + $method($this->file); + } + + public function testResolveDirectorySymlink() + { + // Create a symlink to test + $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); + symlink($this->directory, $link); + + $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveDirectory'); + + $this->assertSame($this->directory, $method($link)); + + unlink($link); + } + + //-------------------------------------------------------------------- + + public function testResolveFileFile() + { + $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveFile'); + + $this->assertSame($this->file, $method($this->file)); + } + + public function testResolveFileSymlink() + { + // Create a symlink to test + $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); + symlink($this->file, $link); + + $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveFile'); + + $this->assertSame($this->file, $method($link)); + + unlink($link); + } + + public function testResolveFileDirectory() + { + $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveFile'); + + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.expectedFile', ['invokeArgs'])); + + $method($this->directory); + } + + //-------------------------------------------------------------------- + + public function testGetScratch() + { + $publisher = new Publisher(); + $this->assertNull($this->getPrivateProperty($publisher, 'scratch')); + + $method = $this->getPrivateMethodInvoker($publisher, 'getScratch'); + $scratch = $method(); + + $this->assertIsString($scratch); + $this->assertDirectoryExists($scratch); + $this->assertDirectoryIsWritable($scratch); + $this->assertNotNull($this->getPrivateProperty($publisher, 'scratch')); + + // Directory and contents should be removed on __destruct() + $file = $scratch . 'obvious_statement.txt'; + file_put_contents($file, 'Bananas are a most peculiar fruit'); + + $publisher->__destruct(); + + $this->assertFileDoesNotExist($file); + $this->assertDirectoryDoesNotExist($scratch); + } + + public function testGetErrors() + { + $publisher = new Publisher(); + $this->assertSame([], $publisher->getErrors()); + + $expected = [ + $this->file => PublisherException::forCollision($this->file, $this->file), + ]; + + $this->setPrivateProperty($publisher, 'errors', $expected); + + $this->assertSame($expected, $publisher->getErrors()); + } + + //-------------------------------------------------------------------- + + public function testWipeDirectory() + { + $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); + mkdir($directory, 0700); + $this->assertDirectoryExists($directory); + + $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); + $method($directory); + + $this->assertDirectoryDoesNotExist($directory); + } + + public function testWipeIgnoresFiles() + { + $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); + $method($this->file); + + $this->assertFileExists($this->file); + } + + public function testWipe() + { + $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); + mkdir($directory, 0700); + $this->assertDirectoryExists($directory); + + $publisher = new Publisher($this->directory, $directory); + $publisher->wipe(); + + $this->assertDirectoryDoesNotExist($directory); + } +} From 291594c041d334722702b224e98405974c66baf2 Mon Sep 17 00:00:00 2001 From: MGatner Date: Mon, 24 May 2021 15:51:16 -0400 Subject: [PATCH 0164/2325] Apply suggestions from code review Co-authored-by: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> --- system/Language/en/Publisher.php | 4 +- .../Exceptions/PublisherException.php | 10 +- system/Publisher/Publisher.php | 125 ++++++++---------- 3 files changed, 60 insertions(+), 79 deletions(-) diff --git a/system/Language/en/Publisher.php b/system/Language/en/Publisher.php index ada599074efe..cb5ce81f10a4 100644 --- a/system/Language/en/Publisher.php +++ b/system/Language/en/Publisher.php @@ -11,7 +11,7 @@ // Publisher language settings return [ - 'expectedFile' => 'Publisher::{0} expects a valid file.', - 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', + 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', + 'expectedFile' => 'Publisher::{0} expects a valid file.', ]; diff --git a/system/Publisher/Exceptions/PublisherException.php b/system/Publisher/Exceptions/PublisherException.php index 23a4b54d3e57..81f9bb4b7174 100644 --- a/system/Publisher/Exceptions/PublisherException.php +++ b/system/Publisher/Exceptions/PublisherException.php @@ -15,6 +15,11 @@ class PublisherException extends FrameworkException { + public static function forCollision(string $from, string $to) + { + return new static(lang('Publisher.collision', [filetype($to), $from, $to])); + } + public static function forExpectedDirectory(string $caller) { return new static(lang('Publisher.expectedDirectory', [$caller])); @@ -24,9 +29,4 @@ public static function forExpectedFile(string $caller) { return new static(lang('Publisher.expectedFile', [$caller])); } - - public static function forCollision(string $from, string $to) - { - return new static(lang('Publisher.collision', [filetype($to), $from, $to])); - } } diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index d7f797e00312..b2e9de8d577b 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -20,24 +20,18 @@ /** * Publisher Class * - * Publishers read in file paths from a variety - * of sources and copy the files out to different - * destinations. - * This class acts both as a base for individual - * publication directives as well as the mode of - * discovery for said instances. - * In this class a "file" is a full path to a - * verified file while a "path" is relative to - * to its source or destination and may indicate - * either a file or directory fo unconfirmed - * existence. - * Class failures throw a PublisherException, - * but some underlying methods may percolate - * different exceptions, like FileException, - * FileNotFoundException, InvalidArgumentException. - * Write operations will catch all errors in the - * file-specific $errors property to minimize - * impact of partial batch operations. + * Publishers read in file paths from a variety of sources and copy + * the files out to different destinations. This class acts both as + * a base for individual publication directives as well as the mode + * of discovery for said instances. In this class a "file" is a full + * path to a verified file while a "path" is relative to its source + * or destination and may indicate either a file or directory of + * unconfirmed existence. + * class failures throw the PublisherException, but some underlying + * methods may percolate different exceptions, like FileException, + * FileNotFoundException or InvalidArgumentException. + * Write operations will catch all errors in the file-specific + * $errors property to minimize impact of partial batch operations. */ class Publisher { @@ -90,14 +84,17 @@ class Publisher * Discovers and returns all Publishers * in the specified namespace directory. * + * @param string $directory + * * @return self[] */ - public static function discover($directory = 'Publishers'): array + public static function discover(string $directory = 'Publishers'): array { if (isset(self::$discovered[$directory])) { return self::$discovered[$directory]; } + self::$discovered[$directory] = []; /** @var FileLocator $locator */ @@ -145,8 +142,7 @@ private static function resolveDirectory(string $directory): string } /** - * Resolves a full path and verifies - * it is an actual file. + * Resolves a full path and verifies it is an actual file. * * @param string $file * @@ -184,11 +180,10 @@ private static function filterFiles(array $files, string $directory): array } /** - * Returns any files whose basename matches - * the given pattern. + * Returns any files whose `basename` matches the given pattern. * - * @param string[] $files - * @param string $pattern Regex or pseudo-regex string + * @param array $files + * @param string $pattern Regex or pseudo-regex string * * @return string[] */ @@ -239,13 +234,12 @@ private static function wipeDirectory(string $directory) } /** - * Copies a file with directory creation - * and identical file awareness. + * Copies a file with directory creation and identical file awareness. * Intentionally allows errors. * - * @param string $from - * @param string $to - * @param bool $replace + * @param string $from + * @param string $to + * @param boolean $replace * * @return void * @@ -301,8 +295,7 @@ public function __construct(string $source = null, string $destination = null) } /** - * Cleans up any temporary files - * in the scratch space. + * Cleans up any temporary files in the scratch space. */ public function __destruct() { @@ -315,14 +308,13 @@ public function __destruct() } /** - * Reads in file sources and copies out - * the files to their destinations. - * This method should be reimplemented by - * child classes intended for discovery. + * Reads files in the sources and copies them out to their destinations. + * This method should be reimplemented by child classes intended for + * discovery. * - * @return bool + * @return boolean */ - public function publish() + public function publish(): bool { return $this->addPath('/')->merge(true); } @@ -347,8 +339,7 @@ protected function getScratch(): string } /** - * Returns any errors from the last - * write operation. + * Returns errors from the last write operation if any. * * @return array */ @@ -358,8 +349,7 @@ public function getErrors(): array } /** - * Optimizes and returns the - * current file list. + * Optimizes and returns the current file list. * * @return string[] */ @@ -372,11 +362,10 @@ public function getFiles(): array } /** - * Sets the file list directly. - * Files are still subject to verification. + * Sets the file list directly, files are still subject to verification. * This works as a "reset" method with []. * - * @param string[] $files A new file list to use + * @param string[] $files The new file list to use * * @return $this */ @@ -407,8 +396,7 @@ public function addFiles(array $files) } /** - * Verifies and adds a single file - * to the file list. + * Verifies and adds a single file to the file list. * * @param string $file * @@ -469,11 +457,10 @@ public function addDirectories(array $directories, bool $recursive = false) } /** - * Verifies and adds all files - * from a directory. + * Verifies and adds all files from a directory. * - * @param string $directory - * @param bool $recursive + * @param string $directory + * @param boolean $recursive * * @return $this */ @@ -520,8 +507,8 @@ public function addPaths(array $paths, bool $recursive = true) /** * Adds a single path to the file list. * - * @param string $path - * @param bool $recursive + * @param string $path + * @param boolean $recursive * * @return $this */ @@ -563,8 +550,7 @@ public function addUris(array $uris) } /** - * Downloads a file from the URI - * and adds it to the file list. + * Downloads a file from the URI, and adds it to the file list. * * @param string $uri Because HTTP\URI is stringable it will still be accepted * @@ -576,8 +562,7 @@ public function addUri(string $uri) $file = $this->getScratch() . basename((new URI($uri))->getPath()); // Get the content and write it to the scratch space - $response = service('curlrequest')->get($uri); - write_file($file, $response->getBody()); + write_file($file, service('curlrequest')->get($uri)->getBody()); return $this->addFile($file); } @@ -585,11 +570,11 @@ public function addUri(string $uri) //-------------------------------------------------------------------- /** - * Removes any files from the list that match - * the supplied pattern (within the optional scope). + * Removes any files from the list that match the supplied pattern + * (within the optional scope). * - * @param string $pattern Regex or pseudo-regex string - * @param string|null $scope A directory to limit the scope + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope The directory to limit the scope * * @return $this */ @@ -601,9 +586,7 @@ public function removePattern(string $pattern, string $scope = null) } // Start with all files or those in scope - $files = is_null($scope) - ? $this->files - : self::filterFiles($this->files, $scope); + $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); // Remove any files that match the pattern return $this->removeFiles(self::matchFiles($files, $pattern)); @@ -611,9 +594,9 @@ public function removePattern(string $pattern, string $scope = null) /** * Keeps only the files from the list that match - * the supplied pattern (within the optional scope). + * (within the optional scope). * - * @param string $pattern Regex or pseudo-regex string + * @param string $pattern Regex or pseudo-regex string * @param string|null $scope A directory to limit the scope * * @return $this @@ -654,10 +637,9 @@ public function wipe() //-------------------------------------------------------------------- /** - * Copies all files into the destination. - * Does not create directory structure. + * Copies all files into the destination, does not create directory structure. * - * @param bool $replace Whether to overwrite existing files. + * @param boolean $replace Whether to overwrite existing files. * * @return boolean Whether all files were copied successfully */ @@ -684,10 +666,9 @@ public function copy(bool $replace = true): bool /** * Merges all files into the destination. - * Creates a mirrored directory structure - * only for files from source. + * Creates a mirrored directory structure only for files from source. * - * @param bool $replace Whether to overwrite existing files. + * @param boolean $replace Whether to overwrite existing files. * * @return boolean Whether all files were copied successfully */ From c18a08fae8102dbbae8ebed7250218d31b86a074 Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 25 May 2021 16:13:09 +0000 Subject: [PATCH 0165/2325] Apply additional suggestions --- system/Publisher/Publisher.php | 48 ++++++++------------- tests/_support/Publishers/TestPublisher.php | 2 +- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index b2e9de8d577b..640dd779756e 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -43,8 +43,7 @@ class Publisher private static $discovered = []; /** - * Directory to use for methods - * that need temporary storage. + * Directory to use for methods that need temporary storage. * Created on-the-fly as needed. * * @var string|null @@ -59,8 +58,7 @@ class Publisher private $files = []; /** - * Exceptions for specific files - * from the last write operation. + * Exceptions for specific files from the last write operation. * * @var array */ @@ -81,8 +79,7 @@ class Publisher protected $destination = FCPATH; /** - * Discovers and returns all Publishers - * in the specified namespace directory. + * Discovers and returns all Publishers in the specified namespace directory. * * @param string $directory * @@ -115,6 +112,7 @@ public static function discover(string $directory = 'Publishers'): array self::$discovered[$directory][] = new $className(); } } + sort(self::$discovered[$directory]); return self::$discovered[$directory]; @@ -123,8 +121,7 @@ public static function discover(string $directory = 'Publishers'): array //-------------------------------------------------------------------- /** - * Resolves a full path and verifies - * it is an actual directory. + * Resolves a full path and verifies it is an actual directory. * * @param string $directory * @@ -162,11 +159,10 @@ private static function resolveFile(string $file): string //-------------------------------------------------------------------- /** - * Filters an array of files, removing files not - * part of the given directory (recursive). + * Removes files that are not part of the given directory (recursive). * * @param string[] $files - * @param string $directory + * @param string $directory * * @return string[] */ @@ -207,15 +203,14 @@ private static function matchFiles(array $files, string $pattern) //-------------------------------------------------------------------- - /** - * Removes a directory and all its files - * and subdirectories. + /* + * Removes a directory and all its files and subdirectories. * * @param string $directory * * @return void */ - private static function wipeDirectory(string $directory) + private static function wipeDirectory(string $directory): void { if (is_dir($directory)) { @@ -267,8 +262,7 @@ private static function safeCopyFile(string $from, string $to, bool $replace): v } // Make sure the directory exists - $directory = pathinfo($to, PATHINFO_DIRNAME); - if (! is_dir($directory)) + if (! is_dir($directory = pathinfo($to, PATHINFO_DIRNAME))) { mkdir($directory, 0775, true); } @@ -280,8 +274,7 @@ private static function safeCopyFile(string $from, string $to, bool $replace): v //-------------------------------------------------------------------- /** - * Loads the helper and verifies the - * source and destination directories. + * Loads the helper and verifies the source and destination directories. * * @param string|null $source * @param string|null $destination @@ -322,8 +315,7 @@ public function publish(): bool //-------------------------------------------------------------------- /** - * Returns the temporary workspace, - * creating it if necessary. + * Returns the temporary workspace, creating it if necessary. * * @return string */ @@ -532,8 +524,7 @@ public function addPath(string $path, bool $recursive = true) //-------------------------------------------------------------------- /** - * Downloads and stages files from - * an array of URIs. + * Downloads and stages files from an array of URIs. * * @param string[] $uris * @@ -609,15 +600,10 @@ public function retainPattern(string $pattern, string $scope = null) } // Start with all files or those in scope - $files = is_null($scope) - ? $this->files - : self::filterFiles($this->files, $scope); - - // Match the pattern within the scoped files - $matched = self::matchFiles($files, $pattern); + $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); - // ... and remove their inverse - return $this->removeFiles(array_diff($files, $matched)); + // Matches the pattern within the scoped files and remove their inverse. + return $this->removeFiles(array_diff($files, self::matchFiles($files, $pattern))); } //-------------------------------------------------------------------- diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php index 8ef30ca90024..fdb3547478d1 100644 --- a/tests/_support/Publishers/TestPublisher.php +++ b/tests/_support/Publishers/TestPublisher.php @@ -9,7 +9,7 @@ class TestPublisher extends Publisher /** * Runs the defined Operations. */ - public function publish() + public function publish(): bool { $this->downloadFromUrls($urls)->mergeToDirectory(FCPATH . 'assets'); } From ea6ca9fec0b2a74d789b2b6b3e2961c567f46544 Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 27 May 2021 20:15:37 +0000 Subject: [PATCH 0166/2325] Add Guide, tweak class --- system/Publisher/Publisher.php | 95 +++- tests/_support/Publishers/TestPublisher.php | 55 ++- .../system/Publisher/PublisherOutputTest.php | 26 +- .../system/Publisher/PublisherSupportTest.php | 17 +- user_guide_src/source/libraries/publisher.rst | 437 ++++++++++++++++++ 5 files changed, 598 insertions(+), 32 deletions(-) create mode 100644 user_guide_src/source/libraries/publisher.rst diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 640dd779756e..b9e5cca24e90 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -15,6 +15,7 @@ use CodeIgniter\Files\File; use CodeIgniter\HTTP\URI; use CodeIgniter\Publisher\Exceptions\PublisherException; +use RuntimeException; use Throwable; /** @@ -64,6 +65,13 @@ class Publisher */ private $errors = []; + /** + * List of file published curing the last write operation. + * + * @var string[] + */ + private $published = []; + /** * Base path to use for the source. * @@ -85,7 +93,7 @@ class Publisher * * @return self[] */ - public static function discover(string $directory = 'Publishers'): array + final public static function discover(string $directory = 'Publishers'): array { if (isset(self::$discovered[$directory])) { @@ -301,7 +309,7 @@ public function __destruct() } /** - * Reads files in the sources and copies them out to their destinations. + * Reads files from the sources and copies them out to their destinations. * This method should be reimplemented by child classes intended for * discovery. * @@ -309,17 +317,42 @@ public function __destruct() */ public function publish(): bool { + if ($this->source === ROOTPATH && $this->destination === FCPATH) + { + throw new RuntimeException('Child classes of Publisher should provide their own source and destination or publish method.'); + } + return $this->addPath('/')->merge(true); } //-------------------------------------------------------------------- + /** + * Returns the source directory. + * + * @return string + */ + final public function getSource(): string + { + return $this->source; + } + + /** + * Returns the destination directory. + * + * @return string + */ + final public function getDestination(): string + { + return $this->destination; + } + /** * Returns the temporary workspace, creating it if necessary. * * @return string */ - protected function getScratch(): string + final public function getScratch(): string { if (is_null($this->scratch)) { @@ -335,17 +368,27 @@ protected function getScratch(): string * * @return array */ - public function getErrors(): array + final public function getErrors(): array { return $this->errors; } + /** + * Returns the files published by the last write operation. + * + * @return string[] + */ + final public function getPublished(): array + { + return $this->published; + } + /** * Optimizes and returns the current file list. * * @return string[] */ - public function getFiles(): array + final public function getFiles(): array { $this->files = array_unique($this->files, SORT_STRING); sort($this->files, SORT_STRING); @@ -353,6 +396,8 @@ public function getFiles(): array return $this->files; } + //-------------------------------------------------------------------- + /** * Sets the file list directly, files are still subject to verification. * This works as a "reset" method with []. @@ -361,15 +406,13 @@ public function getFiles(): array * * @return $this */ - public function setFiles(array $files) + final public function setFiles(array $files) { $this->files = []; return $this->addFiles($files); } - //-------------------------------------------------------------------- - /** * Verifies and adds files to the list. * @@ -377,7 +420,7 @@ public function setFiles(array $files) * * @return $this */ - public function addFiles(array $files) + final public function addFiles(array $files) { foreach ($files as $file) { @@ -394,7 +437,7 @@ public function addFiles(array $files) * * @return $this */ - public function addFile(string $file) + final public function addFile(string $file) { $this->files[] = self::resolveFile($file); @@ -408,7 +451,7 @@ public function addFile(string $file) * * @return $this */ - public function removeFiles(array $files) + final public function removeFiles(array $files) { $this->files = array_diff($this->files, $files); @@ -422,7 +465,7 @@ public function removeFiles(array $files) * * @return $this */ - public function removeFile(string $file) + final public function removeFile(string $file) { return $this->removeFiles([$file]); } @@ -438,7 +481,7 @@ public function removeFile(string $file) * * @return $this */ - public function addDirectories(array $directories, bool $recursive = false) + final public function addDirectories(array $directories, bool $recursive = false) { foreach ($directories as $directory) { @@ -456,7 +499,7 @@ public function addDirectories(array $directories, bool $recursive = false) * * @return $this */ - public function addDirectory(string $directory, bool $recursive = false) + final public function addDirectory(string $directory, bool $recursive = false) { $directory = self::resolveDirectory($directory); @@ -486,7 +529,7 @@ public function addDirectory(string $directory, bool $recursive = false) * * @return $this */ - public function addPaths(array $paths, bool $recursive = true) + final public function addPaths(array $paths, bool $recursive = true) { foreach ($paths as $path) { @@ -504,7 +547,7 @@ public function addPaths(array $paths, bool $recursive = true) * * @return $this */ - public function addPath(string $path, bool $recursive = true) + final public function addPath(string $path, bool $recursive = true) { $full = $this->source . $path; @@ -530,7 +573,7 @@ public function addPath(string $path, bool $recursive = true) * * @return $this */ - public function addUris(array $uris) + final public function addUris(array $uris) { foreach ($uris as $uri) { @@ -547,7 +590,7 @@ public function addUris(array $uris) * * @return $this */ - public function addUri(string $uri) + final public function addUri(string $uri) { // Figure out a good filename (using URI strips queries and fragments) $file = $this->getScratch() . basename((new URI($uri))->getPath()); @@ -569,7 +612,7 @@ public function addUri(string $uri) * * @return $this */ - public function removePattern(string $pattern, string $scope = null) + final public function removePattern(string $pattern, string $scope = null) { if ($pattern === '') { @@ -592,7 +635,7 @@ public function removePattern(string $pattern, string $scope = null) * * @return $this */ - public function retainPattern(string $pattern, string $scope = null) + final public function retainPattern(string $pattern, string $scope = null) { if ($pattern === '') { @@ -613,7 +656,7 @@ public function retainPattern(string $pattern, string $scope = null) * * @return $this */ - public function wipe() + final public function wipe() { self::wipeDirectory($this->destination); @@ -629,9 +672,9 @@ public function wipe() * * @return boolean Whether all files were copied successfully */ - public function copy(bool $replace = true): bool + final public function copy(bool $replace = true): bool { - $this->errors = []; + $this->errors = $this->published = []; foreach ($this->getFiles() as $file) { @@ -640,6 +683,7 @@ public function copy(bool $replace = true): bool try { self::safeCopyFile($file, $to, $replace); + $this->published[] = $to; } catch (Throwable $e) { @@ -658,9 +702,9 @@ public function copy(bool $replace = true): bool * * @return boolean Whether all files were copied successfully */ - public function merge(bool $replace = true): bool + final public function merge(bool $replace = true): bool { - $this->errors = []; + $this->errors = $this->published = []; // Get the file from source for special handling $sourced = self::filterFiles($this->getFiles(), $this->source); @@ -678,6 +722,7 @@ public function merge(bool $replace = true): bool try { self::safeCopyFile($file, $to, $replace); + $this->published[] = $to; } catch (Throwable $e) { diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php index fdb3547478d1..9192c3899b83 100644 --- a/tests/_support/Publishers/TestPublisher.php +++ b/tests/_support/Publishers/TestPublisher.php @@ -4,13 +4,62 @@ use CodeIgniter\Publisher\Publisher; -class TestPublisher extends Publisher +final class TestPublisher extends Publisher { /** - * Runs the defined Operations. + * Fakes an error on the given file. + * + * @return $this + */ + public static function setError(string $file) + { + self::$error = $file; + } + + /** + * A file to cause an error + * + * @var string + */ + private static $error = ''; + + /** + * Base path to use for the source. + * + * @var string + */ + protected $source = SUPPORTPATH . 'Files'; + + /** + * Base path to use for the destination. + * + * @var string + */ + protected $destination = WRITEPATH; + + /** + * Fakes a publish event so no files are actually copied. */ public function publish(): bool { - $this->downloadFromUrls($urls)->mergeToDirectory(FCPATH . 'assets'); + $this->errors = $this->published = []; + + $this->addPath(''); + + // Copy each sourced file to its relative destination + foreach ($this->getFiles() as $file) + { + if ($file === self::$error) + { + $this->errors[$file] = new RuntimeException('Have an error, dear.'); + } + else + { + // Resolve the destination path + $this->published[] = $this->destination . substr($file, strlen($this->source)); + } + } + + return $this->errors === []; } } diff --git a/tests/system/Publisher/PublisherOutputTest.php b/tests/system/Publisher/PublisherOutputTest.php index 5183d188d6b9..0f416440b803 100644 --- a/tests/system/Publisher/PublisherOutputTest.php +++ b/tests/system/Publisher/PublisherOutputTest.php @@ -112,6 +112,7 @@ public function testCopyIgnoresSame() $result = $publisher->copy(true); $this->assertTrue($result); + $this->assertSame([$this->root->url() . '/banana.php'], $publisher->getPublished()); } public function testCopyIgnoresCollision() @@ -121,10 +122,10 @@ public function testCopyIgnoresCollision() mkdir($this->root->url() . '/banana.php'); $result = $publisher->addFile($this->file)->copy(false); - $errors = $publisher->getErrors(); $this->assertTrue($result); - $this->assertSame([], $errors); + $this->assertSame([], $publisher->getErrors()); + $this->assertSame([$this->root->url() . '/banana.php'], $publisher->getPublished()); } public function testCopyCollides() @@ -140,6 +141,7 @@ public function testCopyCollides() $this->assertFalse($result); $this->assertCount(1, $errors); $this->assertSame([$this->file], array_keys($errors)); + $this->assertSame([], $publisher->getPublished()); $this->assertSame($expected, $errors[$this->file]->getMessage()); } @@ -148,6 +150,12 @@ public function testCopyCollides() public function testMerge() { $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + $expected = [ + $this->root->url() . '/able/apple.php', + $this->root->url() . '/able/fig_3.php', + $this->root->url() . '/able/prune_ripe.php', + $this->root->url() . '/baker/banana.php', + ]; $this->assertFileDoesNotExist($this->root->url() . '/able/fig_3.php'); $this->assertDirectoryDoesNotExist($this->root->url() . '/baker'); @@ -157,23 +165,36 @@ public function testMerge() $this->assertTrue($result); $this->assertFileExists($this->root->url() . '/able/fig_3.php'); $this->assertDirectoryExists($this->root->url() . '/baker'); + $this->assertSame($expected, $publisher->getPublished()); } public function testMergeReplace() { $this->assertFalse(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + $expected = [ + $this->root->url() . '/able/apple.php', + $this->root->url() . '/able/fig_3.php', + $this->root->url() . '/able/prune_ripe.php', + $this->root->url() . '/baker/banana.php', + ]; $result = $publisher->addPath('/')->merge(true); $this->assertTrue($result); $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + $this->assertSame($expected, $publisher->getPublished()); } public function testMergeCollides() { $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); $expected = lang('Publisher.collision', ['dir', $this->directory . 'fig_3.php', $this->root->url() . '/able/fig_3.php']); + $published = [ + $this->root->url() . '/able/apple.php', + $this->root->url() . '/able/prune_ripe.php', + $this->root->url() . '/baker/banana.php', + ]; mkdir($this->root->url() . '/able/fig_3.php'); @@ -183,6 +204,7 @@ public function testMergeCollides() $this->assertFalse($result); $this->assertCount(1, $errors); $this->assertSame([$this->directory . 'fig_3.php'], array_keys($errors)); + $this->assertSame($published, $publisher->getPublished()); $this->assertSame($expected, $errors[$this->directory . 'fig_3.php']->getMessage()); } diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index 5592c02fc4ca..f17be3460432 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -126,13 +126,26 @@ public function testResolveFileDirectory() //-------------------------------------------------------------------- + public function testGetSource() + { + $publisher = new Publisher(ROOTPATH); + + $this->assertSame(ROOTPATH, $publisher->getSource()); + } + + public function testGetDestination() + { + $publisher = new Publisher(ROOTPATH, SUPPORTPATH); + + $this->assertSame(SUPPORTPATH, $publisher->getDestination()); + } + public function testGetScratch() { $publisher = new Publisher(); $this->assertNull($this->getPrivateProperty($publisher, 'scratch')); - $method = $this->getPrivateMethodInvoker($publisher, 'getScratch'); - $scratch = $method(); + $scratch = $publisher->getScratch(); $this->assertIsString($scratch); $this->assertDirectoryExists($scratch); diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst new file mode 100644 index 000000000000..ef97e0b52f95 --- /dev/null +++ b/user_guide_src/source/libraries/publisher.rst @@ -0,0 +1,437 @@ +######### +Publisher +######### + +The Publisher library provides a means to copy files within a project using robust detection and error checking. + +.. contents:: + :local: + :depth: 2 + +******************* +Loading the Library +******************* + +Because Publisher instances are specific to their source and destination this library is not available +through ``Services`` but should be instantiated or extended directly. E.g. + + $publisher = new \CodeIgniter\Publisher\Publisher(); + +***************** +Concept and Usage +***************** + +``Publisher`` solves a handful of common problems when working within a backend framework: + +* How do I maintain project assets with version dependencies? +* How do I manage uploads and other "dynamic" files that need to be web accessible? +* How can I update my project when the framework or modules change? +* How can components inject new content into existing projects? + +At its most basic, publishing amounts to copying a file or files into a project. ``Publisher`` uses fluent-style +command chaining to read, filter, and process input files, then copies or merges them into the target destination. +You may use ``Publisher`` on demand in your Controllers or other components, or you may stage publications by extending +the class and leveraging its discovery with ``spark publish``. + +On Demand +========= + +Access ``Publisher`` directly by instantiating a new instance of the class:: + + $publisher = new \CodeIgniter\Publisher\Publisher(); + +By default the source and destination will be set to ``ROOTPATH`` and ``FCPATH`` respectively, giving ``Publisher`` +easy access to take any file from your project and make it web-accessible. Alternatively you may pass a new source +or source and destination into the constructor:: + + $vendorPublisher = new Publisher(ROOTPATH . 'vendor'); + $filterPublisher = new Publisher('/path/to/module/Filters', APPPATH . 'Filters'); + +Once the source and destination are set you may start adding relative input files:: + + $frameworkPublisher = new Publisher(ROOTPATH . 'vendor/codeigniter4/codeigniter4'); + + // All "path" commands are relative to $source + $frameworkPublisher->addPath('app/Config/Cookie.php'); + + // You may also add from outside the source, but the files will not be merged into subdirectories + $frameworkPublisher->addFiles([ + '/opt/mail/susan', + '/opt/mail/ubuntu', + ]); + $frameworkPublisher->addDirectory(SUPPORTPATH . 'Images'); + +Once all the files are staged use one of the output commands (**copy()** or **merge()**) to process the staged files +to their destination(s):: + + // Place all files into $destination + $frameworkPublisher->copy(); + + // Place all files into $destination, overwriting existing files + $frameworkPublisher->copy(true); + + // Place files into their relative $destination directories, overwriting and saving the boolean result + $result = $frameworkPublisher->merge(true); + +See the Library Reference for a full description of available methods. + +Automation and Discovery +======================== + +You may have regular publication tasks embedded as part of your application deployment or upkeep. ``Publisher`` leverages +the powerful ``Autoloader`` to locate any child classes primed for publication:: + + use CodeIgniter\CLI\CLI; + use CodeIgniter\Publisher\Publisher; + + foreach (Publisher::discover() as $publisher) + { + $result = $publisher->publish(); + + if ($result === false) + { + CLI::write(get_class($publisher) . ' failed to publish!', 'red'); + } + } + +By default ``discover()`` will search for the "Publishers" directory across all namespaces, but you may specify a +different directory and it will return any child classes found:: + + $memePublishers = Publisher::discover('CatGIFs'); + +Most of the time you will not need to handle your own discovery, just use the provided "publish" command:: + + > php spark publish + +By default on your class extension ``publish()`` will add all files from your ``$source`` and merge them +out to your destination, overwriting on collision. + +******** +Examples +******** + +Here are a handful of example use cases and their implementations to help you get started publishing. + +File Sync Example +================= + +You want to display a "photo of the day" image on your homepage. You have a feed for daily photos but you +need to get the actual file into a browsable location in your project at **public/images/daily_photo.jpg**. +You can set up :doc:`Custom Command ` to run daily that will handle this for you:: + + namespace App\Commands; + + use CodeIgniter\CLI\BaseCommand; + use CodeIgniter\Publisher\Publisher; + use Throwable; + + class DailyPhoto extends BaseCommand + { + protected $group = 'Publication'; + protected $name = 'publish:daily'; + protected $description = 'Publishes the latest daily photo to the homepage.'; + + public function run(array $params) + { + $publisher = new Publisher('/path/to/photos/', FCPATH . 'assets/images'); + + try + { + $publisher->addPath('daily_photo.jpg')->copy($replace = true); + } + catch (Throwable $e) + { + $this->showError($e); + } + } + } + +Now running ``spark publish:daily`` will keep your homepage's image up-to-date. What if the photo is +coming from an external API? You can use ``addUri()`` in place of ``addPath()`` to download the remote +resource and publish it out instead:: + + $publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy($replace = true); + +Asset Dependencies Example +========================== + +You want to integrate the frontend library "Bootstrap" into your project, but the frequent updates makes it a hassle +to keep up with. You can create a publication definition in your project to sync frontend assets by adding extending +``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this:: + + namespace App\Publishers; + + use CodeIgniter\Publisher\Publisher; + + class BootstrapPublisher extends Publisher + { + /** + * Tell Publisher where to get the files. + * Since we will use Composer to download + * them we point to the "vendor" directory. + * + * @var string + */ + protected $source = 'vendor/twbs/bootstrap/'; + + /** + * FCPATH is always the default destination, + * but we may want them to go in a sub-folder + * to keep things organized. + * + * @var string + */ + protected $destination = FCPATH . 'bootstrap'; + + /** + * Use the "publish" method to indicate that this + * class is ready to be discovered and automated. + * + * @return boolean + */ + public function publish(): bool + { + return $this + // Add all the files relative to $source + ->addPath('dist') + + // Indicate we only want the minimized versions + ->retainPattern('*.min.*) + + // Merge-and-replace to retain the original directory structure + ->merge(true); + } + +Now add the dependency via Composer and call ``spark publish`` to run the publication:: + + > composer require twbs/bootstrap + > php spark publish + +... and you'll end up with something like this: + + public/.htaccess + public/favicon.ico + public/index.php + public/robots.txt + public/ + bootstrap/ + css/ + bootstrap.min.css + bootstrap-utilities.min.css.map + bootstrap-grid.min.css + bootstrap.rtl.min.css + bootstrap.min.css.map + bootstrap-reboot.min.css + bootstrap-utilities.min.css + bootstrap-reboot.rtl.min.css + bootstrap-grid.min.css.map + js/ + bootstrap.esm.min.js + bootstrap.bundle.min.js.map + bootstrap.bundle.min.js + bootstrap.min.js + bootstrap.esm.min.js.map + bootstrap.min.js.map + +Module Deployment Example +========================= + +You want to allow developers using your popular authentication module the ability to expand on the default behavior +of your Migration, Controller, and Model. You can create your own module "publish" command to inject these components +into an application for use:: + + namespace Math\Auth\Commands; + + use CodeIgniter\CLI\BaseCommand; + use CodeIgniter\Publisher\Publisher; + use Throwable; + + class Publish extends BaseCommand + { + protected $group = 'Auth'; + protected $name = 'auth:publish'; + protected $description = 'Publish Auth components into the current application.'; + + public function run(array $params) + { + // Use the Autoloader to figure out the module path + $source = service('autoloader')->getNamespace('Math\\Auth'); + + $publisher = new Publisher($source, APPATH); + + try + { + // Add only the desired components + $publisher->addPaths([ + 'Controllers', + 'Database/Migrations', + 'Models', + ])->merge(false); // Be careful not to overwrite anything + } + catch (Throwable $e) + { + $this->showError($e); + return; + } + + // If publication succeeded then update namespaces + foreach ($publisher->getFiles as $original) + { + // Get the location of the new file + $file = str_replace($source, APPPATH, $original); + + // Replace the namespace + $contents = file_get_contents($file); + $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, ); + file_put_contents($file, $contents); + } + } + } + +Now when your module users run ``php spark auth:publish`` they will have the following added to their project:: + + app/Controllers/AuthController.php + app/Database/Migrations/2017-11-20-223112_create_auth_tables.php.php + app/Models/LoginModel.php + app/Models/UserModel.php + +***************** +Library Reference +***************** + +Support Methods +=============== + +**[static] discover(string $directory = 'Publishers'): Publisher[]** + +Discovers and returns all Publishers in the specified namespace directory. For example, if both +**app/Publishers/FrameworkPublisher.php** and **myModule/src/Publishers/AssetPublisher.php** exist and are +extensions of ``Publisher`` then ``Publisher::discover()`` would return an instance of each. + +**publish(): bool** + +Processes the full input-process-output chain. By default this is the equivalent of calling ``addPath($source)`` +and ``merge(true)`` but child classes will typically provide their own implementation. ``publish()`` is called +on all discovered Publishers when running ``spark publish``. +Returns success or failure. + +**getScratch(): string** + +Returns the temporary workspace, creating it if necessary. Some operations use intermediate storage to stage +files and changes, and this provides the path to a transient, writable directory that you may use as well. + +**getErrors(): array** + +Returns any errors from the last write operation. The array keys are the files that caused the error, and the +values are the Throwable that was caught. Use ``getMessage()`` on the Throwable to get the error message. + +**getFiles(): string[]** + +Returns an array of all the loaded input files. + +Inputting Files +=============== + +**setFiles(array $files)** + +Sets the list of input files to the provided string array of file paths. + +**addFile(string $file)** +**addFiles(array $files)** + +Adds the file or files to the current list of input files. Files are absolute paths to actual files. + +**removeFile(string $file)** +**removeFiles(array $files)** + +Removes the file or files from the current list of input files. + +**addDirectory(string $directory, bool $recursive = false)** +**addDirectories(array $directories, bool $recursive = false)** + +Adds all files from the directory or directories, optionally recursing into sub-directories. Directories are +absolute paths to actual directories. + +**addPath(string $path, bool $recursive = true)** +**addPaths(array $path, bool $recursive = true)** + +Adds all files indicated by the relative paths. Paths are references to actual files or directories relative +to ``$source``. If the relative path resolves to a directory then ``$recursive`` will include sub-directories. + +**addUri(string $uri)** +**addUris(array $uris)** + +Downloads the contents of a URI using ``CURLRequest`` into the scratch workspace then adds the resulting +file to the list. + +.. note:: The CURL request made is a simple ``GET`` and uses the response body for the file contents. Some + remote files may need a custom request to be handled properly. + +Filtering Files +=============== + +**removePattern(string $pattern, string $scope = null)** +**retainPattern(string $pattern, string $scope = null)** + +Filters the current file list through the pattern (and optional scope), removing or retaining matched +files. ``$pattern`` may be a complete regex (like ``'#[A-Za-z]+\.php#'``) or a pseudo-regex similar +to ``glob()`` (like ``*.css``). +If a ``$scope`` is provided then only files in or under that directory will be considered (i.e. files +outside of ``$scope`` are always retained). When no scope is provided then all files are subject. + +Examples:: + + $publisher = new Publisher(APPPATH . 'Config'); + $publisher->addPath('/', true); // Adds all Config files and directories + + $publisher->removePattern('*tion.php'); // Would remove Encryption.php, Validation.php, and boot/production.php + $publisher->removePattern('*tion.php', APPPATH . 'Config/boot'); // Would only remove boot/production.php + + $publisher->retainPattern('#A.+php$#'); // Would keep only Autoload.php + $publisher->retainPattern('#d.+php$#', APPPATH . 'Config/boot'); // Would keep everything but boot/production.php and boot/testing.php + +Outputting Files +================ + +**wipe()** + +Removes all files, directories, and sub-directories from ``$destination``. + +.. important:: Use wisely. + +**copy(bool $replace = true): bool** + +Copies all files into the ``$destination``. This does not recreate the directory structure, so every file +from the current list will end up in the same destination directory. Using ``$replace`` will cause files +to overwrite when there is already an existing file. Returns success or failure, use ``getPublished()`` +and ``getErrors()`` to troubleshoot failures. +Be mindful of duplicate basename collisions, for example:: + + $publisher = new Publisher('/home/source', '/home/destination'); + $publisher->addPaths([ + 'pencil/lead.png', + 'metal/lead.png', + ]); + + // This is bad! Only one file will remain at /home/destination/lead.png + $publisher->copy(true); + +**merge(bool $replace = true): bool** + +Copies all files into the ``$destination`` in appropriate relative sub-directories. Any files that +match ``$source`` will be placed into their equivalent directories in ``$destination``, effectively +creating a "mirror" or "rsync" operation. Using ``$replace`` will cause files +to overwrite when there is already an existing file; since directories are merged this will not +affect other files in the destination. Returns success or failure, use ``getPublished()`` and +``getErrors()`` to troubleshoot failures. + +Example:: + + $publisher = new Publisher('/home/source', '/home/destination'); + $publisher->addPaths([ + 'pencil/lead.png', + 'metal/lead.png', + ]); + + // Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png" + $publisher->merge(); From 7d4cc0b4820b9f6d45a73de9e45d17d506c33004 Mon Sep 17 00:00:00 2001 From: MGatner Date: Sat, 29 May 2021 15:18:50 +0000 Subject: [PATCH 0167/2325] Add Publish command --- system/Commands/Utilities/Publish.php | 114 ++++++++++++++++++ system/Language/en/Publisher.php | 5 + system/Publisher/Publisher.php | 1 + tests/_support/Publishers/TestPublisher.php | 29 ++--- tests/system/Commands/PublishCommandTest.php | 52 ++++++++ user_guide_src/source/libraries/publisher.rst | 7 +- 6 files changed, 181 insertions(+), 27 deletions(-) create mode 100644 system/Commands/Utilities/Publish.php create mode 100644 tests/system/Commands/PublishCommandTest.php diff --git a/system/Commands/Utilities/Publish.php b/system/Commands/Utilities/Publish.php new file mode 100644 index 000000000000..b9665286f348 --- /dev/null +++ b/system/Commands/Utilities/Publish.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CodeIgniter\Commands\Utilities; + +use CodeIgniter\CLI\BaseCommand; +use CodeIgniter\CLI\CLI; +use CodeIgniter\Publisher\Publisher; + +/** + * Discovers all Publisher classes from the "Publishers/" directory + * across namespaces. Executes `publish()` from each instance, parsing + * each result. + */ +class Publish extends BaseCommand +{ + /** + * The group the command is lumped under + * when listing commands. + * + * @var string + */ + protected $group = 'CodeIgniter'; + + /** + * The Command's name + * + * @var string + */ + protected $name = 'publish'; + + /** + * The Command's short description + * + * @var string + */ + protected $description = 'Discovers and executes all predefined Publisher classes.'; + + /** + * The Command's usage + * + * @var string + */ + protected $usage = 'publish [directory]'; + + /** + * The Command's arguments + * + * @var array + */ + protected $arguments = [ + 'directory' => '[Optional] The directory to scan within each namespace. Default: "Publishers".', + ]; + + /** + * the Command's Options + * + * @var array + */ + protected $options = []; + + //-------------------------------------------------------------------- + + /** + * Displays the help for the spark cli script itself. + * + * @param array $params + */ + public function run(array $params) + { + $directory = array_shift($params) ?? 'Publishers'; + + if ([] === $publishers = Publisher::discover($directory)) + { + CLI::write(lang('Publisher.publishMissing', [$directory])); + return; + } + + foreach ($publishers as $publisher) + { + if ($publisher->publish()) + { + CLI::write(lang('Publisher.publishSuccess', [ + get_class($publisher), + count($publisher->getPublished()), + $publisher->getDestination(), + ]), 'green'); + } + else + { + CLI::error(lang('Publisher.publishFailure', [ + get_class($publisher), + $publisher->getDestination(), + ]), 'light_gray', 'red'); + + foreach ($publisher->getErrors() as $file => $exception) + { + CLI::write($file); + CLI::newLine(); + + $this->showError($exception); + } + } + } + } +} diff --git a/system/Language/en/Publisher.php b/system/Language/en/Publisher.php index cb5ce81f10a4..934342b4f98c 100644 --- a/system/Language/en/Publisher.php +++ b/system/Language/en/Publisher.php @@ -14,4 +14,9 @@ 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', 'expectedFile' => 'Publisher::{0} expects a valid file.', + + // Publish Command + 'publishMissing' => 'No Publisher classes detected in {0} across all namespaces.', + 'publishSuccess' => '{0} published {1} file(s) to {2}.', + 'publishFailure' => '{0} failed to publish to {1}!', ]; diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index b9e5cca24e90..7018df15c7d1 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -317,6 +317,7 @@ public function __destruct() */ public function publish(): bool { + // Safeguard against accidental misuse if ($this->source === ROOTPATH && $this->destination === FCPATH) { throw new RuntimeException('Child classes of Publisher should provide their own source and destination or publish method.'); diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php index 9192c3899b83..cf1eefa7ede6 100644 --- a/tests/_support/Publishers/TestPublisher.php +++ b/tests/_support/Publishers/TestPublisher.php @@ -3,6 +3,7 @@ namespace Tests\Support\Publishers; use CodeIgniter\Publisher\Publisher; +use RuntimeException; final class TestPublisher extends Publisher { @@ -11,17 +12,17 @@ final class TestPublisher extends Publisher * * @return $this */ - public static function setError(string $file) + public static function setResult(bool $result) { - self::$error = $file; + self::$result = $result; } /** - * A file to cause an error + * Return value for publish() * - * @var string + * @var boolean */ - private static $error = ''; + private static $result = true; /** * Base path to use for the source. @@ -42,24 +43,8 @@ public static function setError(string $file) */ public function publish(): bool { - $this->errors = $this->published = []; - $this->addPath(''); - // Copy each sourced file to its relative destination - foreach ($this->getFiles() as $file) - { - if ($file === self::$error) - { - $this->errors[$file] = new RuntimeException('Have an error, dear.'); - } - else - { - // Resolve the destination path - $this->published[] = $this->destination . substr($file, strlen($this->source)); - } - } - - return $this->errors === []; + return self::$result; } } diff --git a/tests/system/Commands/PublishCommandTest.php b/tests/system/Commands/PublishCommandTest.php new file mode 100644 index 000000000000..44f2de25f85a --- /dev/null +++ b/tests/system/Commands/PublishCommandTest.php @@ -0,0 +1,52 @@ +streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + parent::tearDown(); + + stream_filter_remove($this->streamFilter); + TestPublisher::setResult(true); + } + + public function testDefault() + { + command('publish'); + + $this->assertStringContainsString(lang('Publisher.publishSuccess', [ + TestPublisher::class, + 0, + WRITEPATH, + ]), CITestStreamFilter::$buffer); + } + + public function testFailure() + { + TestPublisher::setResult(false); + + command('publish'); + + $this->assertStringContainsString(lang('Publisher.publishFailure', [ + TestPublisher::class, + WRITEPATH, + ]), CITestStreamFilter::$buffer); + } +} diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index ef97e0b52f95..23f7c2d9e97e 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -246,7 +246,7 @@ into an application for use:: use CodeIgniter\Publisher\Publisher; use Throwable; - class Publish extends BaseCommand + class AuthPublish extends BaseCommand { protected $group = 'Auth'; protected $name = 'auth:publish'; @@ -275,11 +275,8 @@ into an application for use:: } // If publication succeeded then update namespaces - foreach ($publisher->getFiles as $original) + foreach ($publisher->getPublished() as $file) { - // Get the location of the new file - $file = str_replace($source, APPPATH, $original); - // Replace the namespace $contents = file_get_contents($file); $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, ); From 461942d3eb6fdd7f9e384f16bd4fc0852c176646 Mon Sep 17 00:00:00 2001 From: MGatner Date: Sat, 29 May 2021 15:43:14 +0000 Subject: [PATCH 0168/2325] Fix test bleeding --- tests/system/Publisher/PublisherSupportTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index f17be3460432..2aff0e34d1f6 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -53,7 +53,7 @@ public function testDiscoverNothing() public function testDiscoverStores() { $publisher = Publisher::discover()[0]; - $publisher->addFile($this->file); + $publisher->setFiles([])->addFile($this->file); $result = Publisher::discover(); $this->assertSame($publisher, $result[0]); From 746ed2c7ce7fc487d31f4959e5b90dfb1b1adbb0 Mon Sep 17 00:00:00 2001 From: MGatner Date: Sat, 29 May 2021 20:17:28 +0000 Subject: [PATCH 0169/2325] Fix UG format --- user_guide_src/source/libraries/publisher.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 23f7c2d9e97e..c30bce720815 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -119,6 +119,8 @@ You want to display a "photo of the day" image on your homepage. You have a feed need to get the actual file into a browsable location in your project at **public/images/daily_photo.jpg**. You can set up :doc:`Custom Command ` to run daily that will handle this for you:: + composer require twbs/bootstrap > php spark publish -... and you'll end up with something like this: +... and you'll end up with something like this:: public/.htaccess public/favicon.ico @@ -240,6 +244,8 @@ You want to allow developers using your popular authentication module the abilit of your Migration, Controller, and Model. You can create your own module "publish" command to inject these components into an application for use:: + Date: Tue, 1 Jun 2021 14:44:25 +0000 Subject: [PATCH 0170/2325] Implement review changes --- system/Commands/Utilities/Publish.php | 5 ++--- .../Exceptions/PublisherException.php | 21 +++++++++++++++++++ tests/_support/Publishers/TestPublisher.php | 2 -- user_guide_src/source/libraries/index.rst | 1 + user_guide_src/source/libraries/publisher.rst | 18 +++++++++------- 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/system/Commands/Utilities/Publish.php b/system/Commands/Utilities/Publish.php index b9665286f348..15448fc90db3 100644 --- a/system/Commands/Utilities/Publish.php +++ b/system/Commands/Utilities/Publish.php @@ -49,7 +49,7 @@ class Publish extends BaseCommand * * @var string */ - protected $usage = 'publish [directory]'; + protected $usage = 'publish []'; /** * The Command's arguments @@ -104,9 +104,8 @@ public function run(array $params) foreach ($publisher->getErrors() as $file => $exception) { CLI::write($file); + CLI::error($exception->getMessage()); CLI::newLine(); - - $this->showError($exception); } } } diff --git a/system/Publisher/Exceptions/PublisherException.php b/system/Publisher/Exceptions/PublisherException.php index 81f9bb4b7174..8144fcfeac02 100644 --- a/system/Publisher/Exceptions/PublisherException.php +++ b/system/Publisher/Exceptions/PublisherException.php @@ -13,18 +13,39 @@ use CodeIgniter\Exceptions\FrameworkException; +/** + * Publisher Exception Class + * + * Handles exceptions related to actions taken by a Publisher. + */ class PublisherException extends FrameworkException { + /** + * Throws when a file should be overwritten yet cannot. + * + * @param string $from The source file + * @param string $to The destination file + */ public static function forCollision(string $from, string $to) { return new static(lang('Publisher.collision', [filetype($to), $from, $to])); } + /** + * Throws when an object is expected to be a directory but is not or is missing. + * + * @param string $caller The method causing the exception + */ public static function forExpectedDirectory(string $caller) { return new static(lang('Publisher.expectedDirectory', [$caller])); } + /** + * Throws when an object is expected to be a file but is not or is missing. + * + * @param string $caller The method causing the exception + */ public static function forExpectedFile(string $caller) { return new static(lang('Publisher.expectedFile', [$caller])); diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php index cf1eefa7ede6..47c987a0285a 100644 --- a/tests/_support/Publishers/TestPublisher.php +++ b/tests/_support/Publishers/TestPublisher.php @@ -9,8 +9,6 @@ final class TestPublisher extends Publisher { /** * Fakes an error on the given file. - * - * @return $this */ public static function setResult(bool $result) { diff --git a/user_guide_src/source/libraries/index.rst b/user_guide_src/source/libraries/index.rst index 3af27e900ce5..9f977e91d604 100644 --- a/user_guide_src/source/libraries/index.rst +++ b/user_guide_src/source/libraries/index.rst @@ -14,6 +14,7 @@ Library Reference honeypot images pagination + publisher security sessions throttler diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index c30bce720815..57abcfcd6925 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -44,11 +44,12 @@ By default the source and destination will be set to ``ROOTPATH`` and ``FCPATH`` easy access to take any file from your project and make it web-accessible. Alternatively you may pass a new source or source and destination into the constructor:: + use CodeIgniter\Publisher\Publisher; + $vendorPublisher = new Publisher(ROOTPATH . 'vendor'); $filterPublisher = new Publisher('/path/to/module/Filters', APPPATH . 'Filters'); -Once the source and destination are set you may start adding relative input files:: - + // Once the source and destination are set you may start adding relative input files $frameworkPublisher = new Publisher(ROOTPATH . 'vendor/codeigniter4/codeigniter4'); // All "path" commands are relative to $source @@ -73,7 +74,7 @@ to their destination(s):: // Place files into their relative $destination directories, overwriting and saving the boolean result $result = $frameworkPublisher->merge(true); -See the Library Reference for a full description of available methods. +See the :ref:`reference` for a full description of available methods. Automation and Discovery ======================== @@ -90,7 +91,7 @@ the powerful ``Autoloader`` to locate any child classes primed for publication:: if ($result === false) { - CLI::write(get_class($publisher) . ' failed to publish!', 'red'); + CLI::error(get_class($publisher) . ' failed to publish!', 'red'); } } @@ -139,7 +140,7 @@ You can set up :doc:`Custom Command ` to run daily that will try { - $publisher->addPath('daily_photo.jpg')->copy($replace = true); + $publisher->addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites } catch (Throwable $e) { @@ -152,7 +153,7 @@ Now running ``spark publish:daily`` will keep your homepage's image up-to-date. coming from an external API? You can use ``addUri()`` in place of ``addPath()`` to download the remote resource and publish it out instead:: - $publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy($replace = true); + $publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy(true); Asset Dependencies Example ========================== @@ -161,8 +162,6 @@ You want to integrate the frontend library "Bootstrap" into your project, but th to keep up with. You can create a publication definition in your project to sync frontend assets by adding extending ``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this:: - merge(true); } + } Now add the dependency via Composer and call ``spark publish`` to run the publication:: @@ -298,6 +298,8 @@ Now when your module users run ``php spark auth:publish`` they will have the fol app/Models/LoginModel.php app/Models/UserModel.php +.. _reference: + ***************** Library Reference ***************** From 6484cb6304e141e0c8f420ec3866a9212f711aec Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 1 Jun 2021 17:23:22 +0000 Subject: [PATCH 0171/2325] Tweak formatting --- user_guide_src/source/libraries/publisher.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 57abcfcd6925..1cb27b54aa2b 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -162,6 +162,8 @@ You want to integrate the frontend library "Bootstrap" into your project, but th to keep up with. You can create a publication definition in your project to sync frontend assets by adding extending ``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this:: + addPath('dist') // Indicate we only want the minimized versions - ->retainPattern('*.min.*) + ->retainPattern('*.min.*') // Merge-and-replace to retain the original directory structure ->merge(true); From 55e79f6ef4a2181608fc57ce8b346645cf565b3e Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 8 Jun 2021 16:22:12 +0000 Subject: [PATCH 0172/2325] Add Publisher restrictions --- app/Config/Publisher.php | 28 ++++ system/Config/Publisher.php | 42 ++++++ system/Language/en/Publisher.php | 8 +- .../Exceptions/PublisherException.php | 22 +++ system/Publisher/Publisher.php | 131 +++++++++++------- tests/_support/Config/Registrar.php | 14 ++ tests/system/Publisher/PublisherInputTest.php | 2 +- .../system/Publisher/PublisherOutputTest.php | 5 +- .../Publisher/PublisherRestrictionsTest.php | 108 +++++++++++++++ .../system/Publisher/PublisherSupportTest.php | 3 +- user_guide_src/source/libraries/publisher.rst | 16 ++- 11 files changed, 325 insertions(+), 54 deletions(-) create mode 100644 app/Config/Publisher.php create mode 100644 system/Config/Publisher.php create mode 100644 tests/system/Publisher/PublisherRestrictionsTest.php diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php new file mode 100644 index 000000000000..2588eea2abac --- /dev/null +++ b/app/Config/Publisher.php @@ -0,0 +1,28 @@ + + */ + public $restrictions = [ + ROOTPATH => '*', + FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + ]; +} diff --git a/system/Config/Publisher.php b/system/Config/Publisher.php new file mode 100644 index 000000000000..651600ef9c06 --- /dev/null +++ b/system/Config/Publisher.php @@ -0,0 +1,42 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CodeIgniter\Config; + +/** + * Publisher Configuration + * + * Defines basic security restrictions for the Publisher class + * to prevent abuse by injecting malicious files into a project. + */ +class Publisher extends BaseConfig +{ + /** + * A list of allowed destinations with a (pseudo-)regex + * of allowed files for each destination. + * Attempts to publish to directories not in this list will + * result in a PublisherException. Files that do no fit the + * pattern will cause copy/merge to fail. + * + * @var array + */ + public $restrictions = [ + ROOTPATH => '*', + FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + ]; + + /** + * Disables Registrars to prevent modules from altering the restrictions. + */ + final protected function registerProperties() + { + } +} diff --git a/system/Language/en/Publisher.php b/system/Language/en/Publisher.php index 934342b4f98c..2d7ae8418b25 100644 --- a/system/Language/en/Publisher.php +++ b/system/Language/en/Publisher.php @@ -11,9 +11,11 @@ // Publisher language settings return [ - 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', - 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', - 'expectedFile' => 'Publisher::{0} expects a valid file.', + 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', + 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', + 'expectedFile' => 'Publisher::{0} expects a valid file.', + 'destinationNotAllowed' => 'Destination is not on the allowed list of Publisher directories: {0}', + 'fileNotAllowed' => '{0} fails the following restriction for {1}: {2}', // Publish Command 'publishMissing' => 'No Publisher classes detected in {0} across all namespaces.', diff --git a/system/Publisher/Exceptions/PublisherException.php b/system/Publisher/Exceptions/PublisherException.php index 8144fcfeac02..d54420881ec7 100644 --- a/system/Publisher/Exceptions/PublisherException.php +++ b/system/Publisher/Exceptions/PublisherException.php @@ -50,4 +50,26 @@ public static function forExpectedFile(string $caller) { return new static(lang('Publisher.expectedFile', [$caller])); } + + /** + * Throws when given a destination that is not in the list of allowed directories. + * + * @param string $destination + */ + public static function forDestinationNotAllowed(string $destination) + { + return new static(lang('Publisher.destinationNotAllowed', [$destination])); + } + + /** + * Throws when a file fails to match the allowed pattern for its destination. + * + * @param string $file + * @param string $directory + * @param string $pattern + */ + public static function forFileNotAllowed(string $file, string $directory, string $pattern) + { + return new static(lang('Publisher.fileNotAllowed', [$file, $directory, $pattern])); + } } diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 7018df15c7d1..1bfd4b91768d 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -72,6 +72,14 @@ class Publisher */ private $published = []; + /** + * List of allowed directories and their allowed files regex. + * Restrictions are intentionally private to prevent overriding. + * + * @var array + */ + private $restrictions; + /** * Base path to use for the source. * @@ -134,6 +142,8 @@ final public static function discover(string $directory = 'Publishers'): array * @param string $directory * * @return string + * + * @throws PublisherException */ private static function resolveDirectory(string $directory): string { @@ -152,6 +162,8 @@ private static function resolveDirectory(string $directory): string * @param string $file * * @return string + * + * @throws PublisherException */ private static function resolveFile(string $file): string { @@ -191,7 +203,7 @@ private static function filterFiles(array $files, string $directory): array * * @return string[] */ - private static function matchFiles(array $files, string $pattern) + private static function matchFiles(array $files, string $pattern): array { // Convert pseudo-regex into their true form if (@preg_match($pattern, null) === false) // @phpstan-ignore-line @@ -236,49 +248,6 @@ private static function wipeDirectory(string $directory): void } } - /** - * Copies a file with directory creation and identical file awareness. - * Intentionally allows errors. - * - * @param string $from - * @param string $to - * @param boolean $replace - * - * @return void - * - * @throws PublisherException For unresolvable collisions - */ - private static function safeCopyFile(string $from, string $to, bool $replace): void - { - // Check for an existing file - if (file_exists($to)) - { - // If not replacing or if files are identical then consider successful - if (! $replace || same_file($from, $to)) - { - return; - } - - // If it is a directory then do not try to remove it - if (is_dir($to)) - { - throw PublisherException::forCollision($from, $to); - } - - // Try to remove anything else - unlink($to); - } - - // Make sure the directory exists - if (! is_dir($directory = pathinfo($to, PATHINFO_DIRNAME))) - { - mkdir($directory, 0775, true); - } - - // Allow copy() to throw errors - copy($from, $to); - } - //-------------------------------------------------------------------- /** @@ -293,6 +262,20 @@ public function __construct(string $source = null, string $destination = null) $this->source = self::resolveDirectory($source ?? $this->source); $this->destination = self::resolveDirectory($destination ?? $this->destination); + + // Restrictions are intentionally not injected to prevent overriding + $this->restrictions = config('Publisher')->restrictions; + + // Make sure the destination is allowed + foreach (array_keys($this->restrictions) as $directory) + { + if (strpos($this->destination, $directory) === 0) + { + return; + } + } + + throw PublisherException::forDestinationNotAllowed($this->destination); } /** @@ -314,6 +297,8 @@ public function __destruct() * discovery. * * @return boolean + * + * @throws RuntimeException */ public function publish(): bool { @@ -683,7 +668,7 @@ final public function copy(bool $replace = true): bool try { - self::safeCopyFile($file, $to, $replace); + $this->safeCopyFile($file, $to, $replace); $this->published[] = $to; } catch (Throwable $e) @@ -707,7 +692,7 @@ final public function merge(bool $replace = true): bool { $this->errors = $this->published = []; - // Get the file from source for special handling + // Get the files from source for special handling $sourced = self::filterFiles($this->getFiles(), $this->source); // Handle everything else with a flat copy @@ -722,7 +707,7 @@ final public function merge(bool $replace = true): bool try { - self::safeCopyFile($file, $to, $replace); + $this->safeCopyFile($file, $to, $replace); $this->published[] = $to; } catch (Throwable $e) @@ -733,4 +718,56 @@ final public function merge(bool $replace = true): bool return $this->errors === []; } + + /** + * Copies a file with directory creation and identical file awareness. + * Intentionally allows errors. + * + * @param string $from + * @param string $to + * @param boolean $replace + * + * @return void + * + * @throws PublisherException For collisions and restriction violations + */ + private function safeCopyFile(string $from, string $to, bool $replace): void + { + // Verify this is an allowed file for its destination + foreach ($this->restrictions as $directory => $pattern) + { + if (strpos($to, $directory) === 0 && self::matchFiles([$to], $pattern) === []) + { + throw PublisherException::forFileNotAllowed($from, $directory, $pattern); + } + } + + // Check for an existing file + if (file_exists($to)) + { + // If not replacing or if files are identical then consider successful + if (! $replace || same_file($from, $to)) + { + return; + } + + // If it is a directory then do not try to remove it + if (is_dir($to)) + { + throw PublisherException::forCollision($from, $to); + } + + // Try to remove anything else + unlink($to); + } + + // Make sure the directory exists + if (! is_dir($directory = pathinfo($to, PATHINFO_DIRNAME))) + { + mkdir($directory, 0775, true); + } + + // Allow copy() to throw errors + copy($from, $to); + } } diff --git a/tests/_support/Config/Registrar.php b/tests/_support/Config/Registrar.php index 4a9f3b0fe981..15e8f54ff92d 100644 --- a/tests/_support/Config/Registrar.php +++ b/tests/_support/Config/Registrar.php @@ -121,4 +121,18 @@ public static function Database() return $config; } + + /** + * Demonstrates Publisher security. + * + * @see PublisherRestrictionsTest::testRegistrarsNotAllowed() + * + * @return array + */ + public static function Publisher() + { + return [ + 'restrictions' => [SUPPORTPATH => '*'], + ]; + } } diff --git a/tests/system/Publisher/PublisherInputTest.php b/tests/system/Publisher/PublisherInputTest.php index 553a92b14c53..e7450f5c02a9 100644 --- a/tests/system/Publisher/PublisherInputTest.php +++ b/tests/system/Publisher/PublisherInputTest.php @@ -1,4 +1,4 @@ -root = vfsStream::setup('root', null, $this->structure); + + // Add root to the list of allowed destinations + config('Publisher')->restrictions[$this->root->url()] = '*'; } //-------------------------------------------------------------------- diff --git a/tests/system/Publisher/PublisherRestrictionsTest.php b/tests/system/Publisher/PublisherRestrictionsTest.php new file mode 100644 index 000000000000..27db2e9429a9 --- /dev/null +++ b/tests/system/Publisher/PublisherRestrictionsTest.php @@ -0,0 +1,108 @@ +assertArrayNotHasKey(SUPPORTPATH, config('Publisher')->restrictions); + } + + public function testImmutableRestrictions() + { + $publisher = new Publisher(); + + // Try to "hack" the Publisher by adding our desired destination to the config + config('Publisher')->restrictions[SUPPORTPATH] = '*'; + + $restrictions = $this->getPrivateProperty($publisher, 'restrictions'); + + $this->assertArrayNotHasKey(SUPPORTPATH, $restrictions); + } + + /** + * @dataProvider fileProvider + */ + public function testDefaultPublicRestrictions(string $path) + { + $publisher = new Publisher(ROOTPATH, FCPATH); + $pattern = config('Publisher')->restrictions[FCPATH]; + + // Use the scratch space to create a file + $file = $publisher->getScratch() . $path; + file_put_contents($file, 'To infinity and beyond!'); + + $result = $publisher->addFile($file)->merge(); + $this->assertFalse($result); + + $errors = $publisher->getErrors(); + $this->assertCount(1, $errors); + $this->assertSame([$file], array_keys($errors)); + + $expected = lang('Publisher.fileNotAllowed', [$file, FCPATH, $pattern]); + $this->assertSame($expected, $errors[$file]->getMessage()); + } + + public function fileProvider() + { + yield 'php' => ['index.php']; + yield 'exe' => ['cat.exe']; + yield 'flat' => ['banana']; + } + + /** + * @dataProvider destinationProvider + */ + public function testDestinations(string $destination, bool $allowed) + { + config('Publisher')->restrictions = [ + APPPATH => '', + FCPATH => '', + SUPPORTPATH . 'Files' => '', + SUPPORTPATH . 'Files/../' => '', + ]; + + if (! $allowed) + { + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.destinationNotAllowed', [$destination])); + } + + $publisher = new Publisher(null, $destination); + $this->assertInstanceOf(Publisher::class, $publisher); + } + + public function destinationProvider() + { + return [ + 'explicit' => [ + APPPATH, + true, + ], + 'subdirectory' => [ + APPPATH . 'Config', + true, + ], + 'relative' => [ + SUPPORTPATH . 'Files/able/../', + true, + ], + 'parent' => [ + SUPPORTPATH, + false, + ], + ]; + } +} diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index 2aff0e34d1f6..42f22d721525 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -1,4 +1,4 @@ -assertDirectoryExists($directory); + config('Publisher')->restrictions[$directory] = ''; // Allow the directory $publisher = new Publisher($this->directory, $directory); $publisher->wipe(); diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 1cb27b54aa2b..84b430ba144b 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -107,6 +107,20 @@ Most of the time you will not need to handle your own discovery, just use the pr By default on your class extension ``publish()`` will add all files from your ``$source`` and merge them out to your destination, overwriting on collision. +Security +======== + +In order to prevent modules from injecting malicious code into your projects, ``Publisher`` contains a config file +that defines which directories and file patterns are allowed as destinations. By default, files may only be published +to your project (to prevent access to the rest of the filesystem), and the **public/** folder (``FCPATH``) will only +receive files with the following extensions: +* Web assets: css, scss, js, map +* Non-executable web files: htm, html, xml, json, webmanifest +* Fonts: tff, eot, woff +* Images: gif, jpg, jpeg, tiff, png, webp, bmp, ico, svg + +If you need to add or adjust the security for your project then alter the ``$restrictions`` property of ``Config\Publisher``. + ******** Examples ******** @@ -159,7 +173,7 @@ Asset Dependencies Example ========================== You want to integrate the frontend library "Bootstrap" into your project, but the frequent updates makes it a hassle -to keep up with. You can create a publication definition in your project to sync frontend assets by adding extending +to keep up with. You can create a publication definition in your project to sync frontend assets by extending ``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this:: Date: Sat, 12 Jun 2021 13:25:40 +0200 Subject: [PATCH 0173/2325] Graphic fix on some screen res Before: https://prnt.sc/1559re2 After: https://prnt.sc/1559uou --- app/Views/welcome_message.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php index 7050aa91174a..9ee2e427c308 100644 --- a/app/Views/welcome_message.php +++ b/app/Views/welcome_message.php @@ -163,7 +163,7 @@ color: rgba(200, 200, 200, 1); padding: .25rem 1.75rem; } - @media (max-width: 559px) { + @media (max-width: 629px) { header ul { padding: 0; } From 0b1470eaf86ba6c416ff766973bd62f7004fbdda Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Tue, 15 Jun 2021 11:30:43 +0700 Subject: [PATCH 0174/2325] rename `application` to `app` --- user_guide_src/source/libraries/sessions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index ac4a20719b8c..1472afa4000c 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -610,7 +610,7 @@ setting**. The examples below work both on MySQL and PostgreSQL:: ALTER TABLE ci_sessions DROP PRIMARY KEY; You can choose the Database group to use by adding a new line to the -**application\Config\App.php** file with the name of the group to use:: +**app/Config/App.php** file with the name of the group to use:: public $sessionDBGroup = 'groupName'; From 9dbb7d8471fb106d35a756dc328c49b4897173fd Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Tue, 22 Jun 2021 00:27:38 +0800 Subject: [PATCH 0175/2325] Make CLI detection as interface independent as possible --- system/Common.php | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/system/Common.php b/system/Common.php index 19be6398a8e1..4dfcd2cee170 100644 --- a/system/Common.php +++ b/system/Common.php @@ -644,22 +644,14 @@ function helper($filenames) /** * Check if PHP was invoked from the command line. * - * @codeCoverageIgnore Cannot be tested fully as PHPUnit always run in CLI + * @codeCoverageIgnore Cannot be tested fully as PHPUnit always run in php-cli */ function is_cli(): bool { - if (PHP_SAPI === 'cli') { - return true; - } - if (defined('STDIN')) { return true; } - if (stristr(PHP_SAPI, 'cgi') && getenv('TERM')) { - return true; - } - if (! isset($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['argv']) && count($_SERVER['argv']) > 0) { return true; } From 6a5b2f6c2a315e4e0ba2f4112cd7e0424ee73164 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Mon, 21 Jun 2021 09:31:14 -0700 Subject: [PATCH 0176/2325] Added MySQLi resultMode and updated user guide --- system/Database/MySQLi/Connection.php | 15 ++++++++++- user_guide_src/source/database/results.rst | 30 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 756057528450..78652c25b3f3 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -58,6 +58,19 @@ class Connection extends BaseConnection */ public $mysqli; + /** + * MySQLi constant + * + * For unbuffered queries use `MYSQLI_USE_RESULT`. + * + * Default mode for buffered queries uses `MYSQLI_STORE_RESULT`. + * + * @var int + */ + public $resultMode = MYSQLI_STORE_RESULT; + + //-------------------------------------------------------------------- + /** * Connect to the database. * @@ -277,7 +290,7 @@ protected function execute(string $sql) } try { - return $this->connID->query($this->prepQuery($sql)); + return $this->connID->query($this->prepQuery($sql), $this->resultMode); } catch (mysqli_sql_exception $e) { log_message('error', $e->getMessage()); diff --git a/user_guide_src/source/database/results.rst b/user_guide_src/source/database/results.rst index e3e573d5c460..018c5184cc1b 100644 --- a/user_guide_src/source/database/results.rst +++ b/user_guide_src/source/database/results.rst @@ -159,6 +159,36 @@ it returns the current row and moves the internal data pointer ahead. echo $row->body; } +For use with MySQLi you may set MySQLi's result mode to +``MYSQLI_USE_RESULT`` for maximum memory savings. Use of this is not +generally recommended but it can be beneficial in some circumstances +such as writing large queries to csv. If you change the result mode +be aware of the tradeoffs associated with it. + +:: + + $db->resultMode = MYSQLI_USE_RESULT; // for unbuffered results + + $query = $db->query("YOUR QUERY"); + + $file = new \CodeIgniter\Files\File(WRITEPATH.'data.csv'); + + $csv = $file->openFile('w'); + + while ($row = $query->getUnbufferedRow('array')) + { + $csv->fputcsv($row); + } + + $db->resultMode = MYSQLI_STORE_RESULT; // return to default mode + +.. note:: When using ``MYSQLI_USE_RESULT`` all subsequent calls on the same + connection will result in error until all records have been fetched or + a ``freeResult()`` call has been made. The ``getNumRows()`` method will only + return the number of rows based on the current position of the data pointer. + MyISAM tables will remain locked until all the records have been fetched + or a ``freeResult()`` call has been made. + You can optionally pass 'object' (default) or 'array' in order to specify the returned value's type:: From b0c76eda8f55f44aee8a2444a322f93c5f12d29a Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Wed, 23 Jun 2021 17:57:44 +0200 Subject: [PATCH 0177/2325] Sort timeline elements by start and duration. --- system/Debug/Toolbar.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 16432054d2e2..32e1f951a3df 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -213,6 +213,12 @@ protected function collectTimelineData($collectors): array } // Sort it + $sortArray = [ + array_column($data, 'start'), SORT_NUMERIC, SORT_ASC, + array_column($data, 'duration'), SORT_NUMERIC, SORT_DESC, + &$data + ]; + array_multisort(...$sortArray); return $data; } From f00ced2d1990e3429d1fd6a5ef2d7b2281d89ed0 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 24 Jun 2021 21:57:34 +0800 Subject: [PATCH 0178/2325] Namespace extracted by GeneratorTrait should always end in backslash --- system/CLI/GeneratorTrait.php | 6 +++--- .../system/Commands/CommandGeneratorTest.php | 20 +++++++++++++++++++ 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/system/CLI/GeneratorTrait.php b/system/CLI/GeneratorTrait.php index b0668a49f4d2..51706b477cd4 100644 --- a/system/CLI/GeneratorTrait.php +++ b/system/CLI/GeneratorTrait.php @@ -215,14 +215,14 @@ protected function qualifyClassName(): string // Trims input, normalize separators, and ensure that all paths are in Pascalcase. $class = ltrim(implode('\\', array_map('pascalize', explode('\\', str_replace('/', '\\', trim($class))))), '\\/'); - // Gets the namespace from input. - $namespace = trim(str_replace('/', '\\', $this->getOption('namespace') ?? APP_NAMESPACE), '\\'); + // Gets the namespace from input. Don't forget the ending backslash! + $namespace = trim(str_replace('/', '\\', $this->getOption('namespace') ?? APP_NAMESPACE), '\\') . '\\'; if (strncmp($class, $namespace, strlen($namespace)) === 0) { return $class; // @codeCoverageIgnore } - return $namespace . '\\' . $this->directory . '\\' . str_replace('/', '\\', $class); + return $namespace . $this->directory . '\\' . str_replace('/', '\\', $class); } /** diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php index abe3ce4c7e6e..1d5dd6d116c4 100644 --- a/tests/system/Commands/CommandGeneratorTest.php +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -132,4 +132,24 @@ public function testGeneratorPreservesCaseButChangesComponentName(): void $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); $this->assertFileExists(APPPATH . 'Controllers/TestModuleController.php'); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4857 + */ + public function testGeneratorIsNotConfusedWithNamespaceLikeClassNames(): void + { + $time = time(); + $notExists = true; + command('make:migration App_Lesson'); + + // we got 5 chances to prove that the file created went to app/Database/Migrations + foreach (range(0, 4) as $increment) { + $expectedFile = sprintf('%sDatabase/Migrations/%s_AppLesson.php', APPPATH, gmdate('Y-m-d-His', $time + $increment)); + clearstatcache(true, $expectedFile); + + $notExists = $notExists && ! is_file($expectedFile); + } + + $this->assertFalse($notExists, 'Creating migration file for class "AppLesson" did not go to "app/Database/Migrations"'); + } } From b12cfd5b16820d795fe32604d4596394285e68e3 Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 25 Jun 2021 19:10:40 +0200 Subject: [PATCH 0179/2325] Fix bug with respecting TTL in Predis and File cache --- system/Cache/Handlers/FileHandler.php | 2 +- system/Cache/Handlers/PredisHandler.php | 4 +++- tests/system/Cache/Handlers/FileHandlerTest.php | 12 ++++++++++++ tests/system/Cache/Handlers/MemcachedHandlerTest.php | 12 ++++++++++++ tests/system/Cache/Handlers/PredisHandlerTest.php | 12 ++++++++++++ tests/system/Cache/Handlers/RedisHandlerTest.php | 12 ++++++++++++ 6 files changed, 52 insertions(+), 2 deletions(-) diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index db2e5d6574ee..b6b1cb9c3525 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -210,7 +210,7 @@ public function getMetaData(string $key) } return [ - 'expire' => $data['time'] + $data['ttl'], + 'expire' => $data['ttl'] > 0 ? $data['time'] + $data['ttl'] : null, 'mtime' => filemtime($this->path . $key), 'data' => $data['data'], ]; diff --git a/system/Cache/Handlers/PredisHandler.php b/system/Cache/Handlers/PredisHandler.php index 374b3895ed05..5d1f37cdfc24 100644 --- a/system/Cache/Handlers/PredisHandler.php +++ b/system/Cache/Handlers/PredisHandler.php @@ -127,7 +127,9 @@ public function save(string $key, $value, int $ttl = 60) return false; } - $this->redis->expireat($key, time() + $ttl); + if ($ttl) { + $this->redis->expireat($key, time() + $ttl); + } return true; } diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php index bfd379ae9d8f..0f9f9a10eadf 100644 --- a/tests/system/Cache/Handlers/FileHandlerTest.php +++ b/tests/system/Cache/Handlers/FileHandlerTest.php @@ -156,6 +156,18 @@ public function testSaveExcessiveKeyLength() unlink($file); } + public function testSavePermanent() + { + $this->assertTrue($this->fileHandler->save(self::$key1, 'value', 0)); + $metaData = $this->fileHandler->getMetaData(self::$key1); + + $this->assertSame(null, $metaData['expire']); + $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); + $this->assertSame('value', $metaData['data']); + + $this->assertTrue($this->fileHandler->delete(self::$key1)); + } + public function testDelete() { $this->fileHandler->save(self::$key1, 'value'); diff --git a/tests/system/Cache/Handlers/MemcachedHandlerTest.php b/tests/system/Cache/Handlers/MemcachedHandlerTest.php index f83708bd8c98..9afbdf742236 100644 --- a/tests/system/Cache/Handlers/MemcachedHandlerTest.php +++ b/tests/system/Cache/Handlers/MemcachedHandlerTest.php @@ -102,6 +102,18 @@ public function testSave() $this->assertTrue($this->memcachedHandler->save(self::$key1, 'value')); } + public function testSavePermanent() + { + $this->assertTrue($this->memcachedHandler->save(self::$key1, 'value', 0)); + $metaData = $this->memcachedHandler->getMetaData(self::$key1); + + $this->assertSame(null, $metaData['expire']); + $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); + $this->assertSame('value', $metaData['data']); + + $this->assertTrue($this->memcachedHandler->delete(self::$key1)); + } + public function testDelete() { $this->memcachedHandler->save(self::$key1, 'value'); diff --git a/tests/system/Cache/Handlers/PredisHandlerTest.php b/tests/system/Cache/Handlers/PredisHandlerTest.php index df6dfdbfbaef..867babcddc2a 100644 --- a/tests/system/Cache/Handlers/PredisHandlerTest.php +++ b/tests/system/Cache/Handlers/PredisHandlerTest.php @@ -109,6 +109,18 @@ public function testSave() $this->assertTrue($this->PredisHandler->save(self::$key1, 'value')); } + public function testSavePermanent() + { + $this->assertTrue($this->PredisHandler->save(self::$key1, 'value', 0)); + $metaData = $this->PredisHandler->getMetaData(self::$key1); + + $this->assertSame(null, $metaData['expire']); + $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); + $this->assertSame('value', $metaData['data']); + + $this->assertTrue($this->PredisHandler->delete(self::$key1)); + } + public function testDelete() { $this->PredisHandler->save(self::$key1, 'value'); diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php index 66f3c7fd2244..b3f8cebbb422 100644 --- a/tests/system/Cache/Handlers/RedisHandlerTest.php +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php @@ -109,6 +109,18 @@ public function testSave() $this->assertTrue($this->redisHandler->save(self::$key1, 'value')); } + public function testSavePermanent() + { + $this->assertTrue($this->redisHandler->save(self::$key1, 'value', 0)); + $metaData = $this->redisHandler->getMetaData(self::$key1); + + $this->assertSame(null, $metaData['expire']); + $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); + $this->assertSame('value', $metaData['data']); + + $this->assertTrue($this->redisHandler->delete(self::$key1)); + } + public function testDelete() { $this->redisHandler->save(self::$key1, 'value'); From 788a3325fe914298b02dd98acc68a11f9751ce68 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sat, 26 Jun 2021 11:00:32 +0200 Subject: [PATCH 0180/2325] Fix database session bug with timestamp in MySQLi --- system/Session/Handlers/DatabaseHandler.php | 9 +- .../20160428212500_Create_test_tables.php | 29 ++++ .../_support/Database/Seeds/CITestSeeder.php | 18 +++ tests/system/Database/Live/MetadataTest.php | 4 + .../Session/Handlers/DatabaseHandlerTest.php | 141 ++++++++++++++++++ 5 files changed, 196 insertions(+), 5 deletions(-) create mode 100644 tests/system/Session/Handlers/DatabaseHandlerTest.php diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index 18da544d2873..ebfdfc119d5e 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -172,11 +172,10 @@ public function write($id, $data): bool $insertData = [ 'id' => $id, 'ip_address' => $this->ipAddress, - 'timestamp' => 'now()', 'data' => $this->platform === 'postgre' ? '\x' . bin2hex($data) : $data, ]; - if (! $this->db->table($this->table)->insert($insertData)) { + if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) { return $this->fail(); } @@ -192,13 +191,13 @@ public function write($id, $data): bool $builder = $builder->where('ip_address', $this->ipAddress); } - $updateData = ['timestamp' => 'now()']; + $updateData = []; if ($this->fingerprint !== md5($data)) { $updateData['data'] = ($this->platform === 'postgre') ? '\x' . bin2hex($data) : $data; } - if (! $builder->update($updateData)) { + if (! $builder->set('timestamp', 'now()', false)->update($updateData)) { return $this->fail(); } @@ -257,7 +256,7 @@ public function gc($max_lifetime) $separator = $this->platform === 'postgre' ? '\'' : ' '; $interval = implode($separator, ['', "{$max_lifetime} second", '']); - return $this->db->table($this->table)->delete("timestamp < now() - INTERVAL {$interval}") ? 1 : $this->fail(); + return $this->db->table($this->table)->where('timestamp <', "now() - INTERVAL {$interval}", false)->delete() ? true : $this->fail(); } /** diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index 07b61cdd2451..5b414de228a7 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -127,6 +127,31 @@ public function up() 'ip' => ['type' => 'VARCHAR', 'constraint' => 100], 'ip2' => ['type' => 'VARCHAR', 'constraint' => 100], ])->createTable('ip_table', true); + + // Database session table + if ($this->db->DBDriver === 'MySQLi') { + $this->forge->addField([ + 'id' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => false], + 'ip_address' => ['type' => 'VARCHAR', 'constraint' => 45, 'null' => false], + 'timestamp timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL', + 'data' => ['type' => 'BLOB', 'null' => false], + ]); + $this->forge->addKey('id', true); + $this->forge->addKey('timestamp'); + $this->forge->createTable('ci_sessions', true); + } + + if ($this->db->DBDriver === 'Postgre') { + $this->forge->addField([ + 'id' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => false], + 'ip_address inet NOT NULL', + 'timestamp timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL', + "data bytea DEFAULT '' NOT NULL", + ]); + $this->forge->addKey('id', true); + $this->forge->addKey('timestamp'); + $this->forge->createTable('ci_sessions', true); + } } public function down() @@ -140,5 +165,9 @@ public function down() $this->forge->dropTable('stringifypkey', true); $this->forge->dropTable('without_auto_increment', true); $this->forge->dropTable('ip_table', true); + + if (in_array($this->db->DBDriver, ['MySQLi', 'Postgre'], true)) { + $this->forge->dropTable('ci_sessions', true); + } } } diff --git a/tests/_support/Database/Seeds/CITestSeeder.php b/tests/_support/Database/Seeds/CITestSeeder.php index 0319896159ab..ae4b2af3b0b7 100644 --- a/tests/_support/Database/Seeds/CITestSeeder.php +++ b/tests/_support/Database/Seeds/CITestSeeder.php @@ -146,6 +146,24 @@ public function run() ); } + if ($this->db->DBDriver === 'MySQLi') { + $data['ci_sessions'][] = [ + 'id' => '1f5o06b43phsnnf8if6bo33b635e4p2o', + 'ip_address' => '127.0.0.1', + 'timestamp' => '2021-06-25 21:54:14', + 'data' => '__ci_last_regenerate|i:1624650854;_ci_previous_url|s:40:\"http://localhost/index.php/home/index\";', + ]; + } + + if ($this->db->DBDriver === 'Postgre') { + $data['ci_sessions'][] = [ + 'id' => '1f5o06b43phsnnf8if6bo33b635e4p2o', + 'ip_address' => '127.0.0.1', + 'timestamp' => '2021-06-25 21:54:14.991403+02', + 'data' => '\x' . bin2hex('__ci_last_regenerate|i:1624650854;_ci_previous_url|s:40:\"http://localhost/index.php/home/index\";'), + ]; + } + foreach ($data as $table => $dummy_data) { $this->db->table($table)->truncate(); diff --git a/tests/system/Database/Live/MetadataTest.php b/tests/system/Database/Live/MetadataTest.php index e59b28f7b724..8c6806c4d86e 100644 --- a/tests/system/Database/Live/MetadataTest.php +++ b/tests/system/Database/Live/MetadataTest.php @@ -52,6 +52,10 @@ protected function setUp(): void $prefix . 'without_auto_increment', $prefix . 'ip_table', ]; + + if (in_array($this->db->DBDriver, ['MySQLi', 'Postgre'], true)) { + $this->expectedTables[] = $prefix . 'ci_sessions'; + } } public function testListTables() diff --git a/tests/system/Session/Handlers/DatabaseHandlerTest.php b/tests/system/Session/Handlers/DatabaseHandlerTest.php new file mode 100644 index 000000000000..7e69bf8e6c73 --- /dev/null +++ b/tests/system/Session/Handlers/DatabaseHandlerTest.php @@ -0,0 +1,141 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Session\Handlers; + +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\DatabaseTestTrait; +use CodeIgniter\Test\ReflectionHelper; +use Config\App as AppConfig; +use Config\Database as DatabaseConfig; + +/** + * @internal + */ +final class DatabaseHandlerTest extends CIUnitTestCase +{ + use DatabaseTestTrait; + use ReflectionHelper; + + protected $refresh = true; + + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + + protected function setUp(): void + { + parent::setUp(); + + if (! in_array(config(DatabaseConfig::class)->tests['DBDriver'], ['MySQLi', 'Postgre'], true)) { + $this->markTestSkipped('Database Session Handler requires database driver to be MySQLi or Postgre'); + } + } + + protected function getInstance($options = []) + { + $defaults = [ + 'sessionDriver' => 'CodeIgniter\Session\Handlers\DatabaseHandler', + 'sessionCookieName' => 'ci_session', + 'sessionExpiration' => 7200, + 'sessionSavePath' => 'ci_sessions', + 'sessionMatchIP' => false, + 'sessionTimeToUpdate' => 300, + 'sessionRegenerateDestroy' => false, + 'cookieDomain' => '', + 'cookiePrefix' => '', + 'cookiePath' => '/', + 'cookieSecure' => false, + 'cookieSameSite' => 'Lax', + ]; + + $config = array_merge($defaults, $options); + $appConfig = new AppConfig(); + + foreach ($config as $key => $c) { + $appConfig->{$key} = $c; + } + + return new DatabaseHandler($appConfig, '127.0.0.1'); + } + + public function testOpen() + { + $handler = $this->getInstance(); + $this->assertTrue($handler->open('ci_sessions', 'ci_session')); + } + + public function testReadSuccess() + { + $handler = $this->getInstance(); + $expected = '__ci_last_regenerate|i:1624650854;_ci_previous_url|s:40:\"http://localhost/index.php/home/index\";'; + $this->assertSame($expected, $handler->read('1f5o06b43phsnnf8if6bo33b635e4p2o')); + + $this->assertTrue($this->getPrivateProperty($handler, 'rowExists')); + $this->assertSame('1483201a66afd2bd671e4a67dc6ecf24', $this->getPrivateProperty($handler, 'fingerprint')); + } + + public function testReadFailure() + { + $handler = $this->getInstance(); + $this->assertSame('', $handler->read('123456b43phsnnf8if6bo33b635e4321')); + + $this->assertFalse($this->getPrivateProperty($handler, 'rowExists')); + $this->assertSame('d41d8cd98f00b204e9800998ecf8427e', $this->getPrivateProperty($handler, 'fingerprint')); + } + + public function testWriteInsert() + { + $handler = $this->getInstance(); + + $this->setPrivateProperty($handler, 'lock', true); + + $data = '__ci_last_regenerate|i:1624650854;_ci_previous_url|s:40:\"http://localhost/index.php/home/index\";'; + $this->assertTrue($handler->write('555556b43phsnnf8if6bo33b635e4444', $data)); + + $this->setPrivateProperty($handler, 'lock', false); + + $row = $this->db->table('ci_sessions') + ->getWhere(['id' => '555556b43phsnnf8if6bo33b635e4444']) + ->getRow(); + + $this->assertGreaterThan(time() - 100, strtotime($row->timestamp)); + $this->assertSame('1483201a66afd2bd671e4a67dc6ecf24', $this->getPrivateProperty($handler, 'fingerprint')); + } + + public function testWriteUpdate() + { + $handler = $this->getInstance(); + + $this->setPrivateProperty($handler, 'sessionID', '1f5o06b43phsnnf8if6bo33b635e4p2o'); + $this->setPrivateProperty($handler, 'rowExists', true); + + $lockSession = $this->getPrivateMethodInvoker($handler, 'lockSession'); + $lockSession('1f5o06b43phsnnf8if6bo33b635e4p2o'); + + $data = '__ci_last_regenerate|i:1624650854;_ci_previous_url|s:40:\"http://localhost/index.php/home/index\";'; + $this->assertTrue($handler->write('1f5o06b43phsnnf8if6bo33b635e4p2o', $data)); + + $releaseLock = $this->getPrivateMethodInvoker($handler, 'releaseLock'); + $releaseLock(); + + $row = $this->db->table('ci_sessions') + ->getWhere(['id' => '1f5o06b43phsnnf8if6bo33b635e4p2o']) + ->getRow(); + + $this->assertGreaterThan(time() - 100, strtotime($row->timestamp)); + $this->assertSame('1483201a66afd2bd671e4a67dc6ecf24', $this->getPrivateProperty($handler, 'fingerprint')); + } + + public function testGC() + { + $handler = $this->getInstance(); + $this->assertTrue($handler->gc(3600)); + } +} From 860003281275d68dd3b849a783036b5293452cf8 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sat, 26 Jun 2021 11:14:18 +0200 Subject: [PATCH 0181/2325] Fix for generating session table structure via migrations --- .../Generators/MigrationGenerator.php | 9 +++---- .../Generators/Views/migration.tpl.php | 24 ++++++++++++------- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/system/Commands/Generators/MigrationGenerator.php b/system/Commands/Generators/MigrationGenerator.php index 1cd931e9e460..24ab3ea72330 100644 --- a/system/Commands/Generators/MigrationGenerator.php +++ b/system/Commands/Generators/MigrationGenerator.php @@ -101,10 +101,11 @@ protected function prepare(string $class): string $table = $this->getOption('table'); $DBGroup = $this->getOption('dbgroup'); - $data['session'] = true; - $data['table'] = is_string($table) ? $table : 'ci_sessions'; - $data['DBGroup'] = is_string($DBGroup) ? $DBGroup : 'default'; - $data['matchIP'] = config('App')->sessionMatchIP; + $data['session'] = true; + $data['table'] = is_string($table) ? $table : 'ci_sessions'; + $data['DBGroup'] = is_string($DBGroup) ? $DBGroup : 'default'; + $data['DBDriver'] = config('Database')->{$data['DBGroup']}['DBDriver']; + $data['matchIP'] = config('App')->sessionMatchIP; } return $this->parseTemplate($class, [], [], $data); diff --git a/system/Commands/Generators/Views/migration.tpl.php b/system/Commands/Generators/Views/migration.tpl.php index 436ee85e04cc..321895e670c2 100644 --- a/system/Commands/Generators/Views/migration.tpl.php +++ b/system/Commands/Generators/Views/migration.tpl.php @@ -12,17 +12,23 @@ class {class} extends Migration public function up() { $this->forge->addField([ - 'id' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => false], + 'id' => ['type' => 'VARCHAR', 'constraint' => 128, 'null' => false], + 'ip_address' => ['type' => 'VARCHAR', 'constraint' => 45, 'null' => false], - 'timestamp' => ['type' => 'INT', 'unsigned' => true, 'null' => false, 'default' => 0], - 'data' => ['type' => 'TEXT', 'null' => false, 'default' => ''], + 'timestamp timestamp DEFAULT CURRENT_TIMESTAMP NOT NULL', + 'data' => ['type' => 'BLOB', 'null' => false], + + 'ip_address inet NOT NULL', + 'timestamp timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL', + "data bytea DEFAULT '' NOT NULL", + ]); - - $this->forge->addKey(['id', 'ip_address'], true); - - $this->forge->addKey('id', true); - - $this->forge->addKey('timestamp'); + + $this->forge->addKey(['id', 'ip_address'], true); + + $this->forge->addKey('id', true); + + $this->forge->addKey('timestamp'); $this->forge->createTable('', true); } From bacda111b9a1cfe019de22a0420493ac39f80b21 Mon Sep 17 00:00:00 2001 From: MGatner Date: Sun, 13 Jun 2021 23:05:43 +0000 Subject: [PATCH 0182/2325] Implement FileCollection --- system/Files/Exceptions/FileException.php | 20 + system/Files/FileCollection.php | 386 +++++++++++++ system/Language/en/Files.php | 6 +- system/Language/en/Publisher.php | 2 - .../Exceptions/PublisherException.php | 20 - system/Publisher/Publisher.php | 308 +--------- tests/system/Files/FileCollectionTest.php | 536 ++++++++++++++++++ tests/system/Publisher/PublisherInputTest.php | 338 +---------- .../system/Publisher/PublisherSupportTest.php | 68 +-- user_guide_src/source/libraries/files.rst | 96 ++++ user_guide_src/source/libraries/publisher.rst | 56 +- 11 files changed, 1066 insertions(+), 770 deletions(-) create mode 100644 system/Files/FileCollection.php create mode 100644 tests/system/Files/FileCollectionTest.php diff --git a/system/Files/Exceptions/FileException.php b/system/Files/Exceptions/FileException.php index bbbdc1a3cbb1..40e9fdc20f41 100644 --- a/system/Files/Exceptions/FileException.php +++ b/system/Files/Exceptions/FileException.php @@ -23,4 +23,24 @@ public static function forUnableToMove(?string $from = null, ?string $to = null, { return new static(lang('Files.cannotMove', [$from, $to, $error])); } + + /** + * Throws when an item is expected to be a directory but is not or is missing. + * + * @param string $caller The method causing the exception + */ + public static function forExpectedDirectory(string $caller) + { + return new static(lang('Files.expectedDirectory', [$caller])); + } + + /** + * Throws when an item is expected to be a file but is not or is missing. + * + * @param string $caller The method causing the exception + */ + public static function forExpectedFile(string $caller) + { + return new static(lang('Files.expectedFile', [$caller])); + } } diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php new file mode 100644 index 000000000000..bf4eeaf6b836 --- /dev/null +++ b/system/Files/FileCollection.php @@ -0,0 +1,386 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace CodeIgniter\Files; + +use CodeIgniter\Files\Exceptions\FileException; +use CodeIgniter\Files\Exceptions\FileNotFoundException; +use Countable; +use Generator; +use InvalidArgumentException; +use IteratorAggregate; +use Traversable; + +/** + * File Collection Class + * + * Representation for a group of files, with utilities for locating, + * filtering, and ordering them. + */ +class FileCollection implements Countable, IteratorAggregate +{ + /** + * The current list of file paths. + * + * @var string[] + */ + protected $files = []; + + //-------------------------------------------------------------------- + + /** + * Resolves a full path and verifies it is an actual directory. + * + * @param string $directory + * + * @return string + * + * @throws FileException + */ + protected static function resolveDirectory(string $directory): string + { + if (! is_dir($directory = set_realpath($directory))) + { + $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; + throw FileException::forExpectedDirectory($caller['function']); + } + + return $directory; + } + + /** + * Resolves a full path and verifies it is an actual file. + * + * @param string $file + * + * @return string + * + * @throws FileException + */ + protected static function resolveFile(string $file): string + { + if (! is_file($file = set_realpath($file))) + { + $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; + throw FileException::forExpectedFile($caller['function']); + } + + return $file; + } + + /** + * Removes files that are not part of the given directory (recursive). + * + * @param string[] $files + * @param string $directory + * + * @return string[] + */ + protected static function filterFiles(array $files, string $directory): array + { + $directory = self::resolveDirectory($directory); + + return array_filter($files, function ($value) use ($directory) { + return strpos($value, $directory) === 0; + }); + } + + /** + * Returns any files whose `basename` matches the given pattern. + * + * @param string[] $files + * @param string $pattern Regex or pseudo-regex string + * + * @return string[] + */ + protected static function matchFiles(array $files, string $pattern): array + { + // Convert pseudo-regex into their true form + if (@preg_match($pattern, null) === false) // @phpstan-ignore-line + { + $pattern = str_replace( + ['#', '.', '*', '?'], + ['\#', '\.', '.*', '.'], + $pattern + ); + $pattern = "#{$pattern}#"; + } + + return array_filter($files, function ($value) use ($pattern) { + return (bool) preg_match($pattern, basename($value)); + }); + } + + //-------------------------------------------------------------------- + + /** + * Loads the Filesystem helper and stores initial files. + * + * @param string[] $files + */ + public function __construct(array $files = []) + { + helper(['filesystem']); + + $this->set($files); + } + + /** + * Optimizes and returns the current file list. + * + * @return string[] + */ + public function get(): array + { + $this->files = array_unique($this->files, SORT_STRING); + sort($this->files, SORT_STRING); + + return $this->files; + } + + /** + * Sets the file list directly, files are still subject to verification. + * This works as a "reset" method with []. + * + * @param string[] $files The new file list to use + * + * @return $this + */ + public function set(array $files) + { + $this->files = []; + + return $this->addFiles($files); + } + + /** + * Adds an array/single file or directory to the list. + * + * @param string|string[] $paths + * @param boolean $recursive + * + * @return $this + */ + public function add($paths, bool $recursive = true) + { + if (! is_array($paths)) + { + $paths = [$paths]; + } + + foreach ($paths as $path) + { + if (! is_string($path)) + { + throw new InvalidArgumentException('FileCollection paths must be strings.'); + } + + // Test for a directory + try + { + $directory = self::resolveDirectory($path); + } + catch (FileException $e) + { + return $this->addFile($path); + } + + $this->addDirectory($path, $recursive); + } + + return $this; + } + + //-------------------------------------------------------------------- + + /** + * Verifies and adds files to the list. + * + * @param string[] $files + * + * @return $this + */ + public function addFiles(array $files) + { + foreach ($files as $file) + { + $this->addFile($file); + } + + return $this; + } + + /** + * Verifies and adds a single file to the file list. + * + * @param string $file + * + * @return $this + */ + public function addFile(string $file) + { + $this->files[] = self::resolveFile($file); + + return $this; + } + + /** + * Removes files from the list. + * + * @param string[] $files + * + * @return $this + */ + public function removeFiles(array $files) + { + $this->files = array_diff($this->files, $files); + + return $this; + } + + /** + * Removes a single file from the list. + * + * @param string $file + * + * @return $this + */ + public function removeFile(string $file) + { + return $this->removeFiles([$file]); + } + + //-------------------------------------------------------------------- + + /** + * Verifies and adds files from each + * directory to the list. + * + * @param string[] $directories + * @param bool $recursive + * + * @return $this + */ + public function addDirectories(array $directories, bool $recursive = false) + { + foreach ($directories as $directory) + { + $this->addDirectory($directory, $recursive); + } + + return $this; + } + + /** + * Verifies and adds all files from a directory. + * + * @param string $directory + * @param boolean $recursive + * + * @return $this + */ + public function addDirectory(string $directory, bool $recursive = false) + { + $directory = self::resolveDirectory($directory); + + // Map the directory to depth 2 to so directories become arrays + foreach (directory_map($directory, 2, true) as $key => $path) + { + if (is_string($path)) + { + $this->addFile($directory . $path); + } + elseif ($recursive && is_array($path)) + { + $this->addDirectory($directory . $key, true); + } + } + + return $this; + } + + //-------------------------------------------------------------------- + + /** + * Removes any files from the list that match the supplied pattern + * (within the optional scope). + * + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope The directory to limit the scope + * + * @return $this + */ + public function removePattern(string $pattern, string $scope = null) + { + if ($pattern === '') + { + return $this; + } + + // Start with all files or those in scope + $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); + + // Remove any files that match the pattern + return $this->removeFiles(self::matchFiles($files, $pattern)); + } + + /** + * Keeps only the files from the list that match + * (within the optional scope). + * + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope A directory to limit the scope + * + * @return $this + */ + public function retainPattern(string $pattern, string $scope = null) + { + if ($pattern === '') + { + return $this; + } + + // Start with all files or those in scope + $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); + + // Matches the pattern within the scoped files and remove their inverse. + return $this->removeFiles(array_diff($files, self::matchFiles($files, $pattern))); + } + + //-------------------------------------------------------------------- + + /** + * Returns the current number of files in the collection. + * Fulfills Countable. + * + * @return int + */ + public function count(): int + { + return count($this->files); + } + + /** + * Yields as an Iterator for the current files. + * Fulfills IteratorAggregate. + * + * @throws FileNotFoundException + * + * @return Generator + */ + public function getIterator(): Generator + { + foreach ($this->get() as $file) + { + yield new File($file, true); + } + } +} diff --git a/system/Language/en/Files.php b/system/Language/en/Files.php index 924e98ea354a..bcbc39d7e349 100644 --- a/system/Language/en/Files.php +++ b/system/Language/en/Files.php @@ -11,6 +11,8 @@ // Files language settings return [ - 'fileNotFound' => 'File not found: {0}', - 'cannotMove' => 'Could not move file {0} to {1} ({2}).', + 'fileNotFound' => 'File not found: {0}', + 'cannotMove' => 'Could not move file {0} to {1} ({2}).', + 'expectedDirectory' => '{0} expects a valid directory.', + 'expectedFile' => '{0} expects a valid file.', ]; diff --git a/system/Language/en/Publisher.php b/system/Language/en/Publisher.php index 2d7ae8418b25..77d805a78ff2 100644 --- a/system/Language/en/Publisher.php +++ b/system/Language/en/Publisher.php @@ -12,8 +12,6 @@ // Publisher language settings return [ 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', - 'expectedDirectory' => 'Publisher::{0} expects a valid directory.', - 'expectedFile' => 'Publisher::{0} expects a valid file.', 'destinationNotAllowed' => 'Destination is not on the allowed list of Publisher directories: {0}', 'fileNotAllowed' => '{0} fails the following restriction for {1}: {2}', diff --git a/system/Publisher/Exceptions/PublisherException.php b/system/Publisher/Exceptions/PublisherException.php index d54420881ec7..c3e85a994ebe 100644 --- a/system/Publisher/Exceptions/PublisherException.php +++ b/system/Publisher/Exceptions/PublisherException.php @@ -31,26 +31,6 @@ public static function forCollision(string $from, string $to) return new static(lang('Publisher.collision', [filetype($to), $from, $to])); } - /** - * Throws when an object is expected to be a directory but is not or is missing. - * - * @param string $caller The method causing the exception - */ - public static function forExpectedDirectory(string $caller) - { - return new static(lang('Publisher.expectedDirectory', [$caller])); - } - - /** - * Throws when an object is expected to be a file but is not or is missing. - * - * @param string $caller The method causing the exception - */ - public static function forExpectedFile(string $caller) - { - return new static(lang('Publisher.expectedFile', [$caller])); - } - /** * Throws when given a destination that is not in the list of allowed directories. * diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 1bfd4b91768d..1f28bc331baf 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Publisher; use CodeIgniter\Autoloader\FileLocator; -use CodeIgniter\Files\File; +use CodeIgniter\Files\FileCollection; use CodeIgniter\HTTP\URI; use CodeIgniter\Publisher\Exceptions\PublisherException; use RuntimeException; @@ -28,13 +28,13 @@ * path to a verified file while a "path" is relative to its source * or destination and may indicate either a file or directory of * unconfirmed existence. - * class failures throw the PublisherException, but some underlying + * Class failures throw the PublisherException, but some underlying * methods may percolate different exceptions, like FileException, * FileNotFoundException or InvalidArgumentException. * Write operations will catch all errors in the file-specific * $errors property to minimize impact of partial batch operations. */ -class Publisher +class Publisher extends FileCollection { /** * Array of discovered Publishers. @@ -51,13 +51,6 @@ class Publisher */ private $scratch; - /** - * The current list of files. - * - * @var string[] - */ - private $files = []; - /** * Exceptions for specific files from the last write operation. * @@ -94,6 +87,8 @@ class Publisher */ protected $destination = FCPATH; + //-------------------------------------------------------------------- + /** * Discovers and returns all Publishers in the specified namespace directory. * @@ -134,95 +129,6 @@ final public static function discover(string $directory = 'Publishers'): array return self::$discovered[$directory]; } - //-------------------------------------------------------------------- - - /** - * Resolves a full path and verifies it is an actual directory. - * - * @param string $directory - * - * @return string - * - * @throws PublisherException - */ - private static function resolveDirectory(string $directory): string - { - if (! is_dir($directory = set_realpath($directory))) - { - $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; - throw PublisherException::forExpectedDirectory($caller['function']); - } - - return $directory; - } - - /** - * Resolves a full path and verifies it is an actual file. - * - * @param string $file - * - * @return string - * - * @throws PublisherException - */ - private static function resolveFile(string $file): string - { - if (! is_file($file = set_realpath($file))) - { - $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; - throw PublisherException::forExpectedFile($caller['function']); - } - - return $file; - } - - //-------------------------------------------------------------------- - - /** - * Removes files that are not part of the given directory (recursive). - * - * @param string[] $files - * @param string $directory - * - * @return string[] - */ - private static function filterFiles(array $files, string $directory): array - { - $directory = self::resolveDirectory($directory); - - return array_filter($files, function ($value) use ($directory) { - return strpos($value, $directory) === 0; - }); - } - - /** - * Returns any files whose `basename` matches the given pattern. - * - * @param array $files - * @param string $pattern Regex or pseudo-regex string - * - * @return string[] - */ - private static function matchFiles(array $files, string $pattern): array - { - // Convert pseudo-regex into their true form - if (@preg_match($pattern, null) === false) // @phpstan-ignore-line - { - $pattern = str_replace( - ['#', '.', '*', '?'], - ['\#', '\.', '.*', '.'], - $pattern - ); - $pattern = "#{$pattern}#"; - } - - return array_filter($files, function ($value) use ($pattern) { - return (bool) preg_match($pattern, basename($value)); - }); - } - - //-------------------------------------------------------------------- - /* * Removes a directory and all its files and subdirectories. * @@ -305,7 +211,7 @@ public function publish(): bool // Safeguard against accidental misuse if ($this->source === ROOTPATH && $this->destination === FCPATH) { - throw new RuntimeException('Child classes of Publisher should provide their own source and destination or publish method.'); + throw new RuntimeException('Child classes of Publisher should provide their own publish method or a source and destination.'); } return $this->addPath('/')->merge(true); @@ -369,142 +275,6 @@ final public function getPublished(): array return $this->published; } - /** - * Optimizes and returns the current file list. - * - * @return string[] - */ - final public function getFiles(): array - { - $this->files = array_unique($this->files, SORT_STRING); - sort($this->files, SORT_STRING); - - return $this->files; - } - - //-------------------------------------------------------------------- - - /** - * Sets the file list directly, files are still subject to verification. - * This works as a "reset" method with []. - * - * @param string[] $files The new file list to use - * - * @return $this - */ - final public function setFiles(array $files) - { - $this->files = []; - - return $this->addFiles($files); - } - - /** - * Verifies and adds files to the list. - * - * @param string[] $files - * - * @return $this - */ - final public function addFiles(array $files) - { - foreach ($files as $file) - { - $this->addFile($file); - } - - return $this; - } - - /** - * Verifies and adds a single file to the file list. - * - * @param string $file - * - * @return $this - */ - final public function addFile(string $file) - { - $this->files[] = self::resolveFile($file); - - return $this; - } - - /** - * Removes files from the list. - * - * @param string[] $files - * - * @return $this - */ - final public function removeFiles(array $files) - { - $this->files = array_diff($this->files, $files); - - return $this; - } - - /** - * Removes a single file from the list. - * - * @param string $file - * - * @return $this - */ - final public function removeFile(string $file) - { - return $this->removeFiles([$file]); - } - - //-------------------------------------------------------------------- - - /** - * Verifies and adds files from each - * directory to the list. - * - * @param string[] $directories - * @param bool $recursive - * - * @return $this - */ - final public function addDirectories(array $directories, bool $recursive = false) - { - foreach ($directories as $directory) - { - $this->addDirectory($directory, $recursive); - } - - return $this; - } - - /** - * Verifies and adds all files from a directory. - * - * @param string $directory - * @param boolean $recursive - * - * @return $this - */ - final public function addDirectory(string $directory, bool $recursive = false) - { - $directory = self::resolveDirectory($directory); - - // Map the directory to depth 2 to so directories become arrays - foreach (directory_map($directory, 2, true) as $key => $path) - { - if (is_string($path)) - { - $this->addFile($directory . $path); - } - elseif ($recursive && is_array($path)) - { - $this->addDirectory($directory . $key, true); - } - } - - return $this; - } - //-------------------------------------------------------------------- /** @@ -535,19 +305,9 @@ final public function addPaths(array $paths, bool $recursive = true) */ final public function addPath(string $path, bool $recursive = true) { - $full = $this->source . $path; - - // Test for a directory - try - { - $directory = self::resolveDirectory($full); - } - catch (PublisherException $e) - { - return $this->addFile($full); - } + $this->add($this->source . $path, $recursive); - return $this->addDirectory($full, $recursive); + return $this; } //-------------------------------------------------------------------- @@ -589,54 +349,6 @@ final public function addUri(string $uri) //-------------------------------------------------------------------- - /** - * Removes any files from the list that match the supplied pattern - * (within the optional scope). - * - * @param string $pattern Regex or pseudo-regex string - * @param string|null $scope The directory to limit the scope - * - * @return $this - */ - final public function removePattern(string $pattern, string $scope = null) - { - if ($pattern === '') - { - return $this; - } - - // Start with all files or those in scope - $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); - - // Remove any files that match the pattern - return $this->removeFiles(self::matchFiles($files, $pattern)); - } - - /** - * Keeps only the files from the list that match - * (within the optional scope). - * - * @param string $pattern Regex or pseudo-regex string - * @param string|null $scope A directory to limit the scope - * - * @return $this - */ - final public function retainPattern(string $pattern, string $scope = null) - { - if ($pattern === '') - { - return $this; - } - - // Start with all files or those in scope - $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); - - // Matches the pattern within the scoped files and remove their inverse. - return $this->removeFiles(array_diff($files, self::matchFiles($files, $pattern))); - } - - //-------------------------------------------------------------------- - /** * Removes the destination and all its files and folders. * @@ -662,7 +374,7 @@ final public function copy(bool $replace = true): bool { $this->errors = $this->published = []; - foreach ($this->getFiles() as $file) + foreach ($this->get() as $file) { $to = $this->destination . basename($file); @@ -693,7 +405,7 @@ final public function merge(bool $replace = true): bool $this->errors = $this->published = []; // Get the files from source for special handling - $sourced = self::filterFiles($this->getFiles(), $this->source); + $sourced = self::filterFiles($this->get(), $this->source); // Handle everything else with a flat copy $this->files = array_diff($this->files, $sourced); diff --git a/tests/system/Files/FileCollectionTest.php b/tests/system/Files/FileCollectionTest.php new file mode 100644 index 000000000000..3e77941d5d2f --- /dev/null +++ b/tests/system/Files/FileCollectionTest.php @@ -0,0 +1,536 @@ +getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); + + $this->assertSame($this->directory, $method($this->directory)); + } + + public function testResolveDirectoryFile() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedDirectory', ['invokeArgs'])); + + $method($this->file); + } + + public function testResolveDirectorySymlink() + { + // Create a symlink to test + $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); + symlink($this->directory, $link); + + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); + + $this->assertSame($this->directory, $method($link)); + + unlink($link); + } + + //-------------------------------------------------------------------- + + public function testResolveFileFile() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + + $this->assertSame($this->file, $method($this->file)); + } + + public function testResolveFileSymlink() + { + // Create a symlink to test + $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); + symlink($this->file, $link); + + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + + $this->assertSame($this->file, $method($link)); + + unlink($link); + } + + public function testResolveFileDirectory() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['invokeArgs'])); + + $method($this->directory); + } + + //-------------------------------------------------------------------- + + public function testAddStringFile() + { + $files = new FileCollection(); + + $files->add(SUPPORTPATH . 'Files/baker/banana.php'); + + $this->assertSame([$this->file], $files->get()); + } + + public function testAddStringFileRecursiveDoesNothing() + { + $files = new FileCollection(); + + $files->add(SUPPORTPATH . 'Files/baker/banana.php', true); + + $this->assertSame([$this->file], $files->get()); + } + + public function testAddStringDirectory() + { + $files = new FileCollection(); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $files->add(SUPPORTPATH . 'Files/able'); + + $this->assertSame($expected, $files->get()); + } + + public function testAddStringDirectoryRecursive() + { + $files = new FileCollection(); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $files->add(SUPPORTPATH . 'Files'); + + $this->assertSame($expected, $files->get()); + } + + public function testAddArray() + { + $files = new FileCollection(); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $files->add([ + SUPPORTPATH . 'Files/able', + SUPPORTPATH . 'Files/baker/banana.php', + ]); + + $this->assertSame($expected, $files->get()); + } + + public function testAddArrayRecursive() + { + $files = new FileCollection(); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; + + $files->add([ + SUPPORTPATH . 'Files', + SUPPORTPATH . 'Log', + ], true); + + $this->assertSame($expected, $files->get()); + } + + //-------------------------------------------------------------------- + + public function testAddFile() + { + $collection = new FileCollection(); + $this->assertSame([], $this->getPrivateProperty($collection, 'files')); + + $collection->addFile($this->file); + $this->assertSame([$this->file], $this->getPrivateProperty($collection, 'files')); + } + + public function testAddFileMissing() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + + $collection->addFile('TheHillsAreAlive.bmp'); + } + + public function testAddFileDirectory() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + + $collection->addFile($this->directory); + } + + public function testAddFiles() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->file, + ]; + + $collection->addFiles($files); + $this->assertSame($files, $this->getPrivateProperty($collection, 'files')); + } + + //-------------------------------------------------------------------- + + public function testGet() + { + $collection = new FileCollection(); + $collection->addFile($this->file); + + $this->assertSame([$this->file], $collection->get()); + } + + public function testGetSorts() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $collection->addFiles($files); + + $this->assertSame(array_reverse($files), $collection->get()); + } + + public function testGetUniques() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->file, + ]; + + $collection->addFiles($files); + $this->assertSame([$this->file], $collection->get()); + } + + public function testSet() + { + $collection = new FileCollection(); + + $collection->set([$this->file]); + $this->assertSame([$this->file], $collection->get()); + } + + public function testSetInvalid() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + + $collection->set(['flerb']); + } + + //-------------------------------------------------------------------- + + public function testRemoveFile() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $collection->addFiles($files); + + $collection->removeFile($this->file); + + $this->assertSame([$this->directory . 'apple.php'], $collection->get()); + } + + public function testRemoveFiles() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $collection->addFiles($files); + + $collection->removeFiles($files); + + $this->assertSame([], $collection->get()); + } + + //-------------------------------------------------------------------- + + public function testAddDirectoryInvalid() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedDirectory', ['addDirectory'])); + + $collection->addDirectory($this->file); + } + + public function testAddDirectory() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $collection->addDirectory($this->directory); + + $this->assertSame($expected, $collection->get()); + } + + public function testAddDirectoryRecursive() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $this->assertSame($expected, $collection->get()); + } + + public function testAddDirectories() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->addDirectories([ + $this->directory, + SUPPORTPATH . 'Files/baker', + ]); + + $this->assertSame($expected, $collection->get()); + } + + public function testAddDirectoriesRecursive() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; + + $collection->addDirectories([ + SUPPORTPATH . 'Files', + SUPPORTPATH . 'Log', + ], true); + + $this->assertSame($expected, $collection->get()); + } + + //-------------------------------------------------------------------- + + public function testRemovePatternEmpty() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $files = $collection->get(); + + $collection->removePattern(''); + + $this->assertSame($files, $collection->get()); + } + + public function testRemovePatternRegex() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'apple.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->removePattern('#[a-z]+_.*#'); + + $this->assertSame($expected, $collection->get()); + } + + public function testRemovePatternPseudo() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'apple.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->removePattern('*_*.php'); + + $this->assertSame($expected, $collection->get()); + } + + public function testRemovePatternScope() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->removePattern('*.php', $this->directory); + + $this->assertSame($expected, $collection->get()); + } + + //-------------------------------------------------------------------- + + public function testRetainPatternEmpty() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $files = $collection->get(); + + $collection->retainPattern(''); + + $this->assertSame($files, $collection->get()); + } + + public function testRetainPatternRegex() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $collection->retainPattern('#[a-z]+_.*#'); + + $this->assertSame($expected, $collection->get()); + } + + public function testRetainPatternPseudo() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'fig_3.php', + ]; + + $collection->retainPattern('*_?.php'); + + $this->assertSame($expected, $collection->get()); + } + + public function testRetainPatternScope() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $expected = [ + $this->directory . 'fig_3.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->retainPattern('*_?.php', $this->directory); + + $this->assertSame($expected, $collection->get()); + } + + //-------------------------------------------------------------------- + + public function testCount() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $this->assertCount(4, $collection); + } + + public function testIterable() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $count = 0; + foreach ($collection as $file) + { + $this->assertInstanceOf(File::class, $file); + $count++; + } + + $this->assertSame($count, 4); + } +} diff --git a/tests/system/Publisher/PublisherInputTest.php b/tests/system/Publisher/PublisherInputTest.php index e7450f5c02a9..29d48ef78816 100644 --- a/tests/system/Publisher/PublisherInputTest.php +++ b/tests/system/Publisher/PublisherInputTest.php @@ -35,219 +35,13 @@ public static function setUpBeforeClass(): void //-------------------------------------------------------------------- - public function testAddFile() - { - $publisher = new Publisher(); - $this->assertSame([], $this->getPrivateProperty($publisher, 'files')); - - $publisher->addFile($this->file); - $this->assertSame([$this->file], $this->getPrivateProperty($publisher, 'files')); - } - - public function testAddFileMissing() - { - $publisher = new Publisher(); - - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.expectedFile', ['addFile'])); - - $publisher->addFile('TheHillsAreAlive.bmp'); - } - - public function testAddFileDirectory() - { - $publisher = new Publisher(); - - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.expectedFile', ['addFile'])); - - $publisher->addFile($this->directory); - } - - public function testAddFiles() - { - $publisher = new Publisher(); - $files = [ - $this->file, - $this->file, - ]; - - $publisher->addFiles($files); - $this->assertSame($files, $this->getPrivateProperty($publisher, 'files')); - } - - //-------------------------------------------------------------------- - - public function testGetFiles() - { - $publisher = new Publisher(); - $publisher->addFile($this->file); - - $this->assertSame([$this->file], $publisher->getFiles()); - } - - public function testGetFilesSorts() - { - $publisher = new Publisher(); - $files = [ - $this->file, - $this->directory . 'apple.php', - ]; - - $publisher->addFiles($files); - - $this->assertSame(array_reverse($files), $publisher->getFiles()); - } - - public function testGetFilesUniques() - { - $publisher = new Publisher(); - $files = [ - $this->file, - $this->file, - ]; - - $publisher->addFiles($files); - $this->assertSame([$this->file], $publisher->getFiles()); - } - - public function testSetFiles() - { - $publisher = new Publisher(); - - $publisher->setFiles([$this->file]); - $this->assertSame([$this->file], $publisher->getFiles()); - } - - public function testSetFilesInvalid() - { - $publisher = new Publisher(); - - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.expectedFile', ['addFile'])); - - $publisher->setFiles(['flerb']); - } - - //-------------------------------------------------------------------- - - public function testRemoveFile() - { - $publisher = new Publisher(); - $files = [ - $this->file, - $this->directory . 'apple.php', - ]; - - $publisher->addFiles($files); - - $publisher->removeFile($this->file); - - $this->assertSame([$this->directory . 'apple.php'], $publisher->getFiles()); - } - - public function testRemoveFiles() - { - $publisher = new Publisher(); - $files = [ - $this->file, - $this->directory . 'apple.php', - ]; - - $publisher->addFiles($files); - - $publisher->removeFiles($files); - - $this->assertSame([], $publisher->getFiles()); - } - - //-------------------------------------------------------------------- - - public function testAddDirectoryInvalid() - { - $publisher = new Publisher(); - - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.expectedDirectory', ['addDirectory'])); - - $publisher->addDirectory($this->file); - } - - public function testAddDirectory() - { - $publisher = new Publisher(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - ]; - - $publisher->addDirectory($this->directory); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testAddDirectoryRecursive() - { - $publisher = new Publisher(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testAddDirectories() - { - $publisher = new Publisher(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->addDirectories([ - $this->directory, - SUPPORTPATH . 'Files/baker', - ]); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testAddDirectoriesRecursive() - { - $publisher = new Publisher(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - SUPPORTPATH . 'Log/Handlers/TestHandler.php', - ]; - - $publisher->addDirectories([ - SUPPORTPATH . 'Files', - SUPPORTPATH . 'Log', - ], true); - - $this->assertSame($expected, $publisher->getFiles()); - } - - //-------------------------------------------------------------------- - public function testAddPathFile() { $publisher = new Publisher(SUPPORTPATH . 'Files'); $publisher->addPath('baker/banana.php'); - $this->assertSame([$this->file], $publisher->getFiles()); + $this->assertSame([$this->file], $publisher->get()); } public function testAddPathFileRecursiveDoesNothing() @@ -256,7 +50,7 @@ public function testAddPathFileRecursiveDoesNothing() $publisher->addPath('baker/banana.php', true); - $this->assertSame([$this->file], $publisher->getFiles()); + $this->assertSame([$this->file], $publisher->get()); } public function testAddPathDirectory() @@ -271,7 +65,7 @@ public function testAddPathDirectory() $publisher->addPath('able'); - $this->assertSame($expected, $publisher->getFiles()); + $this->assertSame($expected, $publisher->get()); } public function testAddPathDirectoryRecursive() @@ -287,7 +81,7 @@ public function testAddPathDirectoryRecursive() $publisher->addPath('Files'); - $this->assertSame($expected, $publisher->getFiles()); + $this->assertSame($expected, $publisher->get()); } public function testAddPaths() @@ -306,7 +100,7 @@ public function testAddPaths() 'baker/banana.php', ]); - $this->assertSame($expected, $publisher->getFiles()); + $this->assertSame($expected, $publisher->get()); } public function testAddPathsRecursive() @@ -326,7 +120,7 @@ public function testAddPathsRecursive() 'Log', ], true); - $this->assertSame($expected, $publisher->getFiles()); + $this->assertSame($expected, $publisher->get()); } //-------------------------------------------------------------------- @@ -338,7 +132,7 @@ public function testAddUri() $scratch = $this->getPrivateProperty($publisher, 'scratch'); - $this->assertSame([$scratch . 'composer.json'], $publisher->getFiles()); + $this->assertSame([$scratch . 'composer.json'], $publisher->get()); } public function testAddUris() @@ -351,122 +145,6 @@ public function testAddUris() $scratch = $this->getPrivateProperty($publisher, 'scratch'); - $this->assertSame([$scratch . 'LICENSE', $scratch . 'composer.json'], $publisher->getFiles()); - } - - //-------------------------------------------------------------------- - - public function testRemovePatternEmpty() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $files = $publisher->getFiles(); - - $publisher->removePattern(''); - - $this->assertSame($files, $publisher->getFiles()); - } - - public function testRemovePatternRegex() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $expected = [ - $this->directory . 'apple.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->removePattern('#[a-z]+_.*#'); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testRemovePatternPseudo() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $expected = [ - $this->directory . 'apple.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->removePattern('*_*.php'); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testRemovePatternScope() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $expected = [ - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->removePattern('*.php', $this->directory); - - $this->assertSame($expected, $publisher->getFiles()); - } - - //-------------------------------------------------------------------- - - public function testRetainPatternEmpty() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $files = $publisher->getFiles(); - - $publisher->retainPattern(''); - - $this->assertSame($files, $publisher->getFiles()); - } - - public function testRetainPatternRegex() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $expected = [ - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - ]; - - $publisher->retainPattern('#[a-z]+_.*#'); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testRetainPatternPseudo() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $expected = [ - $this->directory . 'fig_3.php', - ]; - - $publisher->retainPattern('*_?.php'); - - $this->assertSame($expected, $publisher->getFiles()); - } - - public function testRetainPatternScope() - { - $publisher = new Publisher(); - $publisher->addDirectory(SUPPORTPATH . 'Files', true); - - $expected = [ - $this->directory . 'fig_3.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->retainPattern('*_?.php', $this->directory); - - $this->assertSame($expected, $publisher->getFiles()); + $this->assertSame([$scratch . 'LICENSE', $scratch . 'composer.json'], $publisher->get()); } } diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index 42f22d721525..081b831f1241 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -53,75 +53,11 @@ public function testDiscoverNothing() public function testDiscoverStores() { $publisher = Publisher::discover()[0]; - $publisher->setFiles([])->addFile($this->file); + $publisher->set([])->addFile($this->file); $result = Publisher::discover(); $this->assertSame($publisher, $result[0]); - $this->assertSame([$this->file], $result[0]->getFiles()); - } - - //-------------------------------------------------------------------- - - public function testResolveDirectoryDirectory() - { - $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveDirectory'); - - $this->assertSame($this->directory, $method($this->directory)); - } - - public function testResolveDirectoryFile() - { - $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveDirectory'); - - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.expectedDirectory', ['invokeArgs'])); - - $method($this->file); - } - - public function testResolveDirectorySymlink() - { - // Create a symlink to test - $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); - symlink($this->directory, $link); - - $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveDirectory'); - - $this->assertSame($this->directory, $method($link)); - - unlink($link); - } - - //-------------------------------------------------------------------- - - public function testResolveFileFile() - { - $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveFile'); - - $this->assertSame($this->file, $method($this->file)); - } - - public function testResolveFileSymlink() - { - // Create a symlink to test - $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); - symlink($this->file, $link); - - $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveFile'); - - $this->assertSame($this->file, $method($link)); - - unlink($link); - } - - public function testResolveFileDirectory() - { - $method = $this->getPrivateMethodInvoker(Publisher::class, 'resolveFile'); - - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.expectedFile', ['invokeArgs'])); - - $method($this->directory); + $this->assertSame([$this->file], $result[0]->get()); } //-------------------------------------------------------------------- diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index 9b29767d4d19..ad2c8671a4d5 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -107,3 +107,99 @@ The move() method returns a new File instance that for the relocated file, so yo resulting location is needed:: $file = $file->move(WRITEPATH.'uploads'); + +**************** +File Collections +**************** + +Working with groups of files can be cumbersome, so the framework supplies the ``FileCollection`` class to facilitate +locating and working with groups of files across the filesystem. At its most basic, ``FileCollection`` is an index +of files you set or build:: + + $files = new FileCollection([ + FCPATH . 'index.php', + ROOTPATH . 'spark', + ]); + $files->addDirectory(APPPATH . 'Filters'); + +After you have input the files you would like to work with you may remove files or use the filtering commands to remove +or retain files matching a certain regex or glob-style pattern:: + + $files->removeFile(APPPATH . 'Filters/DevelopToolbar'); + + $files->removePattern('#\.gitkeep#'); + $files->retainPattern('*.php'); + +When your collection is complete, you can use ``get()`` to retrieve the final list of file paths, or take advantage of +``FileCollection`` being countable and iterable to work directly with each ``File``:: + + echo 'My files: ' . implode(PHP_EOL, $files->get()); + echo 'I have ' . count($files) . ' files!'; + + foreach ($files as $file) + { + echo 'Moving ' . $file->getBasename() . ', ' . $file->getSizeByUnit('mb'); + $file->move(WRITABLE . $file->getRandomName()); + } + +Below are the specific methods for working with a ``FileCollection``. + +Inputting Files +=============== + +**set(array $files)** + +Sets the list of input files to the provided string array of file paths. + +**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. + +**addFile(string $file)** +**addFiles(array $files)** + +Adds the file or files to the current list of input files. Files are absolute paths to actual files. + +**removeFile(string $file)** +**removeFiles(array $files)** + +Removes the file or files from the current list of input files. + +**addDirectory(string $directory, bool $recursive = false)** +**addDirectories(array $directories, bool $recursive = false)** + +Adds all files from the directory or directories, optionally recursing into sub-directories. Directories are +absolute paths to actual directories. + +Filtering Files +=============== + +**removePattern(string $pattern, string $scope = null)** +**retainPattern(string $pattern, string $scope = null)** + +Filters the current file list through the pattern (and optional scope), removing or retaining matched +files. ``$pattern`` may be a complete regex (like ``'#[A-Za-z]+\.php#'``) or a pseudo-regex similar +to ``glob()`` (like ``*.css``). +If a ``$scope`` is provided then only files in or under that directory will be considered (i.e. files +outside of ``$scope`` are always retained). When no scope is provided then all files are subject. + +Examples:: + + $files = new FileCollection(); + $files->add(APPPATH . 'Config', true); // Adds all Config files and directories + + $files->removePattern('*tion.php'); // Would remove Encryption.php, Validation.php, and boot/production.php + $files->removePattern('*tion.php', APPPATH . 'Config/boot'); // Would only remove boot/production.php + + $files->retainPattern('#A.+php$#'); // Would keep only Autoload.php + $files->retainPattern('#d.+php$#', APPPATH . 'Config/boot'); // Would keep everything but boot/production.php and boot/testing.php + +Retrieving Files +================ + +**get(): string[]** + +Returns an array of all the loaded input files. + +.. note:: ``FileCollection`` is an ``IteratorAggregate`` so you can work with it directly (e.g. ``foreach ($collection as $file)``). diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 84b430ba144b..dc2ec08347a8 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -28,8 +28,8 @@ Concept and Usage * How can I update my project when the framework or modules change? * How can components inject new content into existing projects? -At its most basic, publishing amounts to copying a file or files into a project. ``Publisher`` uses fluent-style -command chaining to read, filter, and process input files, then copies or merges them into the target destination. +At its most basic, publishing amounts to copying a file or files into a project. ``Publisher`` extends ``FileCollection`` +to enact fluent-style command chaining to read, filter, and process input files, then copies or merges them into the target destination. You may use ``Publisher`` on demand in your Controllers or other components, or you may stage publications by extending the class and leveraging its discovery with ``spark publish``. @@ -320,6 +320,8 @@ Now when your module users run ``php spark auth:publish`` they will have the fol Library Reference ***************** +.. note:: ``Publisher`` is an extension of :doc:`FileCollection ` so has access to all those methods for reading and filtering files. + Support Methods =============== @@ -346,33 +348,6 @@ files and changes, and this provides the path to a transient, writable directory Returns any errors from the last write operation. The array keys are the files that caused the error, and the values are the Throwable that was caught. Use ``getMessage()`` on the Throwable to get the error message. -**getFiles(): string[]** - -Returns an array of all the loaded input files. - -Inputting Files -=============== - -**setFiles(array $files)** - -Sets the list of input files to the provided string array of file paths. - -**addFile(string $file)** -**addFiles(array $files)** - -Adds the file or files to the current list of input files. Files are absolute paths to actual files. - -**removeFile(string $file)** -**removeFiles(array $files)** - -Removes the file or files from the current list of input files. - -**addDirectory(string $directory, bool $recursive = false)** -**addDirectories(array $directories, bool $recursive = false)** - -Adds all files from the directory or directories, optionally recursing into sub-directories. Directories are -absolute paths to actual directories. - **addPath(string $path, bool $recursive = true)** **addPaths(array $path, bool $recursive = true)** @@ -388,29 +363,6 @@ file to the list. .. note:: The CURL request made is a simple ``GET`` and uses the response body for the file contents. Some remote files may need a custom request to be handled properly. -Filtering Files -=============== - -**removePattern(string $pattern, string $scope = null)** -**retainPattern(string $pattern, string $scope = null)** - -Filters the current file list through the pattern (and optional scope), removing or retaining matched -files. ``$pattern`` may be a complete regex (like ``'#[A-Za-z]+\.php#'``) or a pseudo-regex similar -to ``glob()`` (like ``*.css``). -If a ``$scope`` is provided then only files in or under that directory will be considered (i.e. files -outside of ``$scope`` are always retained). When no scope is provided then all files are subject. - -Examples:: - - $publisher = new Publisher(APPPATH . 'Config'); - $publisher->addPath('/', true); // Adds all Config files and directories - - $publisher->removePattern('*tion.php'); // Would remove Encryption.php, Validation.php, and boot/production.php - $publisher->removePattern('*tion.php', APPPATH . 'Config/boot'); // Would only remove boot/production.php - - $publisher->retainPattern('#A.+php$#'); // Would keep only Autoload.php - $publisher->retainPattern('#d.+php$#', APPPATH . 'Config/boot'); // Would keep everything but boot/production.php and boot/testing.php - Outputting Files ================ From 7ace2ccab301c91697ba1258ad40d1a955698c93 Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 15 Jun 2021 13:29:46 +0000 Subject: [PATCH 0183/2325] Implement define() --- system/Files/FileCollection.php | 14 ++++++++-- tests/system/Files/FileCollectionTest.php | 32 +++++++++++++++++++++++ user_guide_src/source/libraries/files.rst | 31 +++++++++++++++++++--- 3 files changed, 72 insertions(+), 5 deletions(-) diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index bf4eeaf6b836..fcf2451d357d 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -122,7 +122,7 @@ protected static function matchFiles(array $files, string $pattern): array //-------------------------------------------------------------------- /** - * Loads the Filesystem helper and stores initial files. + * Loads the Filesystem helper and adds any initial files. * * @param string[] $files */ @@ -130,7 +130,17 @@ public function __construct(array $files = []) { helper(['filesystem']); - $this->set($files); + $this->add($files)->define(); + } + + /** + * Applies any initial inputs after the constructor. + * This method is a stub to be implemented by child classes. + * + * @return void + */ + protected function define(): void + { } /** diff --git a/tests/system/Files/FileCollectionTest.php b/tests/system/Files/FileCollectionTest.php index 3e77941d5d2f..a650bc464b01 100644 --- a/tests/system/Files/FileCollectionTest.php +++ b/tests/system/Files/FileCollectionTest.php @@ -99,6 +99,38 @@ public function testResolveFileDirectory() //-------------------------------------------------------------------- + public function testConstructorAddsFiles() + { + $expected = [ + $this->directory . 'apple.php', + $this->file, + ]; + + $collection = new class([$this->file]) extends FileCollection { + + protected $files = [ + SUPPORTPATH . 'Files/able/apple.php', + ]; + }; + + $this->assertSame($expected, $collection->get()); + } + + public function testConstructorCallsDefine() + { + $collection = new class([$this->file]) extends FileCollection { + + protected function define(): void + { + $this->add(SUPPORTPATH . 'Files/baker/banana.php'); + } + }; + + $this->assertSame([$this->file], $collection->get()); + } + + //-------------------------------------------------------------------- + public function testAddStringFile() { $files = new FileCollection(); diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index ad2c8671a4d5..68950b9a3d5f 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -144,12 +144,37 @@ When your collection is complete, you can use ``get()`` to retrieve the final li Below are the specific methods for working with a ``FileCollection``. -Inputting Files -=============== +Starting a Collection +===================== + +**__construct(string[] $files = [])** + +The constructor accepts an optional array of file paths to use as the initial collection. These are passed to +**add()** so any files supplied by child classes in the **$files** will remain. + +**define()** + +Allows child classes to define their own initial files. This method is called by the constructor and allows +predefined collections without having to use their methods. Example:: + + class ConfigCollection extends \CodeIgniter\Files\FileCollection + { + protected function define(): void { + + $this->add(APPPATH . 'Config', true)->retainPattern('*.php'); + } + } + +Now you may use the ``ConfigCollection`` anywhere in your project to access all App Config files without +having to re-call the collection methods every time. **set(array $files)** -Sets the list of input files to the provided string array of file paths. +Sets the list of input files to the provided string array of file paths. This will remove any existing +files from the collection, so ``$collection->set([])`` is essentially a hard reset. + +Inputting Files +=============== **add(string[]|string $paths, bool $recursive = true)** From e19f3928f3d43c03d3cf63b47b1bb4b33a5aa1ae Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 15 Jun 2021 13:43:37 +0000 Subject: [PATCH 0184/2325] Declare final methods --- system/Files/FileCollection.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index fcf2451d357d..f7e7c67324c7 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -45,7 +45,7 @@ class FileCollection implements Countable, IteratorAggregate * * @throws FileException */ - protected static function resolveDirectory(string $directory): string + final protected static function resolveDirectory(string $directory): string { if (! is_dir($directory = set_realpath($directory))) { @@ -65,7 +65,7 @@ protected static function resolveDirectory(string $directory): string * * @throws FileException */ - protected static function resolveFile(string $file): string + final protected static function resolveFile(string $file): string { if (! is_file($file = set_realpath($file))) { @@ -84,7 +84,7 @@ protected static function resolveFile(string $file): string * * @return string[] */ - protected static function filterFiles(array $files, string $directory): array + final protected static function filterFiles(array $files, string $directory): array { $directory = self::resolveDirectory($directory); @@ -101,7 +101,7 @@ protected static function filterFiles(array $files, string $directory): array * * @return string[] */ - protected static function matchFiles(array $files, string $pattern): array + final protected static function matchFiles(array $files, string $pattern): array { // Convert pseudo-regex into their true form if (@preg_match($pattern, null) === false) // @phpstan-ignore-line From 096b5bdd5f11a69f35c35010f89cc77182c2c294 Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 15 Jun 2021 11:12:53 -0400 Subject: [PATCH 0185/2325] Apply suggestions from code review Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/Files/FileCollection.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index f7e7c67324c7..4231c5776642 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -88,7 +88,7 @@ final protected static function filterFiles(array $files, string $directory): ar { $directory = self::resolveDirectory($directory); - return array_filter($files, function ($value) use ($directory) { + return array_filter($files, static function (string $value) use ($directory): bool { return strpos($value, $directory) === 0; }); } @@ -114,7 +114,7 @@ final protected static function matchFiles(array $files, string $pattern): array $pattern = "#{$pattern}#"; } - return array_filter($files, function ($value) use ($pattern) { + return array_filter($files, static function ($value) use ($pattern) { return (bool) preg_match($pattern, basename($value)); }); } @@ -150,7 +150,7 @@ protected function define(): void */ public function get(): array { - $this->files = array_unique($this->files, SORT_STRING); + $this->files = array_unique($this->files); sort($this->files, SORT_STRING); return $this->files; From d1408104b967840efd4b2e889f1570bcf71630e2 Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 23 Jun 2021 13:47:27 +0000 Subject: [PATCH 0186/2325] Implement review suggestions --- system/Files/FileCollection.php | 14 +++++++++++++- system/Publisher/Publisher.php | 14 ++++++++++---- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index 4231c5776642..cc11cf8a7962 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -34,6 +34,8 @@ class FileCollection implements Countable, IteratorAggregate */ protected $files = []; + //-------------------------------------------------------------------- + // Support Methods //-------------------------------------------------------------------- /** @@ -104,7 +106,7 @@ final protected static function filterFiles(array $files, string $directory): ar final protected static function matchFiles(array $files, string $pattern): array { // Convert pseudo-regex into their true form - if (@preg_match($pattern, null) === false) // @phpstan-ignore-line + if (@preg_match($pattern, '') === false) { $pattern = str_replace( ['#', '.', '*', '?'], @@ -119,6 +121,8 @@ final protected static function matchFiles(array $files, string $pattern): array }); } + //-------------------------------------------------------------------- + // Class Core //-------------------------------------------------------------------- /** @@ -209,6 +213,8 @@ public function add($paths, bool $recursive = true) return $this; } + //-------------------------------------------------------------------- + // File Handling //-------------------------------------------------------------------- /** @@ -268,6 +274,8 @@ public function removeFile(string $file) return $this->removeFiles([$file]); } + //-------------------------------------------------------------------- + // Directory Handling //-------------------------------------------------------------------- /** @@ -317,6 +325,8 @@ public function addDirectory(string $directory, bool $recursive = false) return $this; } + //-------------------------------------------------------------------- + // Filtering //-------------------------------------------------------------------- /** @@ -366,6 +376,8 @@ public function retainPattern(string $pattern, string $scope = null) } //-------------------------------------------------------------------- + // Interface Methods + //-------------------------------------------------------------------- /** * Returns the current number of files in the collection. diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 1f28bc331baf..ab4484cdea0b 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -87,6 +87,8 @@ class Publisher extends FileCollection */ protected $destination = FCPATH; + //-------------------------------------------------------------------- + // Support Methods //-------------------------------------------------------------------- /** @@ -154,6 +156,8 @@ private static function wipeDirectory(string $directory): void } } + //-------------------------------------------------------------------- + // Class Core //-------------------------------------------------------------------- /** @@ -217,6 +221,8 @@ public function publish(): bool return $this->addPath('/')->merge(true); } + //-------------------------------------------------------------------- + // Property Accessors //-------------------------------------------------------------------- /** @@ -275,6 +281,8 @@ final public function getPublished(): array return $this->published; } + //-------------------------------------------------------------------- + // Additional Handlers //-------------------------------------------------------------------- /** @@ -310,8 +318,6 @@ final public function addPath(string $path, bool $recursive = true) return $this; } - //-------------------------------------------------------------------- - /** * Downloads and stages files from an array of URIs. * @@ -347,6 +353,8 @@ final public function addUri(string $uri) return $this->addFile($file); } + //-------------------------------------------------------------------- + // Write Methods //-------------------------------------------------------------------- /** @@ -361,8 +369,6 @@ final public function wipe() return $this; } - //-------------------------------------------------------------------- - /** * Copies all files into the destination, does not create directory structure. * From a6d10631092a066d1965afebb9bcb316f842abb7 Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 24 Jun 2021 07:57:49 -0400 Subject: [PATCH 0187/2325] Update system/Files/FileCollection.php Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/Files/FileCollection.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index cc11cf8a7962..128d884940d5 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -185,10 +185,7 @@ public function set(array $files) */ public function add($paths, bool $recursive = true) { - if (! is_array($paths)) - { - $paths = [$paths]; - } + $paths = (array) $paths; foreach ($paths as $path) { From 28bf8467495d9d66eace5bd647bb120b625af53c Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 24 Jun 2021 07:58:26 -0400 Subject: [PATCH 0188/2325] Update user_guide_src/source/libraries/files.rst Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/libraries/files.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index 68950b9a3d5f..ba52138052f5 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -159,8 +159,8 @@ predefined collections without having to use their methods. Example:: class ConfigCollection extends \CodeIgniter\Files\FileCollection { - protected function define(): void { - + protected function define(): void + { $this->add(APPPATH . 'Config', true)->retainPattern('*.php'); } } From 8d5aca773b88ecf818310aeda4462dc544d7189f Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 24 Jun 2021 07:59:38 -0400 Subject: [PATCH 0189/2325] Update tests/system/Files/FileCollectionTest.php --- tests/system/Files/FileCollectionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Files/FileCollectionTest.php b/tests/system/Files/FileCollectionTest.php index a650bc464b01..ae2df9178f5f 100644 --- a/tests/system/Files/FileCollectionTest.php +++ b/tests/system/Files/FileCollectionTest.php @@ -118,7 +118,7 @@ public function testConstructorAddsFiles() public function testConstructorCallsDefine() { - $collection = new class([$this->file]) extends FileCollection { + $collection = new class() extends FileCollection { protected function define(): void { From 22aa7d22d421cb78ab6683de1fa14c5e2e79960a Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 27 Jun 2021 07:42:27 +0200 Subject: [PATCH 0190/2325] Update docblock for redirect function [ci skip] --- system/Common.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/Common.php b/system/Common.php index 4dfcd2cee170..bacac6ac0e4b 100644 --- a/system/Common.php +++ b/system/Common.php @@ -811,9 +811,7 @@ function old(string $key, $default = null, $escape = 'html') /** * Convenience method that works with the current global $request and * $router instances to redirect using named/reverse-routed routes - * to determine the URL to go to. If nothing is found, will treat - * as a traditional redirect and pass the string in, letting - * $response->redirect() determine the correct method and code. + * to determine the URL to go to. * * If more control is needed, you must use $response->redirect explicitly. * From bde51819f3797727ad24d8c0c47078c17787a829 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 27 Jun 2021 08:30:52 +0200 Subject: [PATCH 0191/2325] Fix mysqli ssl connection - certificate is not required to establish a secure connection --- system/Database/MySQLi/Connection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 78652c25b3f3..965d539be878 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -156,7 +156,6 @@ public function connect(bool $persistent = false) } } - $clientFlags += MYSQLI_CLIENT_SSL; $this->mysqli->ssl_set( $ssl['key'] ?? null, $ssl['cert'] ?? null, @@ -165,6 +164,8 @@ public function connect(bool $persistent = false) $ssl['cipher'] ?? null ); } + + $clientFlags += MYSQLI_CLIENT_SSL; } try { From 1db19c952676aa772ab50670aea967484ec6a6f9 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Jun 2021 09:02:59 +0200 Subject: [PATCH 0192/2325] Structure debug toolbar timeline with collapsible elements. --- system/Debug/Toolbar.php | 92 +++++++++++++++++++++++--- system/Debug/Toolbar/Views/toolbar.css | 25 ++++++- system/Debug/Toolbar/Views/toolbar.js | 22 ++++++ 3 files changed, 127 insertions(+), 12 deletions(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 32e1f951a3df..6a5ece61a373 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -149,7 +149,7 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques $data['vars']['response'] = [ 'statusCode' => $response->getStatusCode(), - 'reason' => esc($response->getReason()), + 'reason' => esc($response->getReasonPhrase()), 'contentType' => esc($response->getHeaderLine('content-type')), ]; @@ -166,17 +166,38 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques * Called within the view to display the timeline itself. */ protected function renderTimeline(array $collectors, float $startTime, int $segmentCount, int $segmentDuration, array &$styles): string + { + $rows = $this->collectTimelineData($collectors); + $output = ''; + $styleCount = 0; + + // Use recursive render function + return $this->renderTimelineRecursive($rows, $startTime, $segmentCount, $segmentDuration, $styles, $styleCount); + } + + /** + * Recursively renders timeline elements and their children. + */ + protected function renderTimelineRecursive(array $rows, float $startTime, int $segmentCount, int $segmentDuration, array &$styles, int &$styleCount, int $level = 0, bool $isChild = false): string { $displayTime = $segmentCount * $segmentDuration; - $rows = $this->collectTimelineData($collectors); - $output = ''; - $styleCount = 0; + + $output = ''; foreach ($rows as $row) { - $output .= '

'; - $output .= ""; - $output .= ""; - $output .= "'; + $hasChildren = isset($row['children']) && ! empty($row['children']); + + $open = $row['name'] === 'Controller'; + + if ($hasChildren) { + $output .= ''; + } else { + $output .= ''; + } + + $output .= ''; + $output .= ''; + $output .= ''; $output .= "'; $styleCount++; + + // Add children if any + if ($hasChildren) { + $output .= ''; + $output .= ''; + $output .= ''; + } } return $output; @@ -214,15 +248,51 @@ protected function collectTimelineData($collectors): array // Sort it $sortArray = [ - array_column($data, 'start'), SORT_NUMERIC, SORT_ASC, - array_column($data, 'duration'), SORT_NUMERIC, SORT_DESC, - &$data + array_column($data, 'start'), SORT_NUMERIC, SORT_ASC, + array_column($data, 'duration'), SORT_NUMERIC, SORT_DESC, + &$data, ]; + array_multisort(...$sortArray); + // Add end time to each element + array_walk($data, static function (&$row) { + $row['end'] = $row['start'] + $row['duration']; + }); + + // Group it + $data = $this->structureTimelineData($data); + return $data; } + /** + * Arranges the already sorted timeline data into a parent => child structure. + */ + protected function structureTimelineData(array $elements): array + { + // We define ourselves as the first element of the array + $element = array_shift($elements); + + // If we have children behind us, collect and attach them to us + while (! empty($elements) && $elements[array_key_first($elements)]['end'] <= $element['end']) { + $element['children'][] = array_shift($elements); + } + + // Make sure our children know whether they have children, too + if (isset($element['children'])) { + $element['children'] = $this->structureTimelineData($element['children']); + } + + // If we have no younger siblings, we can return + if (empty($elements)) { + return [$element]; + } + + // Make sure our younger siblings know their relatives, too + return array_merge([$element], $this->structureTimelineData($elements)); + } + /** * Returns an array of data from all of the modules * that should be displayed in the 'Vars' tab. diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index f881dd18d6ec..bc8b4ac44ef7 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -186,6 +186,22 @@ #debug-bar .timeline { margin-left: 0; width: 100%; } + #debug-bar .timeline tr.timeline-parent { + cursor: pointer; } + #debug-bar .timeline tr.timeline-parent td:first-child nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; } + #debug-bar .timeline tr.timeline-parent.timeline-parent-open td:first-child nav { + background-position: 0 75%; } + #debug-bar .timeline tr.timeline-parent.timeline-parent-open { + background-color: #DFDFDF; } + #debug-bar .timeline tr.child-row:hover { + background: transparent; } #debug-bar .timeline th { border-left: 1px solid; font-size: 12px; @@ -200,7 +216,14 @@ padding: 5px; position: relative; } #debug-bar .timeline td:first-child { - border-left: 0; } + border-left: 0; + max-width: none; } + #debug-bar .timeline td.child-container { + padding: 0px; } + #debug-bar .timeline td.child-container .timeline{ + margin: 0px; } + #debug-bar .timeline td.child-container td:first-child:not(.child-container){ + padding-left: calc(5px + 10px * var(--level)); } #debug-bar .timeline .timer { border-radius: 4px; -moz-border-radius: 4px; diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index 563cf21cd682..690535f2de0d 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -141,6 +141,28 @@ var ciDebugBar = { } }, + /** + * Toggle display of timeline child elements + * + * @param obj + */ + toggleChildRows : function (obj) { + if (typeof obj == 'string') + { + par = document.getElementById(obj + '_parent') + obj = document.getElementById(obj + '_children'); + } + + if (par && obj) + { + obj.style.display = obj.style.display == 'none' ? '' : 'none'; + par.classList.toggle('timeline-parent-open'); + } + }, + + + //-------------------------------------------------------------------- + /** * Toggle tool bar from full to icon and icon to full */ From bd15c27f935c8704cb4b9a74bdeb50ec51c4bf9d Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Tue, 29 Jun 2021 23:28:18 -0500 Subject: [PATCH 0193/2325] Updated Query Build custom string option for where to remove make it clear the values do not get escaped. --- user_guide_src/source/database/queries.rst | 1 + user_guide_src/source/database/query_builder.rst | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/database/queries.rst b/user_guide_src/source/database/queries.rst index 366b264cc45c..af15bacea038 100644 --- a/user_guide_src/source/database/queries.rst +++ b/user_guide_src/source/database/queries.rst @@ -15,6 +15,7 @@ Regular Queries To submit a query, use the **query** function:: + $db = db_connect(); $db->query('YOUR QUERY HERE'); The ``query()`` function returns a database result **object** when "read" diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 78c1b3731fd5..342da67461e3 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -244,7 +244,10 @@ This function enables you to set **WHERE** clauses using one of four methods: .. note:: All values passed to this function are escaped automatically, - producing safer queries. + producing safer queries, except when using a custom string. + +.. note:: ``$builder->where()`` accepts an optional third parameter. If you set it to + ``false``, CodeIgniter will not try to protect your field or table names. #. **Simple key/value method:** @@ -294,15 +297,18 @@ methods: #. **Custom string:** You can write your own clauses manually:: + $where = "name='Joe' AND status='boss' OR status='active'"; $builder->where($where); - ``$builder->where()`` accepts an optional third parameter. If you set it to - ``false``, CodeIgniter will not try to protect your field or table names. + If you are using user-supplied data within the string, you MUST escape the + data manually. Failure to do so could result in SQL injections. +:: - :: + $name = $builder->db->escape('Joe'); + $where = "name={$name} AND status='boss' OR status='active'"; + $builder->where($where); - $builder->where('MATCH (field) AGAINST ("value")', null, false); #. **Subqueries:** You can use an anonymous function to create a subquery. From 61c01ed40bc3231c61033f31134b8f4f1581cc22 Mon Sep 17 00:00:00 2001 From: Ferenc Date: Fri, 2 Jul 2021 19:13:54 +0100 Subject: [PATCH 0194/2325] Finalize SQLSRV schema support for 4.2 --- system/Database/SQLSRV/Builder.php | 98 +++++++++++++++++-- system/Database/SQLSRV/Connection.php | 2 +- system/Database/SQLSRV/Forge.php | 92 +++++++++++++---- system/Database/SQLSRV/Utils.php | 8 ++ .../Database/Live/PreparedQueryTest.php | 6 +- .../Migrations/MigrationRunnerTest.php | 5 +- 6 files changed, 181 insertions(+), 30 deletions(-) diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index cda4fac8a825..d4fe5a85b540 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -170,6 +170,16 @@ protected function _insert(string $table, array $keys, array $unescapedKeys): st return $this->keyPermission ? $this->addIdentity($fullTableName, $statement) : $statement; } + /** + * Insert batch statement + * + * Generates a platform-specific insert string from the supplied data. + */ + protected function _insertBatch(string $table, array $keys, array $values): string + { + return 'INSERT ' . $this->compileIgnore('insert') . 'INTO ' . $this->getFullName($table) . ' (' . implode(', ', $keys) . ') VALUES ' . implode(', ', $values); + } + /** * Generates a platform-specific update string from the supplied data */ @@ -183,12 +193,48 @@ protected function _update(string $table, array $values): string $fullTableName = $this->getFullName($table); - $statement = 'UPDATE ' . (empty($this->QBLimit) ? '' : 'TOP(' . $this->QBLimit . ') ') . $fullTableName . ' SET ' - . implode(', ', $valstr) . $this->compileWhereHaving('QBWhere') . $this->compileOrderBy(); + $statement = sprintf('UPDATE %s%s SET ', empty($this->QBLimit) ? '' : 'TOP(' . $this->QBLimit . ') ', $fullTableName); + + $statement .= implode(', ', $valstr) + . $this->compileWhereHaving('QBWhere') + . $this->compileOrderBy(); return $this->keyPermission ? $this->addIdentity($fullTableName, $statement) : $statement; } + /** + * Update_Batch statement + * + * Generates a platform-specific batch update string from the supplied data + */ + protected function _updateBatch(string $table, array $values, string $index): string + { + $ids = []; + $final = []; + + foreach ($values as $val) { + $ids[] = $val[$index]; + + foreach (array_keys($val) as $field) { + if ($field !== $index) { + $final[$field][] = 'WHEN ' . $index . ' = ' . $val[$index] . ' THEN ' . $val[$field]; + } + } + } + + $cases = ''; + + foreach ($final as $k => $v) { + $cases .= $k . " = CASE \n" + . implode("\n", $v) . "\n" + . 'ELSE ' . $k . ' END, '; + } + + $this->where($index . ' IN(' . implode(',', $ids) . ')', null, false); + + return 'UPDATE ' . $this->compileIgnore('update') . ' ' . $this->getFullName($table) . ' SET ' . substr($cases, 0, -2) . $this->compileWhereHaving('QBWhere'); + } + /** * Increments a numeric column by the specified value. * @@ -203,6 +249,7 @@ public function increment(string $column, int $value = 1) } else { $values = [$column => "{$column} + {$value}"]; } + $sql = $this->_update($this->QBFrom[0], $values); return $this->db->query($sql, $this->binds, false); @@ -222,6 +269,7 @@ public function decrement(string $column, int $value = 1) } else { $values = [$column => "{$column} + {$value}"]; } + $sql = $this->_update($this->QBFrom[0], $values); return $this->db->query($sql, $this->binds, false); @@ -304,9 +352,10 @@ public function replace(?array $set = null) return $sql; } - $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->db->escapeIdentifiers($table) . ' ON'); + $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->getFullName($table) . ' ON'); + $result = $this->db->query($sql, $this->binds, false); - $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->db->escapeIdentifiers($table) . ' OFF'); + $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->getFullName($table) . ' OFF'); return $result; } @@ -410,6 +459,40 @@ protected function maxMinAvgSum(string $select = '', string $alias = '', string return $this; } + /** + * "Count All" query + * + * Generates a platform-specific query string that counts all records in + * the particular table + * + * @param bool $reset Are we want to clear query builder values? + * + * @return int|string when $test = true + */ + public function countAll(bool $reset = true) + { + $table = $this->QBFrom[0]; + + $sql = $this->countString . $this->db->escapeIdentifiers('numrows') . ' FROM ' . $this->getFullName($table); + + if ($this->testMode) { + return $sql; + } + + $query = $this->db->query($sql, null, false); + if (empty($query->getResult())) { + return 0; + } + + $query = $query->getRow(); + + if ($reset === true) { + $this->resetSelect(); + } + + return (int) $query->numrows; + } + /** * Delete statement */ @@ -504,9 +587,10 @@ protected function compileSelect($selectOverride = false): string } $sql .= $this->compileWhereHaving('QBWhere') - . $this->compileGroupBy() - . $this->compileWhereHaving('QBHaving') - . $this->compileOrderBy(); // ORDER BY + . $this->compileGroupBy() + . $this->compileWhereHaving('QBHaving') + . $this->compileOrderBy(); // ORDER BY + // LIMIT if ($this->QBLimit) { $sql = $this->_limit($sql . "\n"); diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index f09a96d69213..3c86839d2e88 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -215,7 +215,7 @@ protected function _listColumns(string $table = ''): string */ protected function _indexData(string $table): array { - $sql = 'EXEC sp_helpindex ' . $this->escape($table); + $sql = 'EXEC sp_helpindex ' . $this->escape($this->schema . '.' . $table); if (($query = $this->query($sql)) === false) { throw new DatabaseException(lang('Database.failGetIndexData')); diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index 43131698703f..aa646ccf2d6f 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Database\SQLSRV; +use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\Forge as BaseForge; /** @@ -23,7 +24,7 @@ class Forge extends BaseForge * * @var string */ - protected $dropConstraintStr = 'ALTER TABLE %s DROP CONSTRAINT %s'; + protected $dropConstraintStr; /** * CREATE DATABASE IF statement @@ -61,7 +62,7 @@ class Forge extends BaseForge * * @var string */ - protected $renameTableStr = 'EXEC sp_rename %s , %s ;'; + protected $renameTableStr; /** * UNSIGNED support @@ -80,21 +81,32 @@ class Forge extends BaseForge * * @var string */ - protected $createTableIfStr = "IF NOT EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nCREATE TABLE"; + protected $createTableIfStr; /** * CREATE TABLE statement * * @var string */ - protected $createTableStr = "%s %s (%s\n) "; + protected $createTableStr; - /** - * DROP TABLE IF statement - * - * @var string - */ - protected $_drop_table_if = "IF EXISTS (SELECT * FROM sysobjects WHERE ID = object_id(N'%s') AND OBJECTPROPERTY(id, N'IsUserTable') = 1)\nDROP TABLE"; + public function __construct(BaseConnection $db) + { + parent::__construct($db); + + $this->createTableIfStr = 'IF NOT EXISTS' + . '(SELECT t.name, s.name as schema_name, t.type_desc ' + . 'FROM sys.tables t ' + . 'INNER JOIN sys.schemas s on s.schema_id = t.schema_id ' + . "WHERE s.name=N'" . $this->db->schema . "' " + . "AND t.name=REPLACE(N'%s', '\"', '') " + . "AND t.type_desc='USER_TABLE')\nCREATE TABLE "; + + $this->createTableStr = '%s ' . $this->db->escapeIdentifiers($this->db->schema) . ".%s (%s\n) "; + $this->renameTableStr = 'EXEC sp_rename [' . $this->db->escapeIdentifiers($this->db->schema) . '.%s] , %s ;'; + + $this->dropConstraintStr = 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->schema) . '.%s DROP CONSTRAINT %s'; + } /** * CREATE TABLE attributes @@ -111,9 +123,6 @@ protected function _createTableAttributes(array $attributes): string */ protected function _alterTable(string $alterType, string $table, $field) { - if ($alterType === 'ADD') { - return parent::_alterTable($alterType, $table, $field); - } // Handle DROP here if ($alterType === 'DROP') { @@ -133,7 +142,7 @@ protected function _alterTable(string $alterType, string $table, $field) } } - $sql = 'ALTER TABLE [' . $table . '] DROP '; + $sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table) . ' DROP '; $fields = array_map(static function ($item) { return 'COLUMN [' . trim($item) . ']'; @@ -142,10 +151,19 @@ protected function _alterTable(string $alterType, string $table, $field) return $sql . implode(',', $fields); } - $sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table); + $sql = 'ALTER TABLE ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table); + $sql .= ($alterType === 'ADD') ? 'ADD ' : ' '; $sqls = []; + if ($alterType === 'ADD') { + foreach ($field as $data) { + $sqls[] = $sql . ($data['_literal'] !== false ? $data['_literal'] : $this->_processColumn($data)); + } + + return $sqls; + } + foreach ($field as $data) { if ($data['_literal'] !== false) { return false; @@ -198,6 +216,46 @@ protected function _dropIndex(string $table, object $indexData) return $this->db->simpleQuery($sql); } + /** + * Process indexes + * + * @return array|string + */ + protected function _processIndexes(string $table) + { + $sqls = []; + + for ($i = 0, $c = count($this->keys); $i < $c; $i++) { + $this->keys[$i] = (array) $this->keys[$i]; + + for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) { + if (! isset($this->fields[$this->keys[$i][$i2]])) { + unset($this->keys[$i][$i2]); + } + } + + if (count($this->keys[$i]) <= 0) { + continue; + } + + if (in_array($i, $this->uniqueKeys, true)) { + $sqls[] = 'ALTER TABLE ' + . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table) + . ' ADD CONSTRAINT ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) + . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; + + continue; + } + + $sqls[] = 'CREATE INDEX ' + . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) + . ' ON ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table) + . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; + } + + return $sqls; + } + /** * Process column */ @@ -229,7 +287,7 @@ protected function _processForeignKeys(string $table): string $sql .= ",\n\t CONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) . ' FOREIGN KEY (' . $this->db->escapeIdentifiers($field) . ') ' - . ' REFERENCES ' . $this->db->escapeIdentifiers($this->db->getPrefix() . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; + . ' REFERENCES ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($this->db->getPrefix() . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { $sql .= ' ON DELETE ' . $fkey['onDelete']; @@ -245,8 +303,6 @@ protected function _processForeignKeys(string $table): string /** * Process primary keys - * - * @param string $table Table name */ protected function _processPrimaryKeys(string $table): string { diff --git a/system/Database/SQLSRV/Utils.php b/system/Database/SQLSRV/Utils.php index da4ac8679b9e..cf94d3dad783 100755 --- a/system/Database/SQLSRV/Utils.php +++ b/system/Database/SQLSRV/Utils.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Database\SQLSRV; use CodeIgniter\Database\BaseUtils; +use CodeIgniter\Database\ConnectionInterface; use CodeIgniter\Database\Exceptions\DatabaseException; /** @@ -33,6 +34,13 @@ class Utils extends BaseUtils */ protected $optimizeTable = 'ALTER INDEX all ON %s REORGANIZE'; + public function __construct(ConnectionInterface &$db) + { + parent::__construct($db); + + $this->optimizeTable = 'ALTER INDEX all ON ' . $this->db->schema . '.%s REORGANIZE'; + } + /** * Platform dependent version of the backup function. * diff --git a/tests/system/Database/Live/PreparedQueryTest.php b/tests/system/Database/Live/PreparedQueryTest.php index b71c0498f80e..06999ea93f4c 100644 --- a/tests/system/Database/Live/PreparedQueryTest.php +++ b/tests/system/Database/Live/PreparedQueryTest.php @@ -50,7 +50,7 @@ public function testPrepareReturnsPreparedQuery() if ($this->db->DBDriver === 'SQLSRV') { $database = $this->db->getDatabase(); - $expected = "INSERT INTO {$ec}{$database}{$ec}.{$ec}dbo{$ec}.{$ec}{$pre}user{$ec} ({$ec}name{$ec},{$ec}email{$ec}) VALUES ({$placeholders})"; + $expected = "INSERT INTO {$ec}{$database}{$ec}.{$ec}{$this->db->schema}{$ec}.{$ec}{$pre}user{$ec} ({$ec}name{$ec},{$ec}email{$ec}) VALUES ({$placeholders})"; } else { $expected = "INSERT INTO {$ec}{$pre}user{$ec} ({$ec}name{$ec}, {$ec}email{$ec}) VALUES ({$placeholders})"; } @@ -107,6 +107,10 @@ public function testExecuteRunsQueryAndReturnsManualResultObject() $query = $this->db->prepare(static function ($db) { $sql = "INSERT INTO {$db->DBPrefix}user (name, email, country) VALUES (?, ?, ?)"; + if ($db->DBDriver === 'SQLSRV') { + $sql = "INSERT INTO {$db->schema}.{$db->DBPrefix}user (name, email, country) VALUES (?, ?, ?)"; + } + return (new Query($db))->setQuery($sql); }); diff --git a/tests/system/Database/Migrations/MigrationRunnerTest.php b/tests/system/Database/Migrations/MigrationRunnerTest.php index 9dee57a3434e..fa867c7e1f0e 100644 --- a/tests/system/Database/Migrations/MigrationRunnerTest.php +++ b/tests/system/Database/Migrations/MigrationRunnerTest.php @@ -93,7 +93,7 @@ public function testGetHistory() ]; if ($this->db->DBDriver === 'SQLSRV') { - $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->db->prefixTable('migrations') . ' ON'); + $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->prefixTable('migrations') . ' ON'); } $this->hasInDatabase('migrations', $expected); @@ -110,8 +110,7 @@ public function testGetHistory() $this->assertSame($expected, $history); if ($this->db->DBDriver === 'SQLSRV') { - $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->db->prefixTable('migrations') . ' OFF'); - + $this->db->simpleQuery('SET IDENTITY_INSERT ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->prefixTable('migrations') . ' OFF'); $db = $this->getPrivateProperty($runner, 'db'); $db->table('migrations')->delete(['id' => 4]); } From 906daf8a1d92a910a8d997d26f2f8508a8875ca6 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 4 Jul 2021 10:38:37 +0200 Subject: [PATCH 0195/2325] Update Throttler docs [ci skip] --- user_guide_src/source/libraries/throttler.rst | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/throttler.rst b/user_guide_src/source/libraries/throttler.rst index 22d7829899cd..298825acf8f2 100644 --- a/user_guide_src/source/libraries/throttler.rst +++ b/user_guide_src/source/libraries/throttler.rst @@ -75,10 +75,9 @@ along the lines of:: { $throttler = Services::throttler(); - // Restrict an IP address to no more - // than 1 request per second across the - // entire site. - if ($throttler->check($request->getIPAddress(), 60, MINUTE) === false) { + // Restrict an IP address to no more than 1 request + // per second across the entire site. + if ($throttler->check(md5($request->getIPAddress()), 60, MINUTE) === false) { return Services::response()->setStatusCode(429); } } From 03d778c864666f4d2d2361c3a4eb2bf33daed54e Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 4 Jul 2021 11:34:23 +0200 Subject: [PATCH 0196/2325] Fix getVar method when trying to get variable that does not exists --- system/HTTP/IncomingRequest.php | 4 ++++ tests/system/HTTP/IncomingRequestTest.php | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 4dec7ebc610f..21894949cb29 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -535,6 +535,10 @@ public function getJsonVar(string $index, bool $assoc = false, ?int $filter = nu $data = dot_array_search($index, $this->getJSON(true)); + if ($data === null) { + return null; + } + if (! is_array($data)) { $filter = $filter ?? FILTER_DEFAULT; $flags = is_array($flags) ? $flags : (is_numeric($flags) ? (int) $flags : 0); diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index a64445232aba..4e837436ef12 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -247,7 +247,7 @@ public function testNegotiatesNot() public function testNegotiatesCharset() { - // $_SERVER['HTTP_ACCEPT_CHARSET'] = 'iso-8859-5, unicode-1-1;q=0.8'; + // $_SERVER['HTTP_ACCEPT_CHARSET'] = 'iso-8859-5, unicode-1-1;q=0.8'; $this->request->setHeader('Accept-Charset', 'iso-8859-5, unicode-1-1;q=0.8'); $this->assertSame(strtolower($this->request->config->charset), $this->request->negotiate('charset', ['iso-8859', 'unicode-1-2'])); @@ -299,6 +299,7 @@ public function testCanGetAVariableFromJson() $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); $this->assertSame('bar', $request->getJsonVar('foo')); + $this->assertNull($request->getJsonVar('notExists')); $jsonVar = $request->getJsonVar('baz'); $this->assertIsObject($jsonVar); $this->assertSame('buzz', $jsonVar->fizz); @@ -354,6 +355,7 @@ public function testGetVarWorksWithJson() $this->assertSame('bar', $request->getVar('foo')); $this->assertSame('buzz', $request->getVar('fizz')); + $this->assertNull($request->getVar('notExists')); $multiple = $request->getVar(['foo', 'fizz']); $this->assertIsArray($multiple); From abd07f95ec89ca8eeb691609ab207ae972741d47 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Sun, 4 Jul 2021 21:20:17 +0200 Subject: [PATCH 0197/2325] Update tests/system/HTTP/IncomingRequestTest.php Co-authored-by: MGatner --- tests/system/HTTP/IncomingRequestTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 4e837436ef12..6f6172af54a7 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -300,6 +300,7 @@ public function testCanGetAVariableFromJson() $this->assertSame('bar', $request->getJsonVar('foo')); $this->assertNull($request->getJsonVar('notExists')); + $jsonVar = $request->getJsonVar('baz'); $this->assertIsObject($jsonVar); $this->assertSame('buzz', $jsonVar->fizz); From 1182e065a22a079c2aff605558b64137cf0b6025 Mon Sep 17 00:00:00 2001 From: Michal Sniatala Date: Sun, 4 Jul 2021 21:20:23 +0200 Subject: [PATCH 0198/2325] Update tests/system/HTTP/IncomingRequestTest.php Co-authored-by: MGatner --- tests/system/HTTP/IncomingRequestTest.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 6f6172af54a7..1e975359a120 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -342,11 +342,7 @@ public function testGetJsonVarCanFilter() public function testGetVarWorksWithJson() { - $jsonObj = [ - 'foo' => 'bar', - 'fizz' => 'buzz', - ]; - $json = json_encode($jsonObj); + $json = json_encode(['foo' => 'bar', 'fizz' => 'buzz']); $config = new App(); $config->baseURL = 'http://example.com/'; From 57c53427c4c38e9f0a2ead4211efe4a4b6af999c Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Tue, 6 Jul 2021 12:34:23 +0200 Subject: [PATCH 0199/2325] Do not overwrite startTime. --- system/CodeIgniter.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 4350876bd3a2..4fd3596f94f3 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -490,7 +490,9 @@ protected function bootstrapEnvironment() */ protected function startBenchmark() { - $this->startTime = microtime(true); + if($this->startTime === null) { + $this->startTime = microtime(true); + } $this->benchmark = Services::timer(); $this->benchmark->start('total_execution', $this->startTime); From d263210eef0516d7dd44e90b9910ae32c15b8cf9 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Sun, 4 Jul 2021 18:22:15 +0200 Subject: [PATCH 0200/2325] Enable general benchmarking for filters. Fix copy paste. --- system/CodeIgniter.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 4fd3596f94f3..f18fc38384b6 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -357,7 +357,7 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache { $routeFilter = $this->tryToRouteIt($routes); - // Run "before" filters + // Start up the filters $filters = Services::filters(); // If any filters were specified within the routes file, @@ -371,7 +371,10 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache // Never run filters when running through Spark cli if (! defined('SPARKED')) { + // Run "before" filters + $this->benchmark->start('before_filters'); $possibleResponse = $filters->run($uri, 'before'); + $this->benchmark->stop('before_filters'); // If a ResponseInterface instance is returned then send it back to the client and stop if ($possibleResponse instanceof ResponseInterface) { @@ -410,8 +413,11 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache // Never run filters when running through Spark cli if (! defined('SPARKED')) { $filters->setResponse($this->response); + // Run "after" filters + $this->benchmark->start('after_filters'); $response = $filters->run($uri, 'after'); + $this->benchmark->stop('after_filters'); } else { $response = $this->response; From 3a6cf804692a91fe0f0c58352ad131d9d1c25bf8 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 5 Jul 2021 09:24:42 +0200 Subject: [PATCH 0201/2325] Add toolbar timer styles to sass files. --- admin/css/debug-toolbar/toolbar.scss | 53 ++++++++++++++++++++++++++ system/Debug/Toolbar/Views/toolbar.css | 36 ++++++++--------- 2 files changed, 71 insertions(+), 18 deletions(-) diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss index 8669d0ac12ff..d06731db6ffe 100644 --- a/admin/css/debug-toolbar/toolbar.scss +++ b/admin/css/debug-toolbar/toolbar.scss @@ -326,6 +326,23 @@ &:first-child { border-left: 0; + max-width: none; + } + + &.child-container { + padding: 0px; + + .timeline { + margin: 0px; + + td { + &:first-child { + &:not(.child-container) { + padding-left: calc(5px + 10px * var(--level)); + } + } + } + } } } @@ -336,6 +353,42 @@ position: absolute; top: 30%; } + + .timeline-parent{ + cursor: pointer; + + td { + &:first-child { + nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; + } + } + } + } + + .timeline-parent-open { + background-color: #DFDFDF; + + td { + &:first-child { + nav { + background-position: 0 75%; + } + } + } + } + + .child-row { + &:hover { + background: transparent; + } + } } // The "Routes" tab diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index bc8b4ac44ef7..bd080de2b1c8 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -186,22 +186,6 @@ #debug-bar .timeline { margin-left: 0; width: 100%; } - #debug-bar .timeline tr.timeline-parent { - cursor: pointer; } - #debug-bar .timeline tr.timeline-parent td:first-child nav { - background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; - background-position: 0 25%; - display: inline-block; - height: 15px; - width: 15px; - margin-right: 3px; - vertical-align: middle; } - #debug-bar .timeline tr.timeline-parent.timeline-parent-open td:first-child nav { - background-position: 0 75%; } - #debug-bar .timeline tr.timeline-parent.timeline-parent-open { - background-color: #DFDFDF; } - #debug-bar .timeline tr.child-row:hover { - background: transparent; } #debug-bar .timeline th { border-left: 1px solid; font-size: 12px; @@ -220,9 +204,9 @@ max-width: none; } #debug-bar .timeline td.child-container { padding: 0px; } - #debug-bar .timeline td.child-container .timeline{ + #debug-bar .timeline td.child-container .timeline { margin: 0px; } - #debug-bar .timeline td.child-container td:first-child:not(.child-container){ + #debug-bar .timeline td.child-container .timeline td:first-child:not(.child-container) { padding-left: calc(5px + 10px * var(--level)); } #debug-bar .timeline .timer { border-radius: 4px; @@ -232,6 +216,22 @@ padding: 5px; position: absolute; top: 30%; } + #debug-bar .timeline .timeline-parent { + cursor: pointer; } + #debug-bar .timeline .timeline-parent td:first-child nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; } + #debug-bar .timeline .timeline-parent-open { + background-color: #DFDFDF; } + #debug-bar .timeline .timeline-parent-open td:first-child nav { + background-position: 0 75%; } + #debug-bar .timeline .child-row:hover { + background: transparent; } #debug-bar .route-params, #debug-bar .route-params-item { vertical-align: top; } From 971f511899fde371a3bc5c6470d5cc27a8b8bca4 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Wed, 7 Jul 2021 13:21:55 +0200 Subject: [PATCH 0202/2325] Unify scss styling and switch to spaces. --- admin/css/debug-toolbar/_graphic-charter.scss | 18 +- admin/css/debug-toolbar/_mixins.scss | 13 +- admin/css/debug-toolbar/_theme-dark.scss | 257 +++--- admin/css/debug-toolbar/_theme-light.scss | 250 +++--- admin/css/debug-toolbar/toolbar.scss | 838 +++++++++--------- system/Debug/Toolbar/Views/toolbar.css | 23 +- 6 files changed, 718 insertions(+), 681 deletions(-) diff --git a/admin/css/debug-toolbar/_graphic-charter.scss b/admin/css/debug-toolbar/_graphic-charter.scss index 9e88e7177551..522f07f6e255 100644 --- a/admin/css/debug-toolbar/_graphic-charter.scss +++ b/admin/css/debug-toolbar/_graphic-charter.scss @@ -2,19 +2,19 @@ // ========================================================================== */ // Themes -$t-dark: #252525; +$t-dark: #252525; $t-light: #FFFFFF; // Glossy colors -$g-blue: #5BC0DE; -$g-gray: #434343; -$g-green: #9ACE25; +$g-blue: #5BC0DE; +$g-gray: #434343; +$g-green: #9ACE25; $g-orange: #DD8615; -$g-red: #DD4814; +$g-red: #DD4814; // Matt colors -$m-blue: #D8EAF0; -$m-gray: #DFDFDF; -$m-green: #DFF0D8; +$m-blue: #D8EAF0; +$m-gray: #DFDFDF; +$m-green: #DFF0D8; $m-orange: #FDC894; -$m-red: #EF9090; +$m-red: #EF9090; diff --git a/admin/css/debug-toolbar/_mixins.scss b/admin/css/debug-toolbar/_mixins.scss index c5bde5f5f6da..69af2b67c475 100644 --- a/admin/css/debug-toolbar/_mixins.scss +++ b/admin/css/debug-toolbar/_mixins.scss @@ -2,12 +2,13 @@ // ========================================================================== */ @mixin border-radius($radius) { - border-radius: $radius; - -moz-border-radius: $radius; - -webkit-border-radius: $radius; + border-radius: $radius; + -moz-border-radius: $radius; + -webkit-border-radius: $radius; } + @mixin box-shadow($left, $top, $radius, $color) { - box-shadow: $left $top $radius $color; - -moz-box-shadow: $left $top $radius $color; - -webkit-box-shadow: $left $top $radius $color; + box-shadow: $left $top $radius $color; + -moz-box-shadow: $left $top $radius $color; + -webkit-box-shadow: $left $top $radius $color; } diff --git a/admin/css/debug-toolbar/_theme-dark.scss b/admin/css/debug-toolbar/_theme-dark.scss index 56d4a4bbbac3..b41e8fb086af 100644 --- a/admin/css/debug-toolbar/_theme-dark.scss +++ b/admin/css/debug-toolbar/_theme-dark.scss @@ -12,11 +12,14 @@ // ========================================================================== */ #debug-icon { - background-color: $t-dark; - @include box-shadow(0, 0, 4px, $m-gray); - a:active, a:link, a:visited { - color: $g-orange; - } + background-color: $t-dark; + @include box-shadow(0, 0, 4px, $m-gray); + + a:active, + a:link, + a:visited { + color: $g-orange; + } } @@ -24,119 +27,130 @@ // ========================================================================== */ #debug-bar { - background-color: $t-dark; - color: $m-gray; - - // Reset to prevent conflict with other CSS files - h1, - h2, - h3, - p, - a, - button, - table, - thead, - tr, - td, - button, - .toolbar { - background-color: transparent; - color: $m-gray; - } - - // Buttons - button { - background-color: $t-dark; - } - - // Tables - table { - strong { - color: $m-orange; - } - tbody tr { - &:hover { - background-color: $g-gray; - } - &.current { - background-color: $m-orange; - td { - color: $t-dark; - } - &:hover td { - background-color: $g-red; - color: $t-light; - } - } - } - } - - // The toolbar - .toolbar { - background-color: $g-gray; - @include box-shadow(0, 0, 4px, $g-gray); - img { - filter: brightness(0) invert(1); - } - } - - // Fixed top - &.fixed-top { - & .toolbar { - @include box-shadow(0, 0, 4px, $g-gray); - } - .tab { - @include box-shadow(0, 1px, 4px, $g-gray); - } - } - - // "Muted" elements - .muted { - color: $m-gray; - td { - color: $g-gray; - } - &:hover td { - color: $m-gray; - } - } - - // The toolbar preferences - #toolbar-position, - #toolbar-theme, { - filter: brightness(0) invert(0.6); - } - - // The toolbar menus - .ci-label { - &.active { - background-color: $t-dark; - } - &:hover { - background-color: $t-dark; - } - .badge { - background-color: $g-blue; - color: $m-gray; - } - } - - // The tabs container - .tab { - background-color: $t-dark; - @include box-shadow(0, -1px, 4px, $g-gray); - } - - // The "Timeline" tab - .timeline { - th, - td { - border-color: $g-gray; - } - .timer { - background-color: $g-orange; - } - } + background-color: $t-dark; + color: $m-gray; + + // Reset to prevent conflict with other CSS files + h1, + h2, + h3, + p, + a, + button, + table, + thead, + tr, + td, + button, + .toolbar { + background-color: transparent; + color: $m-gray; + } + + // Buttons + button { + background-color: $t-dark; + } + + // Tables + table { + strong { + color: $m-orange; + } + + tbody tr { + &:hover { + background-color: $g-gray; + } + + &.current { + background-color: $m-orange; + + td { + color: $t-dark; + } + + &:hover td { + background-color: $g-red; + color: $t-light; + } + } + } + } + + // The toolbar + .toolbar { + background-color: $g-gray; + @include box-shadow(0, 0, 4px, $g-gray); + + img { + filter: brightness(0) invert(1); + } + } + + // Fixed top + &.fixed-top { + .toolbar { + @include box-shadow(0, 0, 4px, $g-gray); + } + + .tab { + @include box-shadow(0, 1px, 4px, $g-gray); + } + } + + // "Muted" elements + .muted { + color: $m-gray; + + td { + color: $g-gray; + } + + &:hover td { + color: $m-gray; + } + } + + // The toolbar preferences + #toolbar-position, + #toolbar-theme { + filter: brightness(0) invert(0.6); + } + + // The toolbar menus + .ci-label { + &.active { + background-color: $t-dark; + } + + &:hover { + background-color: $t-dark; + } + + .badge { + background-color: $g-blue; + color: $m-gray; + } + } + + // The tabs container + .tab { + background-color: $t-dark; + @include box-shadow(0, -1px, 4px, $g-gray); + } + + // The "Timeline" tab + .timeline { + th, + td { + border-color: $g-gray; + } + + .timer { + background-color: $g-orange; + } + } } @@ -144,9 +158,10 @@ // ========================================================================== */ .debug-view.show-view { - border-color: $g-orange; + border-color: $g-orange; } + .debug-view-path { - background-color: $m-orange; - color: $g-gray; + background-color: $m-orange; + color: $g-gray; } diff --git a/admin/css/debug-toolbar/_theme-light.scss b/admin/css/debug-toolbar/_theme-light.scss index 744997a4080d..7148cd4c4f6f 100644 --- a/admin/css/debug-toolbar/_theme-light.scss +++ b/admin/css/debug-toolbar/_theme-light.scss @@ -12,11 +12,14 @@ // ========================================================================== */ #debug-icon { - background-color: $t-light; - @include box-shadow(0, 0, 4px, $m-gray); - a:active, a:link, a:visited { - color: $g-orange; - } + background-color: $t-light; + @include box-shadow(0, 0, 4px, $m-gray); + + a:active, + a:link, + a:visited { + color: $g-orange; + } } @@ -24,116 +27,126 @@ // ========================================================================== */ #debug-bar { - background-color: $t-light; - color: $g-gray; - - // Reset to prevent conflict with other CSS files */ - h1, - h2, - h3, - p, - a, - button, - table, - thead, - tr, - td, - button, - .toolbar { - background-color: transparent; - color: $g-gray; - } - - // Buttons - button { - background-color: $t-light; - } - - // Tables - table { - strong { - color: $m-orange; - } - tbody tr { - &:hover { - background-color: $m-gray; - } - &.current { - background-color: $m-orange; - &:hover td { - background-color: $g-red; - color: $t-light; - } - } - } - } - - // The toolbar - .toolbar { - background-color: $t-light; - @include box-shadow(0, 0, 4px, $m-gray); - img { - filter: brightness(0) invert(0.4); - } - } - - // Fixed top - &.fixed-top { - & .toolbar { - @include box-shadow(0, 0, 4px, $m-gray); - } - .tab { - @include box-shadow(0, 1px, 4px, $m-gray); - } - } - - // "Muted" elements - .muted { - color: $g-gray; - td { - color: $m-gray; - } - &:hover td { - color: $g-gray; - } - } - - // The toolbar preferences - #toolbar-position, - #toolbar-theme, { - filter: brightness(0) invert(0.6); - } - - // The toolbar menus - .ci-label { - &.active { - background-color: $m-gray; - } - &:hover { - background-color: $m-gray; - } - .badge { - background-color: $g-blue; - color: $t-light; - } - } - - // The tabs container - .tab { - background-color: $t-light; - @include box-shadow(0, -1px, 4px, $m-gray); - } - - // The "Timeline" tab - .timeline { - th, - td { - border-color: $m-gray; - } - .timer { - background-color: $g-orange; - } - } + background-color: $t-light; + color: $g-gray; + + // Reset to prevent conflict with other CSS files + h1, + h2, + h3, + p, + a, + button, + table, + thead, + tr, + td, + button, + .toolbar { + background-color: transparent; + color: $g-gray; + } + + // Buttons + button { + background-color: $t-light; + } + + // Tables + table { + strong { + color: $m-orange; + } + + tbody tr { + &:hover { + background-color: $m-gray; + } + + &.current { + background-color: $m-orange; + + &:hover td { + background-color: $g-red; + color: $t-light; + } + } + } + } + + // The toolbar + .toolbar { + background-color: $t-light; + @include box-shadow(0, 0, 4px, $m-gray); + + img { + filter: brightness(0) invert(0.4); + } + } + + // Fixed top + &.fixed-top { + .toolbar { + @include box-shadow(0, 0, 4px, $m-gray); + } + + .tab { + @include box-shadow(0, 1px, 4px, $m-gray); + } + } + + // "Muted" elements + .muted { + color: $g-gray; + + td { + color: $m-gray; + } + + &:hover td { + color: $g-gray; + } + } + + // The toolbar preferences + #toolbar-position, + #toolbar-theme { + filter: brightness(0) invert(0.6); + } + + // The toolbar menus + .ci-label { + &.active { + background-color: $m-gray; + } + + &:hover { + background-color: $m-gray; + } + + .badge { + background-color: $g-blue; + color: $t-light; + } + } + + // The tabs container + .tab { + background-color: $t-light; + @include box-shadow(0, -1px, 4px, $m-gray); + } + + // The "Timeline" tab + .timeline { + th, + td { + border-color: $m-gray; + } + + .timer { + background-color: $g-orange; + } + } } @@ -141,9 +154,10 @@ // ========================================================================== */ .debug-view.show-view { - border-color: $g-orange; + border-color: $g-orange; } + .debug-view-path { - background-color: $m-orange; - color: $g-gray; + background-color: $m-orange; + color: $g-gray; } diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss index d06731db6ffe..0f07005ad9ab 100644 --- a/admin/css/debug-toolbar/toolbar.scss +++ b/admin/css/debug-toolbar/toolbar.scss @@ -1,8 +1,8 @@ /*! CodeIgniter 4 - Debug bar * ============================================================================ - * Forum: https://forum.codeigniter.com - * Github: https://github.com/codeigniter4/codeigniter4 - * Slack: https://codeigniterchat.slack.com + * Forum: https://forum.codeigniter.com + * Github: https://github.com/codeigniter4/codeigniter4 + * Slack: https://codeigniterchat.slack.com * Website: https://codeigniter.com */ @@ -17,38 +17,38 @@ // ========================================================================== */ #debug-icon { - // Position - bottom: 0; - position: fixed; - right: 0; - z-index: 10000; - - // Size - height: 36px; - width: 36px; - - // Spacing - margin: 0px; - padding: 0px; - - // Content - clear: both; - text-align: center; - - a svg { - margin: 8px; - max-width: 20px; - max-height: 20px; - } - - &.fixed-top { - bottom: auto; - top: 0; - } - - .debug-bar-ndisplay { - display: none; - } + // Position + bottom: 0; + position: fixed; + right: 0; + z-index: 10000; + + // Size + height: 36px; + width: 36px; + + // Spacing + margin: 0px; + padding: 0px; + + // Content + clear: both; + text-align: center; + + a svg { + margin: 8px; + max-width: 20px; + max-height: 20px; + } + + &.fixed-top { + bottom: auto; + top: 0; + } + + .debug-bar-ndisplay { + display: none; + } } @@ -56,352 +56,352 @@ // ========================================================================== */ #debug-bar { - // Position - bottom: 0; - left: 0; - position: fixed; - right: 0; - z-index: 10000; - - // Size - height: 36px; - - // Spacing - line-height: 36px; - - // Typography - font-family: $base-font; - font-size: $base-size; - font-weight: 400; - - // General elements - h1 { - bottom: 0; - display: inline-block; - font-size: $base-size - 2; - font-weight: normal; - margin: 0 16px 0 0; - padding: 0; - position: absolute; - right: 30px; - text-align: left; - top: 0; - - svg { - width: 16px; - margin-right: 5px; - } - } - - h2 { - font-size: $base-size; - margin: 0; - padding: 5px 0 10px 0; - - span { - font-size: 13px; - } - } - - h3 { - font-size: $base-size - 4; - font-weight: 200; - margin: 0 0 0 10px; - padding: 0; - text-transform: uppercase; - } - - p { - font-size: $base-size - 4; - margin: 0 0 0 15px; - padding: 0; - } - - a { - text-decoration: none; - - &:hover { - text-decoration: underline; - } - } - - button { - border: 1px solid; - @include border-radius(4px); - cursor: pointer; - line-height: 15px; - - &:hover { - text-decoration: underline; - } - } - - table { - border-collapse: collapse; - font-size: $base-size - 2; - line-height: normal; - margin: 5px 10px 15px 10px; // Tables indentation - width: calc(100% - 10px); // Make sure it still fits the container, even with the margins - - strong { - font-weight: 500; - } - - th { - display: table-cell; - font-weight: 600; - padding-bottom: 0.7em; - text-align: left; - } - - tr { - border: none; - } - - td { - border: none; - display: table-cell; - margin: 0; - text-align: left; - - &:first-child { - max-width: 20%; - - &.narrow { - width: 7em; - } - } - } - } - - td[data-debugbar-route] { - form { - display: none; - } - - &:hover { - form { - display: block; - } - - &>div { - display: none; - } - } - - input[type=text] { - padding: 2px; - } - } - - // The toolbar - .toolbar { - display: flex; - overflow: hidden; - overflow-y: auto; - padding: 0 12px 0 12px; - /* give room for OS X scrollbar */ - white-space: nowrap; - z-index: 10000; - } - - // Fixed top - &.fixed-top { - bottom: auto; - top: 0; - - .tab { - bottom: auto; - top: 36px; - } - } - - // The toolbar preferences - #toolbar-position, - #toolbar-theme { - a { - // float: left; - padding: 0 6px; - display: inline-flex; - vertical-align: top; - - &:hover { - text-decoration: none; - } - } - } - - // The "Open/Close" toggle - #debug-bar-link { - bottom: 0; - display: inline-block; - font-size: $base-size; - line-height: 36px; - padding: 6px; - position: absolute; - right: 10px; - top: 0; - width: 24px; - } - - // The toolbar menus - .ci-label { - display: inline-flex; - font-size: $base-size - 2; - // vertical-align: baseline; - - &:hover { - cursor: pointer; - } - - a { - color: inherit; - display: flex; - letter-spacing: normal; - padding: 0 10px; - text-decoration: none; - align-items: center; - } - - // The toolbar icons - img { - // clear: left; - // display: inline-block; - // float: left; - margin: 6px 3px 6px 0; - width: 16px !important; - } - - // The toolbar notification badges - .badge { - @include border-radius(12px); - display: inline-block; - font-size: 75%; - font-weight: bold; - line-height: 12px; - margin-left: 5px; - padding: 2px 5px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; - } - } - - // The tabs container - .tab { - bottom: 35px; - display: none; - left: 0; - max-height: 62%; - overflow: hidden; - overflow-y: auto; - padding: 1em 2em; - position: fixed; - right: 0; - z-index: 9999; - } - - // The "Timeline" tab - .timeline { - margin-left: 0; - width: 100%; - - th { - border-left: 1px solid; - font-size: $base-size - 4; - font-weight: 200; - padding: 5px 5px 10px 5px; - position: relative; - text-align: left; - - &:first-child { - border-left: 0; - } - } - - td { - border-left: 1px solid; - padding: 5px; - position: relative; - - &:first-child { - border-left: 0; - max-width: none; - } - - &.child-container { - padding: 0px; - - .timeline { - margin: 0px; - - td { - &:first-child { - &:not(.child-container) { - padding-left: calc(5px + 10px * var(--level)); - } - } - } - } - } - } - - .timer { - @include border-radius(4px); - display: inline-block; - padding: 5px; - position: absolute; - top: 30%; - } - - .timeline-parent{ - cursor: pointer; - - td { - &:first-child { - nav { - background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; - background-position: 0 25%; - display: inline-block; - height: 15px; - width: 15px; - margin-right: 3px; - vertical-align: middle; - } - } - } - } - - .timeline-parent-open { - background-color: #DFDFDF; - - td { - &:first-child { - nav { - background-position: 0 75%; - } - } - } - } - - .child-row { - &:hover { - background: transparent; - } - } - } - - // The "Routes" tab - .route-params, - .route-params-item { - vertical-align: top; - - td:first-child { - font-style: italic; - padding-left: 1em; - text-align: right; - } - } + // Position + bottom: 0; + left: 0; + position: fixed; + right: 0; + z-index: 10000; + + // Size + height: 36px; + + // Spacing + line-height: 36px; + + // Typography + font-family: $base-font; + font-size: $base-size; + font-weight: 400; + + // General elements + h1 { + bottom: 0; + display: inline-block; + font-size: $base-size - 2; + font-weight: normal; + margin: 0 16px 0 0; + padding: 0; + position: absolute; + right: 30px; + text-align: left; + top: 0; + + svg { + width: 16px; + margin-right: 5px; + } + } + + h2 { + font-size: $base-size; + margin: 0; + padding: 5px 0 10px 0; + + span { + font-size: 13px; + } + } + + h3 { + font-size: $base-size - 4; + font-weight: 200; + margin: 0 0 0 10px; + padding: 0; + text-transform: uppercase; + } + + p { + font-size: $base-size - 4; + margin: 0 0 0 15px; + padding: 0; + } + + a { + text-decoration: none; + + &:hover { + text-decoration: underline; + } + } + + button { + border: 1px solid; + @include border-radius(4px); + cursor: pointer; + line-height: 15px; + + &:hover { + text-decoration: underline; + } + } + + table { + border-collapse: collapse; + font-size: $base-size - 2; + line-height: normal; + + // Tables indentation + margin: 5px 10px 15px 10px; + + // Make sure it still fits the container, even with the margins + width: calc(100% - 10px); + + strong { + font-weight: 500; + } + + th { + display: table-cell; + font-weight: 600; + padding-bottom: 0.7em; + text-align: left; + } + + tr { + border: none; + } + + td { + border: none; + display: table-cell; + margin: 0; + text-align: left; + + &:first-child { + max-width: 20%; + + &.narrow { + width: 7em; + } + } + } + } + + td[data-debugbar-route] { + form { + display: none; + } + + &:hover { + form { + display: block; + } + + &>div { + display: none; + } + } + + input[type=text] { + padding: 2px; + } + } + + // The toolbar + .toolbar { + display: flex; + overflow: hidden; + overflow-y: auto; + padding: 0 12px 0 12px; + + // Give room for OS X scrollbar + white-space: nowrap; + z-index: 10000; + } + + // Fixed top + &.fixed-top { + bottom: auto; + top: 0; + + .tab { + bottom: auto; + top: 36px; + } + } + + // The toolbar preferences + #toolbar-position, + #toolbar-theme { + a { + padding: 0 6px; + display: inline-flex; + vertical-align: top; + + &:hover { + text-decoration: none; + } + } + } + + // The "Open/Close" toggle + #debug-bar-link { + bottom: 0; + display: inline-block; + font-size: $base-size; + line-height: 36px; + padding: 6px; + position: absolute; + right: 10px; + top: 0; + width: 24px; + } + + // The toolbar menus + .ci-label { + display: inline-flex; + font-size: $base-size - 2; + + &:hover { + cursor: pointer; + } + + a { + color: inherit; + display: flex; + letter-spacing: normal; + padding: 0 10px; + text-decoration: none; + align-items: center; + } + + // The toolbar icons + img { + margin: 6px 3px 6px 0; + width: 16px !important; + } + + // The toolbar notification badges + .badge { + @include border-radius(12px); + display: inline-block; + font-size: 75%; + font-weight: bold; + line-height: 12px; + margin-left: 5px; + padding: 2px 5px; + text-align: center; + vertical-align: baseline; + white-space: nowrap; + } + } + + // The tabs container + .tab { + bottom: 35px; + display: none; + left: 0; + max-height: 62%; + overflow: hidden; + overflow-y: auto; + padding: 1em 2em; + position: fixed; + right: 0; + z-index: 9999; + } + + // The "Timeline" tab + .timeline { + margin-left: 0; + width: 100%; + + th { + border-left: 1px solid; + font-size: $base-size - 4; + font-weight: 200; + padding: 5px 5px 10px 5px; + position: relative; + text-align: left; + + &:first-child { + border-left: 0; + } + } + + td { + border-left: 1px solid; + padding: 5px; + position: relative; + + &:first-child { + border-left: 0; + max-width: none; + } + + &.child-container { + padding: 0px; + + .timeline { + margin: 0px; + + td { + &:first-child { + &:not(.child-container) { + padding-left: calc(5px + 10px * var(--level)); + } + } + } + } + } + } + + .timer { + @include border-radius(4px); + display: inline-block; + padding: 5px; + position: absolute; + top: 30%; + } + + .timeline-parent { + cursor: pointer; + + td { + &:first-child { + nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; + } + } + } + } + + .timeline-parent-open { + background-color: #DFDFDF; + + td { + &:first-child { + nav { + background-position: 0 75%; + } + } + } + } + + .child-row { + &:hover { + background: transparent; + } + } + } + + // The "Routes" tab + .route-params, + .route-params-item { + vertical-align: top; + + td:first-child { + font-style: italic; + padding-left: 1em; + text-align: right; + } + } } @@ -409,21 +409,21 @@ // ========================================================================== */ .debug-view.show-view { - border: 1px solid; - margin: 4px; + border: 1px solid; + margin: 4px; } .debug-view-path { - font-family: monospace; - font-size: $base-size - 4; - letter-spacing: normal; - min-height: 16px; - padding: 2px; - text-align: left; + font-family: monospace; + font-size: $base-size - 4; + letter-spacing: normal; + min-height: 16px; + padding: 2px; + text-align: left; } .show-view .debug-view-path { - display: block !important; + display: block !important; } @@ -431,17 +431,17 @@ // ========================================================================== */ @media screen and (max-width: 1024px) { - #debug-bar { - .ci-label { - img { - margin: unset - } - } - } - - .hide-sm { - display: none !important; - } + #debug-bar { + .ci-label { + img { + margin: unset + } + } + } + + .hide-sm { + display: none !important; + } } @@ -453,22 +453,22 @@ // If the browser supports "prefers-color-scheme" and the scheme is "Dark" @media (prefers-color-scheme: dark) { - @import '_theme-dark'; + @import '_theme-dark'; } // If we force the "Dark" theme #toolbarContainer.dark { - @import '_theme-dark'; + @import '_theme-dark'; - td[data-debugbar-route] input[type=text] { - background: #000; - color: #fff; - } + td[data-debugbar-route] input[type=text] { + background: #000; + color: #fff; + } } // If we force the "Light" theme #toolbarContainer.light { - @import '_theme-light'; + @import '_theme-light'; } @@ -476,41 +476,41 @@ // ========================================================================== */ .debug-bar-width30 { - width: 30%; + width: 30%; } .debug-bar-width10 { - width: 10%; + width: 10%; } .debug-bar-width70p { - width: 70px; + width: 70px; } .debug-bar-width140p { - width: 140px; + width: 140px; } .debug-bar-width20e { - width: 20em; + width: 20em; } .debug-bar-width6r { - width: 6rem; + width: 6rem; } .debug-bar-ndisplay { - display: none; + display: none; } .debug-bar-alignRight { - text-align: right; + text-align: right; } .debug-bar-alignLeft { - text-align: left; + text-align: left; } .debug-bar-noverflow { - overflow: hidden; -} \ No newline at end of file + overflow: hidden; +} diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index bd080de2b1c8..f42cd2089027 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -1,8 +1,8 @@ /*! CodeIgniter 4 - Debug bar * ============================================================================ - * Forum: https://forum.codeigniter.com - * Github: https://github.com/codeigniter4/codeigniter4 - * Slack: https://codeigniterchat.slack.com + * Forum: https://forum.codeigniter.com + * Github: https://github.com/codeigniter4/codeigniter4 + * Slack: https://codeigniterchat.slack.com * Website: https://codeigniter.com */ #debug-icon { @@ -117,7 +117,6 @@ overflow: hidden; overflow-y: auto; padding: 0 12px 0 12px; - /* give room for OS X scrollbar */ white-space: nowrap; z-index: 10000; } #debug-bar.fixed-top { @@ -267,7 +266,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, #debug-icon a:link, #debug-icon a:visited { + #debug-icon a:active, + #debug-icon a:link, + #debug-icon a:visited { color: #DD8615; } #debug-bar { @@ -353,7 +354,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, #debug-icon a:link, #debug-icon a:visited { + #debug-icon a:active, + #debug-icon a:link, + #debug-icon a:visited { color: #DD8615; } #debug-bar { background-color: #252525; @@ -437,7 +440,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.dark #debug-icon a:active, #toolbarContainer.dark #debug-icon a:link, #toolbarContainer.dark #debug-icon a:visited { + #toolbarContainer.dark #debug-icon a:active, + #toolbarContainer.dark #debug-icon a:link, + #toolbarContainer.dark #debug-icon a:visited { color: #DD8615; } #toolbarContainer.dark #debug-bar { @@ -528,7 +533,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.light #debug-icon a:active, #toolbarContainer.light #debug-icon a:link, #toolbarContainer.light #debug-icon a:visited { + #toolbarContainer.light #debug-icon a:active, + #toolbarContainer.light #debug-icon a:link, + #toolbarContainer.light #debug-icon a:visited { color: #DD8615; } #toolbarContainer.light #debug-bar { From 23227e98368483a6b1b02d60c07b712e3b41edc2 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Wed, 7 Jul 2021 19:41:05 +0200 Subject: [PATCH 0203/2325] Replace file header. --- admin/css/debug-toolbar/toolbar.scss | 13 +++++++------ system/Debug/Toolbar/Views/toolbar.css | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss index 0f07005ad9ab..c73510182ac7 100644 --- a/admin/css/debug-toolbar/toolbar.scss +++ b/admin/css/debug-toolbar/toolbar.scss @@ -1,9 +1,10 @@ -/*! CodeIgniter 4 - Debug bar - * ============================================================================ - * Forum: https://forum.codeigniter.com - * Github: https://github.com/codeigniter4/codeigniter4 - * Slack: https://codeigniterchat.slack.com - * Website: https://codeigniter.com +/** + * This file is part of the CodeIgniter 4 framework. + * + * (c) CodeIgniter Foundation + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ // IMPORTS diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index f42cd2089027..34b686385fd7 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -1,9 +1,10 @@ -/*! CodeIgniter 4 - Debug bar - * ============================================================================ - * Forum: https://forum.codeigniter.com - * Github: https://github.com/codeigniter4/codeigniter4 - * Slack: https://codeigniterchat.slack.com - * Website: https://codeigniter.com +/** + * This file is part of the CodeIgniter 4 framework. + * + * (c) CodeIgniter Foundation + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ #debug-icon { bottom: 0; From 9f9119e3584fa86c0795f9dc9a55e959609dca21 Mon Sep 17 00:00:00 2001 From: MGatner Date: Sat, 3 Jul 2021 23:35:28 +0000 Subject: [PATCH 0204/2325] Implement Deptrac --- .github/workflows/test-deptrac.yml | 82 ++++++++++ depfile.yaml | 232 +++++++++++++++++++++++++++++ 2 files changed, 314 insertions(+) create mode 100644 .github/workflows/test-deptrac.yml create mode 100644 depfile.yaml diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml new file mode 100644 index 000000000000..9a9179b501d8 --- /dev/null +++ b/.github/workflows/test-deptrac.yml @@ -0,0 +1,82 @@ +# When a PR is opened or a push is made, perform an +# architectural inspection on the code using Deptrac. +name: Deptrac + +on: + pull_request: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**' + - 'system/**' + - 'composer.json' + - 'depfile.yaml' + - '.github/workflows/test-deptrac.yml' + push: + branches: + - 'develop' + - '4.*' + paths: + - 'app/**' + - 'system/**' + - 'composer.json' + - 'depfile.yaml' + - '.github/workflows/test-deptrac.yml' + +jobs: + build: + name: PHP ${{ matrix.php-versions }} Architectural Inspection + runs-on: ubuntu-20.04 + strategy: + fail-fast: false + matrix: + php-versions: ['7.4', '8.0'] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + tools: composer, pecl, phive, phpunit + extensions: intl, json, mbstring, gd, mysqlnd, xdebug, xml, sqlite3 + + - name: Use latest Composer + run: composer self-update + + - name: Validate composer.json + run: composer validate --strict + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Create composer cache directory + run: mkdir -p ${{ steps.composer-cache.outputs.dir }} + + - name: Cache composer dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ runner.os }}-composer- + + - name: Create Deptrac cache directory + run: mkdir -p build/ + + - name: Cache Deptrac results + uses: actions/cache@v2 + with: + path: build + key: ${{ runner.os }}-deptrac-${{ github.sha }} + restore-keys: ${{ runner.os }}-deptrac- + + - name: Install dependencies + run: composer update --ansi --no-interaction + + - name: Run architectural inspection + run: | + sudo phive --no-progress install --global qossmic/deptrac --trust-gpg-keys B8F640134AB1782E + deptrac analyze --cache-file=build/deptrac.cache diff --git a/depfile.yaml b/depfile.yaml new file mode 100644 index 000000000000..147099379891 --- /dev/null +++ b/depfile.yaml @@ -0,0 +1,232 @@ +# Defines the layers for each framework +# component and their allowed interactions. +# The following components are exempt +# due to their global nature: +# - CLI & Commands +# - Config +# - Debug +# - Exception +# - Service +# - Validation\FormatRules +paths: + - ./app + - ./system +exclude_files: + - '#.*test.*#i' +layers: + - name: API + collectors: + - type: className + regex: ^Codeigniter\\API\\.* + - name: Cache + collectors: + - type: className + regex: ^Codeigniter\\Cache\\.* + - name: Controller + collectors: + - type: className + regex: ^CodeIgniter\\Controller$ + - name: Cookie + collectors: + - type: className + regex: ^Codeigniter\\Cookie\\.* + - name: Database + collectors: + - type: className + regex: ^Codeigniter\\Database\\.* + - name: Email + collectors: + - type: className + regex: ^Codeigniter\\Email\\.* + - name: Encryption + collectors: + - type: className + regex: ^Codeigniter\\Encryption\\.* + - name: Entity + collectors: + - type: className + regex: ^Codeigniter\\Entity\\.* + - name: Events + collectors: + - type: className + regex: ^Codeigniter\\Events\\.* + - name: Files + collectors: + - type: className + regex: ^Codeigniter\\Files\\.* + - name: Filters + collectors: + - type: bool + must: + - type: className + regex: ^Codeigniter\\Filters\\Filter.* + - name: Format + collectors: + - type: className + regex: ^Codeigniter\\Format\\.* + - name: Honeypot + collectors: + - type: className + regex: ^Codeigniter\\.*Honeypot.* # includes the Filter + - name: HTTP + collectors: + - type: bool + must: + - type: className + regex: ^Codeigniter\\HTTP\\.* + must_not: + - type: className + regex: (Exception|URI) + - name: I18n + collectors: + - type: className + regex: ^Codeigniter\\I18n\\.* + - name: Images + collectors: + - type: className + regex: ^Codeigniter\\Images\\.* + - name: Language + collectors: + - type: className + regex: ^Codeigniter\\Language\\.* + - name: Log + collectors: + - type: className + regex: ^Codeigniter\\Log\\.* + - name: Model + collectors: + - type: className + regex: ^Codeigniter\\.*Model$ + - name: Modules + collectors: + - type: className + regex: ^Codeigniter\\Modules\\.* + - name: Pager + collectors: + - type: className + regex: ^Codeigniter\\Pager\\.* + - name: Publisher + collectors: + - type: className + regex: ^Codeigniter\\Publisher\\.* + - name: RESTful + collectors: + - type: className + regex: ^Codeigniter\\RESTful\\.* + - name: Router + collectors: + - type: className + regex: ^Codeigniter\\Router\\.* + - name: Security + collectors: + - type: className + regex: ^Codeigniter\\Security\\.* + - name: Session + collectors: + - type: className + regex: ^Codeigniter\\Session\\.* + - name: Throttle + collectors: + - type: className + regex: ^Codeigniter\\Throttle\\.* + - name: Typography + collectors: + - type: className + regex: ^Codeigniter\\Typography\\.* + - name: URI + collectors: + - type: className + regex: ^CodeIgniter\\HTTP\\URI$ + - name: Validation + collectors: + - type: bool + must: + - type: className + regex: ^Codeigniter\\Validation\\.* + must_not: + - type: className + regex: ^Codeigniter\\Validation\\FormatRules$ + - name: View + collectors: + - type: className + regex: ^Codeigniter\\View\\.* +ruleset: + API: + - Format + - HTTP + Controller: + - HTTP + - Validation + Database: + - Entity + - Events + Email: + - Events + Entity: + - I18n + Filters: + - HTTP + Honeypot: + - Filters + - HTTP + HTTP: + - Cookie + - Files + - URI + Images: + - Files + Model: + - Database + - I18n + - Pager + - Validation + Pager: + - URI + - View + Publisher: + - Files + - URI + RESTful: # @todo Transitive Dependency + - API + - Controller + - Format + - HTTP + - Validation + Router: + - HTTP + Security: + - Cookie + - HTTP + Session: + - Cookie + - Database + Throttle: + - Cache + Validation: + - HTTP + View: + - Cache +skip_violations: + # Individual class exemptions + CodeIgniter\Entity\Cast\URICast: + - CodeIgniter\HTTP\URI + CodeIgniter\Log\Handlers\ChromeLoggerHandler: + - CodeIgniter\HTTP\ResponseInterface + CodeIgniter\View\Table: + - CodeIgniter\Database\BaseResult + CodeIgniter\View\Plugins: + - CodeIgniter\HTTP\URI + + # BC changes that should be fixed + CodeIgniter\HTTP\ResponseTrait: + - CodeIgniter\Pager\PagerInterface + CodeIgniter\HTTP\ResponseInterface: + - CodeIgniter\Pager\PagerInterface + CodeIgniter\HTTP\Response: + - CodeIgniter\Pager\PagerInterface + CodeIgniter\HTTP\RedirectResponse: + - CodeIgniter\Pager\PagerInterface + CodeIgniter\HTTP\DownloadResponse: + - CodeIgniter\Pager\PagerInterface + CodeIgniter\Validation\Validation: + - CodeIgniter\View\RendererInterface From d27708ce186e41f07314fdf890cda8b3d42aa2ad Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 15 Jul 2021 15:34:20 +0000 Subject: [PATCH 0205/2325] Simplify Action workflow --- .github/workflows/test-deptrac.yml | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml index 9a9179b501d8..0698809319fe 100644 --- a/.github/workflows/test-deptrac.yml +++ b/.github/workflows/test-deptrac.yml @@ -26,12 +26,8 @@ on: jobs: build: - name: PHP ${{ matrix.php-versions }} Architectural Inspection + name: Architectural Inspection runs-on: ubuntu-20.04 - strategy: - fail-fast: false - matrix: - php-versions: ['7.4', '8.0'] steps: - name: Checkout uses: actions/checkout@v2 @@ -39,13 +35,10 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: ${{ matrix.php-versions }} - tools: composer, pecl, phive, phpunit + php-version: '8.0' + tools: composer, phive extensions: intl, json, mbstring, gd, mysqlnd, xdebug, xml, sqlite3 - - name: Use latest Composer - run: composer self-update - - name: Validate composer.json run: composer validate --strict From 91ca8f36081abbc81b8d5954dc17841454327732 Mon Sep 17 00:00:00 2001 From: MGatner Date: Thu, 15 Jul 2021 15:43:44 +0000 Subject: [PATCH 0206/2325] Implement transitive dependencies --- depfile.yaml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/depfile.yaml b/depfile.yaml index 147099379891..c1d8b87c3db2 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -186,12 +186,9 @@ ruleset: Publisher: - Files - URI - RESTful: # @todo Transitive Dependency - - API - - Controller - - Format - - HTTP - - Validation + RESTful: + - +API + - +Controller Router: - HTTP Security: From 6e64994e6cd4569406ff6c052735cfddfda75efd Mon Sep 17 00:00:00 2001 From: "monken,wu" <610877102@mail.nknu.edu.tw> Date: Tue, 20 Jul 2021 02:13:39 +0800 Subject: [PATCH 0207/2325] fix entity-datamap guide wrong (#4937) --- system/Entity/Entity.php | 2 +- user_guide_src/source/models/entities.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Entity/Entity.php b/system/Entity/Entity.php index 7d44adf3e14c..a98395172e23 100644 --- a/system/Entity/Entity.php +++ b/system/Entity/Entity.php @@ -41,7 +41,7 @@ class Entity implements JsonSerializable * * Example: * $datamap = [ - * 'db_name' => 'class_name' + * 'class_name' => 'db_name' * ]; */ protected $datamap = []; diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 247c0fdce0e3..eec2447adf06 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -275,13 +275,13 @@ simply map the ``full_name`` column in the database to the ``$name`` property, a ]; protected $datamap = [ - 'full_name' => 'name', + 'name' => 'full_name', ]; } By adding our new database name to the ``$datamap`` array, we can tell the class what class property the database column -should be accessible through. The key of the array is the name of the column in the database, where the value in the array -is class property to map it to. +should be accessible through. The key of the array is class property to map it to, where the value in the array is the +name of the column in the database. In this example, when the model sets the ``full_name`` field on the User class, it actually assigns that value to the class' ``$name`` property, so it can be set and retrieved through ``$user->name``. The value will still be accessible From eeaae2a2186189cfe8ed99653c5c010487dcdf02 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 23 Jul 2021 21:16:56 +0800 Subject: [PATCH 0208/2325] Fix splitting of string rules (#4957) --- system/Validation/Validation.php | 43 +++++++++++---- tests/system/Validation/ValidationTest.php | 64 ++++++++++++++++++++++ 2 files changed, 96 insertions(+), 11 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index a41e1ebc558f..027b0018e842 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -672,20 +672,41 @@ protected function getErrorMessage(string $rule, string $field, ?string $label = */ protected function splitRules(string $rules): array { - $nonEscapeBracket = '((?getPrivateMethodInvoker($this->validation, 'splitRules'); + $this->assertSame($expected, $splitter($input)); + } + + public function provideStringRulesCases(): iterable + { + yield [ + 'required', + ['required'], + ]; + + yield [ + 'required|numeric', + ['required', 'numeric'], + ]; + + yield [ + 'required|max_length[500]|hex', + ['required', 'max_length[500]', 'hex'], + ]; + + yield [ + 'required|numeric|regex_match[/[a-zA-Z]+/]', + ['required', 'numeric', 'regex_match[/[a-zA-Z]+/]'], + ]; + + yield [ + 'required|max_length[500]|regex_match[/^;"\'{}\[\]^<>=/]', + ['required', 'max_length[500]', 'regex_match[/^;"\'{}\[\]^<>=/]'], + ]; + + yield [ + 'regex_match[/^;"\'{}\[\]^<>=/]|regex_match[/[^a-z0-9.\|_]+/]', + ['regex_match[/^;"\'{}\[\]^<>=/]', 'regex_match[/[^a-z0-9.\|_]+/]'], + ]; + + yield [ + 'required|regex_match[/^(01[2689]|09)[0-9]{8}$/]|numeric', + ['required', 'regex_match[/^(01[2689]|09)[0-9]{8}$/]', 'numeric'], + ]; + + yield [ + 'required|regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]|max_length[10]', + ['required', 'regex_match[/^[0-9]{4}[\-\.\[\/][0-9]{2}[\-\.\[\/][0-9]{2}/]', 'max_length[10]'], + ]; + + yield [ + 'required|regex_match[/^(01|2689|09)[0-9]{8}$/]|numeric', + ['required', 'regex_match[/^(01|2689|09)[0-9]{8}$/]', 'numeric'], + ]; + } } From cc24a929ea7cec4dce0b106bb3c98c458f508e05 Mon Sep 17 00:00:00 2001 From: Wolf Date: Mon, 2 Aug 2021 14:16:47 +0200 Subject: [PATCH 0209/2325] CLI: Prompt: Introduce promptByKey method --- system/CLI/CLI.php | 49 ++++++++++++++++++++--- user_guide_src/source/cli/cli_library.rst | 34 +++++++++++++++- 2 files changed, 77 insertions(+), 6 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index b463aa6a3016..3ddd544c229c 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -241,25 +241,64 @@ public static function prompt(string $field, $options = null, $validation = null if (empty($opts)) { $extraOutput = $extraOutputDefault; } else { - $extraOutput = ' [' . $extraOutputDefault . ', ' . implode(', ', $opts) . ']'; - $validation[] = 'in_list[' . implode(',', $options) . ']'; + $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $opts) . ']'; + $validation[] = 'in_list[' . implode(', ', $options) . ']'; } $default = $options[0]; } - static::fwrite(STDOUT, $field . $extraOutput . ': '); + static::fwrite(STDOUT, $field . (trim($field) ? ' ' : '') . $extraOutput . ': '); // Read the input from keyboard. $input = trim(static::input()) ?: $default; if ($validation) { - while (! static::validate($field, $input, $validation)) { + while (! static::validate(trim($field), $input, $validation)) { $input = static::prompt($field, $options, $validation); } } - return empty($input) ? '' : $input; + return $input; + } + + /** + * prompt(), but based on the option's key + * + * @param array|string $text Output "field" text or an one or two value array where the first value is the text before listing the options + * and the second value the text before asking to select one option. Provide empty string to omit + * @param array $options A list of options (array(key => description)), the first option will be the default value + * @param array|string|null $validation Validation rules + * + * @return string The selected key of $options + * + * @codeCoverageIgnore + */ + public static function promptByKey($text, array $options, $validation = null): string + { + if (is_string($text)) { + $text = [$text]; + } elseif (! is_array($text)) { + throw new InvalidArgumentException('$text can only be of type string|array'); + } + + if (! $options) { + throw new InvalidArgumentException('No options to select from were provided'); + } + + if ($line = array_shift($text)) { + CLI::write($line); + } + + // +2 for the square brackets around the key + $keyMaxLength = max(array_map('mb_strwidth', array_keys($options))) + 2; + + foreach ($options as $key => $description) { + $name = str_pad(' [' . $key . '] ', $keyMaxLength + 4, ' '); + CLI::write(CLI::color($name, 'green') . CLI::wrap($description, 125, $keyMaxLength + 4)); + } + + return static::prompt(PHP_EOL . array_shift($text), array_keys($options), $validation); } /** diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index d7ddc0993015..41638272eaa5 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -38,7 +38,7 @@ Getting Input from the User Sometimes you need to ask the user for more information. They might not have provided optional command-line arguments, or the script may have encountered an existing file and needs confirmation before overwriting. This is -handled with the ``prompt()`` method. +handled with the ``prompt()`` or ``promptByKey()`` method. You can provide a question by passing it in as the first parameter:: @@ -61,6 +61,38 @@ Validation rules can also be written in the array syntax.:: $email = CLI::prompt('What is your email?', null, ['required', 'valid_email']); + +**promptByKey()** + +Predefined answers (options) for prompt sometimes need to be described or are too complex to select via their value. +``promptByKey()`` allows the user to select an option by its key instead of its value:: + + $fruit = CLI::promptByKey('These are your choices:', ['The red apple', 'The plump orange', 'The ripe banana']); + + //These are your choices: + // [0] The red apple + // [1] The plump orange + // [2] The ripe banana + // + //[0, 1, 2]: + +Named keys are also possible:: + + $fruit = CLI::promptByKey(['These are your choices:', 'Which would you like?'], [ + 'apple' => 'The red apple', + 'orange' => 'The plump orange', + 'banana' => 'The ripe banana' + ]); + + //These are your choices: + // [apple] The red apple + // [orange] The plump orange + // [banana] The ripe banana + // + //Which would you like? [apple, orange, banana]: + +Finally, you can pass :ref:`validation ` rules to the answer input as the third parameter, the acceptable answers are automatically restricted to the passed options. + Providing Feedback ================== From c5f82f77157345c9d15057997798111af9b7e4b3 Mon Sep 17 00:00:00 2001 From: Wolf Date: Mon, 2 Aug 2021 16:31:59 +0200 Subject: [PATCH 0210/2325] CLI: Prompt: Change color of default value to green --- system/CLI/CLI.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 3ddd544c229c..ea1e1ad85611 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -228,13 +228,13 @@ public static function prompt(string $field, $options = null, $validation = null } if (is_string($options)) { - $extraOutput = ' [' . static::color($options, 'white') . ']'; + $extraOutput = ' [' . static::color($options, 'green') . ']'; $default = $options; } if (is_array($options) && $options) { $opts = $options; - $extraOutputDefault = static::color($opts[0], 'white'); + $extraOutputDefault = static::color($opts[0], 'green'); unset($opts[0]); From 5561492918feb6f8e3136a33f61990bd10385675 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Fri, 6 Aug 2021 21:07:03 +0800 Subject: [PATCH 0211/2325] Fix adding foreign keys with only string fields (#4988) --- system/Database/Forge.php | 19 ++++++++-- .../20160428212500_Create_test_tables.php | 2 - tests/system/Database/Live/ForgeTest.php | 37 +++++++++++++++++++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/system/Database/Forge.php b/system/Database/Forge.php index ba3423a890ea..256010e68d2d 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -351,12 +351,25 @@ public function addField($field) throw new InvalidArgumentException('Field information is required for that operation.'); } - $this->fields[] = $field; + $fieldName = explode(' ', $field, 2)[0]; + $fieldName = trim($fieldName, '`\'"'); + + $this->fields[$fieldName] = $field; } } if (is_array($field)) { - $this->fields = array_merge($this->fields, $field); + foreach ($field as $idx => $f) { + if (is_string($f)) { + $this->addField($f); + + continue; + } + + if (is_array($f)) { + $this->fields = array_merge($this->fields, [$idx => $f]); + } + } } return $this; @@ -761,7 +774,7 @@ protected function _processFields(bool $createTable = false): array $fields = []; foreach ($this->fields as $key => $attributes) { - if (is_int($key) && ! is_array($attributes)) { + if (! is_array($attributes)) { $fields[] = ['_literal' => $attributes]; continue; diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index 5b414de228a7..294accbdb898 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -137,7 +137,6 @@ public function up() 'data' => ['type' => 'BLOB', 'null' => false], ]); $this->forge->addKey('id', true); - $this->forge->addKey('timestamp'); $this->forge->createTable('ci_sessions', true); } @@ -149,7 +148,6 @@ public function up() "data bytea DEFAULT '' NOT NULL", ]); $this->forge->addKey('id', true); - $this->forge->addKey('timestamp'); $this->forge->createTable('ci_sessions', true); } } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 69812f98444b..2eaaa9f2af7b 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -427,6 +427,43 @@ public function testForeignKey() $this->forge->dropTable('forge_test_users', true); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4986 + */ + public function testForeignKeyAddingWithStringFields() + { + if ($this->db->DBDriver !== 'MySQLi') { + $this->markTestSkipped('Testing only on MySQLi but fix expands to all DBs.'); + } + + $attributes = ['ENGINE' => 'InnoDB']; + + $this->forge->addField([ + '`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', + '`name` VARCHAR(255) NOT NULL', + ])->createTable('forge_test_users', true, $attributes); + + $this->forge + ->addField([ + '`id` INT(11) NOT NULL AUTO_INCREMENT PRIMARY KEY', + '`users_id` INT(11) NOT NULL', + '`name` VARCHAR(255) NOT NULL', + ]) + ->addForeignKey('users_id', 'forge_test_users', 'id', 'CASCADE', 'CASCADE') + ->createTable('forge_test_invoices', true, $attributes); + + $foreignKeyData = $this->db->getForeignKeyData('forge_test_invoices')[0]; + + $this->assertSame($this->db->DBPrefix . 'forge_test_invoices_users_id_foreign', $foreignKeyData->constraint_name); + $this->assertSame('users_id', $foreignKeyData->column_name); + $this->assertSame('id', $foreignKeyData->foreign_column_name); + $this->assertSame($this->db->DBPrefix . 'forge_test_invoices', $foreignKeyData->table_name); + $this->assertSame($this->db->DBPrefix . 'forge_test_users', $foreignKeyData->foreign_table_name); + + $this->forge->dropTable('forge_test_invoices', true); + $this->forge->dropTable('forge_test_users', true); + } + public function testForeignKeyFieldNotExistException() { $this->expectException(DatabaseException::class); From 68a9a353a34b6e34b190d6c3db547990b30b3973 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Sun, 15 Aug 2021 00:27:10 +0100 Subject: [PATCH 0212/2325] Fix lang() function is overriding locale --- system/Common.php | 21 +++++++++++++++++++-- tests/system/Language/LanguageTest.php | 19 +++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/system/Common.php b/system/Common.php index bacac6ac0e4b..bdea46b26564 100644 --- a/system/Common.php +++ b/system/Common.php @@ -717,8 +717,25 @@ function is_really_writable(string $file): bool */ function lang(string $line, array $args = [], ?string $locale = null) { - return Services::language($locale) - ->getLine($line, $args); + $language = Services::language(); + + //Get active locale + $activeLocale = $language->getLocale(); + + if ($locale && $locale != $activeLocale) + { + $language->setLocale($locale); + } + + $line = $language->getLine($line, $args); + + if ($locale && $locale != $activeLocale) + { + //Reset to active locale + $language->setLocale($activeLocale); + } + + return $line; } } diff --git a/tests/system/Language/LanguageTest.php b/tests/system/Language/LanguageTest.php index 0dd8b3d69adc..ace99172aac4 100644 --- a/tests/system/Language/LanguageTest.php +++ b/tests/system/Language/LanguageTest.php @@ -271,6 +271,25 @@ public function testBaseFallbacks() $this->assertSame('More.shootMe', $this->lang->getLine('More.shootMe')); } + /** + * Test if after using lang() with a locale the Language class keep the locale after return the $line + */ + public function testLangKeepLocale() + { + $this->lang = Services::language('en', true); + + lang('Language.languageGetLineInvalidArgumentException'); + $this->assertEquals('en', $this->lang->getLocale()); + + lang('Language.languageGetLineInvalidArgumentException', [], 'ru'); + $this->assertEquals('en', $this->lang->getLocale()); + + lang('Language.languageGetLineInvalidArgumentException'); + $this->assertEquals('en', $this->lang->getLocale()); + } + + //-------------------------------------------------------------------- + /** * Testing base locale vs variants, with fallback to English. * From ef2c3b4400f058a00411bee0cac7d417dd7bfaa0 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 4 Jul 2021 10:20:59 +0200 Subject: [PATCH 0213/2325] Fix bug with handling boolean values in set() method in BaseBuilder and Model class --- system/Database/BaseBuilder.php | 4 +- system/Database/SQLSRV/Forge.php | 4 + system/Database/SQLite3/Forge.php | 4 + system/Model.php | 8 +- .../20160428212500_Create_test_tables.php | 1 + .../_support/Database/Seeds/CITestSeeder.php | 4 +- tests/system/Database/Builder/UpdateTest.php | 74 +++++++++++++++++++ tests/system/Database/Live/UpdateTest.php | 19 +++++ .../source/installation/upgrade_420.rst | 12 +++ 9 files changed, 123 insertions(+), 7 deletions(-) create mode 100644 user_guide_src/source/installation/upgrade_420.rst diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 7c3253c52685..43cedc8f09eb 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1339,12 +1339,12 @@ protected function _limit(string $sql, bool $offsetIgnore = false): string * Allows key/value pairs to be set for insert(), update() or replace(). * * @param array|object|string $key Field name, or an array of field/value pairs - * @param string|null $value Field value, if $key is a single field + * @param mixed $value Field value, if $key is a single field * @param bool|null $escape Whether to escape values and identifiers * * @return $this */ - public function set($key, ?string $value = '', ?bool $escape = null) + public function set($key, $value = '', ?bool $escape = null) { $key = $this->objectToArray($key); diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index aa646ccf2d6f..28dfe38c9a05 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -349,6 +349,10 @@ protected function _attributeType(array &$attributes) $attributes['TYPE'] = 'DATETIME'; break; + case 'BOOLEAN': + $attributes['TYPE'] = 'BIT'; + break; + default: break; } diff --git a/system/Database/SQLite3/Forge.php b/system/Database/SQLite3/Forge.php index 4d118d04eb62..3275322beb92 100644 --- a/system/Database/SQLite3/Forge.php +++ b/system/Database/SQLite3/Forge.php @@ -198,6 +198,10 @@ protected function _attributeType(array &$attributes) $attributes['TYPE'] = 'TEXT'; break; + case 'BOOLEAN': + $attributes['TYPE'] = 'INT'; + break; + default: break; } diff --git a/system/Model.php b/system/Model.php index 3617f83f69cb..580c691247f6 100644 --- a/system/Model.php +++ b/system/Model.php @@ -557,13 +557,13 @@ public function builder(?string $table = null) * data here. This allows it to be used with any of the other * builder methods and still get validated data, like replace. * - * @param array|string $key Field name, or an array of field/value pairs - * @param string|null $value Field value, if $key is a single field - * @param bool|null $escape Whether to escape values and identifiers + * @param mixed $key Field name, or an array of field/value pairs + * @param mixed $value Field value, if $key is a single field + * @param bool|null $escape Whether to escape values and identifiers * * @return $this */ - public function set($key, ?string $value = '', ?bool $escape = null) + public function set($key, $value = '', ?bool $escape = null) { $data = is_array($key) ? $key : [$key => $value]; diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index 294accbdb898..cf517e988ebc 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -70,6 +70,7 @@ public function up() 'type_double' => ['type' => 'DOUBLE', 'null' => true], 'type_decimal' => ['type' => 'DECIMAL', 'constraint' => '18,4', 'null' => true], 'type_blob' => ['type' => 'BLOB', 'null' => true], + 'type_boolean' => ['type' => 'BOOLEAN', 'null' => true], ]; if ($this->db->DBDriver === 'Postgre') { diff --git a/tests/_support/Database/Seeds/CITestSeeder.php b/tests/_support/Database/Seeds/CITestSeeder.php index ae4b2af3b0b7..372697aaa6ba 100644 --- a/tests/_support/Database/Seeds/CITestSeeder.php +++ b/tests/_support/Database/Seeds/CITestSeeder.php @@ -106,6 +106,7 @@ public function run() 'type_datetime' => '2020-06-18T05:12:24.000+02:00', 'type_timestamp' => '2019-07-18T21:53:21.000+02:00', 'type_bigint' => 2342342, + 'type_boolean' => 1, ], ], ]; @@ -119,7 +120,8 @@ public function run() } if ($this->db->DBDriver === 'Postgre') { - $data['type_test'][0]['type_time'] = '15:22:00'; + $data['type_test'][0]['type_time'] = '15:22:00'; + $data['type_test'][0]['type_boolean'] = true; unset( $data['type_test'][0]['type_enum'], $data['type_test'][0]['type_set'], diff --git a/tests/system/Database/Builder/UpdateTest.php b/tests/system/Database/Builder/UpdateTest.php index 801324d01f79..6d4cc84973c1 100644 --- a/tests/system/Database/Builder/UpdateTest.php +++ b/tests/system/Database/Builder/UpdateTest.php @@ -99,6 +99,80 @@ public function testUpdateWithSet() $this->assertSame($expectedBinds, $builder->getBinds()); } + public function testUpdateWithSetAsInt() + { + $builder = new BaseBuilder('jobs', $this->db); + + $builder->testMode()->set('age', 22)->where('id', 1)->update(null, null, null); + + $expectedSQL = 'UPDATE "jobs" SET "age" = 22 WHERE "id" = 1'; + $expectedBinds = [ + 'age' => [ + 22, + true, + ], + 'id' => [ + 1, + true, + ], + ]; + + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledUpdate())); + $this->assertSame($expectedBinds, $builder->getBinds()); + } + + public function testUpdateWithSetAsBoolean() + { + $builder = new BaseBuilder('jobs', $this->db); + + $builder->testMode()->set('manager', true)->where('id', 1)->update(null, null, null); + + $expectedSQL = 'UPDATE "jobs" SET "manager" = 1 WHERE "id" = 1'; + $expectedBinds = [ + 'manager' => [ + true, + true, + ], + 'id' => [ + 1, + true, + ], + ]; + + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledUpdate())); + $this->assertSame($expectedBinds, $builder->getBinds()); + } + + public function testUpdateWithSetAsArray() + { + $builder = new BaseBuilder('jobs', $this->db); + + $builder->testMode()->set(['name' => 'Programmer', 'age' => 22, 'manager' => true])->where('id', 1)->update(null, null, null); + + $expectedSQL = 'UPDATE "jobs" SET "name" = \'Programmer\', "age" = 22, "manager" = 1 WHERE "id" = 1'; + $expectedBinds = [ + 'name' => [ + 'Programmer', + true, + ], + 'age' => [ + 22, + true, + ], + 'manager' => [ + true, + true, + ], + 'id' => [ + 1, + true, + ], + ]; + + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledUpdate())); + $this->assertSame($expectedBinds, $builder->getBinds()); + } + public function testUpdateThrowsExceptionWithNoData() { $builder = new BaseBuilder('jobs', $this->db); diff --git a/tests/system/Database/Live/UpdateTest.php b/tests/system/Database/Live/UpdateTest.php index f047f16a7bfd..c0f1bd3575d4 100644 --- a/tests/system/Database/Live/UpdateTest.php +++ b/tests/system/Database/Live/UpdateTest.php @@ -211,4 +211,23 @@ public function testSetWithoutEscape() 'description' => 'Developer', ]); } + + public function testSetWithBoolean() + { + $this->db->table('type_test') + ->set('type_boolean', false) + ->update(); + + $this->seeInDatabase('type_test', [ + 'type_boolean' => false, + ]); + + $this->db->table('type_test') + ->set('type_boolean', true) + ->update(); + + $this->seeInDatabase('type_test', [ + 'type_boolean' => true, + ]); + } } diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_420.rst new file mode 100644 index 000000000000..a306b4978347 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_420.rst @@ -0,0 +1,12 @@ +############################# +Upgrading from 4.1.3 to 4.2.0 +############################# + +**Changes for set() method in BaseBuilder and Model class** + +The casting for the ``$value`` parameter has been removed to fix a bug where passing parameters as array and string +to the ``set()`` method were handled differently. If you extended the ``BaseBuilder`` class or ``Model`` class yourself +and modified the ``set()`` method, then you need to change its definition from +``public function set($key, ?string $value = '', ?bool $escape = null)`` to +``public function set($key, $value = '', ?bool $escape = null)``. + From c6a913731c982547a5f2008f7d4628bdbab1ae98 Mon Sep 17 00:00:00 2001 From: michalsn Date: Sun, 4 Jul 2021 10:31:25 +0200 Subject: [PATCH 0214/2325] Update method definition in the user guide --- user_guide_src/source/database/query_builder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 342da67461e3..3494325e5084 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -1726,7 +1726,7 @@ Class Reference .. php:method:: set($key[, $value = ''[, $escape = null]]) :param mixed $key: Field name, or an array of field/value pairs - :param string $value: Field value, if $key is a single field + :param mixed $value: Field value, if $key is a single field :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` From e8ddf0e6d5d2de027afa05317bd9e5950522e125 Mon Sep 17 00:00:00 2001 From: michalsn Date: Fri, 23 Jul 2021 09:53:19 +0200 Subject: [PATCH 0215/2325] add to toctree --- user_guide_src/source/changelogs/index.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index 038d259e4189..a997a57f0c3f 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.0 v4.1.4 v4.1.3 v4.1.2 From 1c51f25e8a4c2684fcd4b6b29c27a122af56d7ba Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 17 Aug 2021 14:53:13 +0000 Subject: [PATCH 0216/2325] Add config for cache keys --- app/Config/Cache.php | 15 +++++++++++++++ system/Cache/Handlers/BaseHandler.php | 10 +++++++--- .../system/Cache/Handlers/BaseHandlerTest.php | 10 ++++++++++ user_guide_src/source/changelogs/v4.2.0.rst | 18 ++++++++++++++++++ 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 user_guide_src/source/changelogs/v4.2.0.rst diff --git a/app/Config/Cache.php b/app/Config/Cache.php index ce1db4d7f24e..3c725c469754 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -2,6 +2,7 @@ namespace Config; +use CodeIgniter\Cache\Handlers\BaseHandler; use CodeIgniter\Cache\Handlers\DummyHandler; use CodeIgniter\Cache\Handlers\FileHandler; use CodeIgniter\Cache\Handlers\MemcachedHandler; @@ -97,6 +98,20 @@ class Cache extends BaseConfig */ public $ttl = 60; + /** + * -------------------------------------------------------------------------- + * Reserved Characters + * -------------------------------------------------------------------------- + * + * A string of reserved characters that will not be allowed in keys or tags. + * Strings that violate this restriction will cause handlers to throw. + * Default: {}()/\@: + * Note: The default set is required for PSR-6 compliance. + * + * @var string + */ + public $reservedCharacters = '{}()/\@:'; + /** * -------------------------------------------------------------------------- * File settings diff --git a/system/Cache/Handlers/BaseHandler.php b/system/Cache/Handlers/BaseHandler.php index cae03b901664..57120208ceeb 100644 --- a/system/Cache/Handlers/BaseHandler.php +++ b/system/Cache/Handlers/BaseHandler.php @@ -22,8 +22,10 @@ abstract class BaseHandler implements CacheInterface { /** - * Reserved characters that cannot be used in a key or tag. + * Reserved characters that cannot be used in a key or tag. May be overridden by the config. * From https://github.com/symfony/cache-contracts/blob/c0446463729b89dd4fa62e9aeecc80287323615d/ItemInterface.php#L43 + * + * @deprecated in favor of the Cache config */ public const RESERVED_CHARACTERS = '{}()/\@:'; @@ -58,8 +60,10 @@ public static function validateKey($key, $prefix = ''): string if ($key === '') { throw new InvalidArgumentException('Cache key cannot be empty.'); } - if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) { - throw new InvalidArgumentException('Cache key contains reserved characters ' . self::RESERVED_CHARACTERS); + + $reserved = config('Cache')->reservedCharacters ?? self::RESERVED_CHARACTERS; + if ($reserved && strpbrk($key, $reserved) !== false) { + throw new InvalidArgumentException('Cache key contains reserved characters ' . $reserved); } // If the key with prefix exceeds the length then return the hashed version diff --git a/tests/system/Cache/Handlers/BaseHandlerTest.php b/tests/system/Cache/Handlers/BaseHandlerTest.php index 5965666a5810..73f46620b559 100644 --- a/tests/system/Cache/Handlers/BaseHandlerTest.php +++ b/tests/system/Cache/Handlers/BaseHandlerTest.php @@ -44,6 +44,16 @@ public function invalidTypeProvider(): array ]; } + public function testValidateKeyUsesConfig() + { + config('Cache')->reservedCharacters = 'b'; + + $this->expectException('InvalidArgumentException'); + $this->expectExceptionMessage('Cache key contains reserved characters b'); + + BaseHandler::validateKey('banana'); + } + public function testValidateKeySuccess() { $string = 'banana'; diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst new file mode 100644 index 000000000000..c1a7d2673ab1 --- /dev/null +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -0,0 +1,18 @@ +Version 4.2.0 +============= + +Release Date: Not released + +**4.2.0 release of CodeIgniter4** + +Enhancements: + +- Added Cache config for reserved characters + +Changes: + +Deprecations: + +- Deprecated ``CodeIgniter\\Cache\\Handlers\\BaseHandler::RESERVED_CHARACTERS`` in favor of the new config property + +Bugs Fixed: From 18f24101d1ae8704d76f535fb921f9dd31cb9384 Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 18 Aug 2021 07:49:41 -0400 Subject: [PATCH 0217/2325] Update app/Config/Cache.php --- app/Config/Cache.php | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Config/Cache.php b/app/Config/Cache.php index 3c725c469754..2d1fea90c9d1 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -2,7 +2,6 @@ namespace Config; -use CodeIgniter\Cache\Handlers\BaseHandler; use CodeIgniter\Cache\Handlers\DummyHandler; use CodeIgniter\Cache\Handlers\FileHandler; use CodeIgniter\Cache\Handlers\MemcachedHandler; From 39ad669599517f6db23d73cb87f756252f6bb3bf Mon Sep 17 00:00:00 2001 From: MonkenWu <610877102@mail.nknu.edu.tw> Date: Wed, 14 Jul 2021 01:34:15 +0800 Subject: [PATCH 0218/2325] =?UTF-8?q?=EF=BB=BFFix=20bug=20with=20DB-Forge?= =?UTF-8?q?=20composite=20foreign=20keys?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- system/Database/Forge.php | 54 +++++++--- system/Database/SQLSRV/Forge.php | 29 ++--- tests/system/Database/Live/ForgeTest.php | 129 +++++++++++++++++++++++ user_guide_src/source/dbmgmt/forge.rst | 14 ++- 4 files changed, 193 insertions(+), 33 deletions(-) diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 256010e68d2d..39d4384a98ae 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -378,21 +378,35 @@ public function addField($field) /** * Add Foreign Key * + * @param string|string[] $fieldName + * @param string|string[] $tableField + * * @throws DatabaseException * * @return Forge */ - public function addForeignKey(string $fieldName = '', string $tableName = '', string $tableField = '', string $onUpdate = '', string $onDelete = '') + public function addForeignKey($fieldName = '', string $tableName = '', $tableField = '', string $onUpdate = '', string $onDelete = '') { - if (! isset($this->fields[$fieldName])) { - throw new DatabaseException(lang('Database.fieldNotExists', [$fieldName])); + $fieldName = (array) $fieldName; + $tableField = (array) $tableField; + $errorNames = []; + + foreach ($fieldName as $name) { + if (! isset($this->fields[$name])) { + $errorNames[] = $name; + } + } + + if ($errorNames !== []) { + throw new DatabaseException(lang('Database.fieldNotExists', $errorNames)); } - $this->foreignKeys[$fieldName] = [ - 'table' => $tableName, - 'field' => $tableField, - 'onDelete' => strtoupper($onDelete), - 'onUpdate' => strtoupper($onUpdate), + $this->foreignKeys[] = [ + 'field' => $fieldName, + 'referenceTable' => $tableName, + 'referenceField' => $tableField, + 'onDelete' => strtoupper($onDelete), + 'onUpdate' => strtoupper($onUpdate), ]; return $this; @@ -1009,18 +1023,24 @@ protected function _processForeignKeys(string $table): string 'SET DEFAULT', ]; - foreach ($this->foreignKeys as $field => $fkey) { - $nameIndex = $table . '_' . $field . '_foreign'; + if ($this->foreignKeys !== []) { + foreach ($this->foreignKeys as $fkey) { + $nameIndex = $table . '_' . implode('_', $fkey['field']) . '_foreign'; + $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); + $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); + $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); + $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); - $sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) - . ' FOREIGN KEY(' . $this->db->escapeIdentifiers($field) . ') REFERENCES ' . $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; + $formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)"; + $sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled); - if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { - $sql .= ' ON DELETE ' . $fkey['onDelete']; - } + if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { + $sql .= ' ON DELETE ' . $fkey['onDelete']; + } - if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { - $sql .= ' ON UPDATE ' . $fkey['onUpdate']; + if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { + $sql .= ' ON UPDATE ' . $fkey['onUpdate']; + } } } diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index 28dfe38c9a05..3fed6c48962f 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -282,19 +282,24 @@ protected function _processForeignKeys(string $table): string $allowActions = ['CASCADE', 'SET NULL', 'NO ACTION', 'RESTRICT', 'SET DEFAULT']; - foreach ($this->foreignKeys as $field => $fkey) { - $nameIndex = $table . '_' . $field . '_foreign'; - - $sql .= ",\n\t CONSTRAINT " . $this->db->escapeIdentifiers($nameIndex) - . ' FOREIGN KEY (' . $this->db->escapeIdentifiers($field) . ') ' - . ' REFERENCES ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($this->db->getPrefix() . $fkey['table']) . ' (' . $this->db->escapeIdentifiers($fkey['field']) . ')'; - - if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { - $sql .= ' ON DELETE ' . $fkey['onDelete']; - } + if ($this->foreignKeys !== []) { + foreach ($this->foreignKeys as $fkey) { + $nameIndex = $table . '_' . implode('_', $fkey['field']) . '_foreign'; + $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); + $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); + $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); + $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); + + $formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)"; + $sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled); + + if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { + $sql .= ' ON DELETE ' . $fkey['onDelete']; + } - if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { - $sql .= ' ON UPDATE ' . $fkey['onUpdate']; + if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { + $sql .= ' ON UPDATE ' . $fkey['onUpdate']; + } } } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 2eaaa9f2af7b..dadcd753e3b5 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -464,6 +464,135 @@ public function testForeignKeyAddingWithStringFields() $this->forge->dropTable('forge_test_users', true); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4310 + */ + public function testCompositeForeignKey() + { + $attributes = []; + + if ($this->db->DBDriver === 'MySQLi') { + $attributes = ['ENGINE' => 'InnoDB']; + } + + $this->forge->addField([ + 'id' => [ + 'type' => 'INTEGER', + 'constraint' => 11, + ], + 'second_id' => [ + 'type' => 'VARCHAR', + 'constraint' => 50, + ], + 'name' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + ]); + $this->forge->addPrimaryKey(['id', 'second_id']); + $this->forge->createTable('forge_test_users', true, $attributes); + + $this->forge->addField([ + 'id' => [ + 'type' => 'INTEGER', + 'constraint' => 11, + ], + 'users_id' => [ + 'type' => 'INTEGER', + 'constraint' => 11, + ], + 'users_second_id' => [ + 'type' => 'VARCHAR', + 'constraint' => 50, + ], + 'name' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + ]); + $this->forge->addPrimaryKey('id'); + $this->forge->addForeignKey(['users_id', 'users_second_id'], 'forge_test_users', ['id', 'second_id'], 'CASCADE', 'CASCADE'); + + $this->forge->createTable('forge_test_invoices', true, $attributes); + + $foreignKeyData = $this->db->getForeignKeyData('forge_test_invoices'); + + if ($this->db->DBDriver === 'SQLite3') { + $this->assertSame($foreignKeyData[0]->constraint_name, 'users_id to db_forge_test_users.id'); + $this->assertSame($foreignKeyData[0]->sequence, 0); + $this->assertSame($foreignKeyData[1]->constraint_name, 'users_second_id to db_forge_test_users.second_id'); + $this->assertSame($foreignKeyData[1]->sequence, 1); + } else { + $haystack = ['users_id', 'users_second_id']; + $this->assertSame($foreignKeyData[0]->constraint_name, $this->db->DBPrefix . 'forge_test_invoices_users_id_users_second_id_foreign'); + $this->assertContains($foreignKeyData[0]->column_name, $haystack); + + $secondIdKey = $this->db->DBDriver === 'Postgre' ? 2 : 1; + $this->assertSame($foreignKeyData[$secondIdKey]->constraint_name, $this->db->DBPrefix . 'forge_test_invoices_users_id_users_second_id_foreign'); + $this->assertContains($foreignKeyData[$secondIdKey]->column_name, $haystack); + } + $this->assertSame($foreignKeyData[0]->table_name, $this->db->DBPrefix . 'forge_test_invoices'); + $this->assertSame($foreignKeyData[0]->foreign_table_name, $this->db->DBPrefix . 'forge_test_users'); + + $this->forge->dropTable('forge_test_invoices', true); + $this->forge->dropTable('forge_test_users', true); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4310 + */ + public function testCompositeForeignKeyFieldNotExistException() + { + $this->expectException(DatabaseException::class); + $this->expectExceptionMessage('Field `user_id, user_second_id` not found.'); + + $attributes = []; + + if ($this->db->DBDriver === 'MySQLi') { + $attributes = ['ENGINE' => 'InnoDB']; + } + + $this->forge->addField([ + 'id' => [ + 'type' => 'INTEGER', + 'constraint' => 11, + ], + 'second_id' => [ + 'type' => 'VARCHAR', + 'constraint' => 50, + ], + 'name' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + ]); + $this->forge->addPrimaryKey(['id', 'second_id']); + $this->forge->createTable('forge_test_users', true, $attributes); + + $this->forge->addField([ + 'id' => [ + 'type' => 'INTEGER', + 'constraint' => 11, + ], + 'users_id' => [ + 'type' => 'INTEGER', + 'constraint' => 11, + ], + 'users_second_id' => [ + 'type' => 'VARCHAR', + 'constraint' => 50, + ], + 'name' => [ + 'type' => 'VARCHAR', + 'constraint' => 255, + ], + ]); + $this->forge->addKey('id', true); + $this->forge->addForeignKey(['user_id', 'user_second_id'], 'forge_test_users', ['id', 'second_id'], 'CASCADE', 'CASCADE'); + + $this->forge->createTable('forge_test_invoices', true, $attributes); + } + public function testForeignKeyFieldNotExistException() { $this->expectException(DatabaseException::class); diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index aba92fc634b2..e16b5ee1e92f 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -230,13 +230,19 @@ Adding Foreign Keys Foreign Keys help to enforce relationships and actions across your tables. For tables that support Foreign Keys, you may add them directly in forge:: - $forge->addForeignKey('users_id','users','id'); - // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) + $forge->addForeignKey('users_id','users','id'); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) + + $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name']); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) You can specify the desired action for the "on delete" and "on update" properties of the constraint:: - $forge->addForeignKey('users_id','users','id','CASCADE','CASCADE'); - // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE + $forge->addForeignKey('users_id','users','id','CASCADE','CASCADE'); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE + + $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name'],'CASCADE','CASCADE'); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) ON DELETE CASCADE ON UPDATE CASCADE Creating a table ================ From 19de0150cce1291747656314b4cc03fb57e95bd3 Mon Sep 17 00:00:00 2001 From: MonkenWu <610877102@mail.nknu.edu.tw> Date: Fri, 23 Jul 2021 17:33:05 +0800 Subject: [PATCH 0219/2325] =?UTF-8?q?=EF=BB=BFcreate=20new=20changelog?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- user_guide_src/source/changelogs/v4.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index c1a7d2673ab1..22a94202a69f 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -8,6 +8,7 @@ Release Date: Not released Enhancements: - Added Cache config for reserved characters +- The ``addForeignKey`` function of the ``Forge`` class can now define composite foreign keys in an array Changes: From 82e9c49092b4fa95f9ec8f3947fa951b64192a3c Mon Sep 17 00:00:00 2001 From: MonkenWu <610877102@mail.nknu.edu.tw> Date: Tue, 27 Jul 2021 22:09:58 +0800 Subject: [PATCH 0220/2325] fix composition foreign keys exception and add new test case --- system/Database/Forge.php | 2 ++ tests/system/Database/Live/ForgeTest.php | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 39d4384a98ae..cd471138db71 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -398,6 +398,8 @@ public function addForeignKey($fieldName = '', string $tableName = '', $tableFie } if ($errorNames !== []) { + $errorNames[0] = implode(', ',$errorNames); + throw new DatabaseException(lang('Database.fieldNotExists', $errorNames)); } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index dadcd753e3b5..531f166f2b7d 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -372,6 +372,8 @@ public function testDropTableWithEmptyName() public function testForeignKey() { + $this->forge->dropTable('forge_test_users', true); + $attributes = []; if ($this->db->DBDriver === 'MySQLi') { @@ -639,6 +641,8 @@ public function testForeignKeyFieldNotExistException() public function testDropForeignKey() { + $this->forge->dropTable('forge_test_users', true); + $attributes = []; if ($this->db->DBDriver === 'MySQLi') { From 1734b5ff34596fcc4209ab7bed8524a2ea30ba53 Mon Sep 17 00:00:00 2001 From: MonkenWu <610877102@mail.nknu.edu.tw> Date: Wed, 18 Aug 2021 14:45:31 +0800 Subject: [PATCH 0221/2325] Modify the parameters in "assertSame" --- tests/system/Database/Live/ForgeTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 531f166f2b7d..d459bc92e391 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -520,21 +520,21 @@ public function testCompositeForeignKey() $foreignKeyData = $this->db->getForeignKeyData('forge_test_invoices'); if ($this->db->DBDriver === 'SQLite3') { - $this->assertSame($foreignKeyData[0]->constraint_name, 'users_id to db_forge_test_users.id'); - $this->assertSame($foreignKeyData[0]->sequence, 0); - $this->assertSame($foreignKeyData[1]->constraint_name, 'users_second_id to db_forge_test_users.second_id'); - $this->assertSame($foreignKeyData[1]->sequence, 1); + $this->assertSame('users_id to db_forge_test_users.id', $foreignKeyData[0]->constraint_name); + $this->assertSame(0, $foreignKeyData[0]->sequence); + $this->assertSame('users_second_id to db_forge_test_users.second_id', $foreignKeyData[1]->constraint_name); + $this->assertSame(1, $foreignKeyData[1]->sequence); } else { $haystack = ['users_id', 'users_second_id']; - $this->assertSame($foreignKeyData[0]->constraint_name, $this->db->DBPrefix . 'forge_test_invoices_users_id_users_second_id_foreign'); + $this->assertSame($this->db->DBPrefix . 'forge_test_invoices_users_id_users_second_id_foreign', $foreignKeyData[0]->constraint_name); $this->assertContains($foreignKeyData[0]->column_name, $haystack); $secondIdKey = $this->db->DBDriver === 'Postgre' ? 2 : 1; - $this->assertSame($foreignKeyData[$secondIdKey]->constraint_name, $this->db->DBPrefix . 'forge_test_invoices_users_id_users_second_id_foreign'); + $this->assertSame($this->db->DBPrefix . 'forge_test_invoices_users_id_users_second_id_foreign', $foreignKeyData[$secondIdKey]->constraint_name); $this->assertContains($foreignKeyData[$secondIdKey]->column_name, $haystack); } - $this->assertSame($foreignKeyData[0]->table_name, $this->db->DBPrefix . 'forge_test_invoices'); - $this->assertSame($foreignKeyData[0]->foreign_table_name, $this->db->DBPrefix . 'forge_test_users'); + $this->assertSame($this->db->DBPrefix . 'forge_test_invoices', $foreignKeyData[0]->table_name); + $this->assertSame($this->db->DBPrefix . 'forge_test_users', $foreignKeyData[0]->foreign_table_name); $this->forge->dropTable('forge_test_invoices', true); $this->forge->dropTable('forge_test_users', true); From eb3ed2b8005c01e43dd9cc8a38bb6d9ef359bf0c Mon Sep 17 00:00:00 2001 From: Mostafa Khudair Date: Fri, 20 Aug 2021 15:17:27 +0200 Subject: [PATCH 0222/2325] Add missing make:config command config view file --- app/Config/Generators.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Config/Generators.php b/app/Config/Generators.php index c47153d47042..11214fdc6e55 100644 --- a/app/Config/Generators.php +++ b/app/Config/Generators.php @@ -27,6 +27,7 @@ class Generators extends BaseConfig */ public $views = [ 'make:command' => 'CodeIgniter\Commands\Generators\Views\command.tpl.php', + 'make:config' => 'CodeIgniter\Commands\Generators\Views\config.tpl.php', 'make:controller' => 'CodeIgniter\Commands\Generators\Views\controller.tpl.php', 'make:entity' => 'CodeIgniter\Commands\Generators\Views\entity.tpl.php', 'make:filter' => 'CodeIgniter\Commands\Generators\Views\filter.tpl.php', From 86f507621842e53c14fad6917a6642e6a87d13e2 Mon Sep 17 00:00:00 2001 From: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> Date: Tue, 24 Aug 2021 15:25:18 +0200 Subject: [PATCH 0223/2325] [Userguide] Add missing generator's command (#5019) * Add missing make:validation command * fix shot title --- user_guide_src/source/cli/cli_generators.rst | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/user_guide_src/source/cli/cli_generators.rst b/user_guide_src/source/cli/cli_generators.rst index f7d0ea380fb3..210226b51edc 100644 --- a/user_guide_src/source/cli/cli_generators.rst +++ b/user_guide_src/source/cli/cli_generators.rst @@ -205,6 +205,27 @@ Options: * ``--suffix``: Append the component suffix to the generated class name. * ``--force``: Set this flag to overwrite existing files on destination. +make:validation +--------------- + +Creates a new validation file. + +Usage: +====== +:: + + make:validation [options] + +Argument: +========= +* ``name``: The name of the validation class. **[REQUIRED]** + +Options: +======== +* ``--namespace``: Set the root namespace. Defaults to value of ``APP_NAMESPACE``. +* ``--suffix``: Append the component suffix to the generated class name. +* ``--force``: Set this flag to overwrite existing files on destination. + .. note:: Do you need to have the generated code in a subfolder? Let's say if you want to create a controller class to reside in the ``Admin`` subfolder of the main ``Controllers`` folder, you will just need to prepend the subfolder to the class name, like this: ``php spark make:controller admin/login``. This From bf84d197690de9a3e53df1cf97753cddf485187f Mon Sep 17 00:00:00 2001 From: Mostafa Khudair Date: Thu, 26 Aug 2021 11:21:06 +0200 Subject: [PATCH 0224/2325] fix make:migration command options --- user_guide_src/source/dbmgmt/migration.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 9da3e2d3e9b3..88b2a2c1e106 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -258,8 +258,11 @@ creates is the Pascal case version of the filename. You can use (make:migration) with the following options: -- ``-n`` - to choose namespace, otherwise the value of ``APP_NAMESPACE`` will be used. -- ``-force`` - If a similarly named migration file is present in destination, this will be overwritten. +- ``--session`` - Generates the migration file for database sessions. +- ``--table`` - Table name to use for database sessions. Default: ``ci_sessions``. +- ``--dbgroup`` - Database group to use for database sessions. Default: ``default``. +- ``--namespace`` - Set root namespace. Default: ``APP_NAMESPACE``. +- ``--suffix`` - Append the component title to the class name. ********************* Migration Preferences From d8c35c179906b529fae60752aec80b80edec43ca Mon Sep 17 00:00:00 2001 From: Mostafa Khudair Date: Wed, 25 Aug 2021 20:33:45 +0200 Subject: [PATCH 0225/2325] Fix wrong cli command option --- user_guide_src/source/dbmgmt/seeds.rst | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/dbmgmt/seeds.rst b/user_guide_src/source/dbmgmt/seeds.rst index 53a2635ed782..f30bc807ddbb 100644 --- a/user_guide_src/source/dbmgmt/seeds.rst +++ b/user_guide_src/source/dbmgmt/seeds.rst @@ -125,15 +125,13 @@ Using the command line, you can easily generate seed files. :: - // This command will create a UserSeeder seed file - // located at app/Database/Seeds/ directory. - > php spark make:seeder UserSeeder + > php spark make:seeder user --suffix + // Output: UserSeeder.php file located at app/Database/Seeds directory. -You can supply the **root** namespace where the seed file will be stored by supplying the ``-n`` option:: +You can supply the **root** namespace where the seed file will be stored by supplying the ``--namespace`` option:: - > php spark make:seeder MySeeder -n Acme\Blog + > php spark make:seeder MySeeder --namespace Acme\Blog -If ``Acme\Blog`` is mapped to ``app/Blog`` directory, then this command will save the -seed file to ``app/Blog/Database/Seeds/``. +If ``Acme\Blog`` is mapped to ``app/Blog`` directory, then this command will generate ``MySeeder.php`` at ``app/Blog/Database/Seeds`` directory. Supplying the ``--force`` option will overwrite existing files in destination. From 107df929b02548351b8c1d589b855252634b0d23 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Tue, 7 Sep 2021 23:30:27 +0800 Subject: [PATCH 0226/2325] Fix coding style violations in 4.2 --- app/Config/Publisher.php | 26 +- system/CodeIgniter.php | 2 +- system/Commands/Utilities/Publish.php | 153 ++- system/Common.php | 10 +- system/Config/Publisher.php | 44 +- system/Database/Forge.php | 30 +- system/Database/MySQLi/Connection.php | 2 - system/Database/SQLSRV/Forge.php | 32 +- system/Debug/Toolbar.php | 1 - system/Files/Exceptions/FileException.php | 36 +- system/Files/FileCollection.php | 678 ++++++------ system/Language/en/Files.php | 4 +- system/Language/en/Publisher.php | 20 +- .../Exceptions/PublisherException.php | 60 +- system/Publisher/Publisher.php | 861 ++++++++-------- system/Session/Handlers/DatabaseHandler.php | 2 +- tests/_support/Publishers/TestPublisher.php | 86 +- .../system/Cache/Handlers/BaseHandlerTest.php | 2 +- .../system/Cache/Handlers/FileHandlerTest.php | 2 +- .../Cache/Handlers/MemcachedHandlerTest.php | 2 +- .../Cache/Handlers/PredisHandlerTest.php | 2 +- .../Cache/Handlers/RedisHandlerTest.php | 2 +- .../system/Commands/CommandGeneratorTest.php | 2 +- tests/system/Commands/PublishCommandTest.php | 94 +- tests/system/Files/FileCollectionTest.php | 964 +++++++++--------- tests/system/Language/LanguageTest.php | 8 +- tests/system/Publisher/PublisherInputTest.php | 280 ++--- .../system/Publisher/PublisherOutputTest.php | 440 ++++---- .../Publisher/PublisherRestrictionsTest.php | 200 ++-- .../system/Publisher/PublisherSupportTest.php | 274 ++--- .../Session/Handlers/DatabaseHandlerTest.php | 2 +- tests/system/Validation/ValidationTest.php | 5 - 32 files changed, 2120 insertions(+), 2206 deletions(-) diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php index 2588eea2abac..f3768bc577b4 100644 --- a/app/Config/Publisher.php +++ b/app/Config/Publisher.php @@ -12,17 +12,17 @@ */ class Publisher extends BasePublisher { - /** - * A list of allowed destinations with a (pseudo-)regex - * of allowed files for each destination. - * Attempts to publish to directories not in this list will - * result in a PublisherException. Files that do no fit the - * pattern will cause copy/merge to fail. - * - * @var array - */ - public $restrictions = [ - ROOTPATH => '*', - FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', - ]; + /** + * A list of allowed destinations with a (pseudo-)regex + * of allowed files for each destination. + * Attempts to publish to directories not in this list will + * result in a PublisherException. Files that do no fit the + * pattern will cause copy/merge to fail. + * + * @var array + */ + public $restrictions = [ + ROOTPATH => '*', + FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + ]; } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index f18fc38384b6..aee11790f406 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -496,7 +496,7 @@ protected function bootstrapEnvironment() */ protected function startBenchmark() { - if($this->startTime === null) { + if ($this->startTime === null) { $this->startTime = microtime(true); } diff --git a/system/Commands/Utilities/Publish.php b/system/Commands/Utilities/Publish.php index 15448fc90db3..cfed0472c439 100644 --- a/system/Commands/Utilities/Publish.php +++ b/system/Commands/Utilities/Publish.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Commands\Utilities; @@ -22,92 +22,83 @@ */ class Publish extends BaseCommand { - /** - * The group the command is lumped under - * when listing commands. - * - * @var string - */ - protected $group = 'CodeIgniter'; + /** + * The group the command is lumped under + * when listing commands. + * + * @var string + */ + protected $group = 'CodeIgniter'; - /** - * The Command's name - * - * @var string - */ - protected $name = 'publish'; + /** + * The Command's name + * + * @var string + */ + protected $name = 'publish'; - /** - * The Command's short description - * - * @var string - */ - protected $description = 'Discovers and executes all predefined Publisher classes.'; + /** + * The Command's short description + * + * @var string + */ + protected $description = 'Discovers and executes all predefined Publisher classes.'; - /** - * The Command's usage - * - * @var string - */ - protected $usage = 'publish []'; + /** + * The Command's usage + * + * @var string + */ + protected $usage = 'publish []'; - /** - * The Command's arguments - * - * @var array - */ - protected $arguments = [ - 'directory' => '[Optional] The directory to scan within each namespace. Default: "Publishers".', - ]; + /** + * The Command's arguments + * + * @var array + */ + protected $arguments = [ + 'directory' => '[Optional] The directory to scan within each namespace. Default: "Publishers".', + ]; - /** - * the Command's Options - * - * @var array - */ - protected $options = []; + /** + * the Command's Options + * + * @var array + */ + protected $options = []; - //-------------------------------------------------------------------- + /** + * Displays the help for the spark cli script itself. + */ + public function run(array $params) + { + $directory = array_shift($params) ?? 'Publishers'; - /** - * Displays the help for the spark cli script itself. - * - * @param array $params - */ - public function run(array $params) - { - $directory = array_shift($params) ?? 'Publishers'; + if ([] === $publishers = Publisher::discover($directory)) { + CLI::write(lang('Publisher.publishMissing', [$directory])); - if ([] === $publishers = Publisher::discover($directory)) - { - CLI::write(lang('Publisher.publishMissing', [$directory])); - return; - } + return; + } - foreach ($publishers as $publisher) - { - if ($publisher->publish()) - { - CLI::write(lang('Publisher.publishSuccess', [ - get_class($publisher), - count($publisher->getPublished()), - $publisher->getDestination(), - ]), 'green'); - } - else - { - CLI::error(lang('Publisher.publishFailure', [ - get_class($publisher), - $publisher->getDestination(), - ]), 'light_gray', 'red'); + foreach ($publishers as $publisher) { + if ($publisher->publish()) { + CLI::write(lang('Publisher.publishSuccess', [ + get_class($publisher), + count($publisher->getPublished()), + $publisher->getDestination(), + ]), 'green'); + } else { + CLI::error(lang('Publisher.publishFailure', [ + get_class($publisher), + $publisher->getDestination(), + ]), 'light_gray', 'red'); - foreach ($publisher->getErrors() as $file => $exception) - { - CLI::write($file); - CLI::error($exception->getMessage()); - CLI::newLine(); - } - } - } - } + foreach ($publisher->getErrors() as $file => $exception) { + CLI::write($file); + CLI::error($exception->getMessage()); + CLI::newLine(); + } + } + } + } } diff --git a/system/Common.php b/system/Common.php index bdea46b26564..9979b30534b2 100644 --- a/system/Common.php +++ b/system/Common.php @@ -719,19 +719,17 @@ function lang(string $line, array $args = [], ?string $locale = null) { $language = Services::language(); - //Get active locale + // Get active locale $activeLocale = $language->getLocale(); - if ($locale && $locale != $activeLocale) - { + if ($locale && $locale !== $activeLocale) { $language->setLocale($locale); } $line = $language->getLine($line, $args); - if ($locale && $locale != $activeLocale) - { - //Reset to active locale + if ($locale && $locale !== $activeLocale) { + // Reset to active locale $language->setLocale($activeLocale); } diff --git a/system/Config/Publisher.php b/system/Config/Publisher.php index 651600ef9c06..608e87afef8e 100644 --- a/system/Config/Publisher.php +++ b/system/Config/Publisher.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Config; @@ -19,24 +19,24 @@ */ class Publisher extends BaseConfig { - /** - * A list of allowed destinations with a (pseudo-)regex - * of allowed files for each destination. - * Attempts to publish to directories not in this list will - * result in a PublisherException. Files that do no fit the - * pattern will cause copy/merge to fail. - * - * @var array - */ - public $restrictions = [ - ROOTPATH => '*', - FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', - ]; + /** + * A list of allowed destinations with a (pseudo-)regex + * of allowed files for each destination. + * Attempts to publish to directories not in this list will + * result in a PublisherException. Files that do no fit the + * pattern will cause copy/merge to fail. + * + * @var array + */ + public $restrictions = [ + ROOTPATH => '*', + FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + ]; - /** - * Disables Registrars to prevent modules from altering the restrictions. - */ - final protected function registerProperties() - { - } + /** + * Disables Registrars to prevent modules from altering the restrictions. + */ + final protected function registerProperties() + { + } } diff --git a/system/Database/Forge.php b/system/Database/Forge.php index cd471138db71..c05b0c760876 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -398,7 +398,7 @@ public function addForeignKey($fieldName = '', string $tableName = '', $tableFie } if ($errorNames !== []) { - $errorNames[0] = implode(', ',$errorNames); + $errorNames[0] = implode(', ', $errorNames); throw new DatabaseException(lang('Database.fieldNotExists', $errorNames)); } @@ -1025,24 +1025,22 @@ protected function _processForeignKeys(string $table): string 'SET DEFAULT', ]; - if ($this->foreignKeys !== []) { - foreach ($this->foreignKeys as $fkey) { - $nameIndex = $table . '_' . implode('_', $fkey['field']) . '_foreign'; - $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); - $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); - $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); - $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); + foreach ($this->foreignKeys as $fkey) { + $nameIndex = $table . '_' . implode('_', $fkey['field']) . '_foreign'; + $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); + $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); + $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); + $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); - $formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)"; - $sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled); + $formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)"; + $sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled); - if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { - $sql .= ' ON DELETE ' . $fkey['onDelete']; - } + if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { + $sql .= ' ON DELETE ' . $fkey['onDelete']; + } - if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { - $sql .= ' ON UPDATE ' . $fkey['onUpdate']; - } + if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { + $sql .= ' ON UPDATE ' . $fkey['onUpdate']; } } diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 965d539be878..62881620c46b 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -69,8 +69,6 @@ class Connection extends BaseConnection */ public $resultMode = MYSQLI_STORE_RESULT; - //-------------------------------------------------------------------- - /** * Connect to the database. * diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index 3fed6c48962f..ae920ceae152 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -282,24 +282,22 @@ protected function _processForeignKeys(string $table): string $allowActions = ['CASCADE', 'SET NULL', 'NO ACTION', 'RESTRICT', 'SET DEFAULT']; - if ($this->foreignKeys !== []) { - foreach ($this->foreignKeys as $fkey) { - $nameIndex = $table . '_' . implode('_', $fkey['field']) . '_foreign'; - $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); - $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); - $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); - $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); - - $formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)"; - $sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled); - - if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { - $sql .= ' ON DELETE ' . $fkey['onDelete']; - } + foreach ($this->foreignKeys as $fkey) { + $nameIndex = $table . '_' . implode('_', $fkey['field']) . '_foreign'; + $nameIndexFilled = $this->db->escapeIdentifiers($nameIndex); + $foreignKeyFilled = implode(', ', $this->db->escapeIdentifiers($fkey['field'])); + $referenceTableFilled = $this->db->escapeIdentifiers($this->db->DBPrefix . $fkey['referenceTable']); + $referenceFieldFilled = implode(', ', $this->db->escapeIdentifiers($fkey['referenceField'])); + + $formatSql = ",\n\tCONSTRAINT %s FOREIGN KEY (%s) REFERENCES %s(%s)"; + $sql .= sprintf($formatSql, $nameIndexFilled, $foreignKeyFilled, $referenceTableFilled, $referenceFieldFilled); + + if ($fkey['onDelete'] !== false && in_array($fkey['onDelete'], $allowActions, true)) { + $sql .= ' ON DELETE ' . $fkey['onDelete']; + } - if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { - $sql .= ' ON UPDATE ' . $fkey['onUpdate']; - } + if ($fkey['onUpdate'] !== false && in_array($fkey['onUpdate'], $allowActions, true)) { + $sql .= ' ON UPDATE ' . $fkey['onUpdate']; } } diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 6a5ece61a373..ef877cd2f365 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -168,7 +168,6 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques protected function renderTimeline(array $collectors, float $startTime, int $segmentCount, int $segmentDuration, array &$styles): string { $rows = $this->collectTimelineData($collectors); - $output = ''; $styleCount = 0; // Use recursive render function diff --git a/system/Files/Exceptions/FileException.php b/system/Files/Exceptions/FileException.php index 40e9fdc20f41..03af1bc57b08 100644 --- a/system/Files/Exceptions/FileException.php +++ b/system/Files/Exceptions/FileException.php @@ -24,23 +24,23 @@ public static function forUnableToMove(?string $from = null, ?string $to = null, return new static(lang('Files.cannotMove', [$from, $to, $error])); } - /** - * Throws when an item is expected to be a directory but is not or is missing. - * - * @param string $caller The method causing the exception - */ - public static function forExpectedDirectory(string $caller) - { - return new static(lang('Files.expectedDirectory', [$caller])); - } + /** + * Throws when an item is expected to be a directory but is not or is missing. + * + * @param string $caller The method causing the exception + */ + public static function forExpectedDirectory(string $caller) + { + return new static(lang('Files.expectedDirectory', [$caller])); + } - /** - * Throws when an item is expected to be a file but is not or is missing. - * - * @param string $caller The method causing the exception - */ - public static function forExpectedFile(string $caller) - { - return new static(lang('Files.expectedFile', [$caller])); - } + /** + * Throws when an item is expected to be a file but is not or is missing. + * + * @param string $caller The method causing the exception + */ + public static function forExpectedFile(string $caller) + { + return new static(lang('Files.expectedFile', [$caller])); + } } diff --git a/system/Files/FileCollection.php b/system/Files/FileCollection.php index 128d884940d5..0b1714425ba9 100644 --- a/system/Files/FileCollection.php +++ b/system/Files/FileCollection.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Files; @@ -17,7 +17,6 @@ use Generator; use InvalidArgumentException; use IteratorAggregate; -use Traversable; /** * File Collection Class @@ -27,360 +26,324 @@ */ class FileCollection implements Countable, IteratorAggregate { - /** - * The current list of file paths. - * - * @var string[] - */ - protected $files = []; - - //-------------------------------------------------------------------- - // Support Methods - //-------------------------------------------------------------------- - - /** - * Resolves a full path and verifies it is an actual directory. - * - * @param string $directory - * - * @return string - * - * @throws FileException - */ - final protected static function resolveDirectory(string $directory): string - { - if (! is_dir($directory = set_realpath($directory))) - { - $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; - throw FileException::forExpectedDirectory($caller['function']); - } - - return $directory; - } - - /** - * Resolves a full path and verifies it is an actual file. - * - * @param string $file - * - * @return string - * - * @throws FileException - */ - final protected static function resolveFile(string $file): string - { - if (! is_file($file = set_realpath($file))) - { - $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; - throw FileException::forExpectedFile($caller['function']); - } - - return $file; - } - - /** - * Removes files that are not part of the given directory (recursive). - * - * @param string[] $files - * @param string $directory - * - * @return string[] - */ - final protected static function filterFiles(array $files, string $directory): array - { - $directory = self::resolveDirectory($directory); - - return array_filter($files, static function (string $value) use ($directory): bool { - return strpos($value, $directory) === 0; - }); - } - - /** - * Returns any files whose `basename` matches the given pattern. - * - * @param string[] $files - * @param string $pattern Regex or pseudo-regex string - * - * @return string[] - */ - final protected static function matchFiles(array $files, string $pattern): array - { - // Convert pseudo-regex into their true form - if (@preg_match($pattern, '') === false) - { - $pattern = str_replace( - ['#', '.', '*', '?'], - ['\#', '\.', '.*', '.'], - $pattern - ); - $pattern = "#{$pattern}#"; - } - - return array_filter($files, static function ($value) use ($pattern) { - return (bool) preg_match($pattern, basename($value)); - }); - } - - //-------------------------------------------------------------------- - // Class Core - //-------------------------------------------------------------------- - - /** - * Loads the Filesystem helper and adds any initial files. - * - * @param string[] $files - */ - public function __construct(array $files = []) - { - helper(['filesystem']); - - $this->add($files)->define(); - } - - /** - * Applies any initial inputs after the constructor. - * This method is a stub to be implemented by child classes. - * - * @return void - */ - protected function define(): void - { - } - - /** - * Optimizes and returns the current file list. - * - * @return string[] - */ - public function get(): array - { - $this->files = array_unique($this->files); - sort($this->files, SORT_STRING); - - return $this->files; - } - - /** - * Sets the file list directly, files are still subject to verification. - * This works as a "reset" method with []. - * - * @param string[] $files The new file list to use - * - * @return $this - */ - public function set(array $files) - { - $this->files = []; - - return $this->addFiles($files); - } - - /** - * Adds an array/single file or directory to the list. - * - * @param string|string[] $paths - * @param boolean $recursive - * - * @return $this - */ - public function add($paths, bool $recursive = true) - { - $paths = (array) $paths; - - foreach ($paths as $path) - { - if (! is_string($path)) - { - throw new InvalidArgumentException('FileCollection paths must be strings.'); - } - - // Test for a directory - try - { - $directory = self::resolveDirectory($path); - } - catch (FileException $e) - { - return $this->addFile($path); - } - - $this->addDirectory($path, $recursive); - } - - return $this; - } - - //-------------------------------------------------------------------- - // File Handling - //-------------------------------------------------------------------- - - /** - * Verifies and adds files to the list. - * - * @param string[] $files - * - * @return $this - */ - public function addFiles(array $files) - { - foreach ($files as $file) - { - $this->addFile($file); - } - - return $this; - } - - /** - * Verifies and adds a single file to the file list. - * - * @param string $file - * - * @return $this - */ - public function addFile(string $file) - { - $this->files[] = self::resolveFile($file); - - return $this; - } - - /** - * Removes files from the list. - * - * @param string[] $files - * - * @return $this - */ - public function removeFiles(array $files) - { - $this->files = array_diff($this->files, $files); - - return $this; - } - - /** - * Removes a single file from the list. - * - * @param string $file - * - * @return $this - */ - public function removeFile(string $file) - { - return $this->removeFiles([$file]); - } - - //-------------------------------------------------------------------- - // Directory Handling - //-------------------------------------------------------------------- - - /** - * Verifies and adds files from each - * directory to the list. - * - * @param string[] $directories - * @param bool $recursive - * - * @return $this - */ - public function addDirectories(array $directories, bool $recursive = false) - { - foreach ($directories as $directory) - { - $this->addDirectory($directory, $recursive); - } - - return $this; - } - - /** - * Verifies and adds all files from a directory. - * - * @param string $directory - * @param boolean $recursive - * - * @return $this - */ - public function addDirectory(string $directory, bool $recursive = false) - { - $directory = self::resolveDirectory($directory); - - // Map the directory to depth 2 to so directories become arrays - foreach (directory_map($directory, 2, true) as $key => $path) - { - if (is_string($path)) - { - $this->addFile($directory . $path); - } - elseif ($recursive && is_array($path)) - { - $this->addDirectory($directory . $key, true); - } - } - - return $this; - } - - //-------------------------------------------------------------------- - // Filtering - //-------------------------------------------------------------------- - - /** - * Removes any files from the list that match the supplied pattern - * (within the optional scope). - * - * @param string $pattern Regex or pseudo-regex string - * @param string|null $scope The directory to limit the scope - * - * @return $this - */ - public function removePattern(string $pattern, string $scope = null) - { - if ($pattern === '') - { - return $this; - } - - // Start with all files or those in scope - $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); - - // Remove any files that match the pattern - return $this->removeFiles(self::matchFiles($files, $pattern)); - } - - /** - * Keeps only the files from the list that match - * (within the optional scope). - * - * @param string $pattern Regex or pseudo-regex string - * @param string|null $scope A directory to limit the scope - * - * @return $this - */ - public function retainPattern(string $pattern, string $scope = null) - { - if ($pattern === '') - { - return $this; - } - - // Start with all files or those in scope - $files = is_null($scope) ? $this->files : self::filterFiles($this->files, $scope); - - // Matches the pattern within the scoped files and remove their inverse. - return $this->removeFiles(array_diff($files, self::matchFiles($files, $pattern))); - } - - //-------------------------------------------------------------------- - // Interface Methods - //-------------------------------------------------------------------- + /** + * The current list of file paths. + * + * @var string[] + */ + protected $files = []; + + //-------------------------------------------------------------------- + // Support Methods + //-------------------------------------------------------------------- + + /** + * Resolves a full path and verifies it is an actual directory. + * + * @throws FileException + */ + final protected static function resolveDirectory(string $directory): string + { + if (! is_dir($directory = set_realpath($directory))) { + $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; + + throw FileException::forExpectedDirectory($caller['function']); + } + + return $directory; + } + + /** + * Resolves a full path and verifies it is an actual file. + * + * @throws FileException + */ + final protected static function resolveFile(string $file): string + { + if (! is_file($file = set_realpath($file))) { + $caller = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2)[1]; + + throw FileException::forExpectedFile($caller['function']); + } + + return $file; + } + + /** + * Removes files that are not part of the given directory (recursive). + * + * @param string[] $files + * + * @return string[] + */ + final protected static function filterFiles(array $files, string $directory): array + { + $directory = self::resolveDirectory($directory); + + return array_filter($files, static function (string $value) use ($directory): bool { + return strpos($value, $directory) === 0; + }); + } + + /** + * Returns any files whose `basename` matches the given pattern. + * + * @param string[] $files + * @param string $pattern Regex or pseudo-regex string + * + * @return string[] + */ + final protected static function matchFiles(array $files, string $pattern): array + { + // Convert pseudo-regex into their true form + if (@preg_match($pattern, '') === false) { + $pattern = str_replace( + ['#', '.', '*', '?'], + ['\#', '\.', '.*', '.'], + $pattern + ); + $pattern = "#{$pattern}#"; + } + + return array_filter($files, static function ($value) use ($pattern) { + return (bool) preg_match($pattern, basename($value)); + }); + } + + //-------------------------------------------------------------------- + // Class Core + //-------------------------------------------------------------------- + + /** + * Loads the Filesystem helper and adds any initial files. + * + * @param string[] $files + */ + public function __construct(array $files = []) + { + helper(['filesystem']); + + $this->add($files)->define(); + } + + /** + * Applies any initial inputs after the constructor. + * This method is a stub to be implemented by child classes. + */ + protected function define(): void + { + } + + /** + * Optimizes and returns the current file list. + * + * @return string[] + */ + public function get(): array + { + $this->files = array_unique($this->files); + sort($this->files, SORT_STRING); + + return $this->files; + } + + /** + * Sets the file list directly, files are still subject to verification. + * This works as a "reset" method with []. + * + * @param string[] $files The new file list to use + * + * @return $this + */ + public function set(array $files) + { + $this->files = []; + + return $this->addFiles($files); + } + + /** + * Adds an array/single file or directory to the list. + * + * @param string|string[] $paths + * + * @return $this + */ + public function add($paths, bool $recursive = true) + { + $paths = (array) $paths; + + foreach ($paths as $path) { + if (! is_string($path)) { + throw new InvalidArgumentException('FileCollection paths must be strings.'); + } + + try { + // Test for a directory + self::resolveDirectory($path); + } catch (FileException $e) { + return $this->addFile($path); + } + + $this->addDirectory($path, $recursive); + } + + return $this; + } + + //-------------------------------------------------------------------- + // File Handling + //-------------------------------------------------------------------- + + /** + * Verifies and adds files to the list. + * + * @param string[] $files + * + * @return $this + */ + public function addFiles(array $files) + { + foreach ($files as $file) { + $this->addFile($file); + } + + return $this; + } + + /** + * Verifies and adds a single file to the file list. + * + * @return $this + */ + public function addFile(string $file) + { + $this->files[] = self::resolveFile($file); + + return $this; + } + + /** + * Removes files from the list. + * + * @param string[] $files + * + * @return $this + */ + public function removeFiles(array $files) + { + $this->files = array_diff($this->files, $files); + + return $this; + } + + /** + * Removes a single file from the list. + * + * @return $this + */ + public function removeFile(string $file) + { + return $this->removeFiles([$file]); + } + + //-------------------------------------------------------------------- + // Directory Handling + //-------------------------------------------------------------------- + + /** + * Verifies and adds files from each + * directory to the list. + * + * @param string[] $directories + * + * @return $this + */ + public function addDirectories(array $directories, bool $recursive = false) + { + foreach ($directories as $directory) { + $this->addDirectory($directory, $recursive); + } + + return $this; + } + + /** + * Verifies and adds all files from a directory. + * + * @return $this + */ + public function addDirectory(string $directory, bool $recursive = false) + { + $directory = self::resolveDirectory($directory); + + // Map the directory to depth 2 to so directories become arrays + foreach (directory_map($directory, 2, true) as $key => $path) { + if (is_string($path)) { + $this->addFile($directory . $path); + } elseif ($recursive && is_array($path)) { + $this->addDirectory($directory . $key, true); + } + } + + return $this; + } + + //-------------------------------------------------------------------- + // Filtering + //-------------------------------------------------------------------- + + /** + * Removes any files from the list that match the supplied pattern + * (within the optional scope). + * + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope The directory to limit the scope + * + * @return $this + */ + public function removePattern(string $pattern, ?string $scope = null) + { + if ($pattern === '') { + return $this; + } + + // Start with all files or those in scope + $files = $scope === null ? $this->files : self::filterFiles($this->files, $scope); + + // Remove any files that match the pattern + return $this->removeFiles(self::matchFiles($files, $pattern)); + } + + /** + * Keeps only the files from the list that match + * (within the optional scope). + * + * @param string $pattern Regex or pseudo-regex string + * @param string|null $scope A directory to limit the scope + * + * @return $this + */ + public function retainPattern(string $pattern, ?string $scope = null) + { + if ($pattern === '') { + return $this; + } + + // Start with all files or those in scope + $files = $scope === null ? $this->files : self::filterFiles($this->files, $scope); + + // Matches the pattern within the scoped files and remove their inverse. + return $this->removeFiles(array_diff($files, self::matchFiles($files, $pattern))); + } + + //-------------------------------------------------------------------- + // Interface Methods + //-------------------------------------------------------------------- /** * Returns the current number of files in the collection. * Fulfills Countable. - * - * @return int */ public function count(): int { @@ -397,9 +360,8 @@ public function count(): int */ public function getIterator(): Generator { - foreach ($this->get() as $file) - { - yield new File($file, true); - } + foreach ($this->get() as $file) { + yield new File($file, true); + } } } diff --git a/system/Language/en/Files.php b/system/Language/en/Files.php index bcbc39d7e349..03fa776e4822 100644 --- a/system/Language/en/Files.php +++ b/system/Language/en/Files.php @@ -13,6 +13,6 @@ return [ 'fileNotFound' => 'File not found: {0}', 'cannotMove' => 'Could not move file {0} to {1} ({2}).', - 'expectedDirectory' => '{0} expects a valid directory.', - 'expectedFile' => '{0} expects a valid file.', + 'expectedDirectory' => '{0} expects a valid directory.', + 'expectedFile' => '{0} expects a valid file.', ]; diff --git a/system/Language/en/Publisher.php b/system/Language/en/Publisher.php index 77d805a78ff2..f335b98423f7 100644 --- a/system/Language/en/Publisher.php +++ b/system/Language/en/Publisher.php @@ -1,22 +1,22 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ // Publisher language settings return [ - 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', - 'destinationNotAllowed' => 'Destination is not on the allowed list of Publisher directories: {0}', - 'fileNotAllowed' => '{0} fails the following restriction for {1}: {2}', + 'collision' => 'Publisher encountered an unexpected {0} while copying {1} to {2}.', + 'destinationNotAllowed' => 'Destination is not on the allowed list of Publisher directories: {0}', + 'fileNotAllowed' => '{0} fails the following restriction for {1}: {2}', - // Publish Command - 'publishMissing' => 'No Publisher classes detected in {0} across all namespaces.', - 'publishSuccess' => '{0} published {1} file(s) to {2}.', - 'publishFailure' => '{0} failed to publish to {1}!', + // Publish Command + 'publishMissing' => 'No Publisher classes detected in {0} across all namespaces.', + 'publishSuccess' => '{0} published {1} file(s) to {2}.', + 'publishFailure' => '{0} failed to publish to {1}!', ]; diff --git a/system/Publisher/Exceptions/PublisherException.php b/system/Publisher/Exceptions/PublisherException.php index c3e85a994ebe..535d3a757d15 100644 --- a/system/Publisher/Exceptions/PublisherException.php +++ b/system/Publisher/Exceptions/PublisherException.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Publisher\Exceptions; @@ -20,36 +20,30 @@ */ class PublisherException extends FrameworkException { - /** - * Throws when a file should be overwritten yet cannot. - * - * @param string $from The source file - * @param string $to The destination file - */ - public static function forCollision(string $from, string $to) - { - return new static(lang('Publisher.collision', [filetype($to), $from, $to])); - } + /** + * Throws when a file should be overwritten yet cannot. + * + * @param string $from The source file + * @param string $to The destination file + */ + public static function forCollision(string $from, string $to) + { + return new static(lang('Publisher.collision', [filetype($to), $from, $to])); + } - /** - * Throws when given a destination that is not in the list of allowed directories. - * - * @param string $destination - */ - public static function forDestinationNotAllowed(string $destination) - { - return new static(lang('Publisher.destinationNotAllowed', [$destination])); - } + /** + * Throws when given a destination that is not in the list of allowed directories. + */ + public static function forDestinationNotAllowed(string $destination) + { + return new static(lang('Publisher.destinationNotAllowed', [$destination])); + } - /** - * Throws when a file fails to match the allowed pattern for its destination. - * - * @param string $file - * @param string $directory - * @param string $pattern - */ - public static function forFileNotAllowed(string $file, string $directory, string $pattern) - { - return new static(lang('Publisher.fileNotAllowed', [$file, $directory, $pattern])); - } + /** + * Throws when a file fails to match the allowed pattern for its destination. + */ + public static function forFileNotAllowed(string $file, string $directory, string $pattern) + { + return new static(lang('Publisher.fileNotAllowed', [$file, $directory, $pattern])); + } } diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index ab4484cdea0b..38e990776ef3 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -1,12 +1,12 @@ * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. */ namespace CodeIgniter\Publisher; @@ -19,8 +19,6 @@ use Throwable; /** - * Publisher Class - * * Publishers read in file paths from a variety of sources and copy * the files out to different destinations. This class acts both as * a base for individual publication directives as well as the mode @@ -28,464 +26,413 @@ * path to a verified file while a "path" is relative to its source * or destination and may indicate either a file or directory of * unconfirmed existence. + * * Class failures throw the PublisherException, but some underlying * methods may percolate different exceptions, like FileException, * FileNotFoundException or InvalidArgumentException. + * * Write operations will catch all errors in the file-specific * $errors property to minimize impact of partial batch operations. */ class Publisher extends FileCollection { - /** - * Array of discovered Publishers. - * - * @var array - */ - private static $discovered = []; - - /** - * Directory to use for methods that need temporary storage. - * Created on-the-fly as needed. - * - * @var string|null - */ - private $scratch; - - /** - * Exceptions for specific files from the last write operation. - * - * @var array - */ - private $errors = []; - - /** - * List of file published curing the last write operation. - * - * @var string[] - */ - private $published = []; - - /** - * List of allowed directories and their allowed files regex. - * Restrictions are intentionally private to prevent overriding. - * - * @var array - */ - private $restrictions; - - /** - * Base path to use for the source. - * - * @var string - */ - protected $source = ROOTPATH; - - /** - * Base path to use for the destination. - * - * @var string - */ - protected $destination = FCPATH; - - //-------------------------------------------------------------------- - // Support Methods - //-------------------------------------------------------------------- - - /** - * Discovers and returns all Publishers in the specified namespace directory. - * - * @param string $directory - * - * @return self[] - */ - final public static function discover(string $directory = 'Publishers'): array - { - if (isset(self::$discovered[$directory])) - { - return self::$discovered[$directory]; - } - - self::$discovered[$directory] = []; - - /** @var FileLocator $locator */ - $locator = service('locator'); - - if ([] === $files = $locator->listFiles($directory)) - { - return []; - } - - // Loop over each file checking to see if it is a Publisher - foreach (array_unique($files) as $file) - { - $className = $locator->findQualifiedNameFromPath($file); - - if (is_string($className) && class_exists($className) && is_a($className, self::class, true)) - { - self::$discovered[$directory][] = new $className(); - } - } - - sort(self::$discovered[$directory]); - - return self::$discovered[$directory]; - } - - /* - * Removes a directory and all its files and subdirectories. - * - * @param string $directory - * - * @return void - */ - private static function wipeDirectory(string $directory): void - { - if (is_dir($directory)) - { - // Try a few times in case of lingering locks - $attempts = 10; - while ((bool) $attempts && ! delete_files($directory, true, false, true)) - { - // @codeCoverageIgnoreStart - $attempts--; - usleep(100000); // .1s - // @codeCoverageIgnoreEnd - } - - @rmdir($directory); - } - } - - //-------------------------------------------------------------------- - // Class Core - //-------------------------------------------------------------------- - - /** - * Loads the helper and verifies the source and destination directories. - * - * @param string|null $source - * @param string|null $destination - */ - public function __construct(string $source = null, string $destination = null) - { - helper(['filesystem']); - - $this->source = self::resolveDirectory($source ?? $this->source); - $this->destination = self::resolveDirectory($destination ?? $this->destination); - - // Restrictions are intentionally not injected to prevent overriding - $this->restrictions = config('Publisher')->restrictions; - - // Make sure the destination is allowed - foreach (array_keys($this->restrictions) as $directory) - { - if (strpos($this->destination, $directory) === 0) - { - return; - } - } - - throw PublisherException::forDestinationNotAllowed($this->destination); - } - - /** - * Cleans up any temporary files in the scratch space. - */ - public function __destruct() - { - if (isset($this->scratch)) - { - self::wipeDirectory($this->scratch); - - $this->scratch = null; - } - } - - /** - * Reads files from the sources and copies them out to their destinations. - * This method should be reimplemented by child classes intended for - * discovery. - * - * @return boolean - * - * @throws RuntimeException - */ - public function publish(): bool - { - // Safeguard against accidental misuse - if ($this->source === ROOTPATH && $this->destination === FCPATH) - { - throw new RuntimeException('Child classes of Publisher should provide their own publish method or a source and destination.'); - } - - return $this->addPath('/')->merge(true); - } - - //-------------------------------------------------------------------- - // Property Accessors - //-------------------------------------------------------------------- - - /** - * Returns the source directory. - * - * @return string - */ - final public function getSource(): string - { - return $this->source; - } - - /** - * Returns the destination directory. - * - * @return string - */ - final public function getDestination(): string - { - return $this->destination; - } - - /** - * Returns the temporary workspace, creating it if necessary. - * - * @return string - */ - final public function getScratch(): string - { - if (is_null($this->scratch)) - { - $this->scratch = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . DIRECTORY_SEPARATOR; - mkdir($this->scratch, 0700); - } - - return $this->scratch; - } - - /** - * Returns errors from the last write operation if any. - * - * @return array - */ - final public function getErrors(): array - { - return $this->errors; - } - - /** - * Returns the files published by the last write operation. - * - * @return string[] - */ - final public function getPublished(): array - { - return $this->published; - } - - //-------------------------------------------------------------------- - // Additional Handlers - //-------------------------------------------------------------------- - - /** - * Verifies and adds paths to the list. - * - * @param string[] $paths - * @param bool $recursive - * - * @return $this - */ - final public function addPaths(array $paths, bool $recursive = true) - { - foreach ($paths as $path) - { - $this->addPath($path, $recursive); - } - - return $this; - } - - /** - * Adds a single path to the file list. - * - * @param string $path - * @param boolean $recursive - * - * @return $this - */ - final public function addPath(string $path, bool $recursive = true) - { - $this->add($this->source . $path, $recursive); - - return $this; - } - - /** - * Downloads and stages files from an array of URIs. - * - * @param string[] $uris - * - * @return $this - */ - final public function addUris(array $uris) - { - foreach ($uris as $uri) - { - $this->addUri($uri); - } - - return $this; - } - - /** - * Downloads a file from the URI, and adds it to the file list. - * - * @param string $uri Because HTTP\URI is stringable it will still be accepted - * - * @return $this - */ - final public function addUri(string $uri) - { - // Figure out a good filename (using URI strips queries and fragments) - $file = $this->getScratch() . basename((new URI($uri))->getPath()); - - // Get the content and write it to the scratch space - write_file($file, service('curlrequest')->get($uri)->getBody()); - - return $this->addFile($file); - } - - //-------------------------------------------------------------------- - // Write Methods - //-------------------------------------------------------------------- - - /** - * Removes the destination and all its files and folders. - * - * @return $this - */ - final public function wipe() - { - self::wipeDirectory($this->destination); - - return $this; - } - - /** - * Copies all files into the destination, does not create directory structure. - * - * @param boolean $replace Whether to overwrite existing files. - * - * @return boolean Whether all files were copied successfully - */ - final public function copy(bool $replace = true): bool - { - $this->errors = $this->published = []; - - foreach ($this->get() as $file) - { - $to = $this->destination . basename($file); - - try - { - $this->safeCopyFile($file, $to, $replace); - $this->published[] = $to; - } - catch (Throwable $e) - { - $this->errors[$file] = $e; - } - } - - return $this->errors === []; - } - - /** - * Merges all files into the destination. - * Creates a mirrored directory structure only for files from source. - * - * @param boolean $replace Whether to overwrite existing files. - * - * @return boolean Whether all files were copied successfully - */ - final public function merge(bool $replace = true): bool - { - $this->errors = $this->published = []; - - // Get the files from source for special handling - $sourced = self::filterFiles($this->get(), $this->source); - - // Handle everything else with a flat copy - $this->files = array_diff($this->files, $sourced); - $this->copy($replace); - - // Copy each sourced file to its relative destination - foreach ($sourced as $file) - { - // Resolve the destination path - $to = $this->destination . substr($file, strlen($this->source)); - - try - { - $this->safeCopyFile($file, $to, $replace); - $this->published[] = $to; - } - catch (Throwable $e) - { - $this->errors[$file] = $e; - } - } - - return $this->errors === []; - } - - /** - * Copies a file with directory creation and identical file awareness. - * Intentionally allows errors. - * - * @param string $from - * @param string $to - * @param boolean $replace - * - * @return void - * - * @throws PublisherException For collisions and restriction violations - */ - private function safeCopyFile(string $from, string $to, bool $replace): void - { - // Verify this is an allowed file for its destination - foreach ($this->restrictions as $directory => $pattern) - { - if (strpos($to, $directory) === 0 && self::matchFiles([$to], $pattern) === []) - { - throw PublisherException::forFileNotAllowed($from, $directory, $pattern); - } - } - - // Check for an existing file - if (file_exists($to)) - { - // If not replacing or if files are identical then consider successful - if (! $replace || same_file($from, $to)) - { - return; - } - - // If it is a directory then do not try to remove it - if (is_dir($to)) - { - throw PublisherException::forCollision($from, $to); - } - - // Try to remove anything else - unlink($to); - } - - // Make sure the directory exists - if (! is_dir($directory = pathinfo($to, PATHINFO_DIRNAME))) - { - mkdir($directory, 0775, true); - } - - // Allow copy() to throw errors - copy($from, $to); - } + /** + * Array of discovered Publishers. + * + * @var array + */ + private static $discovered = []; + + /** + * Directory to use for methods that need temporary storage. + * Created on-the-fly as needed. + * + * @var string|null + */ + private $scratch; + + /** + * Exceptions for specific files from the last write operation. + * + * @var array + */ + private $errors = []; + + /** + * List of file published curing the last write operation. + * + * @var string[] + */ + private $published = []; + + /** + * List of allowed directories and their allowed files regex. + * Restrictions are intentionally private to prevent overriding. + * + * @var array + */ + private $restrictions; + + /** + * Base path to use for the source. + * + * @var string + */ + protected $source = ROOTPATH; + + /** + * Base path to use for the destination. + * + * @var string + */ + protected $destination = FCPATH; + + //-------------------------------------------------------------------- + // Support Methods + //-------------------------------------------------------------------- + + /** + * Discovers and returns all Publishers in the specified namespace directory. + * + * @return self[] + */ + final public static function discover(string $directory = 'Publishers'): array + { + if (isset(self::$discovered[$directory])) { + return self::$discovered[$directory]; + } + + self::$discovered[$directory] = []; + + /** @var FileLocator $locator */ + $locator = service('locator'); + + if ([] === $files = $locator->listFiles($directory)) { + return []; + } + + // Loop over each file checking to see if it is a Publisher + foreach (array_unique($files) as $file) { + $className = $locator->findQualifiedNameFromPath($file); + + if (is_string($className) && class_exists($className) && is_a($className, self::class, true)) { + self::$discovered[$directory][] = new $className(); + } + } + + sort(self::$discovered[$directory]); + + return self::$discovered[$directory]; + } + + /** + * Removes a directory and all its files and subdirectories. + */ + private static function wipeDirectory(string $directory): void + { + if (is_dir($directory)) { + // Try a few times in case of lingering locks + $attempts = 10; + + while ((bool) $attempts && ! delete_files($directory, true, false, true)) { + // @codeCoverageIgnoreStart + $attempts--; + usleep(100000); // .1s + // @codeCoverageIgnoreEnd + } + + @rmdir($directory); + } + } + + //-------------------------------------------------------------------- + // Class Core + //-------------------------------------------------------------------- + + /** + * Loads the helper and verifies the source and destination directories. + */ + public function __construct(?string $source = null, ?string $destination = null) + { + helper(['filesystem']); + + $this->source = self::resolveDirectory($source ?? $this->source); + $this->destination = self::resolveDirectory($destination ?? $this->destination); + + // Restrictions are intentionally not injected to prevent overriding + $this->restrictions = config('Publisher')->restrictions; + + // Make sure the destination is allowed + foreach (array_keys($this->restrictions) as $directory) { + if (strpos($this->destination, $directory) === 0) { + return; + } + } + + throw PublisherException::forDestinationNotAllowed($this->destination); + } + + /** + * Cleans up any temporary files in the scratch space. + */ + public function __destruct() + { + if (isset($this->scratch)) { + self::wipeDirectory($this->scratch); + + $this->scratch = null; + } + } + + /** + * Reads files from the sources and copies them out to their destinations. + * This method should be reimplemented by child classes intended for + * discovery. + * + * @throws RuntimeException + */ + public function publish(): bool + { + // Safeguard against accidental misuse + if ($this->source === ROOTPATH && $this->destination === FCPATH) { + throw new RuntimeException('Child classes of Publisher should provide their own publish method or a source and destination.'); + } + + return $this->addPath('/')->merge(true); + } + + //-------------------------------------------------------------------- + // Property Accessors + //-------------------------------------------------------------------- + + /** + * Returns the source directory. + */ + final public function getSource(): string + { + return $this->source; + } + + /** + * Returns the destination directory. + */ + final public function getDestination(): string + { + return $this->destination; + } + + /** + * Returns the temporary workspace, creating it if necessary. + */ + final public function getScratch(): string + { + if ($this->scratch === null) { + $this->scratch = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . DIRECTORY_SEPARATOR; + mkdir($this->scratch, 0700); + } + + return $this->scratch; + } + + /** + * Returns errors from the last write operation if any. + * + * @return array + */ + final public function getErrors(): array + { + return $this->errors; + } + + /** + * Returns the files published by the last write operation. + * + * @return string[] + */ + final public function getPublished(): array + { + return $this->published; + } + + //-------------------------------------------------------------------- + // Additional Handlers + //-------------------------------------------------------------------- + + /** + * Verifies and adds paths to the list. + * + * @param string[] $paths + * + * @return $this + */ + final public function addPaths(array $paths, bool $recursive = true) + { + foreach ($paths as $path) { + $this->addPath($path, $recursive); + } + + return $this; + } + + /** + * Adds a single path to the file list. + * + * @return $this + */ + final public function addPath(string $path, bool $recursive = true) + { + $this->add($this->source . $path, $recursive); + + return $this; + } + + /** + * Downloads and stages files from an array of URIs. + * + * @param string[] $uris + * + * @return $this + */ + final public function addUris(array $uris) + { + foreach ($uris as $uri) { + $this->addUri($uri); + } + + return $this; + } + + /** + * Downloads a file from the URI, and adds it to the file list. + * + * @param string $uri Because HTTP\URI is stringable it will still be accepted + * + * @return $this + */ + final public function addUri(string $uri) + { + // Figure out a good filename (using URI strips queries and fragments) + $file = $this->getScratch() . basename((new URI($uri))->getPath()); + + // Get the content and write it to the scratch space + write_file($file, service('curlrequest')->get($uri)->getBody()); + + return $this->addFile($file); + } + + //-------------------------------------------------------------------- + // Write Methods + //-------------------------------------------------------------------- + + /** + * Removes the destination and all its files and folders. + * + * @return $this + */ + final public function wipe() + { + self::wipeDirectory($this->destination); + + return $this; + } + + /** + * Copies all files into the destination, does not create directory structure. + * + * @param bool $replace Whether to overwrite existing files. + * + * @return bool Whether all files were copied successfully + */ + final public function copy(bool $replace = true): bool + { + $this->errors = $this->published = []; + + foreach ($this->get() as $file) { + $to = $this->destination . basename($file); + + try { + $this->safeCopyFile($file, $to, $replace); + $this->published[] = $to; + } catch (Throwable $e) { + $this->errors[$file] = $e; + } + } + + return $this->errors === []; + } + + /** + * Merges all files into the destination. + * Creates a mirrored directory structure only for files from source. + * + * @param bool $replace Whether to overwrite existing files. + * + * @return bool Whether all files were copied successfully + */ + final public function merge(bool $replace = true): bool + { + $this->errors = $this->published = []; + + // Get the files from source for special handling + $sourced = self::filterFiles($this->get(), $this->source); + + // Handle everything else with a flat copy + $this->files = array_diff($this->files, $sourced); + $this->copy($replace); + + // Copy each sourced file to its relative destination + foreach ($sourced as $file) { + // Resolve the destination path + $to = $this->destination . substr($file, strlen($this->source)); + + try { + $this->safeCopyFile($file, $to, $replace); + $this->published[] = $to; + } catch (Throwable $e) { + $this->errors[$file] = $e; + } + } + + return $this->errors === []; + } + + /** + * Copies a file with directory creation and identical file awareness. + * Intentionally allows errors. + * + * @throws PublisherException For collisions and restriction violations + */ + private function safeCopyFile(string $from, string $to, bool $replace): void + { + // Verify this is an allowed file for its destination + foreach ($this->restrictions as $directory => $pattern) { + if (strpos($to, $directory) === 0 && self::matchFiles([$to], $pattern) === []) { + throw PublisherException::forFileNotAllowed($from, $directory, $pattern); + } + } + + // Check for an existing file + if (file_exists($to)) { + // If not replacing or if files are identical then consider successful + if (! $replace || same_file($from, $to)) { + return; + } + + // If it is a directory then do not try to remove it + if (is_dir($to)) { + throw PublisherException::forCollision($from, $to); + } + + // Try to remove anything else + unlink($to); + } + + // Make sure the directory exists + if (! is_dir($directory = pathinfo($to, PATHINFO_DIRNAME))) { + mkdir($directory, 0775, true); + } + + // Allow copy() to throw errors + copy($from, $to); + } } diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index ebfdfc119d5e..f0164d2dfc3c 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -256,7 +256,7 @@ public function gc($max_lifetime) $separator = $this->platform === 'postgre' ? '\'' : ' '; $interval = implode($separator, ['', "{$max_lifetime} second", '']); - return $this->db->table($this->table)->where('timestamp <', "now() - INTERVAL {$interval}", false)->delete() ? true : $this->fail(); + return $this->db->table($this->table)->where('timestamp <', "now() - INTERVAL {$interval}", false)->delete() ? 1 : $this->fail(); } /** diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php index 47c987a0285a..357e50f17e1a 100644 --- a/tests/_support/Publishers/TestPublisher.php +++ b/tests/_support/Publishers/TestPublisher.php @@ -1,48 +1,56 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + namespace Tests\Support\Publishers; use CodeIgniter\Publisher\Publisher; -use RuntimeException; final class TestPublisher extends Publisher { - /** - * Fakes an error on the given file. - */ - public static function setResult(bool $result) - { - self::$result = $result; - } - - /** - * Return value for publish() - * - * @var boolean - */ - private static $result = true; - - /** - * Base path to use for the source. - * - * @var string - */ - protected $source = SUPPORTPATH . 'Files'; - - /** - * Base path to use for the destination. - * - * @var string - */ - protected $destination = WRITEPATH; - - /** - * Fakes a publish event so no files are actually copied. - */ - public function publish(): bool - { - $this->addPath(''); - - return self::$result; - } + /** + * Fakes an error on the given file. + */ + public static function setResult(bool $result) + { + self::$result = $result; + } + + /** + * Return value for publish() + * + * @var bool + */ + private static $result = true; + + /** + * Base path to use for the source. + * + * @var string + */ + protected $source = SUPPORTPATH . 'Files'; + + /** + * Base path to use for the destination. + * + * @var string + */ + protected $destination = WRITEPATH; + + /** + * Fakes a publish event so no files are actually copied. + */ + public function publish(): bool + { + $this->addPath(''); + + return self::$result; + } } diff --git a/tests/system/Cache/Handlers/BaseHandlerTest.php b/tests/system/Cache/Handlers/BaseHandlerTest.php index 73f46620b559..b2ebb61e01ef 100644 --- a/tests/system/Cache/Handlers/BaseHandlerTest.php +++ b/tests/system/Cache/Handlers/BaseHandlerTest.php @@ -46,7 +46,7 @@ public function invalidTypeProvider(): array public function testValidateKeyUsesConfig() { - config('Cache')->reservedCharacters = 'b'; + config('Cache')->reservedCharacters = 'b'; $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Cache key contains reserved characters b'); diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php index 0f9f9a10eadf..5b53a9532b8b 100644 --- a/tests/system/Cache/Handlers/FileHandlerTest.php +++ b/tests/system/Cache/Handlers/FileHandlerTest.php @@ -161,7 +161,7 @@ public function testSavePermanent() $this->assertTrue($this->fileHandler->save(self::$key1, 'value', 0)); $metaData = $this->fileHandler->getMetaData(self::$key1); - $this->assertSame(null, $metaData['expire']); + $this->assertNull($metaData['expire']); $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); $this->assertSame('value', $metaData['data']); diff --git a/tests/system/Cache/Handlers/MemcachedHandlerTest.php b/tests/system/Cache/Handlers/MemcachedHandlerTest.php index 9afbdf742236..63a3994d1756 100644 --- a/tests/system/Cache/Handlers/MemcachedHandlerTest.php +++ b/tests/system/Cache/Handlers/MemcachedHandlerTest.php @@ -107,7 +107,7 @@ public function testSavePermanent() $this->assertTrue($this->memcachedHandler->save(self::$key1, 'value', 0)); $metaData = $this->memcachedHandler->getMetaData(self::$key1); - $this->assertSame(null, $metaData['expire']); + $this->assertNull($metaData['expire']); $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); $this->assertSame('value', $metaData['data']); diff --git a/tests/system/Cache/Handlers/PredisHandlerTest.php b/tests/system/Cache/Handlers/PredisHandlerTest.php index 867babcddc2a..3bcafae48fe2 100644 --- a/tests/system/Cache/Handlers/PredisHandlerTest.php +++ b/tests/system/Cache/Handlers/PredisHandlerTest.php @@ -114,7 +114,7 @@ public function testSavePermanent() $this->assertTrue($this->PredisHandler->save(self::$key1, 'value', 0)); $metaData = $this->PredisHandler->getMetaData(self::$key1); - $this->assertSame(null, $metaData['expire']); + $this->assertNull($metaData['expire']); $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); $this->assertSame('value', $metaData['data']); diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php index b3f8cebbb422..d254cd65af97 100644 --- a/tests/system/Cache/Handlers/RedisHandlerTest.php +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php @@ -114,7 +114,7 @@ public function testSavePermanent() $this->assertTrue($this->redisHandler->save(self::$key1, 'value', 0)); $metaData = $this->redisHandler->getMetaData(self::$key1); - $this->assertSame(null, $metaData['expire']); + $this->assertNull($metaData['expire']); $this->assertLessThanOrEqual(1, $metaData['mtime'] - time()); $this->assertSame('value', $metaData['data']); diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php index 1d5dd6d116c4..c878b969d5e9 100644 --- a/tests/system/Commands/CommandGeneratorTest.php +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -138,7 +138,7 @@ public function testGeneratorPreservesCaseButChangesComponentName(): void */ public function testGeneratorIsNotConfusedWithNamespaceLikeClassNames(): void { - $time = time(); + $time = time(); $notExists = true; command('make:migration App_Lesson'); diff --git a/tests/system/Commands/PublishCommandTest.php b/tests/system/Commands/PublishCommandTest.php index 44f2de25f85a..ea7b09e73511 100644 --- a/tests/system/Commands/PublishCommandTest.php +++ b/tests/system/Commands/PublishCommandTest.php @@ -1,52 +1,64 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Filters\CITestStreamFilter; use Tests\Support\Publishers\TestPublisher; +/** + * @internal + */ final class PublishCommandTest extends CIUnitTestCase { - private $streamFilter; - - protected function setUp(): void - { - parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - parent::tearDown(); - - stream_filter_remove($this->streamFilter); - TestPublisher::setResult(true); - } - - public function testDefault() - { - command('publish'); - - $this->assertStringContainsString(lang('Publisher.publishSuccess', [ - TestPublisher::class, - 0, - WRITEPATH, - ]), CITestStreamFilter::$buffer); - } - - public function testFailure() - { - TestPublisher::setResult(false); - - command('publish'); - - $this->assertStringContainsString(lang('Publisher.publishFailure', [ - TestPublisher::class, - WRITEPATH, - ]), CITestStreamFilter::$buffer); - } + private $streamFilter; + + protected function setUp(): void + { + parent::setUp(); + CITestStreamFilter::$buffer = ''; + + $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + } + + protected function tearDown(): void + { + parent::tearDown(); + + stream_filter_remove($this->streamFilter); + TestPublisher::setResult(true); + } + + public function testDefault() + { + command('publish'); + + $this->assertStringContainsString(lang('Publisher.publishSuccess', [ + TestPublisher::class, + 0, + WRITEPATH, + ]), CITestStreamFilter::$buffer); + } + + public function testFailure() + { + TestPublisher::setResult(false); + + command('publish'); + + $this->assertStringContainsString(lang('Publisher.publishFailure', [ + TestPublisher::class, + WRITEPATH, + ]), CITestStreamFilter::$buffer); + } } diff --git a/tests/system/Files/FileCollectionTest.php b/tests/system/Files/FileCollectionTest.php index ae2df9178f5f..5621151842e2 100644 --- a/tests/system/Files/FileCollectionTest.php +++ b/tests/system/Files/FileCollectionTest.php @@ -1,568 +1,556 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use CodeIgniter\Files\Exceptions\FileException; use CodeIgniter\Files\File; use CodeIgniter\Files\FileCollection; use CodeIgniter\Test\CIUnitTestCase; -class FileCollectionTest extends CIUnitTestCase +/** + * @internal + */ +final class FileCollectionTest extends CIUnitTestCase { - /** - * A known, valid file - * - * @var string - */ - private $file = SUPPORTPATH . 'Files/baker/banana.php'; - - /** - * A known, valid directory - * - * @var string - */ - private $directory = SUPPORTPATH . 'Files/able/'; - - /** - * Initialize the helper, since some - * tests call static methods before - * the constructor would load it. - */ - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper(['filesystem']); - } - - //-------------------------------------------------------------------- - - public function testResolveDirectoryDirectory() - { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); - - $this->assertSame($this->directory, $method($this->directory)); - } - - public function testResolveDirectoryFile() - { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); - - $this->expectException(FileException::class); - $this->expectExceptionMessage(lang('Files.expectedDirectory', ['invokeArgs'])); - - $method($this->file); - } - - public function testResolveDirectorySymlink() - { - // Create a symlink to test - $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); - symlink($this->directory, $link); - - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); - - $this->assertSame($this->directory, $method($link)); - - unlink($link); - } - - //-------------------------------------------------------------------- - - public function testResolveFileFile() - { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); - - $this->assertSame($this->file, $method($this->file)); - } - - public function testResolveFileSymlink() - { - // Create a symlink to test - $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); - symlink($this->file, $link); - - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); - - $this->assertSame($this->file, $method($link)); - - unlink($link); - } - - public function testResolveFileDirectory() - { - $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); - - $this->expectException(FileException::class); - $this->expectExceptionMessage(lang('Files.expectedFile', ['invokeArgs'])); - - $method($this->directory); - } - - //-------------------------------------------------------------------- - - public function testConstructorAddsFiles() - { - $expected = [ - $this->directory . 'apple.php', - $this->file, - ]; - - $collection = new class([$this->file]) extends FileCollection { - - protected $files = [ - SUPPORTPATH . 'Files/able/apple.php', - ]; - }; - - $this->assertSame($expected, $collection->get()); - } - - public function testConstructorCallsDefine() - { - $collection = new class() extends FileCollection { - - protected function define(): void - { - $this->add(SUPPORTPATH . 'Files/baker/banana.php'); - } - }; - - $this->assertSame([$this->file], $collection->get()); - } - - //-------------------------------------------------------------------- - - public function testAddStringFile() - { - $files = new FileCollection(); - - $files->add(SUPPORTPATH . 'Files/baker/banana.php'); - - $this->assertSame([$this->file], $files->get()); - } - - public function testAddStringFileRecursiveDoesNothing() - { - $files = new FileCollection(); - - $files->add(SUPPORTPATH . 'Files/baker/banana.php', true); - - $this->assertSame([$this->file], $files->get()); - } - - public function testAddStringDirectory() - { - $files = new FileCollection(); - - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - ]; - - $files->add(SUPPORTPATH . 'Files/able'); - - $this->assertSame($expected, $files->get()); - } - - public function testAddStringDirectoryRecursive() - { - $files = new FileCollection(); - - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $files->add(SUPPORTPATH . 'Files'); + /** + * A known, valid file + * + * @var string + */ + private $file = SUPPORTPATH . 'Files/baker/banana.php'; + + /** + * A known, valid directory + * + * @var string + */ + private $directory = SUPPORTPATH . 'Files/able/'; + + /** + * Initialize the helper, since some + * tests call static methods before + * the constructor would load it. + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); - $this->assertSame($expected, $files->get()); - } + helper(['filesystem']); + } + + public function testResolveDirectoryDirectory() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); - public function testAddArray() - { - $files = new FileCollection(); + $this->assertSame($this->directory, $method($this->directory)); + } - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; + public function testResolveDirectoryFile() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); - $files->add([ - SUPPORTPATH . 'Files/able', - SUPPORTPATH . 'Files/baker/banana.php', - ]); + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedDirectory', ['invokeArgs'])); + + $method($this->file); + } - $this->assertSame($expected, $files->get()); - } + public function testResolveDirectorySymlink() + { + // Create a symlink to test + $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); + symlink($this->directory, $link); - public function testAddArrayRecursive() - { - $files = new FileCollection(); + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveDirectory'); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - SUPPORTPATH . 'Log/Handlers/TestHandler.php', - ]; + $this->assertSame($this->directory, $method($link)); - $files->add([ - SUPPORTPATH . 'Files', - SUPPORTPATH . 'Log', - ], true); + unlink($link); + } + + public function testResolveFileFile() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); - $this->assertSame($expected, $files->get()); - } + $this->assertSame($this->file, $method($this->file)); + } - //-------------------------------------------------------------------- + public function testResolveFileSymlink() + { + // Create a symlink to test + $link = sys_get_temp_dir() . DIRECTORY_SEPARATOR . bin2hex(random_bytes(4)); + symlink($this->file, $link); - public function testAddFile() - { - $collection = new FileCollection(); - $this->assertSame([], $this->getPrivateProperty($collection, 'files')); + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); - $collection->addFile($this->file); - $this->assertSame([$this->file], $this->getPrivateProperty($collection, 'files')); - } + $this->assertSame($this->file, $method($link)); + + unlink($link); + } + + public function testResolveFileDirectory() + { + $method = $this->getPrivateMethodInvoker(FileCollection::class, 'resolveFile'); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['invokeArgs'])); - public function testAddFileMissing() - { - $collection = new FileCollection(); + $method($this->directory); + } - $this->expectException(FileException::class); - $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + public function testConstructorAddsFiles() + { + $expected = [ + $this->directory . 'apple.php', + $this->file, + ]; + + $collection = new class ([$this->file]) extends FileCollection { + protected $files = [ + SUPPORTPATH . 'Files/able/apple.php', + ]; + }; + + $this->assertSame($expected, $collection->get()); + } + + public function testConstructorCallsDefine() + { + $collection = new class () extends FileCollection { + protected function define(): void + { + $this->add(SUPPORTPATH . 'Files/baker/banana.php'); + } + }; - $collection->addFile('TheHillsAreAlive.bmp'); - } + $this->assertSame([$this->file], $collection->get()); + } - public function testAddFileDirectory() - { - $collection = new FileCollection(); + public function testAddStringFile() + { + $files = new FileCollection(); - $this->expectException(FileException::class); - $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + $files->add(SUPPORTPATH . 'Files/baker/banana.php'); - $collection->addFile($this->directory); - } + $this->assertSame([$this->file], $files->get()); + } - public function testAddFiles() - { - $collection = new FileCollection(); - $files = [ - $this->file, - $this->file, - ]; + public function testAddStringFileRecursiveDoesNothing() + { + $files = new FileCollection(); - $collection->addFiles($files); - $this->assertSame($files, $this->getPrivateProperty($collection, 'files')); - } + $files->add(SUPPORTPATH . 'Files/baker/banana.php', true); - //-------------------------------------------------------------------- + $this->assertSame([$this->file], $files->get()); + } - public function testGet() - { - $collection = new FileCollection(); - $collection->addFile($this->file); - - $this->assertSame([$this->file], $collection->get()); - } + public function testAddStringDirectory() + { + $files = new FileCollection(); - public function testGetSorts() - { - $collection = new FileCollection(); - $files = [ - $this->file, - $this->directory . 'apple.php', - ]; - - $collection->addFiles($files); - - $this->assertSame(array_reverse($files), $collection->get()); - } - - public function testGetUniques() - { - $collection = new FileCollection(); - $files = [ - $this->file, - $this->file, - ]; - - $collection->addFiles($files); - $this->assertSame([$this->file], $collection->get()); - } - - public function testSet() - { - $collection = new FileCollection(); - - $collection->set([$this->file]); - $this->assertSame([$this->file], $collection->get()); - } - - public function testSetInvalid() - { - $collection = new FileCollection(); - - $this->expectException(FileException::class); - $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); - - $collection->set(['flerb']); - } - - //-------------------------------------------------------------------- - - public function testRemoveFile() - { - $collection = new FileCollection(); - $files = [ - $this->file, - $this->directory . 'apple.php', - ]; - - $collection->addFiles($files); - - $collection->removeFile($this->file); - - $this->assertSame([$this->directory . 'apple.php'], $collection->get()); - } - - public function testRemoveFiles() - { - $collection = new FileCollection(); - $files = [ - $this->file, - $this->directory . 'apple.php', - ]; - - $collection->addFiles($files); - - $collection->removeFiles($files); - - $this->assertSame([], $collection->get()); - } - - //-------------------------------------------------------------------- - - public function testAddDirectoryInvalid() - { - $collection = new FileCollection(); - - $this->expectException(FileException::class); - $this->expectExceptionMessage(lang('Files.expectedDirectory', ['addDirectory'])); - - $collection->addDirectory($this->file); - } - - public function testAddDirectory() - { - $collection = new FileCollection(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - ]; - - $collection->addDirectory($this->directory); - - $this->assertSame($expected, $collection->get()); - } - - public function testAddDirectoryRecursive() - { - $collection = new FileCollection(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $files->add(SUPPORTPATH . 'Files/able'); - $this->assertSame($expected, $collection->get()); - } + $this->assertSame($expected, $files->get()); + } - public function testAddDirectories() - { - $collection = new FileCollection(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; + public function testAddStringDirectoryRecursive() + { + $files = new FileCollection(); - $collection->addDirectories([ - $this->directory, - SUPPORTPATH . 'Files/baker', - ]); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $files->add(SUPPORTPATH . 'Files'); + + $this->assertSame($expected, $files->get()); + } + + public function testAddArray() + { + $files = new FileCollection(); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $files->add([ + SUPPORTPATH . 'Files/able', + SUPPORTPATH . 'Files/baker/banana.php', + ]); + + $this->assertSame($expected, $files->get()); + } + + public function testAddArrayRecursive() + { + $files = new FileCollection(); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; + + $files->add([ + SUPPORTPATH . 'Files', + SUPPORTPATH . 'Log', + ], true); + + $this->assertSame($expected, $files->get()); + } + + public function testAddFile() + { + $collection = new FileCollection(); + $this->assertSame([], $this->getPrivateProperty($collection, 'files')); + + $collection->addFile($this->file); + $this->assertSame([$this->file], $this->getPrivateProperty($collection, 'files')); + } - $this->assertSame($expected, $collection->get()); - } + public function testAddFileMissing() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + + $collection->addFile('TheHillsAreAlive.bmp'); + } + + public function testAddFileDirectory() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + + $collection->addFile($this->directory); + } + + public function testAddFiles() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->file, + ]; + + $collection->addFiles($files); + $this->assertSame($files, $this->getPrivateProperty($collection, 'files')); + } + + public function testGet() + { + $collection = new FileCollection(); + $collection->addFile($this->file); + + $this->assertSame([$this->file], $collection->get()); + } + + public function testGetSorts() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $collection->addFiles($files); + + $this->assertSame(array_reverse($files), $collection->get()); + } + + public function testGetUniques() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->file, + ]; + + $collection->addFiles($files); + $this->assertSame([$this->file], $collection->get()); + } + + public function testSet() + { + $collection = new FileCollection(); + + $collection->set([$this->file]); + $this->assertSame([$this->file], $collection->get()); + } + + public function testSetInvalid() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedFile', ['addFile'])); + + $collection->set(['flerb']); + } + + public function testRemoveFile() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $collection->addFiles($files); + + $collection->removeFile($this->file); + + $this->assertSame([$this->directory . 'apple.php'], $collection->get()); + } + + public function testRemoveFiles() + { + $collection = new FileCollection(); + $files = [ + $this->file, + $this->directory . 'apple.php', + ]; + + $collection->addFiles($files); + + $collection->removeFiles($files); + + $this->assertSame([], $collection->get()); + } + + public function testAddDirectoryInvalid() + { + $collection = new FileCollection(); + + $this->expectException(FileException::class); + $this->expectExceptionMessage(lang('Files.expectedDirectory', ['addDirectory'])); + + $collection->addDirectory($this->file); + } + + public function testAddDirectory() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $collection->addDirectory($this->directory); + + $this->assertSame($expected, $collection->get()); + } + + public function testAddDirectoryRecursive() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $collection->addDirectory(SUPPORTPATH . 'Files', true); + + $this->assertSame($expected, $collection->get()); + } + + public function testAddDirectories() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; - public function testAddDirectoriesRecursive() - { - $collection = new FileCollection(); - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - SUPPORTPATH . 'Log/Handlers/TestHandler.php', - ]; + $collection->addDirectories([ + $this->directory, + SUPPORTPATH . 'Files/baker', + ]); - $collection->addDirectories([ - SUPPORTPATH . 'Files', - SUPPORTPATH . 'Log', - ], true); + $this->assertSame($expected, $collection->get()); + } - $this->assertSame($expected, $collection->get()); - } + public function testAddDirectoriesRecursive() + { + $collection = new FileCollection(); + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; - //-------------------------------------------------------------------- + $collection->addDirectories([ + SUPPORTPATH . 'Files', + SUPPORTPATH . 'Log', + ], true); - public function testRemovePatternEmpty() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $this->assertSame($expected, $collection->get()); + } - $files = $collection->get(); + public function testRemovePatternEmpty() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $collection->removePattern(''); + $files = $collection->get(); - $this->assertSame($files, $collection->get()); - } + $collection->removePattern(''); - public function testRemovePatternRegex() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $this->assertSame($files, $collection->get()); + } - $expected = [ - $this->directory . 'apple.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; + public function testRemovePatternRegex() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $collection->removePattern('#[a-z]+_.*#'); + $expected = [ + $this->directory . 'apple.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; - $this->assertSame($expected, $collection->get()); - } + $collection->removePattern('#[a-z]+_.*#'); - public function testRemovePatternPseudo() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $this->assertSame($expected, $collection->get()); + } - $expected = [ - $this->directory . 'apple.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; + public function testRemovePatternPseudo() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $collection->removePattern('*_*.php'); + $expected = [ + $this->directory . 'apple.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; - $this->assertSame($expected, $collection->get()); - } + $collection->removePattern('*_*.php'); - public function testRemovePatternScope() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $this->assertSame($expected, $collection->get()); + } - $expected = [ - SUPPORTPATH . 'Files/baker/banana.php', - ]; + public function testRemovePatternScope() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $collection->removePattern('*.php', $this->directory); + $expected = [ + SUPPORTPATH . 'Files/baker/banana.php', + ]; - $this->assertSame($expected, $collection->get()); - } + $collection->removePattern('*.php', $this->directory); - //-------------------------------------------------------------------- + $this->assertSame($expected, $collection->get()); + } - public function testRetainPatternEmpty() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + public function testRetainPatternEmpty() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $files = $collection->get(); + $files = $collection->get(); - $collection->retainPattern(''); + $collection->retainPattern(''); - $this->assertSame($files, $collection->get()); - } + $this->assertSame($files, $collection->get()); + } - public function testRetainPatternRegex() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + public function testRetainPatternRegex() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $expected = [ - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - ]; + $expected = [ + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; - $collection->retainPattern('#[a-z]+_.*#'); + $collection->retainPattern('#[a-z]+_.*#'); - $this->assertSame($expected, $collection->get()); - } + $this->assertSame($expected, $collection->get()); + } - public function testRetainPatternPseudo() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + public function testRetainPatternPseudo() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $expected = [ - $this->directory . 'fig_3.php', - ]; + $expected = [ + $this->directory . 'fig_3.php', + ]; - $collection->retainPattern('*_?.php'); + $collection->retainPattern('*_?.php'); - $this->assertSame($expected, $collection->get()); - } + $this->assertSame($expected, $collection->get()); + } - public function testRetainPatternScope() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + public function testRetainPatternScope() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - $expected = [ - $this->directory . 'fig_3.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; + $expected = [ + $this->directory . 'fig_3.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; - $collection->retainPattern('*_?.php', $this->directory); + $collection->retainPattern('*_?.php', $this->directory); - $this->assertSame($expected, $collection->get()); - } + $this->assertSame($expected, $collection->get()); + } - //-------------------------------------------------------------------- + public function testCount() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - public function testCount() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $this->assertCount(4, $collection); + } - $this->assertCount(4, $collection); - } + public function testIterable() + { + $collection = new FileCollection(); + $collection->addDirectory(SUPPORTPATH . 'Files', true); - public function testIterable() - { - $collection = new FileCollection(); - $collection->addDirectory(SUPPORTPATH . 'Files', true); + $count = 0; - $count = 0; - foreach ($collection as $file) - { - $this->assertInstanceOf(File::class, $file); - $count++; - } + foreach ($collection as $file) { + $this->assertInstanceOf(File::class, $file); + $count++; + } - $this->assertSame($count, 4); - } + $this->assertSame($count, 4); + } } diff --git a/tests/system/Language/LanguageTest.php b/tests/system/Language/LanguageTest.php index ace99172aac4..fcf4beea6257 100644 --- a/tests/system/Language/LanguageTest.php +++ b/tests/system/Language/LanguageTest.php @@ -279,17 +279,15 @@ public function testLangKeepLocale() $this->lang = Services::language('en', true); lang('Language.languageGetLineInvalidArgumentException'); - $this->assertEquals('en', $this->lang->getLocale()); + $this->assertSame('en', $this->lang->getLocale()); lang('Language.languageGetLineInvalidArgumentException', [], 'ru'); - $this->assertEquals('en', $this->lang->getLocale()); + $this->assertSame('en', $this->lang->getLocale()); lang('Language.languageGetLineInvalidArgumentException'); - $this->assertEquals('en', $this->lang->getLocale()); + $this->assertSame('en', $this->lang->getLocale()); } - //-------------------------------------------------------------------- - /** * Testing base locale vs variants, with fallback to English. * diff --git a/tests/system/Publisher/PublisherInputTest.php b/tests/system/Publisher/PublisherInputTest.php index 29d48ef78816..a6f6b8eec582 100644 --- a/tests/system/Publisher/PublisherInputTest.php +++ b/tests/system/Publisher/PublisherInputTest.php @@ -1,150 +1,156 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use CodeIgniter\Publisher\Publisher; use CodeIgniter\Test\CIUnitTestCase; -use Tests\Support\Publishers\TestPublisher; -class PublisherInputTest extends CIUnitTestCase +/** + * @internal + */ +final class PublisherInputTest extends CIUnitTestCase { - /** - * A known, valid file - * - * @var string - */ - private $file = SUPPORTPATH . 'Files/baker/banana.php'; - - /** - * A known, valid directory - * - * @var string - */ - private $directory = SUPPORTPATH . 'Files/able/'; - - /** - * Initialize the helper, since some - * tests call static methods before - * the constructor would load it. - */ - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper(['filesystem']); - } - - //-------------------------------------------------------------------- - - public function testAddPathFile() - { - $publisher = new Publisher(SUPPORTPATH . 'Files'); - - $publisher->addPath('baker/banana.php'); - - $this->assertSame([$this->file], $publisher->get()); - } - - public function testAddPathFileRecursiveDoesNothing() - { - $publisher = new Publisher(SUPPORTPATH . 'Files'); - - $publisher->addPath('baker/banana.php', true); - - $this->assertSame([$this->file], $publisher->get()); - } - - public function testAddPathDirectory() - { - $publisher = new Publisher(SUPPORTPATH . 'Files'); - - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - ]; - - $publisher->addPath('able'); - - $this->assertSame($expected, $publisher->get()); - } - - public function testAddPathDirectoryRecursive() - { - $publisher = new Publisher(SUPPORTPATH); - - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->addPath('Files'); - - $this->assertSame($expected, $publisher->get()); - } - - public function testAddPaths() - { - $publisher = new Publisher(SUPPORTPATH . 'Files'); - - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - ]; - - $publisher->addPaths([ - 'able', - 'baker/banana.php', - ]); - - $this->assertSame($expected, $publisher->get()); - } - - public function testAddPathsRecursive() - { - $publisher = new Publisher(SUPPORTPATH); - - $expected = [ - $this->directory . 'apple.php', - $this->directory . 'fig_3.php', - $this->directory . 'prune_ripe.php', - SUPPORTPATH . 'Files/baker/banana.php', - SUPPORTPATH . 'Log/Handlers/TestHandler.php', - ]; - - $publisher->addPaths([ - 'Files', - 'Log', - ], true); - - $this->assertSame($expected, $publisher->get()); - } - - //-------------------------------------------------------------------- + /** + * A known, valid file + * + * @var string + */ + private $file = SUPPORTPATH . 'Files/baker/banana.php'; + + /** + * A known, valid directory + * + * @var string + */ + private $directory = SUPPORTPATH . 'Files/able/'; + + /** + * Initialize the helper, since some + * tests call static methods before + * the constructor would load it. + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + helper(['filesystem']); + } + + public function testAddPathFile() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $publisher->addPath('baker/banana.php'); + + $this->assertSame([$this->file], $publisher->get()); + } + + public function testAddPathFileRecursiveDoesNothing() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $publisher->addPath('baker/banana.php', true); + + $this->assertSame([$this->file], $publisher->get()); + } + + public function testAddPathDirectory() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + ]; + + $publisher->addPath('able'); + + $this->assertSame($expected, $publisher->get()); + } + + public function testAddPathDirectoryRecursive() + { + $publisher = new Publisher(SUPPORTPATH); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->addPath('Files'); + + $this->assertSame($expected, $publisher->get()); + } + + public function testAddPaths() + { + $publisher = new Publisher(SUPPORTPATH . 'Files'); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + ]; + + $publisher->addPaths([ + 'able', + 'baker/banana.php', + ]); + + $this->assertSame($expected, $publisher->get()); + } + + public function testAddPathsRecursive() + { + $publisher = new Publisher(SUPPORTPATH); + + $expected = [ + $this->directory . 'apple.php', + $this->directory . 'fig_3.php', + $this->directory . 'prune_ripe.php', + SUPPORTPATH . 'Files/baker/banana.php', + SUPPORTPATH . 'Log/Handlers/TestHandler.php', + ]; + + $publisher->addPaths([ + 'Files', + 'Log', + ], true); + + $this->assertSame($expected, $publisher->get()); + } - public function testAddUri() - { - $publisher = new Publisher(); - $publisher->addUri('https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/composer.json'); + public function testAddUri() + { + $publisher = new Publisher(); + $publisher->addUri('https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/composer.json'); - $scratch = $this->getPrivateProperty($publisher, 'scratch'); + $scratch = $this->getPrivateProperty($publisher, 'scratch'); - $this->assertSame([$scratch . 'composer.json'], $publisher->get()); - } + $this->assertSame([$scratch . 'composer.json'], $publisher->get()); + } - public function testAddUris() - { - $publisher = new Publisher(); - $publisher->addUris([ - 'https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/LICENSE', - 'https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/composer.json', - ]); + public function testAddUris() + { + $publisher = new Publisher(); + $publisher->addUris([ + 'https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/LICENSE', + 'https://raw.githubusercontent.com/codeigniter4/CodeIgniter4/develop/composer.json', + ]); - $scratch = $this->getPrivateProperty($publisher, 'scratch'); + $scratch = $this->getPrivateProperty($publisher, 'scratch'); - $this->assertSame([$scratch . 'LICENSE', $scratch . 'composer.json'], $publisher->get()); - } + $this->assertSame([$scratch . 'LICENSE', $scratch . 'composer.json'], $publisher->get()); + } } diff --git a/tests/system/Publisher/PublisherOutputTest.php b/tests/system/Publisher/PublisherOutputTest.php index 489058a1c099..512e051f7663 100644 --- a/tests/system/Publisher/PublisherOutputTest.php +++ b/tests/system/Publisher/PublisherOutputTest.php @@ -1,227 +1,231 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use CodeIgniter\Publisher\Publisher; use CodeIgniter\Test\CIUnitTestCase; -use Tests\Support\Publishers\TestPublisher; use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\vfsStreamDirectory; -class PublisherOutputTest extends CIUnitTestCase +/** + * @internal + */ +final class PublisherOutputTest extends CIUnitTestCase { - /** - * Files to seed to VFS - * - * @var array - */ - private $structure; - - /** - * Virtual destination - * - * @var vfsStreamDirectory - */ - private $root; - - /** - * A known, valid file - * - * @var string - */ - private $file = SUPPORTPATH . 'Files/baker/banana.php'; - - /** - * A known, valid directory - * - * @var string - */ - private $directory = SUPPORTPATH . 'Files/able/'; - - /** - * Initialize the helper, since some - * tests call static methods before - * the constructor would load it. - */ - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper(['filesystem']); - } - - protected function setUp(): void - { - parent::setUp(); - - $this->structure = [ - 'able' => [ - 'apple.php' => 'Once upon a midnight dreary', - 'bazam' => 'While I pondered weak and weary', - ], - 'boo' => [ - 'far' => 'Upon a tome of long-forgotten lore', - 'faz' => 'There came a tapping up on the door', - ], - 'AnEmptyFolder' => [], - 'simpleFile' => 'A tap-tap-tapping upon my door', - '.hidden' => 'There is no spoon', - ]; - - $this->root = vfsStream::setup('root', null, $this->structure); - - // Add root to the list of allowed destinations - config('Publisher')->restrictions[$this->root->url()] = '*'; - } - - //-------------------------------------------------------------------- - - public function testCopy() - { - $publisher = new Publisher($this->directory, $this->root->url()); - $publisher->addFile($this->file); - - $this->assertFileDoesNotExist($this->root->url() . '/banana.php'); - - $result = $publisher->copy(false); - - $this->assertTrue($result); - $this->assertFileExists($this->root->url() . '/banana.php'); - } - - public function testCopyReplace() - { - $file = $this->directory . 'apple.php'; - $publisher = new Publisher($this->directory, $this->root->url() . '/able'); - $publisher->addFile($file); - - $this->assertFileExists($this->root->url() . '/able/apple.php'); - $this->assertFalse(same_file($file, $this->root->url() . '/able/apple.php')); - - $result = $publisher->copy(true); - - $this->assertTrue($result); - $this->assertTrue(same_file($file, $this->root->url() . '/able/apple.php')); - } - - public function testCopyIgnoresSame() - { - $publisher = new Publisher($this->directory, $this->root->url()); - $publisher->addFile($this->file); - - copy($this->file, $this->root->url() . '/banana.php'); - - $result = $publisher->copy(false); - $this->assertTrue($result); - - $result = $publisher->copy(true); - $this->assertTrue($result); - $this->assertSame([$this->root->url() . '/banana.php'], $publisher->getPublished()); - } - - public function testCopyIgnoresCollision() - { - $publisher = new Publisher($this->directory, $this->root->url()); - - mkdir($this->root->url() . '/banana.php'); - - $result = $publisher->addFile($this->file)->copy(false); - - $this->assertTrue($result); - $this->assertSame([], $publisher->getErrors()); - $this->assertSame([$this->root->url() . '/banana.php'], $publisher->getPublished()); - } - - public function testCopyCollides() - { - $publisher = new Publisher($this->directory, $this->root->url()); - $expected = lang('Publisher.collision', ['dir', $this->file, $this->root->url() . '/banana.php']); - - mkdir($this->root->url() . '/banana.php'); - - $result = $publisher->addFile($this->file)->copy(true); - $errors = $publisher->getErrors(); - - $this->assertFalse($result); - $this->assertCount(1, $errors); - $this->assertSame([$this->file], array_keys($errors)); - $this->assertSame([], $publisher->getPublished()); - $this->assertSame($expected, $errors[$this->file]->getMessage()); - } - - //-------------------------------------------------------------------- - - public function testMerge() - { - $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); - $expected = [ - $this->root->url() . '/able/apple.php', - $this->root->url() . '/able/fig_3.php', - $this->root->url() . '/able/prune_ripe.php', - $this->root->url() . '/baker/banana.php', - ]; - - $this->assertFileDoesNotExist($this->root->url() . '/able/fig_3.php'); - $this->assertDirectoryDoesNotExist($this->root->url() . '/baker'); - - $result = $publisher->addPath('/')->merge(false); - - $this->assertTrue($result); - $this->assertFileExists($this->root->url() . '/able/fig_3.php'); - $this->assertDirectoryExists($this->root->url() . '/baker'); - $this->assertSame($expected, $publisher->getPublished()); - } - - public function testMergeReplace() - { - $this->assertFalse(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); - $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); - $expected = [ - $this->root->url() . '/able/apple.php', - $this->root->url() . '/able/fig_3.php', - $this->root->url() . '/able/prune_ripe.php', - $this->root->url() . '/baker/banana.php', - ]; - - $result = $publisher->addPath('/')->merge(true); - - $this->assertTrue($result); - $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); - $this->assertSame($expected, $publisher->getPublished()); - } - - public function testMergeCollides() - { - $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); - $expected = lang('Publisher.collision', ['dir', $this->directory . 'fig_3.php', $this->root->url() . '/able/fig_3.php']); - $published = [ - $this->root->url() . '/able/apple.php', - $this->root->url() . '/able/prune_ripe.php', - $this->root->url() . '/baker/banana.php', - ]; - - mkdir($this->root->url() . '/able/fig_3.php'); - - $result = $publisher->addPath('/')->merge(true); - $errors = $publisher->getErrors(); - - $this->assertFalse($result); - $this->assertCount(1, $errors); - $this->assertSame([$this->directory . 'fig_3.php'], array_keys($errors)); - $this->assertSame($published, $publisher->getPublished()); - $this->assertSame($expected, $errors[$this->directory . 'fig_3.php']->getMessage()); - } - - //-------------------------------------------------------------------- - - public function testPublish() - { - $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); - - $result = $publisher->publish(); - - $this->assertTrue($result); - $this->assertFileExists($this->root->url() . '/able/fig_3.php'); - $this->assertDirectoryExists($this->root->url() . '/baker'); - $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); - } + /** + * Files to seed to VFS + * + * @var array + */ + private $structure; + + /** + * Virtual destination + * + * @var vfsStreamDirectory + */ + private $root; + + /** + * A known, valid file + * + * @var string + */ + private $file = SUPPORTPATH . 'Files/baker/banana.php'; + + /** + * A known, valid directory + * + * @var string + */ + private $directory = SUPPORTPATH . 'Files/able/'; + + /** + * Initialize the helper, since some + * tests call static methods before + * the constructor would load it. + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + helper(['filesystem']); + } + + protected function setUp(): void + { + parent::setUp(); + + $this->structure = [ + 'able' => [ + 'apple.php' => 'Once upon a midnight dreary', + 'bazam' => 'While I pondered weak and weary', + ], + 'boo' => [ + 'far' => 'Upon a tome of long-forgotten lore', + 'faz' => 'There came a tapping up on the door', + ], + 'AnEmptyFolder' => [], + 'simpleFile' => 'A tap-tap-tapping upon my door', + '.hidden' => 'There is no spoon', + ]; + + $this->root = vfsStream::setup('root', null, $this->structure); + + // Add root to the list of allowed destinations + config('Publisher')->restrictions[$this->root->url()] = '*'; + } + + public function testCopy() + { + $publisher = new Publisher($this->directory, $this->root->url()); + $publisher->addFile($this->file); + + $this->assertFileDoesNotExist($this->root->url() . '/banana.php'); + + $result = $publisher->copy(false); + + $this->assertTrue($result); + $this->assertFileExists($this->root->url() . '/banana.php'); + } + + public function testCopyReplace() + { + $file = $this->directory . 'apple.php'; + $publisher = new Publisher($this->directory, $this->root->url() . '/able'); + $publisher->addFile($file); + + $this->assertFileExists($this->root->url() . '/able/apple.php'); + $this->assertFalse(same_file($file, $this->root->url() . '/able/apple.php')); + + $result = $publisher->copy(true); + + $this->assertTrue($result); + $this->assertTrue(same_file($file, $this->root->url() . '/able/apple.php')); + } + + public function testCopyIgnoresSame() + { + $publisher = new Publisher($this->directory, $this->root->url()); + $publisher->addFile($this->file); + + copy($this->file, $this->root->url() . '/banana.php'); + + $result = $publisher->copy(false); + $this->assertTrue($result); + + $result = $publisher->copy(true); + $this->assertTrue($result); + $this->assertSame([$this->root->url() . '/banana.php'], $publisher->getPublished()); + } + + public function testCopyIgnoresCollision() + { + $publisher = new Publisher($this->directory, $this->root->url()); + + mkdir($this->root->url() . '/banana.php'); + + $result = $publisher->addFile($this->file)->copy(false); + + $this->assertTrue($result); + $this->assertSame([], $publisher->getErrors()); + $this->assertSame([$this->root->url() . '/banana.php'], $publisher->getPublished()); + } + + public function testCopyCollides() + { + $publisher = new Publisher($this->directory, $this->root->url()); + $expected = lang('Publisher.collision', ['dir', $this->file, $this->root->url() . '/banana.php']); + + mkdir($this->root->url() . '/banana.php'); + + $result = $publisher->addFile($this->file)->copy(true); + $errors = $publisher->getErrors(); + + $this->assertFalse($result); + $this->assertCount(1, $errors); + $this->assertSame([$this->file], array_keys($errors)); + $this->assertSame([], $publisher->getPublished()); + $this->assertSame($expected, $errors[$this->file]->getMessage()); + } + + public function testMerge() + { + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + $expected = [ + $this->root->url() . '/able/apple.php', + $this->root->url() . '/able/fig_3.php', + $this->root->url() . '/able/prune_ripe.php', + $this->root->url() . '/baker/banana.php', + ]; + + $this->assertFileDoesNotExist($this->root->url() . '/able/fig_3.php'); + $this->assertDirectoryDoesNotExist($this->root->url() . '/baker'); + + $result = $publisher->addPath('/')->merge(false); + + $this->assertTrue($result); + $this->assertFileExists($this->root->url() . '/able/fig_3.php'); + $this->assertDirectoryExists($this->root->url() . '/baker'); + $this->assertSame($expected, $publisher->getPublished()); + } + + public function testMergeReplace() + { + $this->assertFalse(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + $expected = [ + $this->root->url() . '/able/apple.php', + $this->root->url() . '/able/fig_3.php', + $this->root->url() . '/able/prune_ripe.php', + $this->root->url() . '/baker/banana.php', + ]; + + $result = $publisher->addPath('/')->merge(true); + + $this->assertTrue($result); + $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + $this->assertSame($expected, $publisher->getPublished()); + } + + public function testMergeCollides() + { + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + $expected = lang('Publisher.collision', ['dir', $this->directory . 'fig_3.php', $this->root->url() . '/able/fig_3.php']); + $published = [ + $this->root->url() . '/able/apple.php', + $this->root->url() . '/able/prune_ripe.php', + $this->root->url() . '/baker/banana.php', + ]; + + mkdir($this->root->url() . '/able/fig_3.php'); + + $result = $publisher->addPath('/')->merge(true); + $errors = $publisher->getErrors(); + + $this->assertFalse($result); + $this->assertCount(1, $errors); + $this->assertSame([$this->directory . 'fig_3.php'], array_keys($errors)); + $this->assertSame($published, $publisher->getPublished()); + $this->assertSame($expected, $errors[$this->directory . 'fig_3.php']->getMessage()); + } + + public function testPublish() + { + $publisher = new Publisher(SUPPORTPATH . 'Files', $this->root->url()); + + $result = $publisher->publish(); + + $this->assertTrue($result); + $this->assertFileExists($this->root->url() . '/able/fig_3.php'); + $this->assertDirectoryExists($this->root->url() . '/baker'); + $this->assertTrue(same_file($this->directory . 'apple.php', $this->root->url() . '/able/apple.php')); + } } diff --git a/tests/system/Publisher/PublisherRestrictionsTest.php b/tests/system/Publisher/PublisherRestrictionsTest.php index 27db2e9429a9..692e49d7680b 100644 --- a/tests/system/Publisher/PublisherRestrictionsTest.php +++ b/tests/system/Publisher/PublisherRestrictionsTest.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use CodeIgniter\Publisher\Exceptions\PublisherException; use CodeIgniter\Publisher\Publisher; use CodeIgniter\Test\CIUnitTestCase; @@ -9,100 +18,103 @@ * * Tests that the restrictions defined in the configuration * file properly prevent disallowed actions. + * + * @internal */ -class PublisherRestrictionsTest extends CIUnitTestCase +final class PublisherRestrictionsTest extends CIUnitTestCase { - /** - * @see Tests\Support\Config\Registrars::Publisher() - */ - public function testRegistrarsNotAllowed() - { - $this->assertArrayNotHasKey(SUPPORTPATH, config('Publisher')->restrictions); - } - - public function testImmutableRestrictions() - { - $publisher = new Publisher(); - - // Try to "hack" the Publisher by adding our desired destination to the config - config('Publisher')->restrictions[SUPPORTPATH] = '*'; - - $restrictions = $this->getPrivateProperty($publisher, 'restrictions'); - - $this->assertArrayNotHasKey(SUPPORTPATH, $restrictions); - } - - /** - * @dataProvider fileProvider - */ - public function testDefaultPublicRestrictions(string $path) - { - $publisher = new Publisher(ROOTPATH, FCPATH); - $pattern = config('Publisher')->restrictions[FCPATH]; - - // Use the scratch space to create a file - $file = $publisher->getScratch() . $path; - file_put_contents($file, 'To infinity and beyond!'); - - $result = $publisher->addFile($file)->merge(); - $this->assertFalse($result); - - $errors = $publisher->getErrors(); - $this->assertCount(1, $errors); - $this->assertSame([$file], array_keys($errors)); - - $expected = lang('Publisher.fileNotAllowed', [$file, FCPATH, $pattern]); - $this->assertSame($expected, $errors[$file]->getMessage()); - } - - public function fileProvider() - { - yield 'php' => ['index.php']; - yield 'exe' => ['cat.exe']; - yield 'flat' => ['banana']; - } - - /** - * @dataProvider destinationProvider - */ - public function testDestinations(string $destination, bool $allowed) - { - config('Publisher')->restrictions = [ - APPPATH => '', - FCPATH => '', - SUPPORTPATH . 'Files' => '', - SUPPORTPATH . 'Files/../' => '', - ]; - - if (! $allowed) - { - $this->expectException(PublisherException::class); - $this->expectExceptionMessage(lang('Publisher.destinationNotAllowed', [$destination])); - } - - $publisher = new Publisher(null, $destination); - $this->assertInstanceOf(Publisher::class, $publisher); - } - - public function destinationProvider() - { - return [ - 'explicit' => [ - APPPATH, - true, - ], - 'subdirectory' => [ - APPPATH . 'Config', - true, - ], - 'relative' => [ - SUPPORTPATH . 'Files/able/../', - true, - ], - 'parent' => [ - SUPPORTPATH, - false, - ], - ]; - } + /** + * @see Tests\Support\Config\Registrars::Publisher() + */ + public function testRegistrarsNotAllowed() + { + $this->assertArrayNotHasKey(SUPPORTPATH, config('Publisher')->restrictions); + } + + public function testImmutableRestrictions() + { + $publisher = new Publisher(); + + // Try to "hack" the Publisher by adding our desired destination to the config + config('Publisher')->restrictions[SUPPORTPATH] = '*'; + + $restrictions = $this->getPrivateProperty($publisher, 'restrictions'); + + $this->assertArrayNotHasKey(SUPPORTPATH, $restrictions); + } + + /** + * @dataProvider fileProvider + */ + public function testDefaultPublicRestrictions(string $path) + { + $publisher = new Publisher(ROOTPATH, FCPATH); + $pattern = config('Publisher')->restrictions[FCPATH]; + + // Use the scratch space to create a file + $file = $publisher->getScratch() . $path; + file_put_contents($file, 'To infinity and beyond!'); + + $result = $publisher->addFile($file)->merge(); + $this->assertFalse($result); + + $errors = $publisher->getErrors(); + $this->assertCount(1, $errors); + $this->assertSame([$file], array_keys($errors)); + + $expected = lang('Publisher.fileNotAllowed', [$file, FCPATH, $pattern]); + $this->assertSame($expected, $errors[$file]->getMessage()); + } + + public function fileProvider() + { + yield 'php' => ['index.php']; + + yield 'exe' => ['cat.exe']; + + yield 'flat' => ['banana']; + } + + /** + * @dataProvider destinationProvider + */ + public function testDestinations(string $destination, bool $allowed) + { + config('Publisher')->restrictions = [ + APPPATH => '', + FCPATH => '', + SUPPORTPATH . 'Files' => '', + SUPPORTPATH . 'Files/../' => '', + ]; + + if (! $allowed) { + $this->expectException(PublisherException::class); + $this->expectExceptionMessage(lang('Publisher.destinationNotAllowed', [$destination])); + } + + $publisher = new Publisher(null, $destination); + $this->assertInstanceOf(Publisher::class, $publisher); + } + + public function destinationProvider() + { + return [ + 'explicit' => [ + APPPATH, + true, + ], + 'subdirectory' => [ + APPPATH . 'Config', + true, + ], + 'relative' => [ + SUPPORTPATH . 'Files/able/../', + true, + ], + 'parent' => [ + SUPPORTPATH, + false, + ], + ]; + } } diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index 081b831f1241..43be04406891 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -1,149 +1,155 @@ + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + use CodeIgniter\Publisher\Exceptions\PublisherException; use CodeIgniter\Publisher\Publisher; use CodeIgniter\Test\CIUnitTestCase; use Tests\Support\Publishers\TestPublisher; -class PublisherSupportTest extends CIUnitTestCase +/** + * @internal + */ +final class PublisherSupportTest extends CIUnitTestCase { - /** - * A known, valid file - * - * @var string - */ - private $file = SUPPORTPATH . 'Files/baker/banana.php'; - - /** - * A known, valid directory - * - * @var string - */ - private $directory = SUPPORTPATH . 'Files/able/'; - - /** - * Initialize the helper, since some - * tests call static methods before - * the constructor would load it. - */ - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper(['filesystem']); - } - - //-------------------------------------------------------------------- - - public function testDiscoverDefault() - { - $result = Publisher::discover(); - - $this->assertCount(1, $result); - $this->assertInstanceOf(TestPublisher::class, $result[0]); - } - - public function testDiscoverNothing() - { - $result = Publisher::discover('Nothing'); - - $this->assertSame([], $result); - } - - public function testDiscoverStores() - { - $publisher = Publisher::discover()[0]; - $publisher->set([])->addFile($this->file); - - $result = Publisher::discover(); - $this->assertSame($publisher, $result[0]); - $this->assertSame([$this->file], $result[0]->get()); - } - - //-------------------------------------------------------------------- - - public function testGetSource() - { - $publisher = new Publisher(ROOTPATH); - - $this->assertSame(ROOTPATH, $publisher->getSource()); - } - - public function testGetDestination() - { - $publisher = new Publisher(ROOTPATH, SUPPORTPATH); - - $this->assertSame(SUPPORTPATH, $publisher->getDestination()); - } - - public function testGetScratch() - { - $publisher = new Publisher(); - $this->assertNull($this->getPrivateProperty($publisher, 'scratch')); - - $scratch = $publisher->getScratch(); - - $this->assertIsString($scratch); - $this->assertDirectoryExists($scratch); - $this->assertDirectoryIsWritable($scratch); - $this->assertNotNull($this->getPrivateProperty($publisher, 'scratch')); - - // Directory and contents should be removed on __destruct() - $file = $scratch . 'obvious_statement.txt'; - file_put_contents($file, 'Bananas are a most peculiar fruit'); - - $publisher->__destruct(); - - $this->assertFileDoesNotExist($file); - $this->assertDirectoryDoesNotExist($scratch); - } - - public function testGetErrors() - { - $publisher = new Publisher(); - $this->assertSame([], $publisher->getErrors()); - - $expected = [ - $this->file => PublisherException::forCollision($this->file, $this->file), - ]; - - $this->setPrivateProperty($publisher, 'errors', $expected); - - $this->assertSame($expected, $publisher->getErrors()); - } - - //-------------------------------------------------------------------- - - public function testWipeDirectory() - { - $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); - mkdir($directory, 0700); - $this->assertDirectoryExists($directory); - - $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); - $method($directory); + /** + * A known, valid file + * + * @var string + */ + private $file = SUPPORTPATH . 'Files/baker/banana.php'; + + /** + * A known, valid directory + * + * @var string + */ + private $directory = SUPPORTPATH . 'Files/able/'; + + /** + * Initialize the helper, since some + * tests call static methods before + * the constructor would load it. + */ + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + helper(['filesystem']); + } + + public function testDiscoverDefault() + { + $result = Publisher::discover(); + + $this->assertCount(1, $result); + $this->assertInstanceOf(TestPublisher::class, $result[0]); + } + + public function testDiscoverNothing() + { + $result = Publisher::discover('Nothing'); + + $this->assertSame([], $result); + } + + public function testDiscoverStores() + { + $publisher = Publisher::discover()[0]; + $publisher->set([])->addFile($this->file); + + $result = Publisher::discover(); + $this->assertSame($publisher, $result[0]); + $this->assertSame([$this->file], $result[0]->get()); + } + + public function testGetSource() + { + $publisher = new Publisher(ROOTPATH); + + $this->assertSame(ROOTPATH, $publisher->getSource()); + } + + public function testGetDestination() + { + $publisher = new Publisher(ROOTPATH, SUPPORTPATH); + + $this->assertSame(SUPPORTPATH, $publisher->getDestination()); + } + + public function testGetScratch() + { + $publisher = new Publisher(); + $this->assertNull($this->getPrivateProperty($publisher, 'scratch')); + + $scratch = $publisher->getScratch(); + + $this->assertIsString($scratch); + $this->assertDirectoryExists($scratch); + $this->assertDirectoryIsWritable($scratch); + $this->assertNotNull($this->getPrivateProperty($publisher, 'scratch')); + + // Directory and contents should be removed on __destruct() + $file = $scratch . 'obvious_statement.txt'; + file_put_contents($file, 'Bananas are a most peculiar fruit'); + + $publisher->__destruct(); + + $this->assertFileDoesNotExist($file); + $this->assertDirectoryDoesNotExist($scratch); + } + + public function testGetErrors() + { + $publisher = new Publisher(); + $this->assertSame([], $publisher->getErrors()); + + $expected = [ + $this->file => PublisherException::forCollision($this->file, $this->file), + ]; + + $this->setPrivateProperty($publisher, 'errors', $expected); + + $this->assertSame($expected, $publisher->getErrors()); + } + + public function testWipeDirectory() + { + $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); + mkdir($directory, 0700); + $this->assertDirectoryExists($directory); - $this->assertDirectoryDoesNotExist($directory); - } + $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); + $method($directory); + + $this->assertDirectoryDoesNotExist($directory); + } - public function testWipeIgnoresFiles() - { - $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); - $method($this->file); + public function testWipeIgnoresFiles() + { + $method = $this->getPrivateMethodInvoker(Publisher::class, 'wipeDirectory'); + $method($this->file); - $this->assertFileExists($this->file); - } + $this->assertFileExists($this->file); + } - public function testWipe() - { - $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); - mkdir($directory, 0700); - $this->assertDirectoryExists($directory); - config('Publisher')->restrictions[$directory] = ''; // Allow the directory + public function testWipe() + { + $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); + mkdir($directory, 0700); + $this->assertDirectoryExists($directory); + config('Publisher')->restrictions[$directory] = ''; // Allow the directory - $publisher = new Publisher($this->directory, $directory); - $publisher->wipe(); + $publisher = new Publisher($this->directory, $directory); + $publisher->wipe(); - $this->assertDirectoryDoesNotExist($directory); - } + $this->assertDirectoryDoesNotExist($directory); + } } diff --git a/tests/system/Session/Handlers/DatabaseHandlerTest.php b/tests/system/Session/Handlers/DatabaseHandlerTest.php index 7e69bf8e6c73..e001af8eeec8 100644 --- a/tests/system/Session/Handlers/DatabaseHandlerTest.php +++ b/tests/system/Session/Handlers/DatabaseHandlerTest.php @@ -136,6 +136,6 @@ public function testWriteUpdate() public function testGC() { $handler = $this->getInstance(); - $this->assertTrue($handler->gc(3600)); + $this->assertSame(1, $handler->gc(3600)); } } diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index 5e3217654e47..1b21fe394659 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -988,11 +988,6 @@ public function validationArrayDataCaseProvider(): iterable /** * @dataProvider provideStringRulesCases * - * @param string $input - * @param array $expected - * - * @return void - * * @see https://github.com/codeigniter4/CodeIgniter4/issues/4929 */ public function testSplittingOfComplexStringRules(string $input, array $expected): void From 692709227bc2e118aec5c669cc0e4db70146cd15 Mon Sep 17 00:00:00 2001 From: Terrorboy Date: Wed, 8 Sep 2021 22:42:47 +0900 Subject: [PATCH 0227/2325] Fix variable variable `$$id` in RedisHandler --- system/Session/Handlers/RedisHandler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index 8ed7b8c052b8..ce6e7bde5180 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -137,7 +137,7 @@ public function read($id) { if (isset($this->redis) && $this->lockSession($id)) { if (! isset($this->sessionID)) { - $this->sessionID = ${$id}; + $this->sessionID = $id; } $data = $this->redis->get($this->keyPrefix . $id); From 4cd35992e62ef9590f611169cc7fe93902d5eb45 Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 8 Sep 2021 14:20:01 +0000 Subject: [PATCH 0228/2325] Ignore CPD file --- .github/workflows/test-phpcpd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index fcc66f7d682c..93a27ddf6e28 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -40,4 +40,4 @@ jobs: - name: Detect code duplication run: | sudo phive --no-progress install --global --trust-gpg-keys 4AA394086372C20A phpcpd - phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php app/ public/ system/ + phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php system/Database/SQLSRV/Forge.php app/ public/ system/ From ca5537eb2770587e263ac81008fa2d4590e98437 Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 8 Sep 2021 14:22:26 +0000 Subject: [PATCH 0229/2325] Fix typo --- .github/workflows/test-phpcpd.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index 93a27ddf6e28..d78edbea1f0e 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -40,4 +40,4 @@ jobs: - name: Detect code duplication run: | sudo phive --no-progress install --global --trust-gpg-keys 4AA394086372C20A phpcpd - phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php system/Database/SQLSRV/Forge.php app/ public/ system/ + phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php --exclude system/Database/SQLSRV/Forge.php app/ public/ system/ From 0c2a8119400bf7f64a2fe53eec9c745f25644c7b Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Wed, 8 Sep 2021 22:58:39 +0800 Subject: [PATCH 0230/2325] Update 'updated_at' when enabled in replace() --- system/BaseModel.php | 4 +++ system/Database/Postgre/Builder.php | 23 ++++++++----- system/Database/SQLSRV/Builder.php | 4 +-- tests/system/Models/ReplaceModelTest.php | 44 ++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 11 deletions(-) create mode 100644 tests/system/Models/ReplaceModelTest.php diff --git a/system/BaseModel.php b/system/BaseModel.php index e57ac4fec6bd..29c6d1075949 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1031,6 +1031,10 @@ public function replace(?array $data = null, bool $returnSQL = false) return false; } + if ($this->useTimestamps && $this->updatedField && ! array_key_exists($this->updatedField, (array) $data)) { + $data[$this->updatedField] = $this->setDate(); + } + return $this->doReplace($data, $returnSQL); } diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index 2b7a5b3dee06..1006ab20012e 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -39,8 +39,6 @@ class Builder extends BaseBuilder ]; /** - * Compile Ignore Statement - * * Checks if the ignore option is supported by * the Database Driver for the specific statement. * @@ -122,13 +120,11 @@ public function decrement(string $column, int $value = 1) * we simply do a DELETE and an INSERT on the first key/value * combo, assuming that it's either the primary key or a unique key. * - * @param array $set An associative array of insert values + * @param array|null $set An associative array of insert values * * @throws DatabaseException * * @return mixed - * - * @internal */ public function replace(?array $set = null) { @@ -145,18 +141,27 @@ public function replace(?array $set = null) } $table = $this->QBFrom[0]; + $set = $this->binds; + + array_walk($set, static function (array &$item) { + $item = $item[0]; + }); $key = array_key_first($set); $value = $set[$key]; $builder = $this->db->table($table); - $exists = $builder->where("{$key} = {$value}", null, false)->get()->getFirstRow(); + $exists = $builder->where($key, $value, true)->get()->getFirstRow(); - if (empty($exists)) { + if (empty($exists) && $this->testMode) { + $result = $this->getCompiledInsert(); + } elseif (empty($exists)) { $result = $builder->insert($set); + } elseif ($this->testMode) { + $result = $this->where($key, $value, true)->getCompiledUpdate(); } else { - array_pop($set); - $result = $builder->update($set, "{$key} = {$value}"); + array_shift($set); + $result = $builder->where($key, $value, true)->update($set); } unset($builder); diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index cda4fac8a825..851f7fd07860 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -348,9 +348,9 @@ protected function _replace(string $table, array $keys, array $values): string $bingo = []; foreach ($common as $v) { - $k = array_search($v, $escKeyFields, true); + $k = array_search($v, $keys, true); - $bingo[$keyFields[$k]] = $binds[trim($values[$k], ':')]; + $bingo[$keys[$k]] = $binds[trim($values[$k], ':')]; } // Querying existing data diff --git a/tests/system/Models/ReplaceModelTest.php b/tests/system/Models/ReplaceModelTest.php new file mode 100644 index 000000000000..cfa5b8af8573 --- /dev/null +++ b/tests/system/Models/ReplaceModelTest.php @@ -0,0 +1,44 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Models; + +use Tests\Support\Models\UserModel; + +/** + * @internal + */ +final class ReplaceModelTest extends LiveModelTestCase +{ + public function testReplaceRespectsUseTimestamps(): void + { + $this->createModel(UserModel::class); + + $data = [ + 'name' => 'Amanda Holmes', + 'email' => 'amanda@holmes.com', + 'country' => 'US', + ]; + + $id = $this->model->insert($data); + + $data['id'] = $id; + $data['country'] = 'UK'; + + $sql = $this->model->replace($data, true); + $this->assertStringNotContainsString('updated_at', $sql); + + $this->model = $this->createModel(UserModel::class); + $this->setPrivateProperty($this->model, 'useTimestamps', true); + $sql = $this->model->replace($data, true); + $this->assertStringContainsString('updated_at', $sql); + } +} From e023f02587863201f6e27aa87df082b50469ba72 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 07:44:47 +0800 Subject: [PATCH 0231/2325] Document new coding style guide * Document new coding style guide * Update contributing/styleguide.md Co-authored-by: MGatner Co-authored-by: MGatner --- contributing/README.rst | 2 +- contributing/styleguide.md | 259 ++++++++++++++++++++++++++++ contributing/styleguide.rst | 327 ------------------------------------ 3 files changed, 260 insertions(+), 328 deletions(-) create mode 100644 contributing/styleguide.md delete mode 100644 contributing/styleguide.rst diff --git a/contributing/README.rst b/contributing/README.rst index b5539f8a8ae1..0e73b9e5d759 100644 --- a/contributing/README.rst +++ b/contributing/README.rst @@ -8,7 +8,7 @@ Contributing to CodeIgniter - `Contribution CSS <./css.rst>`_ - `Framework internals <./internals.rst>`_ - `CodeIgniter documentation <./documentation.rst>`_ -- `PHP Style Guide <./styleguide.rst>`_ +- `CodeIgniter Coding Style Guide <./styleguide.md>`_ - `Developer's Certificate of Origin <../DCO.txt>`_ CodeIgniter is a community driven project and accepts contributions of code diff --git a/contributing/styleguide.md b/contributing/styleguide.md new file mode 100644 index 000000000000..d746e672d33e --- /dev/null +++ b/contributing/styleguide.md @@ -0,0 +1,259 @@ +# CodeIgniter Coding Style Guide + +This document declares a set of coding conventions and rules to be followed when contributing PHP code +to the CodeIgniter project. + +**Note:** +> While we would recommend it, there's no requirement that you follow these conventions and rules in your +own projects. Usage is discretionary within your projects but strictly enforceable within the framework. + +We follow the [PSR-12: Extended Coding Style][psr12] plus a set of our own +styling conventions. + +The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", +"MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](http://tools.ietf.org/html/rfc2119). + +_Portions of the following rules are from and attributed to [PSR-12][psr12]. Even if we do not copy all the rules to this coding style guide explicitly, such uncopied rules SHALL still apply._ + +[psr12]: https://www.php-fig.org/psr/psr-12/ +## Implementation + +Our team uses [PHP CS Fixer](https://github.com/FriendsOfPHP/PHP-CS-Fixer) to apply coding standard fixes automatically. If you would like to leverage these tools yourself visit the [Official CodeIgniter Coding Standard](https://github.com/CodeIgniter/coding-standard) repository for details. + +## General + +### Files + +- All PHP files MUST use the Unix LF (linefeed) line ending only. +- All PHP files MUST end with a non-blank line, terminated with a single LF. +- The closing `?>` tag MUST be omitted from files containing only PHP. + +### Lines + +- There MUST NOT be a hard limit on line length. +- The soft limit on line length MUST be 120 characters. +- Lines SHOULD NOT be longer than 80 characters; lines longer than that SHOULD be split into multiple subsequent lines of no more than 80 characters each. +- There MUST NOT be trailing whitespace at the end of lines. +- Blank lines MAY be added to improve readability and to indicate related blocks of code except where explicitly forbidden. +- There MUST NOT be more than one statement per line. + +### Indenting + +- Code MUST use an indent of 4 spaces for each indent level, and MUST NOT use tabs for indenting. + +### Keywords and Types + +- All PHP reserved [keywords][1] and [types][2] MUST be in lower case. +- Any new types and keywords added to future PHP versions MUST be in lower case. +- Short form of type keywords MUST be used i.e. `bool` instead of `boolean`, `int` instead of `integer` etc. + +[1]: http://php.net/manual/en/reserved.keywords.php +[2]: http://php.net/manual/en/reserved.other-reserved-words.php + +## Declare Statements, Namespace, and Import Statements + +The header of a PHP file may consist of a number of different blocks. If present, each of the blocks below +MUST be separated by a single blank line, and MUST NOT contain a blank line. Each block MUST be in the order +listed below, although blocks that are not relevant may be omitted. + +- Opening ` All the preceding rules are quoted from PSR-12. You may visit its website to view the code block samples. + +## Custom Conventions + +### File Naming + +- Files containing PHP code SHOULD end with a ".php" extension. +- Files containing templates SHOULD end with a ".tpl" extension. +- Files containing classes, interfaces, or traits MUST have their base name exactly matching the name +of the classes they declare. +- Files declaring procedural functions SHOULD be written in snake_case format. + +### Naming of Structural Elements + +- Constants MUST be declared in UPPERCASE_SEPARATED_WITH_UNDERSCORES. +- Class names MUST be declared in PascalCase. +- Method and property names MUST be declared in camelCase. +- Procedural functions MUST be in snake_case. +- Abbreviations/acronyms/initialisms SHOULD be written in their own natural format. + +### Logical Operators + +- The negation operator `!` SHOULD have one space from its argument. +```diff +-!$result ++! $result +``` + +- Use parentheses to clarify potentially confusing logical expressions. + +### PHP Docblocks (PHPDoc) + +- There SHOULD be no useless PHPDoc annotations. +```diff +-/** +- * @param string $data Data +- * @return void +- */ + public function analyse(string $data): void {}; +``` + +### PHPUnit Assertions + +- As much as possible, you SHOULD always use the strict version of assertions. +```diff +-$this->assertEquals(12, (int) $axis); ++$this->assertSame(12, (int) $axis); +``` + +- Use the dedicated assertion instead of using internal types. +```diff +-$this->assertSame(true, is_cli()); ++$this->assertTrue(is_cli()); + +-$this->assertTrue(array_key_exists('foo', $array)); ++$this->assertArrayHasKey('foo', $array); +``` diff --git a/contributing/styleguide.rst b/contributing/styleguide.rst deleted file mode 100644 index a500d663fe11..000000000000 --- a/contributing/styleguide.rst +++ /dev/null @@ -1,327 +0,0 @@ -###################### -PHP Coding Style Guide -###################### - -The following document declares a set of coding convention rules to be -followed when contributing PHP code to the CodeIgniter project. - -Some of these rules, like naming conventions for example, *may* be -incorporated into the framework's logic and therefore be functionally -enforced (which would be separately documented), but while we would -recommend it, there's no requirement that you follow these conventions in -your own applications. - -The `PHP Interop Group `_ has proposed a number of -canonical recommendations for PHP code style. CodeIgniter is not a member of -of PHP-FIG. We commend their efforts to unite the PHP community, -but no not agree with all of their recommendations. - -PSR-2 is PHP-FIG's Coding Style Guide. We do not claim conformance with it, -although there are a lot of similarities. The differences will be pointed out -below. - -The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", -"SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to -be interpreted as described in `RFC 2119 `_. - -*Note: When used below, the term "class" refers to all kinds of classes, -interfaces and traits.* - -***** -Files -***** - -Formatting -========== - -- Files MUST use UTF-8 character set encoding without BOM. -- Files MUST use UNIX line endings (LF: `\n`). -- Files MUST end with a single empty line (i.e. LF: `\n`). - -Structure -========= - -- A single file SHOULD NOT declare more than one class. - Examples where we feel that more than one class in a source file - is appropriate: - - - `system/Debug/CustomExceptions` contains a number of CodeIgniter - exceptions and errors, that we want to use for a consistent - experience across applications. - If we stick with the purist route, then each of the 13+/- custom - exceptions would require an additional file, which would have a - performance impact at times. - - `system/HTTP/Response` provides a RedirectException, used with the - Response class. - - `system/Router/Router` similarly provides a RedirectException, used with - the Router class. - -- Files SHOULD either declare symbols (i.e. classes, functions, constants) - or execute non-declarative logic, but SHOULD NOT do both. - -Naming -====== - -- File names MUST end with a ".php" name extension and MUST NOT have - multiple name extensions. -- Files declaring classes, interfaces or traits MUST have names exactly matching - the classes that they declare (obviously excluding the ".php" name extension). -- Files declaring functions SHOULD be named in *snake_case.php*. - -************************************* -Whitespace, indentation and alignment -************************************* - -- Best practice: indentation SHOULD use only tabs. -- Best practice: alignment SHOULD use only spaces. -- If using tabs for anything, you MUST set the tab spacing to 4. - -This will accommodate the widest range of developer environment options, -while maintaining consistency of code appearance. - -Following the "best practice" above, -the following code block would have a single tab at the beginning of -each line containing braces, and two tabs at the beginning of the -nested statements. No alignment is implied:: - - { - $first = 1; - $second = 2; - $third = 3; - } - -Following the "best practice" above, -the following code block would use spaces to have the assignment -operators line up with each other:: - - { - $first = 1; - $second = 2; - $third = 3; - } - -.. note:: Our indenting and alignment convention differs from PSR-2, which - **only** uses spaces for both indenting and alignment. - -- Unnecessary whitespace characters MUST NOT be present anywhere within a - script. - - That includes trailing whitespace after a line of code, two or - more spaces used when only one is necessary (excluding alignment), as - well as any other whitespace usage that is not functionally required or - explicitly described in this document. - -.. note:: With conforming tab settings, alignment spacing should - be preserved in all development environments. - A pull request that deals only with tabs or spaces for alignment - will not be favorably considered. - -**** -Code -**** - -PHP tags -======== - -- Opening tags MUST only use the `` tags SHOULD NOT be used, unless the intention is to start - direct output. - - - Scripts that don't produce output MUST NOT use the closing `?>` tag. - -Namespaces and classes -====================== - -- Class names and namespaces SHOULD be declared in `UpperCamelCase`, - also called `StudlyCaps`, unless - another form is *functionally* required. - - - Abbreviations in namespaces, class names and method names SHOULD be - written in capital letters (e.g. PHP). - -- Class constants MUST be declared in `CAPITALS_SEPARATED_BY_UNDERSCORES`. -- Class methods, property names and other variables MUST be declared in - `lowerCamelCase()`. -- Class methods and properties MUST have visibility declarations (i.e. - `public`, `private` or `protected`). - -Methods -------- - -To maintain consistency between core classes, class properties MUST -be private or protected, and the following public methods -MUST be used for each such property "x" - -- `getX()` when the method returns returns a property value, or null if not set -- `setX(value)` changes a property value, doesn't return anything, and can - throw exceptions -- `hasX()` returns a boolean to if a property exists -- `newX()` creates an instance of a/the component object and returns it, - and can throw exceptions -- `isX()` returns true/false for boolean properties - -- Methods SHOULD use type hints and return type hints - -Procedural code -=============== - -- Function and variable names SHOULD be declared in `snake_case()` (all - lowercase letters, separated by underscores), unless another form is - *functionally* required. -- Constants MUST be declared in `CAPITALS_SEPARATED_BY_UNDERSCORES`. - -Keywords -======== - -- All keywords MUST be written in lowercase letters. This includes "scalar" - types, but does NOT include core PHP classes such as `stdClass` or - `Exception`. -- Adjacent keywords are separated by a single space character. -- The keywords `require`, `require_once`, `include`, `include_once` MUST - be followed by a single space character and MUST NOT be followed by a - parenthesis anywhere within the declaration. -- The `function` keyword MUST be immediately followed by either an opening - parenthesis or a single space and a function name. -- Other keywords not explicitly mentioned in this section MUST be separated - by a single space character from any printable characters around them and - on the same line. - -Operators -========= - -- The single dot concatenation, incrementing, decrementing, error - suppression operators and references MUST NOT be separated from their - subjects. -- Other operators not explicitly mentioned in this section MUST be - separated by a single space character from any printable characters - around them and on the same line. -- An operator MUST NOT be the last set of printable characters on a line. -- An operator MAY be the first set of printable characters on a line. - -Logical Operators -================= - -- Use the symbol versions (**||** and **&&**) of the logical operators - instead of the word versions (**OR** and **AND**). - - - This is consistent with other programming languages - - It avoids the problem of the assignment operator (**=**) having - higher precedence:: - - $result = true && false; // $result is false, expected - $result = true AND false; // $result is true, evaluated as "($result = true) AND false" - $result = (true AND false); // $result is false - -- The logical negation operator MUST be separated from its argument by a - single space, as in **! $result** instead of **!$result** -- If there is potential confusion with a logical expression, then use - parentheses for clarity, as shown above. - -Control Structures -================== - -- Control structures, such as **if/else** statements, **for/foreach** statements, or - **while/do** statements, MUST use a brace-surrounded block for their body - segments. - - Good control structure examples:: - - if ( $foo ) - { - $bar += $baz; - } - else - { - $baz = 'bar'; - } - - Not-acceptable control structures:: - - if ( $foo ) $bar = $oneThing + $anotherThing + $yetAnotherThing + $evenMore; - - if ( $foo ) $bar += $baz; - else $baz = 'bar'; - -Docblocks -========= - -We use phpDocumentor (phpdoc) to generate the API docs, for all of the source -code inside the `system` folder. - -It wants to see a file summary docblock at the top of a PHP file, -before any PHP statements, and then a docblock before each documentable -component, namely any class/interface/trait, and all public and protected -methods/functions/variables. The docblock for a method or function -is expected to describe the parameters, return value, and any exceptions -thrown. - -Deviations from the above are considered errors by phpdoc. - -An example:: - - group = 'Unknown'; - } - - /** - * Model a fruit ripening over time. - * - * @param array $params - */ - abstract public function ripen(array $params); - } - -Other -===== - -- Argument separators (comma: `,`) MUST NOT be preceded by a whitespace - character and MUST be followed by a space character or a newline - (LF: `\n`). -- Semi-colons (i.e. `;`) MUST NOT be preceded by a whitespace character - and MUST be followed by a newline (LF: `\n`). - -- Opening parentheses SHOULD NOT be followed by a space character. -- Closing parentheses SHOULD NOT be preceded by a space character. - -- Opening square brackets SHOULD NOT be followed by a space character, - unless when using the "short array" declaration syntax. -- Closing square brackets SHOULD NOT be preceded by a space character, - unless when using the "short array" declaration syntax. - -- A curly brace SHOULD be the only printable character on a line, unless: - - - When declaring an anonymous function. - - Inside a "variable variable" (i.e. `${$foo}` or `${'foo'.$bar}`). - - Around a variable in a double-quoted string (i.e. `"Foo {$bar}"`). - -.. note:: Our control structures braces convention differs from PSR-2. - We use "Allman style" notation instead. From 31653be8c2ddd7cdb315d5fc6feac63d25570b1e Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 07:45:29 +0800 Subject: [PATCH 0232/2325] Update to phpdocumentor v3.1.1 --- .github/workflows/deploy-apidocs.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 3b441e36485d..a7117d8f1f6a 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -41,12 +41,9 @@ jobs: php-version: '8.0' coverage: none - - name: Download phpDocumentor v3.1 - run: | - cd ./source - curl \ - -L https://github.com/phpDocumentor/phpDocumentor/releases/download/v3.1.0/phpDocumentor.phar \ - -o admin/phpDocumentor.phar + - name: Download latest phpDocumentor + working-directory: source + run: phive install --no-progress --trust-gpg-keys 67F861C3D889C656 --target ./admin phpDocumentor - name: Prepare API repo working-directory: api From a0cbea707550c2bfad30e38520a4bfe1c574c023 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 09:40:51 +0800 Subject: [PATCH 0233/2325] Add phive to tools in workflow --- .github/workflows/deploy-apidocs.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index a7117d8f1f6a..53b358d27f4b 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -39,11 +39,12 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: '8.0' + tools: phive coverage: none - name: Download latest phpDocumentor working-directory: source - run: phive install --no-progress --trust-gpg-keys 67F861C3D889C656 --target ./admin phpDocumentor + run: sudo phive install --no-progress --trust-gpg-keys 67F861C3D889C656 --target ./admin phpDocumentor - name: Prepare API repo working-directory: api From a68a267a0d666b2e39fe6d87b31f1551cb4788fa Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 09:42:51 +0800 Subject: [PATCH 0234/2325] Fix interchanged command options --- .github/workflows/deploy-apidocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 53b358d27f4b..5c4d2a12458f 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -44,7 +44,7 @@ jobs: - name: Download latest phpDocumentor working-directory: source - run: sudo phive install --no-progress --trust-gpg-keys 67F861C3D889C656 --target ./admin phpDocumentor + run: sudo phive --no-progress install --trust-gpg-keys 67F861C3D889C656 --target ./admin phpDocumentor - name: Prepare API repo working-directory: api From 27b9f3113585b37000d08b837e98ce578c744f3c Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 09:50:42 +0800 Subject: [PATCH 0235/2325] Fix path resolution --- .github/workflows/deploy-apidocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 5c4d2a12458f..4704b4f31696 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -44,7 +44,7 @@ jobs: - name: Download latest phpDocumentor working-directory: source - run: sudo phive --no-progress install --trust-gpg-keys 67F861C3D889C656 --target ./admin phpDocumentor + run: sudo phive --no-progress install --trust-gpg-keys 67F861C3D889C656 --target admin phpDocumentor - name: Prepare API repo working-directory: api From 501d823a0556c7e532facc12a00d9fbbe0037aac Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 09:53:58 +0800 Subject: [PATCH 0236/2325] Remove phar extension --- .github/workflows/deploy-apidocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 4704b4f31696..3e19f09de6ad 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -56,7 +56,7 @@ jobs: - name: Build API in source repo working-directory: source run: | - php admin/phpDocumentor.phar run --ansi --verbose + php admin/phpDocumentor run --ansi --verbose cp -R ${GITHUB_WORKSPACE}/source/api/build/* ${GITHUB_WORKSPACE}/api/docs - name: Deploy to API repo From 7a6899c443983afb4b95b919d1f5437caf0589cb Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 9 Sep 2021 10:13:20 +0800 Subject: [PATCH 0237/2325] Fix faulty phive installation of phpDocumentor --- .github/workflows/deploy-apidocs.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 3e19f09de6ad..4a7d20dd502b 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -44,7 +44,7 @@ jobs: - name: Download latest phpDocumentor working-directory: source - run: sudo phive --no-progress install --trust-gpg-keys 67F861C3D889C656 --target admin phpDocumentor + run: sudo phive --no-progress install --global --trust-gpg-keys 67F861C3D889C656 phpDocumentor - name: Prepare API repo working-directory: api @@ -56,7 +56,7 @@ jobs: - name: Build API in source repo working-directory: source run: | - php admin/phpDocumentor run --ansi --verbose + phpDocumentor run --ansi --verbose cp -R ${GITHUB_WORKSPACE}/source/api/build/* ${GITHUB_WORKSPACE}/api/docs - name: Deploy to API repo From 9390c69cd91d9e98b9c3884eaf900091fcfacf1f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Sep 2021 11:05:27 +0900 Subject: [PATCH 0238/2325] docs: fix RST format --- user_guide_src/source/installation/upgrade_414.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_414.rst b/user_guide_src/source/installation/upgrade_414.rst index 613823132351..d3e19b0a9954 100644 --- a/user_guide_src/source/installation/upgrade_414.rst +++ b/user_guide_src/source/installation/upgrade_414.rst @@ -8,7 +8,7 @@ This release focuses on code style. All changes (except those noted below) are c **Method Scope** The following methods were changed from "public" to "protected" to match their parent class methods and better align with their uses. -If you relied on any of these methods being public (highly unlikely) adjust your code accordingly:: +If you relied on any of these methods being public (highly unlikely) adjust your code accordingly: * ``CodeIgniter\Database\MySQLi\Connection::execute()`` * ``CodeIgniter\Database\MySQLi\Connection::_fieldData()`` From ee3e1e704aa89b471a06d564f213a65921c0f59e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Sep 2021 11:06:37 +0900 Subject: [PATCH 0239/2325] docs: update coding-standard links --- .../source/installation/repositories.rst | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/user_guide_src/source/installation/repositories.rst b/user_guide_src/source/installation/repositories.rst index 18bd3e7c6a18..b585ca8e8f6b 100644 --- a/user_guide_src/source/installation/repositories.rst +++ b/user_guide_src/source/installation/repositories.rst @@ -6,17 +6,15 @@ The CodeIgniter 4 open source project has its own There are several development repositories, of interest to potential contributors: -+------------------+--------------+-----------------------------------------------------------------+ -| Repository | Audience | Description | -+==================+==============+=================================================================+ -| CodeIgniter4 | contributors | Project codebase, including tests & user guide sources | -+------------------+--------------+-----------------------------------------------------------------+ -| translations | developers | System message translations | -+------------------+--------------+-----------------------------------------------------------------+ -| coding-standard | contributors | Coding style conventions & rules | -+------------------+--------------+-----------------------------------------------------------------+ -| | | | -+------------------+--------------+-----------------------------------------------------------------+ ++---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ +| Repository | Audience | Description | ++=====================================================================+==============+=================================================================+ +| CodeIgniter4 | contributors | Project codebase, including tests & user guide sources | ++---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ +| translations | developers | System message translations | ++---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ +| `coding-standard `_ | contributors | Coding style conventions & rules | ++---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ There are also several deployment repositories, referenced in the installation directions. The deployment repositories are built automatically when a new version is released, and they @@ -32,8 +30,6 @@ are not directly contributed to. +------------------+--------------+-----------------------------------------------------------------+ | userguide | anyone | Pre-built user guide | +------------------+--------------+-----------------------------------------------------------------+ -| | | | -+------------------+--------------+-----------------------------------------------------------------+ In all the above, the latest version of a repository can be downloaded by selecting the "releases" link in the secondary navbar inside @@ -50,7 +46,7 @@ These correspond to the repositories mentioned above: - `codeigniter4/framework `_ - `codeigniter4/appstarter `_ - `codeigniter4/translations `_ -- `codeigniter4/coding-standard `_ +- `codeigniter/coding-standard `_ See the :doc:`Installation ` page for more information. From 831c693bdb7a29cc109c9a17606066563fd5db4f Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 10 Sep 2021 09:07:32 +0700 Subject: [PATCH 0240/2325] Update to latest laminas-escaper 2.9.0 --- .github/workflows/test-phpunit.yml | 1 - admin/framework/composer.json | 2 +- composer.json | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index c093190233cb..aa7d584991a6 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -124,7 +124,6 @@ jobs: run: | composer update --ansi --no-interaction composer remove --ansi --dev --unused -W rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config codeigniter/coding-standard - php -r 'file_put_contents("vendor/laminas/laminas-zendframework-bridge/src/autoload.php", "");' env: COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} diff --git a/admin/framework/composer.json b/admin/framework/composer.json index 6e3852d2af79..6c02a4b71eb9 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -11,7 +11,7 @@ "ext-json": "*", "ext-mbstring": "*", "kint-php/kint": "^3.3", - "laminas/laminas-escaper": "^2.8", + "laminas/laminas-escaper": "^2.9", "psr/log": "^1.1" }, "require-dev": { diff --git a/composer.json b/composer.json index 7b9d50b8e620..43768c06c524 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ "ext-json": "*", "ext-mbstring": "*", "kint-php/kint": "^3.3", - "laminas/laminas-escaper": "^2.8", + "laminas/laminas-escaper": "^2.9", "psr/log": "^1.1" }, "require-dev": { From de4c6abd162a54833f85c12c7adeaecf99d43076 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Sep 2021 13:56:11 +0900 Subject: [PATCH 0241/2325] docs: add session table change for upgrade --- .../source/installation/upgrade_420.rst | 17 ++++++++++++++++- .../source/installation/upgrading.rst | 1 + 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_420.rst index a306b4978347..cfbcbdbf1aeb 100644 --- a/user_guide_src/source/installation/upgrade_420.rst +++ b/user_guide_src/source/installation/upgrade_420.rst @@ -1,5 +1,5 @@ ############################# -Upgrading from 4.1.3 to 4.2.0 +Upgrading from 4.1.4 to 4.2.0 ############################# **Changes for set() method in BaseBuilder and Model class** @@ -10,3 +10,18 @@ and modified the ``set()`` method, then you need to change its definition from ``public function set($key, ?string $value = '', ?bool $escape = null)`` to ``public function set($key, $value = '', ?bool $escape = null)``. +**Session DatabaseHandler's database table change** + +The types of the following columns in the session table have been changed for optimization. + +- MySQL + - ``timestamp`` +- PostgreSQL + - ``ip_address`` + - ``timestamp`` + - ``data`` + +Update the definition of the session table. See the :doc:`/libraries/sessions` for the new definition. + +The change was introduced in v4.1.2. But due to `a bug `_, +the DatabaseHandler Driver did not work properly. diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 64696e691dc7..b6ef428e8b47 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -8,6 +8,7 @@ upgrading from. .. toctree:: :titlesonly: + Upgrading from 4.1.4 to 4.2.0 Upgrading from 4.1.3 to 4.1.4 Upgrading from 4.1.2 to 4.1.3 Upgrading from 4.1.1 to 4.1.2 From 5e6b4a3dffa4023956f69a79e7c98cf5b0297cb0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Sep 2021 16:16:40 +0900 Subject: [PATCH 0242/2325] docs: update PSR Compliance (PSR-12) --- user_guide_src/source/intro/psr.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/intro/psr.rst b/user_guide_src/source/intro/psr.rst index 92f47fc235f0..a7ab555b7a11 100644 --- a/user_guide_src/source/intro/psr.rst +++ b/user_guide_src/source/intro/psr.rst @@ -10,13 +10,13 @@ status of our compliance with the various accepted, and some draft, proposals. **PSR-1: Basic Coding Standard** This recommendation covers basic class, method, and file-naming standards. Our -`style guide `_ +`style guide `_ meets PSR-1 and adds its own requirements on top of it. -**PSR-2: Coding Style Guide** +**PSR-12: Extended Coding Style** -This PSR was fairly controversial when it first came out. CodeIgniter meets many of the recommendations within, -but does not, and will not, meet all of them. +Our +`style guide `_ follows the recommendation plus a set of our own styling conventions. **PSR-3: Logger Interface** From 152c4050dfde9d697f861563b36135a0539b9796 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Sep 2021 18:54:18 +0000 Subject: [PATCH 0243/2325] Update rector/rector requirement from 0.11.52 to 0.11.53 (#5071) --- composer.json | 2 +- system/Helpers/number_helper.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 43768c06c524..13454e9d77ec 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.52", + "rector/rector": "0.11.53", "symplify/package-builder": "^9.3" }, "suggest": { diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index 6e1391556c49..d7f49c15f852 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -26,7 +26,7 @@ function number_to_size($num, int $precision = 1, ?string $locale = null) { // Strip any formatting & ensure numeric input try { - $num = 0 + str_replace(',', '', $num); // @phpstan-ignore-line + $num = 0 + str_replace(',', '', $num); } catch (ErrorException $ee) { return false; } From 151cc63e855ade9585d22b5ab28978373b2f5ba6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Sep 2021 23:07:58 +0900 Subject: [PATCH 0244/2325] docs: fix view_parser --- .../source/outgoing/view_parser.rst | 568 +++++++++--------- 1 file changed, 284 insertions(+), 284 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 37c20c82e11e..96b5440887b5 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -12,32 +12,32 @@ It can parse simple variables or variable tag pairs. Pseudo-variable names or control constructs are enclosed in braces, like this:: - - - {blog_title} - - -

{blog_heading}

+ + + {blog_title} + + +

{blog_heading}

- {blog_entries} -
{title}
-

{body}

- {/blog_entries} + {blog_entries} +
{title}
+

{body}

+ {/blog_entries} - - + + These variables are not actual PHP variables, but rather plain text representations that allow you to eliminate PHP from your templates (view files). .. note:: CodeIgniter does **not** require you to use this class since - using pure PHP in your view pages (for instance using the - :doc:`View renderer ` ) - lets them run a little faster. - However, some developers prefer to use some form of template engine if - they work with designers who they feel would find some - confusion working with PHP. + using pure PHP in your view pages (for instance using the + :doc:`View renderer ` ) + lets them run a little faster. + However, some developers prefer to use some form of template engine if + they work with designers who they feel would find some + confusion working with PHP. *************************** Using the View Parser Class @@ -45,12 +45,12 @@ Using the View Parser Class The simplest method to load the parser class is through its service:: - $parser = \Config\Services::parser(); + $parser = \Config\Services::parser(); Alternately, if you are not using the ``Parser`` class as your default renderer, you can instantiate it directly:: - $parser = new \CodeIgniter\View\Parser(); + $parser = new \CodeIgniter\View\Parser(); Then you can use any of the three standard rendering methods that it provides: **render(viewpath, options, save)**, **setVar(name, value, context)** and @@ -87,13 +87,13 @@ Parser templates You can use the ``render()`` method to parse (or render) simple templates, like this:: - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - ]; + $data = [ + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + ]; - echo $parser->setData($data) - ->render('blog_template'); + echo $parser->setData($data) + ->render('blog_template'); View parameters are passed to ``setData()`` as an associative array of data to be replaced in the template. In the above example, the @@ -110,18 +110,18 @@ Several options can be passed to the ``render()`` or ``renderString()`` methods. - ``cache`` - the time in seconds, to save a view's results; ignored for renderString() - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath; - ignored for renderString() + ignored for renderString() - ``saveData`` - true if the view data parameters should be retained for subsequent calls; - default is **false** -- ``cascadeData`` - true if pseudo-variable settings should be passed on to nested - substitutions; default is **true** + default is **false** +- ``cascadeData`` - true if pseudo-variable settings should be passed on to nested + substitutions; default is **true** :: - echo $parser->render('blog_template', [ - 'cache' => HOUR, - 'cache_name' => 'something_unique', - ]); + echo $parser->render('blog_template', [ + 'cache' => HOUR, + 'cache_name' => 'something_unique', + ]); *********************** Substitution Variations @@ -134,12 +134,12 @@ The **simple substitution** performed by the parser is a one-to-one replacement of pseudo-variables where the corresponding data parameter has either a scalar or string value, as in this example:: - $template = '{blog_title}'; - $data = ['blog_title' => 'My ramblings']; + $template = '{blog_title}'; + $data = ['blog_title' => 'My ramblings']; - echo $parser->setData($data)->renderString($template); + echo $parser->setData($data)->renderString($template); - // Result: My ramblings + // Result: My ramblings The ``Parser`` takes substitution a lot further with "variable pairs", used for nested substitutions or looping, and with some advanced @@ -147,9 +147,9 @@ constructs for conditional substitution. When the parser executes, it will generally -- handle any conditional substitutions -- handle any nested/looping substitutions -- handle the remaining single substitutions +- handle any conditional substitutions +- handle any nested/looping substitutions +- handle the remaining single substitutions Loop Substitutions ================== @@ -162,20 +162,20 @@ you would like an entire block of variables to be repeated, with each iteration containing new values? Consider the template example we showed at the top of the page:: - - - {blog_title} - - -

{blog_heading}

+ + + {blog_title} + + +

{blog_heading}

- {blog_entries} -
{title}
-

{body}

- {/blog_entries} + {blog_entries} +
{title}
+

{body}

+ {/blog_entries} - - + + In the above code you'll notice a pair of variables: {blog_entries} data... {/blog_entries}. In a case like this, the entire chunk of data @@ -186,20 +186,20 @@ Parsing variable pairs is done using the identical code shown above to parse single variables, except, you will add a multi-dimensional array corresponding to your variable pair data. Consider this example:: - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => [ - ['title' => 'Title 1', 'body' => 'Body 1'], - ['title' => 'Title 2', 'body' => 'Body 2'], - ['title' => 'Title 3', 'body' => 'Body 3'], - ['title' => 'Title 4', 'body' => 'Body 4'], - ['title' => 'Title 5', 'body' => 'Body 5'], - ], - ]; - - echo $parser->setData($data) - ->render('blog_template'); + $data = [ + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + 'blog_entries' => [ + ['title' => 'Title 1', 'body' => 'Body 1'], + ['title' => 'Title 2', 'body' => 'Body 2'], + ['title' => 'Title 3', 'body' => 'Body 3'], + ['title' => 'Title 4', 'body' => 'Body 4'], + ['title' => 'Title 5', 'body' => 'Body 5'], + ], + ]; + + echo $parser->setData($data) + ->render('blog_template'); The value for the pseudo-variable ``blog_entries`` is a sequential array of associative arrays. The outer level does not have keys associated @@ -209,16 +209,16 @@ If your "pair" data is coming from a database result, which is already a multi-dimensional array, you can simply use the database ``getResultArray()`` method:: - $query = $db->query("SELECT * FROM blog"); + $query = $db->query("SELECT * FROM blog"); - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => $query->getResultArray(), - ]; + $data = [ + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + 'blog_entries' => $query->getResultArray(), + ]; - echo $parser->setData($data) - ->render('blog_template'); + echo $parser->setData($data) + ->render('blog_template'); If the array you are trying to loop over contains objects instead of arrays, the parser will first look for an ``asArray`` method on the object. If it exists, @@ -236,17 +236,17 @@ Nested Substitutions A nested substitution happens when the value for a pseudo-variable is an associative array of values, like a record from a database:: - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entry' => [ - 'title' => 'Title 1', - 'body' => 'Body 1', - ], - ]; + $data = [ + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + 'blog_entry' => [ + 'title' => 'Title 1', + 'body' => 'Body 1', + ], + ]; - echo $parser->setData($data) - ->render('blog_template'); + echo $parser->setData($data) + ->render('blog_template'); The value for the pseudo-variable ``blog_entry`` is an associative array. The key/value pairs defined inside it will be exposed inside @@ -254,13 +254,13 @@ the variable pair loop for that variable. A ``blog_template`` that might work for the above:: -

{blog_title} - {blog_heading}

- {blog_entry} -
-

{title}

-

{body}

-
- {/blog_entry} +

{blog_title} - {blog_heading}

+ {blog_entry} +
+

{title}

+

{body}

+
+ {/blog_entry} If you would like the other pseudo-variables accessible inside the "blog_entry" scope, then make sure that the "cascadeData" option is set to true. @@ -273,13 +273,13 @@ comments in a ``{# #}`` symbols. :: - {# This comment is removed during parsing. #} - {blog_entry} -
-

{title}

-

{body}

-
- {/blog_entry} + {# This comment is removed during parsing. #} + {blog_entry} +
+

{title}

+

{body}

+
+ {/blog_entry} Cascading Data ============== @@ -289,30 +289,30 @@ data pairs into the inner substitution. The following example is not impacted by cascading:: - $template = '{name} lives in {location}{city} on {planet}{/location}.'; + $template = '{name} lives in {location}{city} on {planet}{/location}.'; - $data = [ - 'name' => 'George', - 'location' => ['city' => 'Red City', 'planet' => 'Mars'], - ]; + $data = [ + 'name' => 'George', + 'location' => ['city' => 'Red City', 'planet' => 'Mars'], + ]; - echo $parser->setData($data)->renderString($template); - // Result: George lives in Red City on Mars. + echo $parser->setData($data)->renderString($template); + // Result: George lives in Red City on Mars. This example gives different results, depending on cascading:: - $template = '{location}{name} lives in {city} on {planet}{/location}.'; + $template = '{location}{name} lives in {city} on {planet}{/location}.'; - $data = [ - 'name' => 'George', - 'location' => ['city' => 'Red City', 'planet' => 'Mars'], - ]; + $data = [ + 'name' => 'George', + 'location' => ['city' => 'Red City', 'planet' => 'Mars'], + ]; - echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]); - // Result: {name} lives in Red City on Mars. + echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]); + // Result: {name} lives in Red City on Mars. - echo $parser->setData($data)->renderString($template, ['cascadeData'=>true]); - // Result: George lives in Red City on Mars. + echo $parser->setData($data)->renderString($template, ['cascadeData'=>true]); + // Result: George lives in Red City on Mars. Preventing Parsing ================== @@ -322,9 +322,9 @@ section will stay exactly as it is, with no variable substitution, looping, etc, :: - {noparse} -

Untouched Code

- {/noparse} + {noparse} +

Untouched Code

+ {/noparse} Conditional Logic ================= @@ -332,15 +332,15 @@ Conditional Logic The Parser class supports some basic conditionals to handle ``if``, ``else``, and ``elseif`` syntax. All ``if`` blocks must be closed with an ``endif`` tag:: - {if $role=='admin'} -

Welcome, Admin!

- {endif} + {if $role=='admin'} +

Welcome, Admin!

+ {endif} This simple block is converted to the following during parsing:: - -

Welcome, Admin!

- + +

Welcome, Admin!

+ All variables used within if statements must have been previously set with the same name. Other than that, it is treated exactly like a standard PHP conditional, and all standard PHP rules would apply here. You can use any @@ -348,16 +348,16 @@ of the comparison operators you would normally, like ``==``, ``===``, ``!==``, ` :: - {if $role=='admin'} -

Welcome, Admin

- {elseif $role=='moderator'} -

Welcome, Moderator

- {else} -

Welcome, User

- {endif} + {if $role=='admin'} +

Welcome, Admin

+ {elseif $role=='moderator'} +

Welcome, Moderator

+ {else} +

Welcome, User

+ {endif} .. note:: In the background, conditionals are parsed using an **eval()**, so you must ensure that you take - care with the user data that is used within conditionals, or you could open your application up to security risks. + care with the user data that is used within conditionals, or you could open your application up to security risks. Escaping Data ============= @@ -367,13 +367,13 @@ supports several different contexts, like general **html**, when it's in an HTML else is specified, the data will be assumed to be in an HTML context. You can specify the context used by using the **esc** filter:: - { user_styles | esc(css) } - { title } + { user_styles | esc(css) } + { title } There will be times when you absolutely need something to used and NOT escaped. You can do this by adding exclamation marks to the opening and closing braces:: - {! unescaped_var !} + {! unescaped_var !} Filters ======= @@ -385,17 +385,17 @@ need to format the same data differently in several sections on the same page. Filters are commands that come after the pseudo-variable name, and are separated by the pipe symbol, ``|``:: - // -55 is displayed as 55 - { value|abs } + // -55 is displayed as 55 + { value|abs } If the parameter takes any arguments, they must be separated by commas and enclosed in parentheses:: - { created_at|date(Y-m-d) } + { created_at|date(Y-m-d) } Multiple filters can be applied to the value by piping multiple ones together. They are processed in order, from left to right:: - { created_at|date_modify(+5 days)|date(Y-m-d) } + { created_at|date_modify(+5 days)|date(Y-m-d) } Provided Filters ---------------- @@ -473,10 +473,10 @@ You can easily create your own filters by editing **app/Config/View.php** and ad ``$filters`` array. Each key is the name of the filter is called by in the view, and its value is any valid PHP callable:: - public $filters = [ - 'abs' => '\CodeIgniter\View\Filters::abs', - 'capitalize' => '\CodeIgniter\View\Filters::capitalize', - ]; + public $filters = [ + 'abs' => '\CodeIgniter\View\Filters::abs', + 'capitalize' => '\CodeIgniter\View\Filters::capitalize', + ]; PHP Native functions as Filters ------------------------------- @@ -485,9 +485,9 @@ You can use native php function as filters by editing **app/Config/View.php** an ``$filters`` array.Each key is the name of the native PHP function is called by in the view, and its value is any valid native PHP function prefixed with:: - public $filters = [ - 'str_repeat' => '\str_repeat', - ]; + public $filters = [ + 'str_repeat' => '\str_repeat', + ]; Parser Plugins ============== @@ -495,7 +495,7 @@ Parser Plugins Plugins allow you to extend the parser, adding custom features for each project. They can be any PHP callable, making them very simple to implement. Within templates, plugins are specified by ``{+ +}`` tags:: - {+ foo +} inner content {+ /foo +} + {+ foo +} inner content {+ /foo +} This example shows a plugin named **foo**. It can manipulate any of the content between its opening and closing tags. In this example, it could work with the text " inner content ". Plugins are processed before any pseudo-variable @@ -503,16 +503,16 @@ replacements happen. While plugins will often consist of tag pairs, like shown above, they can also be a single tag, with no closing tag:: - {+ foo +} + {+ foo +} Opening tags can also contain parameters that can customize how the plugin works. The parameters are represented as key/value pairs:: - {+ foo bar=2 baz="x y" } + {+ foo bar=2 baz="x y" } Parameters can also be single values:: - {+ include somefile.php +} + {+ include somefile.php +} Provided Plugins ---------------- @@ -520,14 +520,14 @@ Provided Plugins The following plugins are available when using the parser: ==================== ========================== ================================================================================== ================================================================ -Plugin Arguments Description Example +Plugin Arguments Description Example ==================== ========================== ================================================================================== ================================================================ current_url Alias for the current_url helper function. {+ current_url +} -previous_url Alias for the previous_url helper function. {+ previous_url +} +previous_url Alias for the previous_url helper function. {+ previous_url +} siteURL Alias for the site_url helper function. {+ siteURL "login" +} -mailto email, title, attributes Alias for the mailto helper function. {+ mailto email=foo@example.com title="Stranger Things" +} -safe_mailto email, title, attributes Alias for the safe_mailto helper function. {+ safe_mailto email=foo@example.com title="Stranger Things" +} -lang language string Alias for the lang helper function. {+ lang number.terabyteAbbr +} +mailto email, title, attributes Alias for the mailto helper function. {+ mailto email=foo@example.com title="Stranger Things" +} +safe_mailto email, title, attributes Alias for the safe_mailto helper function. {+ safe_mailto email=foo@example.com title="Stranger Things" +} +lang language string Alias for the lang helper function. {+ lang number.terabyteAbbr +} validation_errors fieldname(optional) Returns either error string for the field (if specified) or all validation errors. {+ validation_errors +} , {+ validation_errors field="email" +} route route name Alias for the route_to helper function. {+ route "login" +} ==================== ========================== ================================================================================== ================================================================ @@ -539,12 +539,12 @@ At its simplest, all you need to do to register a new plugin and make it ready f **app/Config/View.php**, under the **$plugins** array. The key is the name of the plugin that is used within the template file. The value is any valid PHP callable, including static class methods, and closures:: - public $plugins = [ - 'foo' => '\Some\Class::methodName', - 'bar' => function ($str, array $params=[]) { - return $str; - }, - ]; + public $plugins = [ + 'foo' => '\Some\Class::methodName', + 'bar' => function ($str, array $params=[]) { + return $str; + }, + ]; Any closures that are being used must be defined in the config file's constructor:: @@ -565,21 +565,21 @@ Any closures that are being used must be defined in the config file's constructo If the callable is on its own, it is treated as a single tag, not a open/close one. It will be replaced by the return value from the plugin:: - public $plugins = [ - 'foo' => '\Some\Class::methodName' - ]; + public $plugins = [ + 'foo' => '\Some\Class::methodName' + ]; - // Tag is replaced by the return value of Some\Class::methodName static function. - {+ foo +} + // Tag is replaced by the return value of Some\Class::methodName static function. + {+ foo +} If the callable is wrapped in an array, it is treated as an open/close tag pair that can operate on any of the content between its tags:: - public $plugins = [ - 'foo' => ['\Some\Class::methodName'] - ]; + public $plugins = [ + 'foo' => ['\Some\Class::methodName'] + ]; - {+ foo +} inner content {+ /foo +} + {+ foo +} inner content {+ /foo +} *********** Usage Notes @@ -588,49 +588,49 @@ Usage Notes If you include substitution parameters that are not referenced in your template, they are ignored:: - $template = 'Hello, {firstname} {lastname}'; - $data = [ - 'title' => 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe' - ]; - echo $parser->setData($data) - ->renderString($template); + $template = 'Hello, {firstname} {lastname}'; + $data = [ + 'title' => 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe' + ]; + echo $parser->setData($data) + ->renderString($template); - // Result: Hello, John Doe + // Result: Hello, John Doe If you do not include a substitution parameter that is referenced in your template, the original pseudo-variable is shown in the result:: - $template = 'Hello, {firstname} {initials} {lastname}'; - $data = [ - 'title' => 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', - ]; - echo $parser->setData($data) - ->renderString($template); + $template = 'Hello, {firstname} {initials} {lastname}'; + $data = [ + 'title' => 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe', + ]; + echo $parser->setData($data) + ->renderString($template); - // Result: Hello, John {initials} Doe + // Result: Hello, John {initials} Doe If you provide a string substitution parameter when an array is expected, i.e., for a variable pair, the substitution is done for the opening variable pair tag, but the closing variable pair tag is not rendered properly:: - $template = 'Hello, {firstname} {lastname} ({degrees}{degree} {/degrees})'; - $data = [ - 'degrees' => 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'titles' => [ - ['degree' => 'BSc'], - ['degree' => 'PhD'], - ], - ]; - echo $parser->setData($data) - ->renderString($template); - - // Result: Hello, John Doe (Mr{degree} {/degrees}) + $template = 'Hello, {firstname} {lastname} ({degrees}{degree} {/degrees})'; + $data = [ + 'degrees' => 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe', + 'titles' => [ + ['degree' => 'BSc'], + ['degree' => 'PhD'], + ], + ]; + echo $parser->setData($data) + ->renderString($template); + + // Result: Hello, John Doe (Mr{degree} {/degrees}) View Fragments ============== @@ -642,53 +642,53 @@ of in the view. An example with the iteration controlled in the view:: - $template = '
    {menuitems} -
  • {title}
  • - {/menuitems}
'; + $template = '
    {menuitems} +
  • {title}
  • + {/menuitems}
'; - $data = [ - 'menuitems' => [ - ['title' => 'First Link', 'link' => '/first'], - ['title' => 'Second Link', 'link' => '/second'], - ] - ]; - echo $parser->setData($data) - ->renderString($template); + $data = [ + 'menuitems' => [ + ['title' => 'First Link', 'link' => '/first'], + ['title' => 'Second Link', 'link' => '/second'], + ] + ]; + echo $parser->setData($data) + ->renderString($template); Result:: - + An example with the iteration controlled in the controller, using a view fragment:: - $temp = ''; - $template1 = '
  • {title}
  • '; - $data1 = [ - ['title' => 'First Link', 'link' => '/first'], - ['title' => 'Second Link', 'link' => '/second'], - ]; + $temp = ''; + $template1 = '
  • {title}
  • '; + $data1 = [ + ['title' => 'First Link', 'link' => '/first'], + ['title' => 'Second Link', 'link' => '/second'], + ]; - foreach ($data1 as $menuItem),{ - $temp .= $parser->setData($menuItem)->renderString($template1); - } + foreach ($data1 as $menuItem),{ + $temp .= $parser->setData($menuItem)->renderString($template1); + } - $template2 = '
      {menuitems}
    '; - $data = [ - 'menuitems' => $temp, - ]; - echo $parser->setData($data) - ->renderString($template2); + $template2 = '
      {menuitems}
    '; + $data = [ + 'menuitems' => $temp, + ]; + echo $parser->setData($data) + ->renderString($template2); Result:: - + *************** Class Reference @@ -696,80 +696,80 @@ Class Reference .. php:class:: CodeIgniter\\View\\Parser - .. php:method:: render($view[, $options[, $saveData=false]]) + .. php:method:: render($view[, $options[, $saveData=false]]) - :param string $view: File name of the view source - :param array $options: Array of options, as key/value pairs - :param boolean $saveData: If true, will save data for use with any other calls, if false, will clean the data after rendering the view. - :returns: The rendered text for the chosen view - :rtype: string + :param string $view: File name of the view source + :param array $options: Array of options, as key/value pairs + :param boolean $saveData: If true, will save data for use with any other calls, if false, will clean the data after rendering the view. + :returns: The rendered text for the chosen view + :rtype: string - Builds the output based upon a file name and any data that has already been set:: + Builds the output based upon a file name and any data that has already been set:: - echo $parser->render('myview'); + echo $parser->render('myview'); Options supported: - - ``cache`` - the time in seconds, to save a view's results - - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath - - ``cascadeData`` - true if the data pairs in effect when a nested or loop substitution occurs should be propagated - - ``saveData`` - true if the view data parameter should be retained for subsequent calls - - ``leftDelimiter`` - the left delimiter to use in pseudo-variable syntax - - ``rightDelimiter`` - the right delimiter to use in pseudo-variable syntax + - ``cache`` - the time in seconds, to save a view's results + - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath + - ``cascadeData`` - true if the data pairs in effect when a nested or loop substitution occurs should be propagated + - ``saveData`` - true if the view data parameter should be retained for subsequent calls + - ``leftDelimiter`` - the left delimiter to use in pseudo-variable syntax + - ``rightDelimiter`` - the right delimiter to use in pseudo-variable syntax - Any conditional substitutions are performed first, then remaining - substitutions are performed for each data pair. + Any conditional substitutions are performed first, then remaining + substitutions are performed for each data pair. - .. php:method:: renderString($template[, $options[, $saveData=false]]) + .. php:method:: renderString($template[, $options[, $saveData=false]]) - :param string $template: View source provided as a string - :param array $options: Array of options, as key/value pairs - :param boolean $saveData: If true, will save data for use with any other calls, if false, will clean the data after rendering the view. - :returns: The rendered text for the chosen view - :rtype: string + :param string $template: View source provided as a string + :param array $options: Array of options, as key/value pairs + :param boolean $saveData: If true, will save data for use with any other calls, if false, will clean the data after rendering the view. + :returns: The rendered text for the chosen view + :rtype: string - Builds the output based upon a provided template source and any data that has already been set:: + Builds the output based upon a provided template source and any data that has already been set:: - echo $parser->render('myview'); + echo $parser->render('myview'); Options supported, and behavior, as above. - .. php:method:: setData([$data[, $context=null]]) + .. php:method:: setData([$data[, $context=null]]) - :param array $data: Array of view data strings, as key/value pairs - :param string $context: The context to use for data escaping. - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface. + :param array $data: Array of view data strings, as key/value pairs + :param string $context: The context to use for data escaping. + :returns: The Renderer, for method chaining + :rtype: CodeIgniter\\View\\RendererInterface. - Sets several pieces of view data at once:: + Sets several pieces of view data at once:: - $renderer->setData(['name'=>'George', 'position'=>'Boss']); + $renderer->setData(['name'=>'George', 'position'=>'Boss']); Supported escape contexts: html, css, js, url, or attr or raw. - If 'raw', no escaping will happen. + If 'raw', no escaping will happen. - .. php:method:: setVar($name[, $value=null[, $context=null]]) + .. php:method:: setVar($name[, $value=null[, $context=null]]) - :param string $name: Name of the view data variable - :param mixed $value: The value of this view data - :param string $context: The context to use for data escaping. - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface. + :param string $name: Name of the view data variable + :param mixed $value: The value of this view data + :param string $context: The context to use for data escaping. + :returns: The Renderer, for method chaining + :rtype: CodeIgniter\\View\\RendererInterface. - Sets a single piece of view data:: + Sets a single piece of view data:: - $renderer->setVar('name','Joe','html'); + $renderer->setVar('name','Joe','html'); Supported escape contexts: html, css, js, url, attr or raw. - If 'raw', no escaping will happen. + If 'raw', no escaping will happen. - .. php:method:: setDelimiters($leftDelimiter = '{', $rightDelimiter = '}') + .. php:method:: setDelimiters($leftDelimiter = '{', $rightDelimiter = '}') - :param string $leftDelimiter: Left delimiter for substitution fields - :param string $rightDelimiter: right delimiter for substitution fields - :returns: The Renderer, for method chaining - :rtype: CodeIgniter\\View\\RendererInterface. + :param string $leftDelimiter: Left delimiter for substitution fields + :param string $rightDelimiter: right delimiter for substitution fields + :returns: The Renderer, for method chaining + :rtype: CodeIgniter\\View\\RendererInterface. - Override the substitution field delimiters:: + Override the substitution field delimiters:: - $renderer->setDelimiters('[',']'); + $renderer->setDelimiters('[',']'); From 642924553c84dce8cda11e3cf59a7151aaf573f6 Mon Sep 17 00:00:00 2001 From: Niklas Schmolke Date: Mon, 12 Apr 2021 17:26:37 +0200 Subject: [PATCH 0245/2325] Added upgrade guidelines --- .../source/installation/upgrade_database.rst | 68 ++++++++ .../source/installation/upgrade_emails.rst | 60 +++++++ .../installation/upgrade_encryption.rst | 51 ++++++ .../installation/upgrade_file_upload.rst | 108 ++++++++++++ .../installation/upgrade_html_tables.rst | 55 ++++++ .../installation/upgrade_localization.rst | 66 ++++++++ .../installation/upgrade_pagination.rst | 62 +++++++ .../source/installation/upgrade_responses.rst | 47 ++++++ .../source/installation/upgrade_routing.rst | 77 +++++++++ .../source/installation/upgrade_security.rst | 71 ++++++++ .../source/installation/upgrade_sessions.rst | 53 ++++++ .../installation/upgrade_validations.rst | 159 ++++++++++++++++++ .../installation/upgrade_view_parser.rst | 56 ++++++ 13 files changed, 933 insertions(+) create mode 100644 user_guide_src/source/installation/upgrade_database.rst create mode 100644 user_guide_src/source/installation/upgrade_emails.rst create mode 100644 user_guide_src/source/installation/upgrade_encryption.rst create mode 100644 user_guide_src/source/installation/upgrade_file_upload.rst create mode 100644 user_guide_src/source/installation/upgrade_html_tables.rst create mode 100644 user_guide_src/source/installation/upgrade_localization.rst create mode 100644 user_guide_src/source/installation/upgrade_pagination.rst create mode 100644 user_guide_src/source/installation/upgrade_responses.rst create mode 100644 user_guide_src/source/installation/upgrade_routing.rst create mode 100644 user_guide_src/source/installation/upgrade_security.rst create mode 100644 user_guide_src/source/installation/upgrade_sessions.rst create mode 100644 user_guide_src/source/installation/upgrade_validations.rst create mode 100644 user_guide_src/source/installation/upgrade_view_parser.rst diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst new file mode 100644 index 000000000000..2c6a05e987f5 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -0,0 +1,68 @@ +Upgrade Database +################ + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Database Reference Documentation Codeigniter 3.X `_ +- `Working with Databases Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- The functionality in CI4 is basically the same as in CI4. +- The method names have changed to camelCase and the query builder now needs to be initialized before you can run queries on it. + +Upgrade Guide +============= +1. Add your database credentials to ``app/Config/Database.php``. The options are pretty much the same as in CI3 only some names have changed slightly. +2. Everywhere you have used the database you have to replace ``$this->load->database();`` with ``$db = \Config\Database::connect();``. +3. If you use multiple databases use the following code to load additional databases ``$db = \Config\Database::connect('group_name');``. +4. Now you have to change all database queries. The most important change here is to replace ``$this->db`` with just ``$db`` and adjust the method name and ``$db``. Here are some examples: + +- ``$this->db->query('YOUR QUERY HERE');`` to ``$db->query('YOUR QUERY HERE');`` +- ``$this->db->simple_query('YOUR QUERY')`` to ``$db->simpleQuery('YOUR QUERY')`` +- ``$this->db->escape("something")`` to ``$db->escape("something");`` +- ``$this->db->affected_rows();`` to ``$db->affectedRows();`` +- ``$query->result();`` to ``$query->getResult();`` +- ``$query->result_array();`` to ``$query->getResultArray();`` +- ``echo $this->db->count_all('my_table');`` to ``echo $db->table('my_table')->countAll();`` + +5. To use the new Query Builder Class you have to initialize the builder ``$builder = $db->table('mytable');`` after that you can run the queries on the ``$builder``. Here are some examples: + +- ``$this->db->get()`` to ``$builder->get();`` +- ``$this->db->get_where('mytable', array('id' => $id), $limit, $offset);`` to ``$builder->getWhere(['id' => $id], $limit, $offset);`` +- ``$this->db->select('title, content, date');`` to ``$builder->select('title, content, date');`` +- ``$this->db->select_max('age');`` to ``$builder->selectMax('age');`` +- ``$this->db->join('comments', 'comments.id = blogs.id');`` to ``$builder->join('comments', 'comments.id = blogs.id');`` +- ``$this->db->having('user_id', 45);`` to ``$builder->having('user_id', 45);`` + + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $query = $this->db->select('title') + ->where('id', $id) + ->limit(10, 20) + ->get('mytable'); + +Codeigniter Version 4.x +----------------------- +:: + + $builder = $db->table('mytable'); + + $query = $builder->select('title') + ->where('id', $id) + ->limit(10, 20) + ->get(); + diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst new file mode 100644 index 000000000000..b0007289020e --- /dev/null +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -0,0 +1,60 @@ +Upgrade Emails +############## + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Email Documentation Codeigniter 3.X `_ +- `Email Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- Only small things like the method names and the loading of the library have changed. + +Upgrade Guide +============= +1. Within your class change the ``$this->load->library('email');`` to ``$email = \Config\Services::email();``. +2. From that on you have to replace every line starting with ``$this->email`` to ``$email``. +3. The methods in the Email class are named slightly different. All methods, except for ``send()``, ``attach()``, ``printDebugger()`` and ``clear()`` have a ``set`` as prefix followed by the previous method name. ``bcc()`` is now ``setBcc()`` and so on. +4. The config attributes in ``app/Config/Email.php`` have changed. You should have a look at the `Email Class Documentation `_ to have a list of the new attributes. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->load->library('email'); + + $this->email->from('your@example.com', 'Your Name'); + $this->email->to('someone@example.com'); + $this->email->cc('another@another-example.com'); + $this->email->bcc('them@their-example.com'); + + $this->email->subject('Email Test'); + $this->email->message('Testing the email class.'); + + $this->email->send(); + +Codeigniter Version 4.x +----------------------- +:: + + $email = \Config\Services::email(); + + $email->setFrom('your@example.com', 'Your Name'); + $email->setTo('someone@example.com'); + $email->setCC('another@another-example.com'); + $email->setBCC('them@their-example.com'); + + $email->setSubject('Email Test'); + $email->setMessage('Testing the email class.'); + + $email->send(); diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst new file mode 100644 index 000000000000..ee1365cd5c42 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -0,0 +1,51 @@ +Upgrade Encryption +################## + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Encryption Library Documentation Codeigniter 3.X `_ +- `Encryption Service Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- The support for ``MCrypt`` has been dropped, as that has been deprecated as of PHP 7.2. + +Upgrade Guide +============= +1. Within your configs the ``$config['encryption_key'] = 'abc123';`` moved from ``application/config/config.php`` to ``public $key = 'abc123';`` in ``app/Config/Encryption.php``. +2. Wherever you have used the encryption library you have to replace ``$this->load->library('encryption');`` with ``$encrypter = \Config\Services::encrypter();`` and change the methods for encryption and decrypting like in the following code example. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->load->library('encryption'); + + $plain_text = 'This is a plain-text message!'; + $ciphertext = $this->encryption->encrypt($plain_text); + + // Outputs: This is a plain-text message! + echo $this->encryption->decrypt($ciphertext); + + +Codeigniter Version 4.x +----------------------- +:: + + $encrypter = \Config\Services::encrypter(); + + $plainText = 'This is a plain-text message!'; + $ciphertext = $encrypter->encrypt($plainText); + + // Outputs: This is a plain-text message! + echo $encrypter->decrypt($ciphertext); diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst new file mode 100644 index 000000000000..069164dd2f68 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -0,0 +1,108 @@ +Upgrade Working with Uploaded Files +################################### + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== +- `Output Class Documentation Codeigniter 3.X `_ +- `Working with Uploaded Files Documentation Codeigniter 4.X `_ + +What has been changed +===================== +- The functionality of the file upload has changed a lot. You can now check if the file got uploaded without errors and moving / storing files is simpler. + +Upgrade Guide +============= +In CI4 you access uploaded files with ``$file = $this->request->getFile('userfile')``. From there you can validate if the file got uploaded successfully with ``$file->isValid()``. +To store the file you could use ``$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg');`` This will store the file in ``writable/uploads/head_img/user_name.jpg``. + +You have to change your file uploading code to match the new methods. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + load->helper(array('form', 'url')); + } + + public function index() + { + $this->load->view('upload_form', array('error' => ' ' )); + } + + public function do_upload() + { + $config['upload_path'] = './uploads/'; + $config['allowed_types'] = 'gif|jpg|png'; + $config['max_size'] = 100; + $config['max_width'] = 1024; + $config['max_height'] = 768; + + $this->load->library('upload', $config); + + if ( ! $this->upload->do_upload('userfile')) + { + $error = array('error' => $this->upload->display_errors()); + + $this->load->view('upload_form', $error); + } + else + { + $data = array('upload_data' => $this->upload->data()); + + $this->load->view('upload_success', $data); + } + } + } + ?> + +Codeigniter Version 4.x +----------------------- +:: + + ' ']); + } + + public function do_upload() + { + $this->validate([ + 'userfile' => 'uploaded[userfile]|max_size[userfile,1024]|mime_in[userfile,image/png,image/jpg,image/gif]|max_dims[userfile,1024,768]' + ]); + + $file = $this->request->getFile('userfile'); + + if ( ! $path = $file->store()) + { + echo view('upload_form', ['error' => "upload failed"]); + } + else + { + $data = ['upload_file_path' => $path]; + + echo view('upload_success', $data); + } + } + } + ?> diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst new file mode 100644 index 000000000000..82d75f143584 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -0,0 +1,55 @@ +Upgrade HTML Tables +################### + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `HTML Table Documentation Codeigniter 3.X `_ +- `HTML Table Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- Only small things like the method names and the loading of the library have changed. + +Upgrade Guide +============= +1. Within your class change the ``$this->load->library('table');`` to ``$table = new \CodeIgniter\View\Table();``. +2. From that on you have to replace every line starting with ``$this->table`` to ``$table``. For example: ``echo $this->table->generate($query);`` will become ``echo $table->generate($query);`` +3. The methods in the HTML Table class could be named slightly different. The most important change in the naming is the switch from underscored method names to camelCase. The method ``set_heading()`` from version 3 is now named ``setHeading()`` and so on. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->load->library('table'); + + $this->table->set_heading('Name', 'Color', 'Size'); + + $this->table->add_row('Fred', 'Blue', 'Small'); + $this->table->add_row('Mary', 'Red', 'Large'); + $this->table->add_row('John', 'Green', 'Medium'); + + echo $this->table->generate(); + +Codeigniter Version 4.x +----------------------- +:: + + $table = new \CodeIgniter\View\Table(); + + $table->setHeading('Name', 'Color', 'Size'); + + $table->addRow('Fred', 'Blue', 'Small'); + $table->addRow('Mary', 'Red', 'Large'); + $table->addRow('John', 'Green', 'Medium'); + + echo $table->generate(); diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst new file mode 100644 index 000000000000..14c6f7099f44 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -0,0 +1,66 @@ +Upgrade Localization +#################### + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Language Documentation Codeigniter 3.X `_ +- `Localization Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- In CI4 the language files return the language lines as array. + +Upgrade Guide +============= +1. Specify the default language in *Config/App.php*::: + + public $defaultLocale = 'en'; + +2. Now move your language files to ``app/Language//``. +3. After that you have to change the syntax within the language files. Below in the Code Example you will see how the language array within the file should look like. +4. Remove from every file the language loader ``$this->lang->load($file, $lang);``. +5. Replace the method to load the language line ``$this->lang->line('error_email_missing')`` with ``echo lang('Errors.errorEmailMissing');``. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $lang['error_email_missing'] = 'You must submit an email address'; + $lang['error_url_missing'] = 'You must submit a URL'; + $lang['error_username_missing'] = 'You must submit a username'; + + ... + + $this->lang->load('error', $lang); + echo $this->lang->line('error_email_missing'); + +Codeigniter Version 4.x +----------------------- +:: + + return [ + 'errorEmailMissing' => 'You must submit an email address', + 'errorURLMissing' => 'You must submit a URL', + 'errorUsernameMissing' => 'You must submit a username', + 'nested' => [ + 'error' => [ + 'message' => 'A specific error message', + ], + ], + ]; + + ... + + echo lang('Errors.errorEmailMissing'); + + diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst new file mode 100644 index 000000000000..bb5ffedbc632 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -0,0 +1,62 @@ +Upgrade Pagination +################## + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Pagination Class Documentation Codeigniter 3.X `_ +- `Pagination Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- In CI4 the pagination is a built-in method in the Model class. You have to change the views and also the controller in order to use the new pagination library. + +Upgrade Guide +============= +1. Within the views change to following: + +- ``pagination->create_links(); ?>`` to ``links() ?>`` + +2. Within the controller you have to make the following changes: + +- You can use the built-in ``paginate()`` method on every Model. Have a look at the code example below to see how you setup the pagination on a specific model. + + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->load->library('pagination'); + $config['base_url'] = base_url().'users/index/'; + $config['total_rows'] = $this->db->count_all('users'); + $config['per_page'] = 10; + $config['uri_segment'] = 3; + $config['attributes'] = array('class' => 'pagination-link'); + $this->pagination->initialize($config); + + $data['users'] = $this->user_model->get_users(FALSE, $config['per_page'], $offset); + + $this->load->view('posts/index', $data); + +Codeigniter Version 4.x +----------------------- +:: + + $model = new \App\Models\UserModel(); + + $data = [ + 'users' => $model->paginate(10), + 'pager' => $model->pager, + ]; + + echo view('users/index', $data); + diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst new file mode 100644 index 000000000000..c0ba918cbb68 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -0,0 +1,47 @@ +Upgrade HTTP Responses +###################### + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== +- `Output Class Documentation Codeigniter 3.X `_ +- `HTTP Responses Documentation Codeigniter 4.X `_ + +What has been changed +===================== +- The methods have been renamed + +Upgrade Guide +============= +1. The methods in the HTML Responses class are named slightly different. The most important change in the naming is the switch from underscored method names to camelCase. The method ``set_content_type()`` from version 3 is now named ``setContentType()`` and so on. +2. In the most cases you have to change ``$this->output`` to ``$this->response`` followed by the method. You can find all methods `here `_. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->output->set_status_header(404); + + ... + + $this->output + ->set_content_type('application/json') + ->set_output(json_encode(array('foo' => 'bar'))); + +Codeigniter Version 4.x +----------------------- +:: + + $this->response->setStatusCode(404) + ->setBody($body); + + ... + + return $this->response->setJSON(['foo' => 'bar']); diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst new file mode 100644 index 000000000000..575a0699561d --- /dev/null +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -0,0 +1,77 @@ +Upgrade Routing +################## + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `URI Routing Documentation Codeigniter 3.X `_ +- `URI Routing Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- 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: + +- ``$route['journals'] = 'blogs';`` to ``$routes->add('journals', 'App\Blogs');`` this would map to the ``index()`` method in the "Blogs" class. +- ``$route['product/(:any)'] = 'catalog/product_lookup';`` to ``$routes->add('product/(:any)', 'Catalog::productLookup');`` +- ``$route['login/(.+)'] = 'auth/login/$1';`` to ``$routes->add('login/(.+)', 'Auth::login/$1');`` + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +Path: ``application/config/routes.php``:: + + add('posts', 'posts::index'); + $routes->add('teams/create', 'teams::create'); + $routes->add('teams/edit/(:any)', 'teams::edit/$1'); + + $routes->add('posts/create', 'posts::create'); + $routes->add('posts/edit/(:any)', 'posts::edit/$1'); + $routes->add('drivers/create', 'drivers::create'); + $routes->add('drivers/edit/(:any)', 'drivers::edit/$1'); + $routes->add('posts/(:any)', 'posts::view/$1'); + diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst new file mode 100644 index 000000000000..88f4814ddb12 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -0,0 +1,71 @@ +Upgrade Security +################ + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Security Class Documentation Codeigniter 3.X `_ +- `Security Documentation Codeigniter 4.X `_ + +.. note:: + If you use the `form helper `_, then form_open() will automatically insert a hidden csrf field in your forms. So you do not have to upgrade this by yourself. + +What has been changed +===================== +- The method to implement csrf tokens to html forms has been changed. + +Upgrade Guide +============= +1. To enable csrf protection in CI4 you have to enable it in ``app/Config/Filters.php``:: + + public $globals = [ + 'before' => [ + //'honeypot' + 'csrf' + ] + ]; + +2. Within you html forms you have to remove the csrf input which looks similar to ````. +3. Now within your html forms you have to add ```` somewhere in the form body, unless you are using `form_open()``. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $csrf = array( + 'name' => $this->security->get_csrf_token_name(), + 'hash' => $this->security->get_csrf_hash() + ); + + ... + +
    + + + + + + + + +Codeigniter Version 4.x +----------------------- +:: + +
    + + + + + + + + diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst new file mode 100644 index 000000000000..e3d7b4da343b --- /dev/null +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -0,0 +1,53 @@ +Upgrade Sessions +################ + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Session Library Documentation Codeigniter 3.X `_ +- `Session Library Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- Only small things like the method names and the loading of the library have changed. + +Upgrade Guide +============= +1. Wherever you use the Session Library replace ``$this->load->library('session');`` with ``$session = \Config\Services::session();``. +2. From that on you have to replace every line starting with ``$this->session`` with ``$session`` followed by the new method name. + +- To access session data use the syntax ``$session->item`` or ``$session->get('item')`` instead of the CI3 syntax ``$this->session->name``. +- To set data use ``$session->set($array);`` instead of ``$this->session->set_userdata($array);``. +- To remove data use ``unset($_SESSION['some_name']);`` or ``$session->remove('some_name');`` instead of ``$this->session->unset_userdata('some_name');``. +- To mark session data as flasdata, which will only be available for the next request, use ``$session->markAsFlashdata('item');`` instead of ``$this->session->mark_as_flash('item');``` + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->load->library('session'); + + $_SESSION['item']; + $this->session->item; + $this->session->userdata('item'); + +Codeigniter Version 4.x +----------------------- +:: + + $session = \Config\Services::session(); + + $_SESSION['item']; + $session->get('item'); + $session->item; + session('item'); + diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst new file mode 100644 index 000000000000..020952a1d9c6 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -0,0 +1,159 @@ +Upgrade Validations +################### + +.. contents:: + :local: + :depth: 1 + + +Documentations of Library +========================= + +- `Form Validation Documentation Codeigniter 3.X `_ +- `Validation Documentation Codeigniter 4.X `_ + + +What has been changed +===================== + + +Upgrade Guide +============= +1. Within the view which contains the form you have to change: + +- ```` to ``listErrors() ?>`` +- ```` to ```` + +2. Within the controller you have to change the following: + +- ``$this->load->helper(array('form', 'url'));`` to ``helper(['form', 'url']);`` +- remove the line ``$this->load->library('form_validation');`` +- ``if($this->form_validation->run() == FALSE)`` to ``if (! $this->validate([]))`` +- ``$this->load->view('myform');`` to ``echo view('myform', ['validation' => $this->validator,]);`` + +3. You have to change the validation rules. The new syntax is to set the rules as array in the controller:: + + $input = $this->validate([ + 'name' => 'required|min_length[3]', + 'email' => 'required|valid_email', + 'phone' => 'required|numeric|max_length[10]' + ]); + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +Path: ``application/views``:: + + + + My Form + + + + + + + +
    Username
    + + +
    Password
    + + +
    Password Confirm
    + + +
    Email Address
    + + +
    + + + + + + +Path: ``application/controllers/``:: + + load->helper(array('form', 'url')); + + $this->load->library('form_validation'); + + if ($this->form_validation->run() == FALSE) + { + $this->load->view('myform'); + } + else + { + $this->load->view('formsuccess'); + } + } + } + +Codeigniter Version 4.x +----------------------- +Path: ``app/Views``:: + + + + My Form + + + + listErrors() ?> + + + +
    Username
    + + +
    Password
    + + +
    Password Confirm
    + + +
    Email Address
    + + +
    + + + + + + +Path: ``app/Controllers/``:: + + validate([])) + { + echo view('Signup', [ + 'validation' => $this->validator, + ]); + } + else + { + echo view('Success'); + } + } + } \ No newline at end of file diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst new file mode 100644 index 000000000000..3b23a4ea1d0b --- /dev/null +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -0,0 +1,56 @@ +Upgrade View Parser +################### + +.. contents:: + :local: + :depth: 1 + + +Documentations +============== + +- `Template Parser Documentation Codeigniter 3.X `_ +- `View Parser Documentation Codeigniter 4.X `_ + + +What has been changed +===================== +- You have to change the implementation and loading of the Parser Library. +- The Views can copied from CI3. Usually no changes there are required. + +Upgrade Guide +============= +1. Wherever you use the View Parser Library replace ``$this->load->library('parser');`` with ``$parser = \Config\Services::parser();``. +2. You have to change the render part in your controller from ``$this->parser->parse('blog_template', $data);`` to ``echo $parser->setData($data)->render('blog_template');``. + +Code Example +============ + +Codeigniter Version 3.11 +------------------------ +:: + + $this->load->library('parser'); + + $data = array( + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading' + ); + + $this->parser + ->parse('blog_template', $data); + +Codeigniter Version 4.x +----------------------- +:: + + $parser = \Config\Services::parser(); + + $data = [ + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading' + ]; + + echo $parser->setData($data) + ->render('blog_template'); + From 446974f285e0dec3f221b80a34518d8463abb5ed Mon Sep 17 00:00:00 2001 From: Niklas Schmolke Date: Mon, 12 Apr 2021 17:27:11 +0200 Subject: [PATCH 0246/2325] Updated upgrade_migrations.rst Signed-off-by: Niklas Schmolke --- .../installation/upgrade_migrations.rst | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 2124a67d60b0..f21243a2b565 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -119,3 +119,22 @@ Path: ``app/Database/Migrations``:: $this->forge->dropTable('blog'); } } + +Search & Replace +================ + +You can use to following table to search & replace your old CI3 files. + ++------------------------------+----------------------------+ +| Search | Replace | ++==============================+============================+ +| extends CI_Migration | extends Migration | ++------------------------------+----------------------------+ +| $this->dbforge->add_field | $this->forge->addField | ++------------------------------+----------------------------+ +| $this->dbforge->add_key | $this->forge->addKey | ++------------------------------+----------------------------+ +| $this->dbforge->create_table | $this->forge->createTable | ++------------------------------+----------------------------+ +| $this->dbforge->drop_table | $this->forge->dropTable | ++------------------------------+----------------------------+ From c9d969443ce2ea97d17b0d408818ad484bdebbb6 Mon Sep 17 00:00:00 2001 From: nschmolke <79579458+nschmolke@users.noreply.github.com> Date: Wed, 14 Apr 2021 14:42:21 +0200 Subject: [PATCH 0247/2325] Apply suggestions from code review Co-authored-by: Toto --- user_guide_src/source/installation/upgrade_database.rst | 5 ++--- user_guide_src/source/installation/upgrade_emails.rst | 4 ++-- user_guide_src/source/installation/upgrade_encryption.rst | 2 +- user_guide_src/source/installation/upgrade_file_upload.rst | 2 +- user_guide_src/source/installation/upgrade_html_tables.rst | 2 +- user_guide_src/source/installation/upgrade_localization.rst | 3 +-- user_guide_src/source/installation/upgrade_pagination.rst | 3 +-- user_guide_src/source/installation/upgrade_responses.rst | 4 ++-- user_guide_src/source/installation/upgrade_routing.rst | 3 +-- user_guide_src/source/installation/upgrade_security.rst | 3 +-- user_guide_src/source/installation/upgrade_sessions.rst | 3 +-- user_guide_src/source/installation/upgrade_validations.rst | 4 ++-- user_guide_src/source/installation/upgrade_view_parser.rst | 3 +-- 13 files changed, 17 insertions(+), 24 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index 2c6a05e987f5..3472aef4d69e 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -10,12 +10,12 @@ Documentations ============== - `Database Reference Documentation Codeigniter 3.X `_ -- `Working with Databases Documentation Codeigniter 4.X `_ +- :doc:`Working with Databases Documentation Codeigniter 4.X ` What has been changed ===================== -- The functionality in CI4 is basically the same as in CI4. +- The functionality in CI3 is basically the same as in CI4. - The method names have changed to camelCase and the query builder now needs to be initialized before you can run queries on it. Upgrade Guide @@ -65,4 +65,3 @@ Codeigniter Version 4.x ->where('id', $id) ->limit(10, 20) ->get(); - diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index b0007289020e..0915948afabd 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -10,7 +10,7 @@ Documentations ============== - `Email Documentation Codeigniter 3.X `_ -- `Email Documentation Codeigniter 4.X `_ +- :doc:`Email Documentation Codeigniter 4.X ` What has been changed @@ -22,7 +22,7 @@ Upgrade Guide 1. Within your class change the ``$this->load->library('email');`` to ``$email = \Config\Services::email();``. 2. From that on you have to replace every line starting with ``$this->email`` to ``$email``. 3. The methods in the Email class are named slightly different. All methods, except for ``send()``, ``attach()``, ``printDebugger()`` and ``clear()`` have a ``set`` as prefix followed by the previous method name. ``bcc()`` is now ``setBcc()`` and so on. -4. The config attributes in ``app/Config/Email.php`` have changed. You should have a look at the `Email Class Documentation `_ to have a list of the new attributes. +4. The config attributes in ``app/Config/Email.php`` have changed. You should have a look at the `Email Class Documentation `__ to have a list of the new attributes. Code Example ============ diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index ee1365cd5c42..4ca341017b5d 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -10,7 +10,7 @@ Documentations ============== - `Encryption Library Documentation Codeigniter 3.X `_ -- `Encryption Service Documentation Codeigniter 4.X `_ +- :doc:`Encryption Service Documentation Codeigniter 4.X ` What has been changed diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index 069164dd2f68..194c94374846 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -9,7 +9,7 @@ Upgrade Working with Uploaded Files Documentations ============== - `Output Class Documentation Codeigniter 3.X `_ -- `Working with Uploaded Files Documentation Codeigniter 4.X `_ +- :doc:`Working with Uploaded Files Documentation Codeigniter 4.X ` What has been changed ===================== diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst index 82d75f143584..f8563c0ca9a5 100644 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -10,7 +10,7 @@ Documentations ============== - `HTML Table Documentation Codeigniter 3.X `_ -- `HTML Table Documentation Codeigniter 4.X `_ +- :doc:`HTML Table Documentation Codeigniter 4.X ` What has been changed diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index 14c6f7099f44..c6336ac700d9 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -10,7 +10,7 @@ Documentations ============== - `Language Documentation Codeigniter 3.X `_ -- `Localization Documentation Codeigniter 4.X `_ +- :doc:`Localization Documentation Codeigniter 4.X ` What has been changed @@ -63,4 +63,3 @@ Codeigniter Version 4.x echo lang('Errors.errorEmailMissing'); - diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index bb5ffedbc632..a44240b8d4d5 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -10,7 +10,7 @@ Documentations ============== - `Pagination Class Documentation Codeigniter 3.X `_ -- `Pagination Documentation Codeigniter 4.X `_ +- :doc:`Pagination Documentation Codeigniter 4.X ` What has been changed @@ -59,4 +59,3 @@ Codeigniter Version 4.x ]; echo view('users/index', $data); - diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index c0ba918cbb68..a8ea5961b279 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -9,7 +9,7 @@ Upgrade HTTP Responses Documentations ============== - `Output Class Documentation Codeigniter 3.X `_ -- `HTTP Responses Documentation Codeigniter 4.X `_ +- :doc:`HTTP Responses Documentation Codeigniter 4.X ` What has been changed ===================== @@ -18,7 +18,7 @@ What has been changed Upgrade Guide ============= 1. The methods in the HTML Responses class are named slightly different. The most important change in the naming is the switch from underscored method names to camelCase. The method ``set_content_type()`` from version 3 is now named ``setContentType()`` and so on. -2. In the most cases you have to change ``$this->output`` to ``$this->response`` followed by the method. You can find all methods `here `_. +2. In the most cases you have to change ``$this->output`` to ``$this->response`` followed by the method. You can find all methods :doc:`here `. Code Example ============ diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 575a0699561d..3c55995d8a17 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -10,7 +10,7 @@ Documentations ============== - `URI Routing Documentation Codeigniter 3.X `_ -- `URI Routing Documentation Codeigniter 4.X `_ +- :doc:`URI Routing Documentation Codeigniter 4.X ` What has been changed @@ -74,4 +74,3 @@ Path: ``app/Config/Routes.php``:: $routes->add('drivers/create', 'drivers::create'); $routes->add('drivers/edit/(:any)', 'drivers::edit/$1'); $routes->add('posts/(:any)', 'posts::view/$1'); - diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 88f4814ddb12..e07331e8b752 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -10,7 +10,7 @@ Documentations ============== - `Security Class Documentation Codeigniter 3.X `_ -- `Security Documentation Codeigniter 4.X `_ +- :doc:`Security Documentation Codeigniter 4.X ` .. note:: If you use the `form helper `_, then form_open() will automatically insert a hidden csrf field in your forms. So you do not have to upgrade this by yourself. @@ -68,4 +68,3 @@ Codeigniter Version 4.x - diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index e3d7b4da343b..77e25a6fd091 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -10,7 +10,7 @@ Documentations ============== - `Session Library Documentation Codeigniter 3.X `_ -- `Session Library Documentation Codeigniter 4.X `_ +- :doc:`Session Library Documentation Codeigniter 4.X ` What has been changed @@ -50,4 +50,3 @@ Codeigniter Version 4.x $session->get('item'); $session->item; session('item'); - diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 020952a1d9c6..b0e58106d9f4 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -10,7 +10,7 @@ Documentations of Library ========================= - `Form Validation Documentation Codeigniter 3.X `_ -- `Validation Documentation Codeigniter 4.X `_ +- :doc:`Validation Documentation Codeigniter 4.X ` What has been changed @@ -156,4 +156,4 @@ Path: ``app/Controllers/``:: echo view('Success'); } } - } \ No newline at end of file + } diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index 3b23a4ea1d0b..b6c335fd3df5 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -10,7 +10,7 @@ Documentations ============== - `Template Parser Documentation Codeigniter 3.X `_ -- `View Parser Documentation Codeigniter 4.X `_ +- :doc:`View Parser Documentation Codeigniter 4.X ` What has been changed @@ -53,4 +53,3 @@ Codeigniter Version 4.x echo $parser->setData($data) ->render('blog_template'); - From 6192271268eedaac022f02f18a2dc5e1cd48427a Mon Sep 17 00:00:00 2001 From: nschmolke <79579458+nschmolke@users.noreply.github.com> Date: Mon, 19 Apr 2021 14:15:34 +0200 Subject: [PATCH 0248/2325] Apply suggestions from code review Co-authored-by: kenjis --- user_guide_src/source/installation/upgrade_file_upload.rst | 4 ++-- user_guide_src/source/installation/upgrade_localization.rst | 3 ++- user_guide_src/source/installation/upgrade_security.rst | 4 ++-- user_guide_src/source/installation/upgrade_validations.rst | 4 ++-- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index 194c94374846..2bfbd99765fa 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -47,7 +47,7 @@ Codeigniter Version 3.11 public function do_upload() { $config['upload_path'] = './uploads/'; - $config['allowed_types'] = 'gif|jpg|png'; + $config['allowed_types'] = 'png|jpg|gif'; $config['max_size'] = 100; $config['max_width'] = 1024; $config['max_height'] = 768; @@ -88,7 +88,7 @@ Codeigniter Version 4.x public function do_upload() { $this->validate([ - 'userfile' => 'uploaded[userfile]|max_size[userfile,1024]|mime_in[userfile,image/png,image/jpg,image/gif]|max_dims[userfile,1024,768]' + 'userfile' => 'uploaded[userfile]|max_size[userfile,100]|mime_in[userfile,image/png,image/jpg,image/gif]|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]' ]); $file = $this->request->getFile('userfile'); diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index c6336ac700d9..5c6125851a92 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -35,6 +35,7 @@ Codeigniter Version 3.11 ------------------------ :: + // error.php $lang['error_email_missing'] = 'You must submit an email address'; $lang['error_url_missing'] = 'You must submit a URL'; $lang['error_username_missing'] = 'You must submit a username'; @@ -48,6 +49,7 @@ Codeigniter Version 4.x ----------------------- :: + // Errors.php return [ 'errorEmailMissing' => 'You must submit an email address', 'errorURLMissing' => 'You must submit a URL', @@ -62,4 +64,3 @@ Codeigniter Version 4.x ... echo lang('Errors.errorEmailMissing'); - diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index e07331e8b752..7b8f51d4fbc0 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -30,7 +30,7 @@ Upgrade Guide ] ]; -2. Within you html forms you have to remove the csrf input which looks similar to ````. +2. Within you html forms you have to remove the csrf input which looks similar to ````. 3. Now within your html forms you have to add ```` somewhere in the form body, unless you are using `form_open()``. Code Example @@ -52,7 +52,7 @@ Codeigniter Version 3.11 - + diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index b0e58106d9f4..44a7a9bd1e31 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -147,13 +147,13 @@ Path: ``app/Controllers/``:: if (! $this->validate([])) { - echo view('Signup', [ + echo view('myform', [ 'validation' => $this->validator, ]); } else { - echo view('Success'); + echo view('formsuccess'); } } } From e492274c4187e1f85d02b1d82639ac48cc3098ec Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Tue, 29 Jun 2021 23:46:37 -0500 Subject: [PATCH 0249/2325] Using common helper methods in place of fully qualified Service calls. --- user_guide_src/source/installation/upgrade_database.rst | 4 ++-- user_guide_src/source/installation/upgrade_emails.rst | 4 ++-- user_guide_src/source/installation/upgrade_encryption.rst | 4 ++-- user_guide_src/source/installation/upgrade_sessions.rst | 4 ++-- user_guide_src/source/installation/upgrade_view_parser.rst | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index 3472aef4d69e..0ebc8f75277f 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -21,8 +21,8 @@ What has been changed Upgrade Guide ============= 1. Add your database credentials to ``app/Config/Database.php``. The options are pretty much the same as in CI3 only some names have changed slightly. -2. Everywhere you have used the database you have to replace ``$this->load->database();`` with ``$db = \Config\Database::connect();``. -3. If you use multiple databases use the following code to load additional databases ``$db = \Config\Database::connect('group_name');``. +2. Everywhere you have used the database you have to replace ``$this->load->database();`` with ``$db = db_connect();``. +3. If you use multiple databases use the following code to load additional databases ``$db = db_connect('group_name');``. 4. Now you have to change all database queries. The most important change here is to replace ``$this->db`` with just ``$db`` and adjust the method name and ``$db``. Here are some examples: - ``$this->db->query('YOUR QUERY HERE');`` to ``$db->query('YOUR QUERY HERE');`` diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index 0915948afabd..1a65f279cfa7 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -19,7 +19,7 @@ What has been changed Upgrade Guide ============= -1. Within your class change the ``$this->load->library('email');`` to ``$email = \Config\Services::email();``. +1. Within your class change the ``$this->load->library('email');`` to ``$email = service('email');``. 2. From that on you have to replace every line starting with ``$this->email`` to ``$email``. 3. The methods in the Email class are named slightly different. All methods, except for ``send()``, ``attach()``, ``printDebugger()`` and ``clear()`` have a ``set`` as prefix followed by the previous method name. ``bcc()`` is now ``setBcc()`` and so on. 4. The config attributes in ``app/Config/Email.php`` have changed. You should have a look at the `Email Class Documentation `__ to have a list of the new attributes. @@ -47,7 +47,7 @@ Codeigniter Version 4.x ----------------------- :: - $email = \Config\Services::email(); + $email = service('email'); $email->setFrom('your@example.com', 'Your Name'); $email->setTo('someone@example.com'); diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index 4ca341017b5d..7dadbba63e85 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -20,7 +20,7 @@ What has been changed Upgrade Guide ============= 1. Within your configs the ``$config['encryption_key'] = 'abc123';`` moved from ``application/config/config.php`` to ``public $key = 'abc123';`` in ``app/Config/Encryption.php``. -2. Wherever you have used the encryption library you have to replace ``$this->load->library('encryption');`` with ``$encrypter = \Config\Services::encrypter();`` and change the methods for encryption and decrypting like in the following code example. +2. Wherever you have used the encryption library you have to replace ``$this->load->library('encryption');`` with ``$encrypter = service('encrypter');`` and change the methods for encryption and decrypting like in the following code example. Code Example ============ @@ -42,7 +42,7 @@ Codeigniter Version 4.x ----------------------- :: - $encrypter = \Config\Services::encrypter(); + $encrypter = service('encrypter'); $plainText = 'This is a plain-text message!'; $ciphertext = $encrypter->encrypt($plainText); diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index 77e25a6fd091..84757dbfd665 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -19,7 +19,7 @@ What has been changed Upgrade Guide ============= -1. Wherever you use the Session Library replace ``$this->load->library('session');`` with ``$session = \Config\Services::session();``. +1. Wherever you use the Session Library replace ``$this->load->library('session');`` with ``$session = session();``. 2. From that on you have to replace every line starting with ``$this->session`` with ``$session`` followed by the new method name. - To access session data use the syntax ``$session->item`` or ``$session->get('item')`` instead of the CI3 syntax ``$this->session->name``. @@ -44,7 +44,7 @@ Codeigniter Version 4.x ----------------------- :: - $session = \Config\Services::session(); + $session = session(); $_SESSION['item']; $session->get('item'); diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index b6c335fd3df5..f3147bbcd6fd 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -20,7 +20,7 @@ What has been changed Upgrade Guide ============= -1. Wherever you use the View Parser Library replace ``$this->load->library('parser');`` with ``$parser = \Config\Services::parser();``. +1. Wherever you use the View Parser Library replace ``$this->load->library('parser');`` with ``$parser = service('parser');``. 2. You have to change the render part in your controller from ``$this->parser->parse('blog_template', $data);`` to ``echo $parser->setData($data)->render('blog_template');``. Code Example @@ -44,7 +44,7 @@ Codeigniter Version 4.x ----------------------- :: - $parser = \Config\Services::parser(); + $parser = service('parser'); $data = [ 'blog_title' => 'My Blog Title', From 24ed44417d6f4d42e125a21753b2cdd1540b3595 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 12:19:29 +0900 Subject: [PATCH 0250/2325] docs: fix indentation of lists --- .../source/installation/upgrade_migrations.rst | 8 ++++---- .../source/installation/upgrade_pagination.rst | 4 ++-- .../source/installation/upgrade_validations.rst | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index f21243a2b565..13a0082ff983 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -30,10 +30,10 @@ Upgrade Guide 6. Replace ``extends CI_Migration`` with ``extends Migration``. 7. The method names within the ``Forge`` class has been changed to use camelCase. For example: -- ``$this->dbforge->add_field`` to ``$this->forge->addField`` -- ``$this->dbforge->add_key`` to ``$this->forge->addKey`` -- ``$this->dbforge->create_table`` to ``$this->forge->addTable`` -- ``$this->dbforge->drop_table`` to ``$this->forge->addTable`` + - ``$this->dbforge->add_field`` to ``$this->forge->addField`` + - ``$this->dbforge->add_key`` to ``$this->forge->addKey`` + - ``$this->dbforge->create_table`` to ``$this->forge->addTable`` + - ``$this->dbforge->drop_table`` to ``$this->forge->addTable`` 8. (optional) You can change the array syntax from ``array(...)`` to ``[...]`` diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index a44240b8d4d5..29fa4f968633 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -21,11 +21,11 @@ Upgrade Guide ============= 1. Within the views change to following: -- ``pagination->create_links(); ?>`` to ``links() ?>`` + - ``pagination->create_links(); ?>`` to ``links() ?>`` 2. Within the controller you have to make the following changes: -- You can use the built-in ``paginate()`` method on every Model. Have a look at the code example below to see how you setup the pagination on a specific model. + - You can use the built-in ``paginate()`` method on every Model. Have a look at the code example below to see how you setup the pagination on a specific model. Code Example diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 44a7a9bd1e31..da04af513351 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -21,15 +21,15 @@ Upgrade Guide ============= 1. Within the view which contains the form you have to change: -- ```` to ``listErrors() ?>`` -- ```` to ```` + - ```` to ``listErrors() ?>`` + - ```` to ```` 2. Within the controller you have to change the following: -- ``$this->load->helper(array('form', 'url'));`` to ``helper(['form', 'url']);`` -- remove the line ``$this->load->library('form_validation');`` -- ``if($this->form_validation->run() == FALSE)`` to ``if (! $this->validate([]))`` -- ``$this->load->view('myform');`` to ``echo view('myform', ['validation' => $this->validator,]);`` + - ``$this->load->helper(array('form', 'url'));`` to ``helper(['form', 'url']);`` + - remove the line ``$this->load->library('form_validation');`` + - ``if($this->form_validation->run() == FALSE)`` to ``if (! $this->validate([]))`` + - ``$this->load->view('myform');`` to ``echo view('myform', ['validation' => $this->validator,]);`` 3. You have to change the validation rules. The new syntax is to set the rules as array in the controller:: From a407185d98b74d3059ebafe6b18003787da65b7f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 12:19:54 +0900 Subject: [PATCH 0251/2325] docs: add links to each upgrade page --- .../source/installation/upgrade_4xx.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index 676e76110306..dcf19217b277 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -134,8 +134,21 @@ Upgrading Libraries .. toctree:: :titlesonly: - upgrade_migrations upgrade_configuration + upgrade_database + upgrade_emails + upgrade_encryption + upgrade_file_upload + upgrade_html_tables + upgrade_localization + upgrade_migrations + upgrade_pagination + upgrade_responses + upgrade_routing + upgrade_security + upgrade_sessions + upgrade_validations + upgrade_view_parser .. note:: More upgrade guides coming soon From a5ff5a7ea7dae0c1f633ab75d9f9d2c2886e67e7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 12:21:05 +0900 Subject: [PATCH 0252/2325] docs: replace HTML with HTTP https://github.com/codeigniter4/CodeIgniter4/pull/4565#discussion_r633463661 --- user_guide_src/source/installation/upgrade_responses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index a8ea5961b279..15cf10aae0a7 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -17,7 +17,7 @@ What has been changed Upgrade Guide ============= -1. The methods in the HTML Responses class are named slightly different. The most important change in the naming is the switch from underscored method names to camelCase. The method ``set_content_type()`` from version 3 is now named ``setContentType()`` and so on. +1. The methods in the HTTP Responses class are named slightly different. The most important change in the naming is the switch from underscored method names to camelCase. The method ``set_content_type()`` from version 3 is now named ``setContentType()`` and so on. 2. In the most cases you have to change ``$this->output`` to ``$this->response`` followed by the method. You can find all methods :doc:`here `. Code Example From c04075456e0cd3c0f8429143f5941a4985ca76df Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 12:26:10 +0900 Subject: [PATCH 0253/2325] docs: remove unneeded code --- user_guide_src/source/installation/upgrade_responses.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index 15cf10aae0a7..6b5cc1b4ef7b 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -39,8 +39,7 @@ Codeigniter Version 4.x ----------------------- :: - $this->response->setStatusCode(404) - ->setBody($body); + $this->response->setStatusCode(404); ... From afb1832a2602e1efa5dcd75fe5401e13e4ae0e71 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:19:10 +0900 Subject: [PATCH 0254/2325] docs: remove unneeded change instruction --- user_guide_src/source/installation/upgrade_validations.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index da04af513351..b518e4fd8b36 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -22,7 +22,6 @@ Upgrade Guide 1. Within the view which contains the form you have to change: - ```` to ``listErrors() ?>`` - - ```` to ```` 2. Within the controller you have to change the following: From e9669b7fd59c6f1a616625a0c366e8b9015afe1a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:20:37 +0900 Subject: [PATCH 0255/2325] docs: fix coding style --- user_guide_src/source/installation/upgrade_validations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index b518e4fd8b36..e5029a1b012e 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -27,7 +27,7 @@ Upgrade Guide - ``$this->load->helper(array('form', 'url'));`` to ``helper(['form', 'url']);`` - remove the line ``$this->load->library('form_validation');`` - - ``if($this->form_validation->run() == FALSE)`` to ``if (! $this->validate([]))`` + - ``if ($this->form_validation->run() == FALSE)`` to ``if (! $this->validate([]))`` - ``$this->load->view('myform');`` to ``echo view('myform', ['validation' => $this->validator,]);`` 3. You have to change the validation rules. The new syntax is to set the rules as array in the controller:: From f0b4ba4e91ea64737b77670ef7c61490d02ea638 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:28:30 +0900 Subject: [PATCH 0256/2325] docs: add about validation rule setting --- user_guide_src/source/installation/upgrade_validations.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index e5029a1b012e..d498da5eaedc 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -86,6 +86,8 @@ Path: ``application/controllers/``:: $this->load->library('form_validation'); + // Set validation rules + if ($this->form_validation->run() == FALSE) { $this->load->view('myform'); @@ -144,8 +146,9 @@ Path: ``app/Controllers/``:: { helper(['form', 'url']); - if (! $this->validate([])) - { + if (! $this->validate([ + // Validation rules + ])) { echo view('myform', [ 'validation' => $this->validator, ]); From 2479e2d36570ccb0f45b7defe164424829f7e86d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:29:43 +0900 Subject: [PATCH 0257/2325] docs: rename variable to more appropriate name --- user_guide_src/source/installation/upgrade_validations.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index d498da5eaedc..3dddcf177ff1 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -32,8 +32,8 @@ Upgrade Guide 3. You have to change the validation rules. The new syntax is to set the rules as array in the controller:: - $input = $this->validate([ 'name' => 'required|min_length[3]', + $isValid = $this->validate([ 'email' => 'required|valid_email', 'phone' => 'required|numeric|max_length[10]' ]); From 3b02a1e0d2d86d3c4c83a400e1f9163fe37ad42d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:31:24 +0900 Subject: [PATCH 0258/2325] docs: fix coding style --- user_guide_src/source/installation/upgrade_validations.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 3dddcf177ff1..f26cd53d1b5a 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -32,8 +32,8 @@ Upgrade Guide 3. You have to change the validation rules. The new syntax is to set the rules as array in the controller:: - 'name' => 'required|min_length[3]', $isValid = $this->validate([ + 'name' => 'required|min_length[3]', 'email' => 'required|valid_email', 'phone' => 'required|numeric|max_length[10]' ]); @@ -152,9 +152,7 @@ Path: ``app/Controllers/``:: echo view('myform', [ 'validation' => $this->validator, ]); - } - else - { + } else { echo view('formsuccess'); } } From 9af8a8952cc5bfed67e70f98f4e7d61effbe34d5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:39:06 +0900 Subject: [PATCH 0259/2325] docs: fix and add "What has been changed" --- user_guide_src/source/installation/upgrade_pagination.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index 29fa4f968633..012e0c6b7544 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -15,7 +15,10 @@ Documentations What has been changed ===================== -- In CI4 the pagination is a built-in method in the Model class. You have to change the views and also the controller in order to use the new pagination library. +- You have to change the views and also the controller in order to use the new pagination library. +- If you want to customize the pagination links, you need to create View Templates. +- In CI4 the pagination uses the actual page number only. You can't use the starting index (offset) for the items which is the default in CI3. +- If you use ``CodeIgniter\Model``, you can use the built-in method in the Model class. Upgrade Guide ============= From be5f610970692e3fcd358429465f81ee2a64c5d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:46:54 +0900 Subject: [PATCH 0260/2325] docs: add link to CodeIgniter\Model --- user_guide_src/source/installation/upgrade_pagination.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index 012e0c6b7544..8151e82465e5 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -18,7 +18,7 @@ What has been changed - You have to change the views and also the controller in order to use the new pagination library. - If you want to customize the pagination links, you need to create View Templates. - In CI4 the pagination uses the actual page number only. You can't use the starting index (offset) for the items which is the default in CI3. -- If you use ``CodeIgniter\Model``, you can use the built-in method in the Model class. +- If you use :doc:`CodeIgnite\\Model `, you can use the built-in method in the Model class. Upgrade Guide ============= From 81658aaa77f84250c3524c3bdb6bb3fbe96fe061 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:47:38 +0900 Subject: [PATCH 0261/2325] docs: fix coding style --- user_guide_src/source/installation/upgrade_routing.rst | 3 +-- user_guide_src/source/installation/upgrade_security.rst | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 3c55995d8a17..4b30b24f7f2c 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -58,8 +58,7 @@ Path: ``app/Config/Routes.php``:: // Load the system's routing file first, so that the app and ENVIRONMENT // can override as needed. - if (file_exists(SYSTEMPATH . 'Config/Routes.php')) - { + if (file_exists(SYSTEMPATH . 'Config/Routes.php')) { require SYSTEMPATH . 'Config/Routes.php'; } diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 7b8f51d4fbc0..d272a7609236 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -25,8 +25,8 @@ Upgrade Guide public $globals = [ 'before' => [ - //'honeypot' - 'csrf' + //'honeypot', + 'csrf', ] ]; @@ -41,8 +41,8 @@ Codeigniter Version 3.11 :: $csrf = array( - 'name' => $this->security->get_csrf_token_name(), - 'hash' => $this->security->get_csrf_hash() + 'name' => $this->security->get_csrf_token_name(), + 'hash' => $this->security->get_csrf_hash() ); ... From a8380fa724021e977b1104ca937cb99bbbe30146 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:47:53 +0900 Subject: [PATCH 0262/2325] docs: add "What has been changed" --- user_guide_src/source/installation/upgrade_validations.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index f26cd53d1b5a..d3301c4cb37f 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -15,7 +15,10 @@ Documentations of Library What has been changed ===================== - +- If you want to change validation error display, you have to set CI4 validation View templates. +- CI4 validation has no Callbacks nor Callable in CI3. +- CI4 validation format rules do not permit empty string. +- CI4 validation never changes your data. Upgrade Guide ============= From 1f74b171e76ab6564b54f87cffe48a0d718f32f8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 13:49:17 +0900 Subject: [PATCH 0263/2325] docs: fix coding style --- user_guide_src/source/installation/upgrade_security.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index d272a7609236..d72de56f334f 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -25,8 +25,8 @@ Upgrade Guide public $globals = [ 'before' => [ - //'honeypot', - 'csrf', + //'honeypot', + 'csrf', ] ]; From 1a7ec9bfb66859060a5c80d92f29cb5d192e6d06 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 14:05:39 +0900 Subject: [PATCH 0264/2325] docs: fix indentation of lists --- .../source/installation/upgrade_database.rst | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index 0ebc8f75277f..798b24a1c6c0 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -25,22 +25,22 @@ Upgrade Guide 3. If you use multiple databases use the following code to load additional databases ``$db = db_connect('group_name');``. 4. Now you have to change all database queries. The most important change here is to replace ``$this->db`` with just ``$db`` and adjust the method name and ``$db``. Here are some examples: -- ``$this->db->query('YOUR QUERY HERE');`` to ``$db->query('YOUR QUERY HERE');`` -- ``$this->db->simple_query('YOUR QUERY')`` to ``$db->simpleQuery('YOUR QUERY')`` -- ``$this->db->escape("something")`` to ``$db->escape("something");`` -- ``$this->db->affected_rows();`` to ``$db->affectedRows();`` -- ``$query->result();`` to ``$query->getResult();`` -- ``$query->result_array();`` to ``$query->getResultArray();`` -- ``echo $this->db->count_all('my_table');`` to ``echo $db->table('my_table')->countAll();`` + - ``$this->db->query('YOUR QUERY HERE');`` to ``$db->query('YOUR QUERY HERE');`` + - ``$this->db->simple_query('YOUR QUERY')`` to ``$db->simpleQuery('YOUR QUERY')`` + - ``$this->db->escape("something")`` to ``$db->escape("something");`` + - ``$this->db->affected_rows();`` to ``$db->affectedRows();`` + - ``$query->result();`` to ``$query->getResult();`` + - ``$query->result_array();`` to ``$query->getResultArray();`` + - ``echo $this->db->count_all('my_table');`` to ``echo $db->table('my_table')->countAll();`` 5. To use the new Query Builder Class you have to initialize the builder ``$builder = $db->table('mytable');`` after that you can run the queries on the ``$builder``. Here are some examples: -- ``$this->db->get()`` to ``$builder->get();`` -- ``$this->db->get_where('mytable', array('id' => $id), $limit, $offset);`` to ``$builder->getWhere(['id' => $id], $limit, $offset);`` -- ``$this->db->select('title, content, date');`` to ``$builder->select('title, content, date');`` -- ``$this->db->select_max('age');`` to ``$builder->selectMax('age');`` -- ``$this->db->join('comments', 'comments.id = blogs.id');`` to ``$builder->join('comments', 'comments.id = blogs.id');`` -- ``$this->db->having('user_id', 45);`` to ``$builder->having('user_id', 45);`` + - ``$this->db->get()`` to ``$builder->get();`` + - ``$this->db->get_where('mytable', array('id' => $id), $limit, $offset);`` to ``$builder->getWhere(['id' => $id], $limit, $offset);`` + - ``$this->db->select('title, content, date');`` to ``$builder->select('title, content, date');`` + - ``$this->db->select_max('age');`` to ``$builder->selectMax('age');`` + - ``$this->db->join('comments', 'comments.id = blogs.id');`` to ``$builder->join('comments', 'comments.id = blogs.id');`` + - ``$this->db->having('user_id', 45);`` to ``$builder->having('user_id', 45);`` Code Example From dea1374475832220576fcd6b22ae7b1f03725e74 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 14:05:55 +0900 Subject: [PATCH 0265/2325] docs: fix RST format --- user_guide_src/source/installation/upgrade_security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index d72de56f334f..4f2b8107a96b 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -31,7 +31,7 @@ Upgrade Guide ]; 2. Within you html forms you have to remove the csrf input which looks similar to ````. -3. Now within your html forms you have to add ```` somewhere in the form body, unless you are using `form_open()``. +3. Now within your html forms you have to add ```` somewhere in the form body, unless you are using ``form_open()``. Code Example ============ From 2359ae455736516b28c12e4db4993964d003b1f4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 14:06:25 +0900 Subject: [PATCH 0266/2325] docs: fix coding style --- .../installation/upgrade_file_upload.rst | 103 +++++++++--------- .../installation/upgrade_localization.rst | 4 +- .../installation/upgrade_validations.rst | 26 ++--- 3 files changed, 65 insertions(+), 68 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index 2bfbd99765fa..e93884f7fa81 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -33,42 +33,41 @@ Codeigniter Version 3.11 class Upload extends CI_Controller { - public function __construct() + public function __construct() + { + parent::__construct(); + $this->load->helper(array('form', 'url')); + } + + public function index() + { + $this->load->view('upload_form', array('error' => ' ' )); + } + + public function do_upload() + { + $config['upload_path'] = './uploads/'; + $config['allowed_types'] = 'png|jpg|gif'; + $config['max_size'] = 100; + $config['max_width'] = 1024; + $config['max_height'] = 768; + + $this->load->library('upload', $config); + + if ( ! $this->upload->do_upload('userfile')) { - parent::__construct(); - $this->load->helper(array('form', 'url')); - } + $error = array('error' => $this->upload->display_errors()); - public function index() - { - $this->load->view('upload_form', array('error' => ' ' )); + $this->load->view('upload_form', $error); } - - public function do_upload() + else { - $config['upload_path'] = './uploads/'; - $config['allowed_types'] = 'png|jpg|gif'; - $config['max_size'] = 100; - $config['max_width'] = 1024; - $config['max_height'] = 768; - - $this->load->library('upload', $config); - - if ( ! $this->upload->do_upload('userfile')) - { - $error = array('error' => $this->upload->display_errors()); - - $this->load->view('upload_form', $error); - } - else - { - $data = array('upload_data' => $this->upload->data()); - - $this->load->view('upload_success', $data); - } + $data = array('upload_data' => $this->upload->data()); + + $this->load->view('upload_success', $data); } + } } - ?> Codeigniter Version 4.x ----------------------- @@ -80,29 +79,27 @@ Codeigniter Version 4.x class Upload extends BaseController { - public function index() - { - echo view('upload_form', ['error' => ' ']); - } + public function index() + { + echo view('upload_form', ['error' => ' ']); + } - public function do_upload() - { - $this->validate([ - 'userfile' => 'uploaded[userfile]|max_size[userfile,100]|mime_in[userfile,image/png,image/jpg,image/gif]|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]' - ]); - - $file = $this->request->getFile('userfile'); - - if ( ! $path = $file->store()) - { - echo view('upload_form', ['error' => "upload failed"]); - } - else - { - $data = ['upload_file_path' => $path]; - - echo view('upload_success', $data); - } + public function do_upload() + { + $this->validate([ + 'userfile' => 'uploaded[userfile]|max_size[userfile,100]' + . '|mime_in[userfile,image/png,image/jpg,image/gif]' + . '|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]' + ]); + + $file = $this->request->getFile('userfile'); + + if (! $path = $file->store()) { + echo view('upload_form', ['error' => "upload failed"]); + } else { + $data = ['upload_file_path' => $path]; + + echo view('upload_success', $data); } + } } - ?> diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index 5c6125851a92..bb01d0057228 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -36,8 +36,8 @@ Codeigniter Version 3.11 :: // error.php - $lang['error_email_missing'] = 'You must submit an email address'; - $lang['error_url_missing'] = 'You must submit a URL'; + $lang['error_email_missing'] = 'You must submit an email address'; + $lang['error_url_missing'] = 'You must submit a URL'; $lang['error_username_missing'] = 'You must submit a username'; ... diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index d3301c4cb37f..0bc0928ee32e 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -83,23 +83,23 @@ Path: ``application/controllers/``:: class Form extends CI_Controller { - public function index() - { - $this->load->helper(array('form', 'url')); + public function index() + { + $this->load->helper(array('form', 'url')); - $this->load->library('form_validation'); + $this->load->library('form_validation'); - // Set validation rules + // Set validation rules - if ($this->form_validation->run() == FALSE) - { - $this->load->view('myform'); - } - else - { - $this->load->view('formsuccess'); - } + if ($this->form_validation->run() == FALSE) + { + $this->load->view('myform'); } + else + { + $this->load->view('formsuccess'); + } + } } Codeigniter Version 4.x From c453fa7152249885867c369bec12b505cd3c9a95 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 15:35:59 +0900 Subject: [PATCH 0267/2325] docs: small fixes for entities --- user_guide_src/source/models/entities.rst | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index eec2447adf06..10828c0dc56b 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -70,7 +70,7 @@ Create the model first at **app/Models/UserModel.php** so that we can interact w protected $allowedFields = [ 'username', 'email', 'password', ]; - protected $returnType = 'App\Entities\User'; + protected $returnType = \App\Entities\User::class; protected $useTimestamps = true; } @@ -464,7 +464,7 @@ Now you need to register it:: //Bind the type to the handler protected $castHandlers = [ - 'base64' => 'App\Entity\Cast\CastBase64', + 'base64' => \App\Entity\Cast\CastBase64::class, ]; } @@ -496,16 +496,18 @@ Additional parameters are indicated in square brackets and listed with a comma. :: - //Defining a type with parameters + // Defining a type with parameters protected $casts = [ 'some_attribute' => 'class[App\SomeClass, param2, param3]', ]; - //Bind the type to the handler + // Bind the type to the handler protected $castHandlers = [ 'class' => 'SomeHandler', ]; +:: + use CodeIgniter\Entity\Cast\BaseCast; class SomeHandler extends BaseCast @@ -535,7 +537,7 @@ Checking for Changed Attributes You can check if an Entity attribute has changed since it was created. The only parameter is the name of the attribute to check:: - $user = new User(); + $user = new \App\Entities\User(); $user->hasChanged('name'); // false $user->name = 'Fred'; From 9d1570ae60f5e03bd4cd3f06bd998819b4d59027 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 16:10:26 +0900 Subject: [PATCH 0268/2325] docs: fix db_forge --- user_guide_src/source/dbmgmt/forge.rst | 386 +++++++++++++------------ 1 file changed, 199 insertions(+), 187 deletions(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index e16b5ee1e92f..6cbdfe506e8a 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -13,16 +13,16 @@ Initializing the Forge Class **************************** .. important:: In order to initialize the Forge class, your database - driver must already be running, since the forge class relies on it. + driver must already be running, since the forge class relies on it. Load the Forge Class as follows:: - $forge = \Config\Database::forge(); + $forge = \Config\Database::forge(); You can also pass another database group name to the DB Forge loader, in case the database you want to manage isn't the default one:: - $this->myforge = \Config\Database::forge('other_db'); + $this->myforge = \Config\Database::forge('other_db'); In the above example, we're passing the name of a different database group to connect to as the first parameter. @@ -36,27 +36,27 @@ Creating and Dropping Databases Permits you to create the database specified in the first parameter. Returns true/false based on success or failure:: - if ($forge->createDatabase('my_db')) { - echo 'Database created!'; - } + if ($forge->createDatabase('my_db')) { + echo 'Database created!'; + } An optional second parameter set to true will add IF EXISTS statement or will check if a database exists before create it (depending on DBMS). :: - $forge->createDatabase('my_db', true); - // gives CREATE DATABASE IF NOT EXISTS my_db - // or will check if a database exists + $forge->createDatabase('my_db', true); + // gives CREATE DATABASE IF NOT EXISTS my_db + // or will check if a database exists **$forge->dropDatabase('db_name')** Permits you to drop the database specified in the first parameter. Returns true/false based on success or failure:: - if ($forge->dropDatabase('my_db')) { - echo 'Database deleted!'; - } + if ($forge->dropDatabase('my_db')) { + echo 'Database deleted!'; + } Creating Databases in the Command Line ====================================== @@ -67,7 +67,7 @@ will complain that the database creation has failed. To start, just type the command and the name of the database (e.g., ``foo``):: - php spark db:create foo + php spark db:create foo If everything went fine, you should expect the ``Database "foo" successfully created.`` message displayed. @@ -76,12 +76,12 @@ for the file where the database will be created using the ``--ext`` option. Vali ``sqlite`` and defaults to ``db``. Remember that these should not be preceded by a period. :: - php spark db:create foo --ext sqlite - // will create the db file in WRITEPATH/foo.sqlite + php spark db:create foo --ext sqlite + // will create the db file in WRITEPATH/foo.sqlite .. note:: When using the special SQLite3 database name ``:memory:``, expect that the command will still - produce a success message but no database file is created. This is because SQLite3 will just use - an in-memory database. + produce a success message but no database file is created. This is because SQLite3 will just use + an in-memory database. **************************** Creating and Dropping Tables @@ -101,13 +101,13 @@ also require a 'constraint' key. :: - $fields = [ - 'users' => [ - 'type' => 'VARCHAR', - 'constraint' => 100, - ], - ]; - // will translate to "users VARCHAR(100)" when the field is added. + $fields = [ + 'users' => [ + 'type' => 'VARCHAR', + 'constraint' => 100, + ], + ]; + // will translate to "users VARCHAR(100)" when the field is added. Additionally, the following key/values can be used: @@ -122,33 +122,33 @@ Additionally, the following key/values can be used: :: - $fields = [ - 'id' => [ - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true - ], - 'title' => [ - 'type' => 'VARCHAR', - 'constraint' => '100', - 'unique' => true, - ], - 'author' => [ - 'type' =>'VARCHAR', - 'constraint' => 100, - 'default' => 'King of Town', - ], - 'description' => [ - 'type' => 'TEXT', - 'null' => true, - ], - 'status' => [ - 'type' => 'ENUM', - 'constraint' => ['publish', 'pending', 'draft'], - 'default' => 'pending', - ], - ]; + $fields = [ + 'id' => [ + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => true, + 'auto_increment' => true + ], + 'title' => [ + 'type' => 'VARCHAR', + 'constraint' => '100', + 'unique' => true, + ], + 'author' => [ + 'type' =>'VARCHAR', + 'constraint' => 100, + 'default' => 'King of Town', + ], + 'description' => [ + 'type' => 'TEXT', + 'null' => true, + ], + 'status' => [ + 'type' => 'ENUM', + 'constraint' => ['publish', 'pending', 'draft'], + 'default' => 'pending', + ], + ]; After the fields have been defined, they can be added using ``$forge->addField($fields);`` followed by a call to the @@ -166,7 +166,7 @@ string into the field definitions with addField() :: - $forge->addField("label varchar(100) NOT NULL DEFAULT 'default label'"); + $forge->addField("label varchar(100) NOT NULL DEFAULT 'default label'"); .. note:: Passing raw strings as fields cannot be followed by ``addKey()`` calls on those fields. @@ -181,8 +181,8 @@ Primary Key. :: - $forge->addField('id'); - // gives id INT(9) NOT NULL AUTO_INCREMENT + $forge->addField('id'); + // gives id INT(9) NOT NULL AUTO_INCREMENT Adding Keys =========== @@ -198,30 +198,30 @@ below is for MySQL. :: - $forge->addKey('blog_id', true); - // gives PRIMARY KEY `blog_id` (`blog_id`) + $forge->addKey('blog_id', true); + // gives PRIMARY KEY `blog_id` (`blog_id`) - $forge->addKey('blog_id', true); - $forge->addKey('site_id', true); - // gives PRIMARY KEY `blog_id_site_id` (`blog_id`, `site_id`) + $forge->addKey('blog_id', true); + $forge->addKey('site_id', true); + // gives PRIMARY KEY `blog_id_site_id` (`blog_id`, `site_id`) - $forge->addKey('blog_name'); - // gives KEY `blog_name` (`blog_name`) + $forge->addKey('blog_name'); + // gives KEY `blog_name` (`blog_name`) - $forge->addKey(['blog_name', 'blog_label']); - // gives KEY `blog_name_blog_label` (`blog_name`, `blog_label`) + $forge->addKey(['blog_name', 'blog_label']); + // gives KEY `blog_name_blog_label` (`blog_name`, `blog_label`) - $forge->addKey(['blog_id', 'uri'], false, true); - // gives UNIQUE KEY `blog_id_uri` (`blog_id`, `uri`) + $forge->addKey(['blog_id', 'uri'], false, true); + // gives UNIQUE KEY `blog_id_uri` (`blog_id`, `uri`) To make code reading more objective it is also possible to add primary and unique keys with specific methods:: - $forge->addPrimaryKey('blog_id'); - // gives PRIMARY KEY `blog_id` (`blog_id`) + $forge->addPrimaryKey('blog_id'); + // gives PRIMARY KEY `blog_id` (`blog_id`) - $forge->addUniqueKey(['blog_id', 'uri']); - // gives UNIQUE KEY `blog_id_uri` (`blog_id`, `uri`) + $forge->addUniqueKey(['blog_id', 'uri']); + // gives UNIQUE KEY `blog_id_uri` (`blog_id`, `uri`) Adding Foreign Keys @@ -230,19 +230,19 @@ Adding Foreign Keys Foreign Keys help to enforce relationships and actions across your tables. For tables that support Foreign Keys, you may add them directly in forge:: - $forge->addForeignKey('users_id','users','id'); - // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) + $forge->addForeignKey('users_id','users','id'); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) - $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name']); - // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) + $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name']); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) You can specify the desired action for the "on delete" and "on update" properties of the constraint:: - $forge->addForeignKey('users_id','users','id','CASCADE','CASCADE'); - // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE + $forge->addForeignKey('users_id','users','id','CASCADE','CASCADE'); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name'],'CASCADE','CASCADE'); - // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) ON DELETE CASCADE ON UPDATE CASCADE + $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name'],'CASCADE','CASCADE'); + // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) ON DELETE CASCADE ON UPDATE CASCADE Creating a table ================ @@ -252,26 +252,26 @@ with :: - $forge->createTable('table_name'); - // gives CREATE TABLE table_name + $forge->createTable('table_name'); + // gives CREATE TABLE table_name An optional second parameter set to true adds an "IF NOT EXISTS" clause into the definition :: - $forge->createTable('table_name', true); - // gives CREATE TABLE IF NOT EXISTS table_name + $forge->createTable('table_name', true); + // gives CREATE TABLE IF NOT EXISTS table_name You could also pass optional table attributes, such as MySQL's ``ENGINE``:: - $attributes = ['ENGINE' => 'InnoDB']; - $forge->createTable('table_name', false, $attributes); - // produces: CREATE TABLE `table_name` (...) ENGINE = InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci + $attributes = ['ENGINE' => 'InnoDB']; + $forge->createTable('table_name', false, $attributes); + // produces: CREATE TABLE `table_name` (...) ENGINE = InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci .. note:: Unless you specify the ``CHARACTER SET`` and/or ``COLLATE`` attributes, - ``createTable()`` will always add them with your configured *charset* - and *DBCollat* values, as long as they are not empty (MySQL only). + ``createTable()`` will always add them with your configured *charset* + and *DBCollat* values, as long as they are not empty (MySQL only). Dropping a table ================ @@ -280,19 +280,19 @@ Execute a DROP TABLE statement and optionally add an IF EXISTS clause. :: - // Produces: DROP TABLE table_name - $forge->dropTable('table_name'); + // Produces: DROP TABLE table_name + $forge->dropTable('table_name'); - // Produces: DROP TABLE IF EXISTS table_name - $forge->dropTable('table_name', true); + // Produces: DROP TABLE IF EXISTS table_name + $forge->dropTable('table_name', true); A third parameter can be passed to add a "CASCADE" option, which might be required for some drivers to handle removal of tables with foreign keys. :: - // Produces: DROP TABLE table_name CASCADE - $forge->dropTable('table_name', false, true); + // Produces: DROP TABLE table_name CASCADE + $forge->dropTable('table_name', false, true); Dropping a Foreign Key ====================== @@ -301,8 +301,8 @@ Execute a DROP FOREIGN KEY. :: - // Produces: ALTER TABLE 'tablename' DROP FOREIGN KEY 'users_foreign' - $forge->dropForeignKey('tablename','users_foreign'); + // Produces: ALTER TABLE 'tablename' DROP FOREIGN KEY 'users_foreign' + $forge->dropForeignKey('tablename','users_foreign'); Renaming a table ================ @@ -311,8 +311,8 @@ Executes a TABLE rename :: - $forge->renameTable('old_table_name', 'new_table_name'); - // gives ALTER TABLE old_table_name RENAME TO new_table_name + $forge->renameTable('old_table_name', 'new_table_name'); + // gives ALTER TABLE old_table_name RENAME TO new_table_name **************** Modifying Tables @@ -329,26 +329,26 @@ number of additional fields. :: - $fields = [ - 'preferences' => ['type' => 'TEXT'] - ]; - $forge->addColumn('table_name', $fields); - // Executes: ALTER TABLE table_name ADD preferences TEXT + $fields = [ + 'preferences' => ['type' => 'TEXT'] + ]; + $forge->addColumn('table_name', $fields); + // Executes: ALTER TABLE table_name ADD preferences TEXT If you are using MySQL or CUBIRD, then you can take advantage of their AFTER and FIRST clauses to position the new column. Examples:: - // Will place the new column after the `another_field` column: - $fields = [ - 'preferences' => ['type' => 'TEXT', 'after' => 'another_field'] - ]; + // Will place the new column after the `another_field` column: + $fields = [ + 'preferences' => ['type' => 'TEXT', 'after' => 'another_field'] + ]; - // Will place the new column at the start of the table definition: - $fields = [ - 'preferences' => ['type' => 'TEXT', 'first' => true] - ]; + // Will place the new column at the start of the table definition: + $fields = [ + 'preferences' => ['type' => 'TEXT', 'first' => true] + ]; Dropping Columns From a Table ============================== @@ -359,7 +359,7 @@ Used to remove a column from a table. :: - $forge->dropColumn('table_name', 'column_to_drop'); // to drop one single column + $forge->dropColumn('table_name', 'column_to_drop'); // to drop one single column Used to remove multiple columns from a table. @@ -379,14 +379,14 @@ change the name, you can add a "name" key into the field defining array. :: - $fields = [ - 'old_name' => [ - 'name' => 'new_name', - 'type' => 'TEXT', - ], - ]; - $forge->modifyColumn('table_name', $fields); - // gives ALTER TABLE table_name CHANGE old_name new_name TEXT + $fields = [ + 'old_name' => [ + 'name' => 'new_name', + 'type' => 'TEXT', + ], + ]; + $forge->modifyColumn('table_name', $fields); + // gives ALTER TABLE table_name CHANGE old_name new_name TEXT *************** Class Reference @@ -394,108 +394,120 @@ Class Reference .. php:class:: CodeIgniter\\Database\\Forge - .. php:method:: addColumn($table[, $field = []]) + .. php:method:: addColumn($table[, $field = []]) - :param string $table: Table name to add the column to - :param array $field: Column definition(s) - :returns: true on success, false on failure - :rtype: bool + :param string $table: Table name to add the column to + :param array $field: Column definition(s) + :returns: true on success, false on failure + :rtype: bool - Adds a column to a table. Usage: See `Adding a Column to a Table`_. + Adds a column to a table. Usage: See `Adding a Column to a Table`_. - .. php:method:: addField($field) + .. php:method:: addField($field) - :param array $field: Field definition to add - :returns: \CodeIgniter\Database\Forge instance (method chaining) - :rtype: \CodeIgniter\Database\Forge + :param array $field: Field definition to add + :returns: \CodeIgniter\Database\Forge instance (method chaining) + :rtype: \CodeIgniter\Database\Forge Adds a field to the set that will be used to create a table. Usage: See `Adding fields`_. - .. php:method:: addKey($key[, $primary = false[, $unique = false]]) + .. php:method:: addForeignKey($fieldName, $tableName, $tableField[, $onUpdate = '', $onDelete = '']) - :param mixed $key: Name of a key field or an array of fields - :param bool $primary: Set to true if it should be a primary key or a regular one - :param bool $unique: Set to true if it should be a unique key or a regular one - :returns: \CodeIgniter\Database\Forge instance (method chaining) - :rtype: \CodeIgniter\Database\Forge + :param string|string[] $fieldName: Name of a key field or an array of fields + :param string $tableName: Name of a parent table + :param string|string[] $tableField: Name of a parent table field or an array of fields + :param string $onUpdate: Desired action for the “on update” + :param string $onDelete: Desired action for the “on delete” + :returns: \CodeIgniter\Database\Forge instance (method chaining) + :rtype: \CodeIgniter\Database\Forge - Adds a key to the set that will be used to create a table. Usage: See `Adding Keys`_. + Adds a foreign key to the set that will be used to create a table. Usage: See `Adding Foreign Keys`_. - .. php:method:: addPrimaryKey($key) + .. php:method:: addKey($key[, $primary = false[, $unique = false]]) - :param mixed $key: Name of a key field or an array of fields - :returns: \CodeIgniter\Database\Forge instance (method chaining) - :rtype: \CodeIgniter\Database\Forge + :param mixed $key: Name of a key field or an array of fields + :param bool $primary: Set to true if it should be a primary key or a regular one + :param bool $unique: Set to true if it should be a unique key or a regular one + :returns: \CodeIgniter\Database\Forge instance (method chaining) + :rtype: \CodeIgniter\Database\Forge - Adds a primary key to the set that will be used to create a table. Usage: See `Adding Keys`_. + Adds a key to the set that will be used to create a table. Usage: See `Adding Keys`_. - .. php:method:: addUniqueKey($key) + .. php:method:: addPrimaryKey($key) - :param mixed $key: Name of a key field or an array of fields - :returns: \CodeIgniter\Database\Forge instance (method chaining) - :rtype: \CodeIgniter\Database\Forge + :param mixed $key: Name of a key field or an array of fields + :returns: \CodeIgniter\Database\Forge instance (method chaining) + :rtype: \CodeIgniter\Database\Forge - Adds a unique key to the set that will be used to create a table. Usage: See `Adding Keys`_. + Adds a primary key to the set that will be used to create a table. Usage: See `Adding Keys`_. - .. php:method:: createDatabase($dbName[, $ifNotExists = false]) + .. php:method:: addUniqueKey($key) - :param string $db_name: Name of the database to create - :param string $ifNotExists: Set to true to add an 'IF NOT EXISTS' clause or check if database exists - :returns: true on success, false on failure - :rtype: bool + :param mixed $key: Name of a key field or an array of fields + :returns: \CodeIgniter\Database\Forge instance (method chaining) + :rtype: \CodeIgniter\Database\Forge - Creates a new database. Usage: See `Creating and Dropping Databases`_. + Adds a unique key to the set that will be used to create a table. Usage: See `Adding Keys`_. - .. php:method:: createTable($table[, $if_not_exists = false[, array $attributes = []]]) + .. php:method:: createDatabase($dbName[, $ifNotExists = false]) - :param string $table: Name of the table to create - :param string $if_not_exists: Set to true to add an 'IF NOT EXISTS' clause - :param string $attributes: An associative array of table attributes - :returns: Query object on success, false on failure - :rtype: mixed + :param string $db_name: Name of the database to create + :param string $ifNotExists: Set to true to add an 'IF NOT EXISTS' clause or check if database exists + :returns: true on success, false on failure + :rtype: bool - Creates a new table. Usage: See `Creating a table`_. + Creates a new database. Usage: See `Creating and Dropping Databases`_. - .. php:method:: dropColumn($table, $column_name) + .. php:method:: createTable($table[, $if_not_exists = false[, array $attributes = []]]) - :param string $table: Table name - :param mixed $column_names: Comma-delimited string or an array of column names - :returns: true on success, false on failure - :rtype: bool + :param string $table: Name of the table to create + :param string $if_not_exists: Set to true to add an 'IF NOT EXISTS' clause + :param string $attributes: An associative array of table attributes + :returns: Query object on success, false on failure + :rtype: mixed - Drops single or multiple columns from a table. Usage: See `Dropping Columns From a Table`_. + Creates a new table. Usage: See `Creating a table`_. - .. php:method:: dropDatabase($dbName) + .. php:method:: dropColumn($table, $column_name) - :param string $dbName: Name of the database to drop - :returns: true on success, false on failure - :rtype: bool + :param string $table: Table name + :param mixed $column_names: Comma-delimited string or an array of column names + :returns: true on success, false on failure + :rtype: bool - Drops a database. Usage: See `Creating and Dropping Databases`_. + Drops single or multiple columns from a table. Usage: See `Dropping Columns From a Table`_. - .. php:method:: dropTable($table_name[, $if_exists = false]) + .. php:method:: dropDatabase($dbName) - :param string $table: Name of the table to drop - :param string $if_exists: Set to true to add an 'IF EXISTS' clause - :returns: true on success, false on failure - :rtype: bool + :param string $dbName: Name of the database to drop + :returns: true on success, false on failure + :rtype: bool - Drops a table. Usage: See `Dropping a table`_. + Drops a database. Usage: See `Creating and Dropping Databases`_. - .. php:method:: modifyColumn($table, $field) + .. php:method:: dropTable($table_name[, $if_exists = false]) - :param string $table: Table name - :param array $field: Column definition(s) - :returns: true on success, false on failure - :rtype: bool + :param string $table: Name of the table to drop + :param string $if_exists: Set to true to add an 'IF EXISTS' clause + :returns: true on success, false on failure + :rtype: bool - Modifies a table column. Usage: See `Modifying a Column in a Table`_. + Drops a table. Usage: See `Dropping a table`_. - .. php:method:: renameTable($table_name, $new_table_name) + .. php:method:: modifyColumn($table, $field) - :param string $table: Current of the table - :param string $new_table_name: New name of the table - :returns: Query object on success, false on failure - :rtype: mixed + :param string $table: Table name + :param array $field: Column definition(s) + :returns: true on success, false on failure + :rtype: bool - Renames a table. Usage: See `Renaming a table`_. + Modifies a table column. Usage: See `Modifying a Column in a Table`_. + + .. php:method:: renameTable($table_name, $new_table_name) + + :param string $table: Current of the table + :param string $new_table_name: New name of the table + :returns: Query object on success, false on failure + :rtype: mixed + + Renames a table. Usage: See `Renaming a table`_. From 1b55d7bc98e334578da7f707ce4676689423bbed Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 22:12:13 +0900 Subject: [PATCH 0269/2325] docs: add about upgrading migration table --- user_guide_src/source/installation/upgrade_migrations.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 13a0082ff983..66bfcbaabc1d 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -15,6 +15,8 @@ What has been changed ===================== - First of all, the sequential naming (``001_create_users``, ``002_create_posts``) of migrations is not longer supported. Version 4 of CodeIgniter only supports the timestamp scheme (``20121031100537_create_users``, ``20121031500638_create_posts``) . If you have used sequential naming you have to rename each migration file. +- The migration table definition was changed. If you upgrade from CI3 to CI4 and use the same database, + You need to upgrade the migration table definition and its data. - The migration procedure has been also changed. You can now migrate the database with a simple CLI command:: > php spark migrate @@ -36,6 +38,12 @@ Upgrade Guide - ``$this->dbforge->drop_table`` to ``$this->forge->addTable`` 8. (optional) You can change the array syntax from ``array(...)`` to ``[...]`` +9. Upgrade the migration table, if you use the same database. + + - **(development)** Run the CI4 migration in the development environment or so with brand new database, to create the new migration table. + - **(development)** Export the migration table. + - **(production)** Drop (or rename) the existing CI3 migration table. + - **(production)** Import the new migration table and the data. Code Example ============ From 04a31f00f6b293bf82587179cab9bd93e54ebb86 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Sep 2021 22:13:09 +0900 Subject: [PATCH 0270/2325] docs: rename v4.2.0 to v4.1.5 --- user_guide_src/source/changelogs/index.rst | 2 +- user_guide_src/source/changelogs/{v4.2.0.rst => v4.1.5.rst} | 4 ++-- .../source/installation/{upgrade_420.rst => upgrade_415.rst} | 2 +- user_guide_src/source/installation/upgrading.rst | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) rename user_guide_src/source/changelogs/{v4.2.0.rst => v4.1.5.rst} (88%) rename user_guide_src/source/installation/{upgrade_420.rst => upgrade_415.rst} (97%) diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index a997a57f0c3f..2ec12f649150 100644 --- a/user_guide_src/source/changelogs/index.rst +++ b/user_guide_src/source/changelogs/index.rst @@ -12,7 +12,7 @@ See all the changes. .. toctree:: :titlesonly: - v4.2.0 + v4.1.5 v4.1.4 v4.1.3 v4.1.2 diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.1.5.rst similarity index 88% rename from user_guide_src/source/changelogs/v4.2.0.rst rename to user_guide_src/source/changelogs/v4.1.5.rst index 22a94202a69f..b57f3b79a85a 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.1.5.rst @@ -1,9 +1,9 @@ -Version 4.2.0 +Version 4.1.5 ============= Release Date: Not released -**4.2.0 release of CodeIgniter4** +**4.1.5 release of CodeIgniter4** Enhancements: diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_415.rst similarity index 97% rename from user_guide_src/source/installation/upgrade_420.rst rename to user_guide_src/source/installation/upgrade_415.rst index cfbcbdbf1aeb..bb075023e7bc 100644 --- a/user_guide_src/source/installation/upgrade_420.rst +++ b/user_guide_src/source/installation/upgrade_415.rst @@ -1,5 +1,5 @@ ############################# -Upgrading from 4.1.4 to 4.2.0 +Upgrading from 4.1.4 to 4.1.5 ############################# **Changes for set() method in BaseBuilder and Model class** diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index b6ef428e8b47..0264b6eaa3bb 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -8,7 +8,7 @@ upgrading from. .. toctree:: :titlesonly: - Upgrading from 4.1.4 to 4.2.0 + Upgrading from 4.1.4 to 4.1.5 Upgrading from 4.1.3 to 4.1.4 Upgrading from 4.1.2 to 4.1.3 Upgrading from 4.1.1 to 4.1.2 From a7d7de65c2747dcc20939aaef8fded199c22605c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 13 Sep 2021 13:48:08 +0700 Subject: [PATCH 0271/2325] [Rector] Clean up rector skip config --- rector.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rector.php b/rector.php index 054ed3ea09ad..931b89304416 100644 --- a/rector.php +++ b/rector.php @@ -28,7 +28,6 @@ use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; use Rector\Core\Configuration\Option; use Rector\Core\ValueObject\PhpVersion; -use Rector\DeadCode\Rector\Cast\RecastingRemovalRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPromotedPropertyRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; @@ -91,11 +90,6 @@ __DIR__ . '/system/CodeIgniter.php', ], - // casted to Entity via EntityTest->getCastEntity() - RecastingRemovalRector::class => [ - __DIR__ . '/tests/system/Entity/EntityTest.php', - ], - // session handlers have the gc() method with underscored parameter `$max_lifetime` UnderscoreToCamelCaseVariableNameRector::class => [ __DIR__ . '/system/Session/Handlers', From 419eb39a63cad50aee155783399bd0350c1efeae Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Sep 2021 15:58:28 +0900 Subject: [PATCH 0272/2325] docs: fix query_builder RST format --- .../source/database/query_builder.rst | 106 +++++++----------- 1 file changed, 40 insertions(+), 66 deletions(-) diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 3494325e5084..45380416fdac 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -259,9 +259,7 @@ methods: Notice that the equal sign is added for you. If you use multiple function calls they will be chained together with - AND between them: - - :: + AND between them:: $builder->where('name', $name); $builder->where('title', $title); @@ -271,9 +269,7 @@ methods: #. **Custom key/value method:** You can include an operator in the first parameter in order to - control the comparison: - - :: + control the comparison:: $builder->where('name !=', $name); $builder->where('id <', $id); @@ -287,33 +283,30 @@ methods: $builder->where($array); // Produces: WHERE name = 'Joe' AND title = 'boss' AND status = 'active' - You can include your own operators using this method as well: - - :: + You can include your own operators using this method as well:: $array = ['name !=' => $name, 'id <' => $id, 'date >' => $date]; $builder->where($array); #. **Custom string:** - You can write your own clauses manually:: + You can write your own clauses manually:: $where = "name='Joe' AND status='boss' OR status='active'"; $builder->where($where); If you are using user-supplied data within the string, you MUST escape the data manually. Failure to do so could result in SQL injections. -:: + + :: $name = $builder->db->escape('Joe'); $where = "name={$name} AND status='boss' OR status='active'"; $builder->where($where); - #. **Subqueries:** - You can use an anonymous function to create a subquery. - :: + You can use an anonymous function to create a subquery:: $builder->where('advance_amount <', function (BaseBuilder $builder) { return $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); @@ -323,48 +316,38 @@ methods: **$builder->orWhere()** This function is identical to the one above, except that multiple -instances are joined by OR - - :: +instances are joined by OR:: - $builder->where('name !=', $name); - $builder->orWhere('id >', $id); - // Produces: WHERE name != 'Joe' OR id > 50 + $builder->where('name !=', $name); + $builder->orWhere('id >', $id); + // Produces: WHERE name != 'Joe' OR id > 50 **$builder->whereIn()** Generates a WHERE field IN ('item', 'item') SQL query joined with AND if -appropriate - - :: +appropriate:: - $names = ['Frank', 'Todd', 'James']; - $builder->whereIn('username', $names); - // Produces: WHERE username IN ('Frank', 'Todd', 'James') - -You can use subqueries instead of an array of values. + $names = ['Frank', 'Todd', 'James']; + $builder->whereIn('username', $names); + // Produces: WHERE username IN ('Frank', 'Todd', 'James') - :: +You can use subqueries instead of an array of values:: - $builder->whereIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); - }); - // Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + $builder->whereIn('id', function (BaseBuilder $builder) { + return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); + }); + // Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) **$builder->orWhereIn()** Generates a ``WHERE field IN ('item', 'item')`` SQL query joined with OR if -appropriate - - :: +appropriate:: $names = ['Frank', 'Todd', 'James']; $builder->orWhereIn('username', $names); // Produces: OR username IN ('Frank', 'Todd', 'James') -You can use subqueries instead of an array of values. - - :: +You can use subqueries instead of an array of values:: $builder->orWhereIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); @@ -375,45 +358,36 @@ You can use subqueries instead of an array of values. **$builder->whereNotIn()** Generates a WHERE field NOT IN ('item', 'item') SQL query joined with -AND if appropriate +AND if appropriate:: - :: - - $names = ['Frank', 'Todd', 'James']; - $builder->whereNotIn('username', $names); - // Produces: WHERE username NOT IN ('Frank', 'Todd', 'James') + $names = ['Frank', 'Todd', 'James']; + $builder->whereNotIn('username', $names); + // Produces: WHERE username NOT IN ('Frank', 'Todd', 'James') -You can use subqueries instead of an array of values. +You can use subqueries instead of an array of values:: - :: - - $builder->whereNotIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); - }); - - // Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + $builder->whereNotIn('id', function (BaseBuilder $builder) { + return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); + }); + // Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) **$builder->orWhereNotIn()** Generates a ``WHERE field NOT IN ('item', 'item')`` SQL query joined with OR -if appropriate +if appropriate:: - :: + $names = ['Frank', 'Todd', 'James']; + $builder->orWhereNotIn('username', $names); + // Produces: OR username NOT IN ('Frank', 'Todd', 'James') - $names = ['Frank', 'Todd', 'James']; - $builder->orWhereNotIn('username', $names); - // Produces: OR username NOT IN ('Frank', 'Todd', 'James') +You can use subqueries instead of an array of values:: -You can use subqueries instead of an array of values. - - :: - - $builder->orWhereNotIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); - }); + $builder->orWhereNotIn('id', function (BaseBuilder $builder) { + return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); + }); - // Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + // Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) ************************ Looking for Similar Data From e4194f4273cc9550df43dd8f3691b134171192d0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Sep 2021 15:58:54 +0900 Subject: [PATCH 0273/2325] docs: fix controller classnames in sample code --- .../source/installation/upgrade_routing.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 4b30b24f7f2c..7243d41345db 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -64,12 +64,12 @@ Path: ``app/Config/Routes.php``:: ... - $routes->add('posts', 'posts::index'); - $routes->add('teams/create', 'teams::create'); - $routes->add('teams/edit/(:any)', 'teams::edit/$1'); - - $routes->add('posts/create', 'posts::create'); - $routes->add('posts/edit/(:any)', 'posts::edit/$1'); - $routes->add('drivers/create', 'drivers::create'); - $routes->add('drivers/edit/(:any)', 'drivers::edit/$1'); - $routes->add('posts/(:any)', 'posts::view/$1'); + $routes->add('posts', 'Posts::index'); + $routes->add('teams/create', 'Teams::create'); + $routes->add('teams/edit/(:any)', 'Teams::edit/$1'); + + $routes->add('posts/create', 'Posts::create'); + $routes->add('posts/edit/(:any)', 'Posts::edit/$1'); + $routes->add('drivers/create', 'Drivers::create'); + $routes->add('drivers/edit/(:any)', 'Drivers::edit/$1'); + $routes->add('posts/(:any)', 'Posts::view/$1'); From 6b5b8dec061541cefb35d760a15fbd53147eba3f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 13 Sep 2021 15:59:45 +0900 Subject: [PATCH 0274/2325] docs: small fixes for configuration --- .../source/general/configuration.rst | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index ee1486d91056..5f43477bbaaf 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -124,9 +124,9 @@ To save on typing, you can reuse variables that you've already specified in the variable name within ``${...}`` :: - BASE_DIR="/var/webroot/project-root" - CACHE_DIR="${BASE_DIR}/cache" - TMP_DIR="${BASE_DIR}/tmp" + BASE_DIR="/var/webroot/project-root" + CACHE_DIR="${BASE_DIR}/cache" + TMP_DIR="${BASE_DIR}/tmp" Namespaced Variables ==================== @@ -262,17 +262,17 @@ wish to supply an additional template to ``Pager`` without overwriting whatever already configured. In **src/Config/Registrar.php** there would be a ``Registrar`` class with the single ``Pager()`` method (note the case-sensitivity):: - class Registrar - { - public static function Pager(): array - { - return [ - 'templates' => [ - 'module_pager' => 'MyModule\Views\Pager', - ], - ]; - } - } + class Registrar + { + public static function Pager(): array + { + return [ + 'templates' => [ + 'module_pager' => 'MyModule\Views\Pager', + ], + ]; + } + } Registrar methods must always return an array, with keys corresponding to the properties of the target config file. Existing values are merged, and Registrar properties have @@ -337,4 +337,3 @@ by treating ``RegionalSales`` as a "registrar". The resulting configuration prop $target = 45; $campaign = "Winter Wonderland"; - From 7823fe8d281630cb8230d3c9d024a7446bb2a136 Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 14 Sep 2021 23:05:23 +0000 Subject: [PATCH 0275/2325] Ignore unroutable responses --- system/CodeIgniter.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index aee11790f406..1bcb12a627b9 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -19,6 +19,7 @@ use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\DownloadResponse; use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; @@ -929,6 +930,11 @@ public function storePreviousURL($uri) return; } + // Ignore unroutable responses + if ($this->response instanceof DownloadResponse || $this->response instanceof RedirectResponse) { + return; + } + // This is mainly needed during testing... if (is_string($uri)) { $uri = new URI($uri); From 8e1b2805ce6e59a6bfc430a2cada8f7e19b787f6 Mon Sep 17 00:00:00 2001 From: MGatner Date: Wed, 15 Sep 2021 01:47:19 +0000 Subject: [PATCH 0276/2325] Add tests --- system/CodeIgniter.php | 4 ++-- tests/system/CodeIgniterTest.php | 23 ++++++++++++++++++++--- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 1bcb12a627b9..1ac65c4663cd 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -922,8 +922,8 @@ protected function gatherOutput(?Cache $cacheConfig = null, $returned = null) public function storePreviousURL($uri) { // Ignore CLI requests - if (is_cli()) { - return; + if (is_cli() && ENVIRONMENT !== 'testing') { + return; // @codeCoverageIgnore } // Ignore AJAX requests if (method_exists($this->request, 'isAJAX') && $this->request->isAJAX()) { diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index af0488f3c7f5..0a3ad80921d7 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -345,7 +345,24 @@ public function testRunRedirectionWithHTTPCode303() $this->assertSame(303, $response->getStatusCode()); } - public function testRunRedirectionWithHTTPCode301() + public function testStoresPreviousURL() + { + $_SERVER['argv'] = ['index.php', '/']; + $_SERVER['argc'] = 2; + + // Inject mock router. + $router = Services::router(null, Services::request(), false); + Services::injectMock('router', $router); + + ob_start(); + $this->codeigniter->useSafeOutput(true)->run(); + ob_get_clean(); + + $this->assertArrayHasKey('_ci_previous_url', $_SESSION); + $this->assertSame('http://example.com/index.php', $_SESSION['_ci_previous_url']); + } + + public function testNotStoresPreviousURL() { $_SERVER['argv'] = ['index.php', 'example']; $_SERVER['argc'] = 2; @@ -364,8 +381,8 @@ public function testRunRedirectionWithHTTPCode301() ob_start(); $this->codeigniter->useSafeOutput(true)->run(); ob_get_clean(); - $response = $this->getPrivateProperty($this->codeigniter, 'response'); - $this->assertSame(301, $response->getStatusCode()); + + $this->assertArrayNotHasKey('_ci_previous_url', $_SESSION); } /** From 9b202fcc4e3f4ba2c0d47d258a72d3fd4c13ec83 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Sep 2021 12:08:27 +0900 Subject: [PATCH 0277/2325] docs: fix indentation --- user_guide_src/source/dbmgmt/migration.rst | 227 +++++++++++---------- 1 file changed, 114 insertions(+), 113 deletions(-) diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 88b2a2c1e106..027c12d3dc70 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -43,41 +43,41 @@ migrations go in the **app/Database/Migrations/** directory and have names such as *20121031100537_add_blog.php*. :: - forge->addField([ - 'blog_id' => [ - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true, - ], - 'blog_title' => [ - 'type' => 'VARCHAR', - 'constraint' => '100', - ], - 'blog_description' => [ - 'type' => 'TEXT', - 'null' => true, - ], - ]); - $this->forge->addKey('blog_id', true); - $this->forge->createTable('blog'); - } - - public function down() - { - $this->forge->dropTable('blog'); - } - } + forge->addField([ + 'blog_id' => [ + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => true, + 'auto_increment' => true, + ], + 'blog_title' => [ + 'type' => 'VARCHAR', + 'constraint' => '100', + ], + 'blog_description' => [ + 'type' => 'TEXT', + 'null' => true, + ], + ]); + $this->forge->addKey('blog_id', true); + $this->forge->createTable('blog'); + } + + public function down() + { + $this->forge->dropTable('blog'); + } + } The database connection and the database Forge class are both available to you through ``$this->db`` and ``$this->forge``, respectively. @@ -94,14 +94,14 @@ To temporarily bypass the foreign key checks while running migrations, use the ` :: - public function up() - { - $this->db->disableForeignKeyChecks() + public function up() + { + $this->db->disableForeignKeyChecks() - // Migration rules would go here.. + // Migration rules would go here.. - $this->db->enableForeignKeyChecks(); - } + $this->db->enableForeignKeyChecks(); + } Database Groups =============== @@ -114,26 +114,26 @@ another database is used for mission critical data. You can ensure that migratio against the proper group by setting the ``$DBGroup`` property on your migration. This name must match the name of the database group exactly:: - APPPATH, - 'MyCompany' => ROOTPATH . 'MyCompany', - ]; + $psr4 = [ + 'App' => APPPATH, + 'MyCompany' => ROOTPATH . 'MyCompany', + ]; This will look for any migrations located at both **APPPATH/Database/Migrations** and **ROOTPATH/MyCompany/Database/Migrations**. This makes it simple to include migrations in your @@ -164,23 +164,23 @@ Usage Example In this example some simple code is placed in **app/Controllers/Migrate.php** to update the schema:: - latest(); - } catch (\Throwable $e) { - // Do something with the error here... - } - } - } + try { + $migrate->latest(); + } catch (\Throwable $e) { + // Do something with the error here... + } + } + } ******************* Command-Line Tools @@ -284,62 +284,63 @@ Class Reference .. php:class:: CodeIgniter\\Database\\MigrationRunner - .. php:method:: findMigrations() + .. php:method:: findMigrations() - :returns: An array of migration files - :rtype: array + :returns: An array of migration files + :rtype: array - An array of migration filenames are returned that are found in the **path** property. + An array of migration filenames are returned that are found in the **path** property. - .. php:method:: latest($group) + .. php:method:: latest($group) - :param mixed $group: database group name, if null default database group will be used. - :returns: ``true`` on success, ``false`` on failure - :rtype: bool + :param mixed $group: database group name, if null default database group will be used. + :returns: ``true`` on success, ``false`` on failure + :rtype: bool - This locates migrations for a namespace (or all namespaces), determines which migrations - have not yet been run, and runs them in order of their version (namespaces intermingled). + This locates migrations for a namespace (or all namespaces), determines which migrations + have not yet been run, and runs them in order of their version (namespaces intermingled). - .. php:method:: regress($batch, $group) + .. php:method:: regress($batch, $group) - :param mixed $batch: previous batch to migrate down to; 1+ specifies the batch, 0 reverts all, negative refers to the relative batch (e.g., -3 means "three batches back") - :param mixed $group: database group name, if null default database group will be used. - :returns: ``true`` on success, ``false`` on failure or no migrations are found - :rtype: bool + :param mixed $batch: previous batch to migrate down to; 1+ specifies the batch, 0 reverts all, negative refers to the relative batch (e.g., -3 means "three batches back") + :param mixed $group: database group name, if null default database group will be used. + :returns: ``true`` on success, ``false`` on failure or no migrations are found + :rtype: bool - Regress can be used to roll back changes to a previous state, batch by batch. - :: + Regress can be used to roll back changes to a previous state, batch by batch. + :: - $migration->regress(5); - $migration->regress(-1); + $migration->regress(5); + $migration->regress(-1); - .. php:method:: force($path, $namespace, $group) + .. php:method:: force($path, $namespace, $group) - :param mixed $path: path to a valid migration file. - :param mixed $namespace: namespace of the provided migration. - :param mixed $group: database group name, if null default database group will be used. - :returns: ``true`` on success, ``false`` on failure - :rtype: bool + :param mixed $path: path to a valid migration file. + :param mixed $namespace: namespace of the provided migration. + :param mixed $group: database group name, if null default database group will be used. + :returns: ``true`` on success, ``false`` on failure + :rtype: bool - This forces a single file to migrate regardless of order or batches. Method "up" or "down" is detected based on whether it has already been migrated. + This forces a single file to migrate regardless of order or batches. Method "up" or "down" is detected based on whether it has already been migrated. - .. note:: This method is recommended only for testing and could cause data consistency issues. + .. note:: This method is recommended only for testing and could cause data consistency issues. - .. php:method:: setNamespace($namespace) + .. php:method:: setNamespace($namespace) - :param string $namespace: application namespace. - :returns: The current MigrationRunner instance - :rtype: CodeIgniter\\Database\\MigrationRunner + :param string $namespace: application namespace. + :returns: The current MigrationRunner instance + :rtype: CodeIgniter\\Database\\MigrationRunner - Sets the namespace the library should look for migration files:: + Sets the namespace the library should look for migration files:: - $migration->setNamespace($namespace)->latest(); - .. php:method:: setGroup($group) + $migration->setNamespace($namespace)->latest(); - :param string $group: database group name. - :returns: The current MigrationRunner instance - :rtype: CodeIgniter\\Database\\MigrationRunner + .. php:method:: setGroup($group) - Sets the group the library should look for migration files:: + :param string $group: database group name. + :returns: The current MigrationRunner instance + :rtype: CodeIgniter\\Database\\MigrationRunner - $migration->setGroup($group)->latest(); + Sets the group the library should look for migration files:: + + $migration->setGroup($group)->latest(); From 094b95a62fdd627b761268053e2c93444d89a68e Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Sep 2021 12:09:00 +0900 Subject: [PATCH 0278/2325] docs: add new line at end of file --- user_guide_src/source/database/call_function.rst | 2 +- user_guide_src/source/database/index.rst | 2 +- user_guide_src/source/general/ajax.rst | 2 +- user_guide_src/source/helpers/number_helper.rst | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/database/call_function.rst b/user_guide_src/source/database/call_function.rst index 6c0453146cd6..9617c2361df0 100644 --- a/user_guide_src/source/database/call_function.rst +++ b/user_guide_src/source/database/call_function.rst @@ -40,4 +40,4 @@ The result ID can be accessed from within your result object, like this:: $query = $db->query("SOME QUERY"); - $query->resultID; \ No newline at end of file + $query->resultID; diff --git a/user_guide_src/source/database/index.rst b/user_guide_src/source/database/index.rst index 62002afd00a8..73cd1a4ecff9 100644 --- a/user_guide_src/source/database/index.rst +++ b/user_guide_src/source/database/index.rst @@ -20,4 +20,4 @@ patterns. The database functions offer clear, simple syntax. Getting MetaData Custom Function Calls Database Events - Database Utilities \ No newline at end of file + Database Utilities diff --git a/user_guide_src/source/general/ajax.rst b/user_guide_src/source/general/ajax.rst index 6324930b199b..710406b41272 100644 --- a/user_guide_src/source/general/ajax.rst +++ b/user_guide_src/source/general/ajax.rst @@ -50,4 +50,4 @@ React .. code-block:: javascript - axios.get("your url", {headers: {'Content-Type': 'application/json'}}) \ No newline at end of file + axios.get("your url", {headers: {'Content-Type': 'application/json'}}) diff --git a/user_guide_src/source/helpers/number_helper.rst b/user_guide_src/source/helpers/number_helper.rst index 2c6c5045ac77..ae5f8238b156 100644 --- a/user_guide_src/source/helpers/number_helper.rst +++ b/user_guide_src/source/helpers/number_helper.rst @@ -115,4 +115,4 @@ The following functions are available: echo number_to_roman(2534); // Returns MMDXXXIV This function only handles numbers in the range 1 through 3999. - It will return null for any value outside that range . \ No newline at end of file + It will return null for any value outside that range. From 7610085940b2831d9d63bc62c26505a61b51b04b Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Sep 2021 12:09:35 +0900 Subject: [PATCH 0279/2325] docs: replace tab with space --- user_guide_src/source/testing/controllers.rst | 46 +++++++++---------- user_guide_src/source/testing/feature.rst | 6 +-- user_guide_src/source/testing/overview.rst | 26 +++++------ user_guide_src/source/testing/response.rst | 8 ++-- 4 files changed, 43 insertions(+), 43 deletions(-) diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst index 464a06c5fbcd..4333ad26ec0e 100644 --- a/user_guide_src/source/testing/controllers.rst +++ b/user_guide_src/source/testing/controllers.rst @@ -209,13 +209,13 @@ on an unfiltered route you could add it to the Config:: { use FilterTestTrait; - protected function testFilterFailsOnAdminRoute() - { - $this->filtersConfig->globals['before'] = ['admin-only-filter']; + protected function testFilterFailsOnAdminRoute() + { + $this->filtersConfig->globals['before'] = ['admin-only-filter']; - $this->assertHasFilters('unfiltered/route', 'before'); - } - ... + $this->assertHasFilters('unfiltered/route', 'before'); + } + ... Checking Routes --------------- @@ -227,14 +227,14 @@ a large performance advantage over Controller and HTTP Testing. .. php:function:: getFiltersForRoute($route, $position) - :param string $route: The URI to check - :param string $position: The filter method to check, "before" or "after" - :returns: Aliases for each filter that would have run - :rtype: string[] + :param string $route: The URI to check + :param string $position: The filter method to check, "before" or "after" + :returns: Aliases for each filter that would have run + :rtype: string[] Usage example:: - $result = $this->getFiltersForRoute('/', 'after'); // ['toolbar'] + $result = $this->getFiltersForRoute('/', 'after'); // ['toolbar'] Calling Filter Methods ---------------------- @@ -245,22 +245,22 @@ method using these properties to test your Filter code safely and check the resu .. php:function:: getFilterCaller($filter, $position) - :param FilterInterface|string $filter: The filter instance, class, or alias - :param string $position: The filter method to run, "before" or "after" - :returns: A callable method to run the simulated Filter event - :rtype: Closure + :param FilterInterface|string $filter: The filter instance, class, or alias + :param string $position: The filter method to run, "before" or "after" + :returns: A callable method to run the simulated Filter event + :rtype: Closure Usage example:: - protected function testUnauthorizedAccessRedirects() - { - $caller = $this->getFilterCaller('permission', 'before'); - $result = $caller('MayEditWidgets'); + protected function testUnauthorizedAccessRedirects() + { + $caller = $this->getFilterCaller('permission', 'before'); + $result = $caller('MayEditWidgets'); + + $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); + } - $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); - } - - Notice how the ``Closure`` can take input parameters which are passed to your filter method. + Notice how the ``Closure`` can take input parameters which are passed to your filter method. Assertions ---------- diff --git a/user_guide_src/source/testing/feature.rst b/user_guide_src/source/testing/feature.rst index 6ec786c67079..c48c24b221c5 100644 --- a/user_guide_src/source/testing/feature.rst +++ b/user_guide_src/source/testing/feature.rst @@ -29,20 +29,20 @@ are called if you implement your own methods. class TestFoo extends FeatureTestCase { - use DatabaseTestTrait, FeatureTestTrait; + use DatabaseTestTrait, FeatureTestTrait; protected function setUp(): void { parent::setUp(); - $this->myClassMethod(); + $this->myClassMethod(); } protected function tearDown(): void { parent::tearDown(); - $this->anotherClassMethod(); + $this->anotherClassMethod(); } } diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 28e99b9b4bbc..f237acc03412 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -159,19 +159,19 @@ to run named for the trait itself. For example, if you needed to add authenticat of your test cases you could create an authentication trait with a set up method to fake a logged in user:: - trait AuthTrait - { - protected setUpAuthTrait() - { - $user = $this->createFakeUser(); - $this->logInUser($user); - } - ... - - class AuthenticationFeatureTest - { - use AuthTrait; - ... + trait AuthTrait + { + protected setUpAuthTrait() + { + $user = $this->createFakeUser(); + $this->logInUser($user); + } + ... + + class AuthenticationFeatureTest + { + use AuthTrait; + ... Additional Assertions diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index 4152feff03d1..e5e0f34852ff 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -7,8 +7,8 @@ from your test cases. Usually a ``TestResponse`` will be provided for you as a r `Controller Tests `_ or `HTTP Feature Tests `_, but you can always create your own directly using any ``ResponseInterface``:: - $result = new \CodeIgniter\Test\TestResponse($response); - $result->assertOK(); + $result = new \CodeIgniter\Test\TestResponse($response); + $result->assertOK(); Testing the Response ==================== @@ -299,8 +299,8 @@ This method will return the body of the response as a JSON string:: You can use this method to determine if ``$response`` actually holds JSON content:: - // Verify the response is JSON - $this->assertTrue($result->getJSON() !== false) + // Verify the response is JSON + $this->assertTrue($result->getJSON() !== false) .. note:: Be aware that the JSON string will be pretty-printed in the result. From b57266c4be8e0c5a2e9fe5f9046cf5305ee169d6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Sep 2021 12:10:10 +0900 Subject: [PATCH 0280/2325] docs: fix typo in Factories --- system/Config/Factories.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Config/Factories.php b/system/Config/Factories.php index 8aa779220aed..8bcef3e09610 100644 --- a/system/Config/Factories.php +++ b/system/Config/Factories.php @@ -17,7 +17,7 @@ /** * Factories for creating instances. * - * Factories allows dynamic loading of components by their path + * Factories allow dynamic loading of components by their path * and name. The "shared instance" implementation provides a * large performance boost and helps keep code clean of lengthy * instantiation checks. From 0261a26622b6353114af72a8a03de0e5b069f4f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Sep 2021 14:39:46 +0900 Subject: [PATCH 0281/2325] docs: fix api responses * docs: add a space before and after `=` * docs: replace tab with space * docs: fix description and RST format * docs: add `$this->` and empty line --- .../source/outgoing/api_responses.rst | 93 +++++++++++-------- 1 file changed, 52 insertions(+), 41 deletions(-) diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index 4758fe4f02bb..99e89783f7d5 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -43,29 +43,40 @@ In this example, an HTTP status code of 201 is returned, with the generic status exist for the most common use cases:: // Generic response method - respond($data, 200); + $this->respond($data, 200); + // Generic failure response - fail($errors, 400); + $this->fail($errors, 400); + // Item created response - respondCreated($data); + $this->respondCreated($data); + // Item successfully deleted - respondDeleted($data); + $this->respondDeleted($data); + // Command executed by no response required - respondNoContent($message); + $this->respondNoContent($message); + // Client isn't authorized - failUnauthorized($description); + $this->failUnauthorized($description); + // Forbidden action - failForbidden($description); + $this->failForbidden($description); + // Resource Not Found - failNotFound($description); + $this->failNotFound($description); + // Data did not validate - failValidationError($description); + $this->failValidationError($description); + // Resource already exists - failResourceExists($description); + $this->failResourceExists($description); + // Resource previously deleted - failResourceGone($description); + $this->failResourceGone($description); + // Client made too many requests - failTooManyRequests($description); + $this->failTooManyRequests($description); *********************** Handling Response Types @@ -74,10 +85,10 @@ Handling Response Types When you pass your data in any of these methods, they will determine the data type to format the results as based on the following criteria: -* If $data is a string, it will be treated as HTML to send back to the client. -* If $data is an array, it will be formatted according to the controller's ``$this->format`` value. If that is empty - it will try to negotiate the content type with what the client asked for, defaulting to JSON - if nothing else has been specified within Config\API.php, the ``$supportedResponseFormats`` property. +* If data is a string, it will be treated as HTML to send back to the client. +* If data is an array, it will be formatted according to the controller's ``$this->format`` value. If that is empty, + it will try to negotiate the content type with what the client asked for, defaulting to JSON + if nothing else has been specified within **Config/Format.php**, the ``$supportedResponseFormats`` property. To define the formatter that is used, edit **Config/Format.php**. The ``$supportedResponseFormats`` contains a list of mime types that your application can automatically format the response for. By default, the system knows how to @@ -119,7 +130,7 @@ Class Reference return $this->setResponseFormat('json')->respond(['error' => false]); -.. php:method:: respond($data[, $statusCode=200[, $message='']]) +.. php:method:: respond($data[, $statusCode = 200[, $message = '']]) :param mixed $data: The data to return to the client. Either string or array. :param int $statusCode: The HTTP status code to return. Defaults to 200 @@ -138,7 +149,7 @@ Class Reference .. note:: Since it sets the status code and body on the active Response instance, this should always be the final method in the script execution. -.. php:method:: fail($messages[, int $status=400[, string $code=null[, string $message='']]]) +.. php:method:: fail($messages[, int $status = 400[, string $code = null[, string $message = '']]]) :param mixed $messages: A string or array of strings that contain error messages encountered. :param int $status: The HTTP status code to return. Defaults to 400. @@ -162,14 +173,14 @@ Class Reference The response is an array with two elements: ``error`` and ``messages``. The ``error`` element contains the status code of the error. The ``messages`` element contains an array of error messages. It would look something like:: - $response = [ - 'status' => 400, - 'code' => '321a', - 'messages' => [ - 'Error message 1', - 'Error message 2', - ], - ]; + $response = [ + 'status' => 400, + 'code' => '321a', + 'messages' => [ + 'Error message 1', + 'Error message 2', + ], + ]; .. php:method:: respondCreated($data = null[, string $message = '']) @@ -179,8 +190,8 @@ Class Reference Sets the appropriate status code to use when a new resource was created, typically 201.:: - $user = $userModel->insert($data); - return $this->respondCreated($user); + $user = $userModel->insert($data); + return $this->respondCreated($user); .. php:method:: respondDeleted($data = null[, string $message = '']) @@ -192,8 +203,8 @@ Class Reference :: - $user = $userModel->delete($id); - return $this->respondDeleted(['id' => $id]); + $user = $userModel->delete($id); + return $this->respondDeleted(['id' => $id]); .. php:method:: respondNoContent(string $message = 'No Content') @@ -205,10 +216,10 @@ Class Reference :: - sleep(1); - return $this->respondNoContent(); + sleep(1); + return $this->respondNoContent(); -.. php:method:: failUnauthorized(string $description = 'Unauthorized'[, string $code=null[, string $message = '']]) +.. php:method:: failUnauthorized(string $description = 'Unauthorized'[, string $code = null[, string $message = '']]) :param string $description: The error message to show the user. :param string $code: A custom, API-specific, error code. @@ -220,7 +231,7 @@ Class Reference :: - return $this->failUnauthorized('Invalid Auth token'); + return $this->failUnauthorized('Invalid Auth token'); .. php:method:: failForbidden(string $description = 'Forbidden'[, string $code=null[, string $message = '']]) @@ -235,7 +246,7 @@ Class Reference :: - return $this->failForbidden('Invalid API endpoint.'); + return $this->failForbidden('Invalid API endpoint.'); .. php:method:: failNotFound(string $description = 'Not Found'[, string $code=null[, string $message = '']]) @@ -248,7 +259,7 @@ Class Reference :: - return $this->failNotFound('User 13 cannot be found.'); + return $this->failNotFound('User 13 cannot be found.'); .. php:method:: failValidationErrors($errors[, string $code=null[, string $message = '']]) @@ -261,7 +272,7 @@ Class Reference :: - return $this->failValidationErrors($validation->getErrors()); + return $this->failValidationErrors($validation->getErrors()); .. php:method:: failResourceExists(string $description = 'Conflict'[, string $code=null[, string $message = '']]) @@ -275,7 +286,7 @@ Class Reference :: - return $this->failResourceExists('A user already exists with that email.'); + return $this->failResourceExists('A user already exists with that email.'); .. php:method:: failResourceGone(string $description = 'Gone'[, string $code=null[, string $message = '']]) @@ -289,7 +300,7 @@ Class Reference :: - return $this->failResourceGone('That user has been previously deleted.'); + return $this->failResourceGone('That user has been previously deleted.'); .. php:method:: failTooManyRequests(string $description = 'Too Many Requests'[, string $code=null[, string $message = '']]) @@ -303,7 +314,7 @@ Class Reference :: - return $this->failTooManyRequests('You must wait 15 seconds before making another request.'); + return $this->failTooManyRequests('You must wait 15 seconds before making another request.'); .. php:method:: failServerError(string $description = 'Internal Server Error'[, string $code = null[, string $message = '']]) @@ -316,4 +327,4 @@ Class Reference :: - return $this->failServerError('Server error.'); + return $this->failServerError('Server error.'); From 3ab742eb6ab6d655e357c8a35493d2b84d63c643 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Sep 2021 18:42:02 +0900 Subject: [PATCH 0282/2325] chore: remove --using-cache=no from php-cs-fixer --- admin/pre-commit | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/pre-commit b/admin/pre-commit index d05724d58146..ffa9936ca9c9 100644 --- a/admin/pre-commit +++ b/admin/pre-commit @@ -52,9 +52,9 @@ if [ "$FILES" != "" ]; then # Run on whole codebase to skip on unnecessary filtering # Run first on app, admin, public if [ -d /proc/cygdrive ]; then - ./vendor/bin/php-cs-fixer fix --verbose --dry-run --using-cache=no --diff --config=.no-header.php-cs-fixer.dist.php + ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php else - php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --using-cache=no --diff --config=.no-header.php-cs-fixer.dist.php + php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php fi if [ $? != 0 ]; then @@ -64,9 +64,9 @@ if [ "$FILES" != "" ]; then # Next, run on system, tests, utils, and root PHP files if [ -d /proc/cygdrive ]; then - ./vendor/bin/php-cs-fixer fix --verbose --dry-run --using-cache=no --diff + ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff else - php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --using-cache=no --diff + php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff fi if [ $? != 0 ]; then From ec6288615fb5f19bd4c00a7926d70ab04cf239d7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Sep 2021 21:50:52 +0900 Subject: [PATCH 0283/2325] docs: fix cli library --- user_guide_src/source/cli/cli_library.rst | 28 +++++++++++++++++------ 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 41638272eaa5..6ba08ab80554 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -59,7 +59,7 @@ Finally, you can pass :ref:`validation ` rules to the answer input a Validation rules can also be written in the array syntax.:: - $email = CLI::prompt('What is your email?', null, ['required', 'valid_email']); + $email = CLI::prompt('What is your email?', null, ['required', 'valid_email']); **promptByKey()** @@ -199,6 +199,15 @@ on the right with their descriptions. By default, this will wrap back to the lef doesn't allow things to line up in columns. In cases like this, you can pass in a number of spaces to pad every line after the first line, so that you will have a crisp column edge on the left:: + $titles = [ + 'task1a', + 'task1abc', + ]; + $descriptions = [ + 'Lorem Ipsum is simply dummy text of the printing and typesetting industry.', + "Lorem Ipsum has been the industry's standard dummy text ever since the", + ]; + // Determine the maximum length of all titles // to determine the width of the left column $maxlen = max(array_map('strlen', $titles)); @@ -206,7 +215,11 @@ every line after the first line, so that you will have a crisp column edge on th for ($i = 0; $i < count($titles); $i++) { CLI::write( // Display the title on the left of the row - $titles[$i] . ' ' . + substr( + $titles[$i] . str_repeat(' ', $maxlen + 3), + 0, + $maxlen + 3 + ) . // Wrap the descriptions in a right-hand column // with its left side 3 characters wider than // the longest item on the left. @@ -218,11 +231,12 @@ Would create something like this: .. code-block:: none - task1a Lorem Ipsum is simply dummy - text of the printing and typesetting - industry. - task1abc Lorem Ipsum has been the industry's - standard dummy text ever since the + task1a Lorem Ipsum is simply dummy + text of the printing and + typesetting industry. + task1abc Lorem Ipsum has been the + industry's standard dummy + text ever since the **newLine()** From 640a11e3731205ddf6c882734c08d8db23cb4fa7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Sep 2021 21:52:39 +0900 Subject: [PATCH 0284/2325] chore: add `composer cs` and `composer cs-fix` --- composer.json | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 13454e9d77ec..25ec1512ad23 100644 --- a/composer.json +++ b/composer.json @@ -60,7 +60,21 @@ "bash -c \"if [ -f admin/setup.sh ]; then bash admin/setup.sh; fi\"" ], "analyze": "phpstan analyse", - "test": "phpunit" + "test": "phpunit", + "cs": [ + "php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php", + "php-cs-fixer fix --verbose --dry-run --diff" + ], + "cs-fix": [ + "php-cs-fixer fix --verbose --diff --config=.no-header.php-cs-fixer.dist.php", + "php-cs-fixer fix --verbose --diff" + ] + }, + "scripts-descriptions": { + "analyze": "Run static analysis", + "test": "Run unit tests", + "cs": "Check the coding style", + "cs-fix": "Fix the coding style" }, "support": { "forum": "http://forum.codeigniter.com/", From 8f81ebad484ba10f64cb5d4194b43a048165ce43 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 17 Sep 2021 05:11:14 +0700 Subject: [PATCH 0285/2325] [Rector] Apply Rector: SimplifyEmptyArrayCheckRector --- rector.php | 2 ++ system/View/Cell.php | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rector.php b/rector.php index 931b89304416..aa9546d37ca9 100644 --- a/rector.php +++ b/rector.php @@ -9,6 +9,7 @@ * the LICENSE file that was distributed with this source code. */ +use Rector\CodeQuality\Rector\BooleanAnd\SimplifyEmptyArrayCheckRector; use Rector\CodeQuality\Rector\Expression\InlineIfToExplicitIfRector; use Rector\CodeQuality\Rector\For_\ForToForeachRector; use Rector\CodeQuality\Rector\Foreach_\UnusedForeachValueToArrayKeysRector; @@ -131,4 +132,5 @@ $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); $services->set(FixClassCaseSensitivityNameRector::class); + $services->set(SimplifyEmptyArrayCheckRector::class); }; diff --git a/system/View/Cell.php b/system/View/Cell.php index 7affd2742049..50168a153be6 100644 --- a/system/View/Cell.php +++ b/system/View/Cell.php @@ -174,7 +174,7 @@ public function prepareParams($params) unset($newParams); } - if (is_array($params) && empty($params)) { + if ($params === []) { return []; } From e9c452e3c92e77f2ec07c43bee7fc7f70d4bc9f2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Sep 2021 18:04:30 +0900 Subject: [PATCH 0286/2325] docs: replace tab with space --- .../source/extending/basecontroller.rst | 38 ++-- .../source/extending/core_classes.rst | 16 +- .../source/helpers/cookie_helper.rst | 28 +-- user_guide_src/source/helpers/xml_helper.rst | 2 +- .../source/incoming/controllers.rst | 2 +- .../source/libraries/curlrequest.rst | 196 +++++++++--------- .../source/outgoing/alternative_php.rst | 28 +-- 7 files changed, 155 insertions(+), 155 deletions(-) diff --git a/user_guide_src/source/extending/basecontroller.rst b/user_guide_src/source/extending/basecontroller.rst index 424329257fc1..bd5a76bf2386 100644 --- a/user_guide_src/source/extending/basecontroller.rst +++ b/user_guide_src/source/extending/basecontroller.rst @@ -6,16 +6,16 @@ CodeIgniter's core Controller should not be changed, but a default class extensi **app/Controllers/BaseController.php**. Any new controllers you make should extend ``BaseController`` to take advantage of preloaded components and any additional functionality you provide:: - session = \Config\Services::session(); - } + public function initController(...) + { + // Do Not Edit This Line + parent::initController($request, $response, $logger); + + $this->session = \Config\Services::session(); + } Additional Methods ================== @@ -54,7 +54,7 @@ the public controllers and make ``AdminController`` for any administrative contr If you do not want to use the base controller you may bypass it by having your controllers extend the system Controller instead:: - class Home extends \CodeIgniter\Controller - { - - } + class Home extends \CodeIgniter\Controller + { + + } diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index 6d7b0c9a3b64..2e856f1eeaed 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -62,14 +62,14 @@ the core system class, you would create your class like this:: Then you would modify the ``routes`` service to load your class instead:: - public static function routes(bool $getShared = true) - { - if ($getShared) { - return static::getSharedInstance('routes'); - } - - return new RouteCollection(static::locator(), config('Modules')); - } + public static function routes(bool $getShared = true) + { + if ($getShared) { + return static::getSharedInstance('routes'); + } + + return new RouteCollection(static::locator(), config('Modules')); + } Extending Core Classes ====================== diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 4175bb2b99c4..2a7f0e6e6c43 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -22,16 +22,16 @@ The following functions are available: .. php:function:: set_cookie($name[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = false[, $httpOnly = false[, $sameSite = '']]]]]]]]) - :param mixed $name: Cookie name *or* associative array of all of the parameters available to this function - :param string $value: Cookie value - :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 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 `config/App.php` is used - :rtype: void + :param mixed $name: Cookie name *or* associative array of all of the parameters available to this function + :param string $value: Cookie value + :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 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 `config/App.php` is used + :rtype: void This helper function gives you friendlier syntax to set browser cookies. Refer to the :doc:`Response Library ` for @@ -40,10 +40,10 @@ The following functions are available: .. php:function:: get_cookie($index[, $xssClean = false]) - :param string $index: Cookie name - :param bool $xss_clean: Whether to apply XSS filtering to the returned value - :returns: The cookie value or null if not found - :rtype: mixed + :param string $index: Cookie name + :param bool $xss_clean: Whether to apply XSS filtering to the returned value + :returns: The cookie value or null if not found + :rtype: mixed This helper function gives you friendlier syntax to get browser cookies. Refer to the :doc:`IncomingRequest Library ` for diff --git a/user_guide_src/source/helpers/xml_helper.rst b/user_guide_src/source/helpers/xml_helper.rst index 4f7ff453384a..ebccaca79f91 100644 --- a/user_guide_src/source/helpers/xml_helper.rst +++ b/user_guide_src/source/helpers/xml_helper.rst @@ -27,7 +27,7 @@ The following functions are available: :param string $str: the text string to convert :param bool $protect_all: Whether to protect all content that looks like a potential entity instead of just numbered entities, e.g., &foo; :returns: XML-converted string - :rtype: string + :rtype: string Takes a string as input and converts the following reserved XML characters to entities: diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 49075fc84500..dfca82fea06e 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -262,7 +262,7 @@ if you were to define a method like this for the `Helloworld` controller:: then trying to access it using the following URL will not work:: - example.com/index.php/helloworld/utility/ + example.com/index.php/helloworld/utility/ Organizing Your Controllers into Sub-directories ================================================ diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index 08dc0c0a41c9..c9c69ea7ae08 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -27,27 +27,27 @@ The library can be loaded either manually or through the :doc:`Services class 'http://example.com/api/v1/', - 'timeout' => 3, - ]; - $client = \Config\Services::curlrequest($options); + $options = [ + 'baseURI' => 'http://example.com/api/v1/', + 'timeout' => 3, + ]; + $client = \Config\Services::curlrequest($options); When creating the class manually, you need to pass a few dependencies in. The first parameter is an instance of the ``Config\App`` class. The second parameter is a URI instance. The third parameter is a Response object. The fourth parameter is the optional ``$options`` array:: - $client = new \CodeIgniter\HTTP\CURLRequest( - new \Config\App(), - new \CodeIgniter\HTTP\URI(), - new \CodeIgniter\HTTP\Response(new \Config\App()), - $options - ); + $client = new \CodeIgniter\HTTP\CURLRequest( + new \Config\App(), + new \CodeIgniter\HTTP\URI(), + new \CodeIgniter\HTTP\Response(new \Config\App()), + $options + ); ************************ Working with the Library @@ -64,19 +64,19 @@ Most communication is done through the ``request()`` method, which fires off the a Response instance to you. This takes the HTTP method, the url and an array of options as the parameters. :: - $client = \Config\Services::curlrequest(); + $client = \Config\Services::curlrequest(); - $response = $client->request('GET', 'https://api.github.com/user', [ - 'auth' => ['user', 'pass'], - ]); + $response = $client->request('GET', 'https://api.github.com/user', [ + 'auth' => ['user', 'pass'], + ]); Since the response is an instance of ``CodeIgniter\HTTP\Response`` you have all of the normal information available to you:: - echo $response->getStatusCode(); - echo $response->getBody(); - echo $response->getHeader('Content-Type'); - $language = $response->negotiateLanguage(['en', 'fr']); + echo $response->getStatusCode(); + echo $response->getBody(); + echo $response->getHeader('Content-Type'); + $language = $response->negotiateLanguage(['en', 'fr']); While the ``request()`` method is the most flexible, you can also use the following shortcut methods. They each take the URL as the first parameter and an array of options as the second:: @@ -96,31 +96,31 @@ A ``baseURI`` can be set as one of the options during the instantiation of the c set a base URI, and then make all requests with that client using relative URLs. This is especially handy when working with APIs:: - $client = \Config\Services::curlrequest([ - 'baseURI' => 'https://example.com/api/v1/', - ]); + $client = \Config\Services::curlrequest([ + 'baseURI' => 'https://example.com/api/v1/', + ]); - // GET http:example.com/api/v1/photos - $client->get('photos'); + // GET http:example.com/api/v1/photos + $client->get('photos'); - // GET http:example.com/api/v1/photos/13 - $client->delete('photos/13'); + // GET http:example.com/api/v1/photos/13 + $client->delete('photos/13'); When a relative URI is provided to the ``request()`` method or any of the shortcut methods, it will be combined with the baseURI according to the rules described by `RFC 2986, section 2 `_. To save you some time, here are some examples of how the combinations are resolved. - ===================== ================ ======================== - baseURI URI Result - ===================== ================ ======================== - `http://foo.com` /bar `http://foo.com/bar` - `http://foo.com/foo` /bar `http://foo.com/bar` - `http://foo.com/foo` bar `http://foo.com/bar` - `http://foo.com/foo/` bar `http://foo.com/foo/bar` - `http://foo.com` `http://baz.com` `http://baz.com` - `http://foo.com/?bar` bar `http://foo.com/bar` - ===================== ================ ======================== + ===================== ================ ======================== + baseURI URI Result + ===================== ================ ======================== + `http://foo.com` /bar `http://foo.com/bar` + `http://foo.com/foo` /bar `http://foo.com/bar` + `http://foo.com/foo` bar `http://foo.com/bar` + `http://foo.com/foo/` bar `http://foo.com/foo/bar` + `http://foo.com` `http://baz.com` `http://baz.com` + `http://foo.com/?bar` bar `http://foo.com/bar` + ===================== ================ ======================== Using Responses =============== @@ -130,29 +130,29 @@ methods. The most commonly used methods let you determine the response itself. You can get the status code and reason phrase of the response:: - $code = $response->getStatusCode(); // 200 - $reason = $response->getReason(); // OK + $code = $response->getStatusCode(); // 200 + $reason = $response->getReason(); // OK You can retrieve headers from the response:: - // Get a header line - echo $response->getHeaderLine('Content-Type'); + // Get a header line + echo $response->getHeaderLine('Content-Type'); - // Get all headers - foreach ($response->getHeaders() as $name => $value) { - echo $name .': '. $response->getHeaderLine($name) ."\n"; - } + // Get all headers + foreach ($response->getHeaders() as $name => $value) { + echo $name .': '. $response->getHeaderLine($name) ."\n"; + } The body can be retrieved using the ``getBody()`` method:: - $body = $response->getBody(); + $body = $response->getBody(); The body is the raw body provided by the remote getServer. If the content type requires formatting, you will need to ensure that your script handles that:: - if (strpos($response->getHeader('content-type'), 'application/json') !== false) { - $body = json_decode($body); - } + if (strpos($response->getHeader('content-type'), 'application/json') !== false) { + $body = json_decode($body); + } *************** Request Options @@ -169,23 +169,23 @@ allows you to modify how that works. If you set the value to ``false``, then it will not follow any redirects at all:: - $client->request('GET', 'http://example.com', ['allow_redirects' => false]); + $client->request('GET', 'http://example.com', ['allow_redirects' => false]); Setting it to ``true`` will apply the default settings to the request:: - $client->request('GET', 'http://example.com', ['allow_redirects' => true]); + $client->request('GET', 'http://example.com', ['allow_redirects' => true]); - // Sets the following defaults: - 'max' => 5, // Maximum number of redirects to follow before stopping - 'strict' => true, // Ensure POST requests stay POST requests through redirects - 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols + // Sets the following defaults: + 'max' => 5, // Maximum number of redirects to follow before stopping + 'strict' => true, // Ensure POST requests stay POST requests through redirects + 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols You can pass in array as the value of the ``allow_redirects`` option to specify new settings in place of the defaults:: - $client->request('GET', 'http://example.com', ['allow_redirects' => [ - 'max' => 10, - 'protocols' => ['https'] // Force HTTPS domains only. - ]]); + $client->request('GET', 'http://example.com', ['allow_redirects' => [ + 'max' => 10, + 'protocols' => ['https'] // Force HTTPS domains only. + ]]); .. note:: Following redirects does not work when PHP is in safe_mode or open_basedir is enabled. @@ -198,7 +198,7 @@ Digest authentication - this simply passes the username and password along for y array where the first element is the username, and the second is the password. The third parameter should be the type of authentication to use, either ``basic`` or ``digest``:: - $client->request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]); + $client->request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]); body ==== @@ -206,12 +206,12 @@ body There are two ways to set the body of the request for request types that support them, like PUT, OR POST. The first way is to use the ``setBody()`` method:: - $client->setBody($body) ->request('put', 'http://example.com'); + $client->setBody($body) ->request('put', 'http://example.com'); The second method is by passing a ``body`` option in. This is provided to maintain Guzzle API compatibility, and functions the exact same way as the previous example. The value must be a string:: - $client->request('put', 'http://example.com', ['body' => $body]); + $client->request('put', 'http://example.com', ['body' => $body]); cert ==== @@ -229,7 +229,7 @@ By default, CodeIgniter does not impose a limit for cURL to attempt to connect t modify this value, you can do so by passing the amount of time in seconds with the ``connect_timeout`` option. You can pass 0 to wait indefinitely:: - $response->request('GET', 'http://example.com', ['connect_timeout' => 0]); + $response->request('GET', 'http://example.com', ['connect_timeout' => 0]); cookie ====== @@ -238,7 +238,7 @@ This specifies the filename that CURL should use to read cookie values from, and to save cookie values to. This is done using the CURL_COOKIEJAR and CURL_COOKIEFILE options. An example:: - $response->request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); + $response->request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); debug ===== @@ -248,19 +248,19 @@ script execution. This is done by passing CURLOPT_VERBOSE and echoing the output server via ``spark serve`` you will see the output in the console. Otherwise, the output will be written to the server's error log. - $response->request('GET', 'http://example.com', ['debug' => true]); + $response->request('GET', 'http://example.com', ['debug' => true]); You can pass a filename as the value for debug to have the output written to a file:: - $response->request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); + $response->request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); delay ===== Allows you to pause a number of milliseconds before sending the request:: - // Delay for 2 seconds - $response->request('GET', 'http://example.com', ['delay' => 2000]); + // Delay for 2 seconds + $response->request('GET', 'http://example.com', ['delay' => 2000]); form_params =========== @@ -269,12 +269,12 @@ You can send form data in an application/x-www-form-urlencoded POST request by p the ``form_params`` option. This will set the ``Content-Type`` header to ``application/x-www-form-urlencoded`` if it's not already set:: - $client->request('POST', '/post', [ - 'form_params' => [ - 'foo' => 'bar', - 'baz' => ['hi', 'there'], - ], - ]); + $client->request('POST', '/post', [ + 'form_params' => [ + 'foo' => 'bar', + 'baz' => ['hi', 'there'], + ], + ]); .. note:: ``form_params`` cannot be used with the ``multipart`` option. You will need to use one or the other. Use ``form_params`` for ``application/x-www-form-urlencoded`` request, and ``multipart`` for ``multipart/form-data`` @@ -287,13 +287,13 @@ While you can set any headers this request needs by using the ``setHeader()`` me array of headers in as an option. Each key is the name of a header, and each value is a string or array of strings representing the header field values:: - $client->request('get', '/', [ - 'headers' => [ - 'User-Agent' => 'testing/1.0', - 'Accept' => 'application/json', - 'X-Foo' => ['Bar', 'Baz'], - ], - ]); + $client->request('get', '/', [ + 'headers' => [ + 'User-Agent' => 'testing/1.0', + 'Accept' => 'application/json', + 'X-Foo' => ['Bar', 'Baz'], + ], + ]); If headers are passed into the constructor they are treated as default values that will be overridden later by any further headers arrays or calls to ``setHeader()``. @@ -318,7 +318,7 @@ The ``json`` option is used to easily upload JSON encoded data as the body of a of ``application/json`` is added, overwriting any Content-Type that might be already set. The data provided to this option can be any value that ``json_encode()`` accepts:: - $response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]); + $response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]); .. note:: This option does not allow for any customization of the ``json_encode()`` function, or the Content-Type header. If you need that ability, you will need to encode the data manually, passing it through the ``setBody()`` @@ -332,10 +332,10 @@ the `CURLFile Class `_. The va of POST data to send. For safer usage, the legacy method of uploading files by prefixing their name with an `@` has been disabled. Any files that you want to send must be passed as instances of CURLFile:: - $post_data = [ - 'foo' => 'bar', - 'userfile' => new \CURLFile('/path/to/file.txt'), - ]; + $post_data = [ + 'foo' => 'bar', + 'userfile' => new \CURLFile('/path/to/file.txt'), + ]; .. note:: ``multipart`` cannot be used with the ``form_params`` option. You can only use one or the other. Use ``form_params`` for ``application/x-www-form-urlencoded`` requests, and ``multipart`` for ``multipart/form-data`` @@ -346,8 +346,8 @@ query You can pass along data to send as query string variables by passing an associative array as the ``query`` option:: - // Send a GET request to /get?foo=bar - $client->request('GET', '/get', ['query' => ['foo' => 'bar']]); + // Send a GET request to /get?foo=bar + $client->request('GET', '/get', ['query' => ['foo' => 'bar']]); timeout ======= @@ -355,14 +355,14 @@ timeout By default, cURL functions are allowed to run as long as they take, with no time limit. You can modify this with the ``timeout`` option. The value should be the number of seconds you want the functions to execute for. Use 0 to wait indefinitely:: - $response->request('GET', 'http://example.com', ['timeout' => 5]); + $response->request('GET', 'http://example.com', ['timeout' => 5]); user_agent ========== Allows specifying the User Agent for requests:: - $response->request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); + $response->request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); verify ====== @@ -373,14 +373,14 @@ will disable the certificate verification (this is insecure, and allows man-in-t to a string that contains the path to a CA bundle to enable verification with a custom certificate. The default value is true:: - // Use the system's CA bundle (this is the default setting) - $client->request('GET', '/', ['verify' => true]); + // Use the system's CA bundle (this is the default setting) + $client->request('GET', '/', ['verify' => true]); - // Use a custom SSL certificate on disk. - $client->request('GET', '/', ['verify' => '/path/to/cert.pem']); + // Use a custom SSL certificate on disk. + $client->request('GET', '/', ['verify' => '/path/to/cert.pem']); - // Disable validation entirely. (Insecure!) - $client->request('GET', '/', ['verify' => false]); + // Disable validation entirely. (Insecure!) + $client->request('GET', '/', ['verify' => false]); version ======= @@ -388,5 +388,5 @@ version To set the HTTP protocol to use, you can pass a string or float with the version number (typically either 1.0 or 1.1, 2.0 is currently unsupported.):: - // Force HTTP/1.0 - $client->request('GET', '/', ['version' => 1.0]); + // Force HTTP/1.0 + $client->request('GET', '/', ['version' => 1.0]); diff --git a/user_guide_src/source/outgoing/alternative_php.rst b/user_guide_src/source/outgoing/alternative_php.rst index 702953fee287..70a86e2ebb75 100644 --- a/user_guide_src/source/outgoing/alternative_php.rst +++ b/user_guide_src/source/outgoing/alternative_php.rst @@ -15,11 +15,11 @@ Alternative Echos Normally to echo, or print out a variable you would do this:: - + With the alternative syntax you can instead do it this way:: - + Alternative Control Structures ============================== @@ -27,15 +27,15 @@ Alternative Control Structures Controls structures, like if, for, foreach, and while can be written in a simplified format as well. Here is an example using ``foreach``:: -
      +
        - + -
      • +
      • - + -
      +
    Notice that there are no braces. Instead, the end brace is replaced with ``endforeach``. Each of the control structures listed above has a similar @@ -46,16 +46,16 @@ Also notice that instead of using a semicolon after each structure Here is another example, using ``if``/``elseif``/``else``. Notice the colons:: - + -

    Hi Sally

    +

    Hi Sally

    - + -

    Hi Joe

    +

    Hi Joe

    - + -

    Hi unknown user

    +

    Hi unknown user

    - + From dc5a313f3f3c6e281f003b27d99123e5ad6ac95c Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Sep 2021 14:19:13 +0900 Subject: [PATCH 0287/2325] docs: replace tab with space --- user_guide_src/source/helpers/text_helper.rst | 158 +++---- user_guide_src/source/libraries/email.rst | 396 +++++++++--------- .../source/libraries/encryption.rst | 172 ++++---- user_guide_src/source/libraries/images.rst | 166 ++++---- user_guide_src/source/libraries/publisher.rst | 388 ++++++++--------- user_guide_src/source/libraries/sessions.rst | 268 ++++++------ .../source/libraries/user_agent.rst | 178 ++++---- user_guide_src/source/outgoing/table.rst | 340 +++++++-------- user_guide_src/source/outgoing/views.rst | 164 ++++---- 9 files changed, 1115 insertions(+), 1115 deletions(-) diff --git a/user_guide_src/source/helpers/text_helper.rst b/user_guide_src/source/helpers/text_helper.rst index 6b875e3d7e36..98a6f3b9e332 100755 --- a/user_guide_src/source/helpers/text_helper.rst +++ b/user_guide_src/source/helpers/text_helper.rst @@ -21,10 +21,10 @@ The following functions are available: .. php:function:: random_string([$type = 'alnum'[, $len = 8]]) - :param string $type: Randomization type - :param int $len: Output string length - :returns: A random string - :rtype: string + :param string $type: Randomization type + :param int $len: Output string length + :returns: A random string + :rtype: string Generates a random string based on the type and length you specify. Useful for creating passwords or generating random hashes. @@ -47,11 +47,11 @@ The following functions are available: .. php:function:: increment_string($str[, $separator = '_'[, $first = 1]]) - :param string $str: Input string - :param string $separator: Separator to append a duplicate number with - :param int $first: Starting number - :returns: An incremented string - :rtype: string + :param string $str: Input string + :param string $separator: Separator to append a duplicate number with + :param int $first: Starting number + :returns: An incremented string + :rtype: string Increments a string by appending a number to it or increasing the number. Useful for creating "copies" or a file or duplicating database @@ -65,9 +65,9 @@ The following functions are available: .. php:function:: alternator($args) - :param mixed $args: A variable number of arguments - :returns: Alternated string(s) - :rtype: mixed + :param mixed $args: A variable number of arguments + :returns: Alternated string(s) + :rtype: mixed Allows two or more items to be alternated between, when cycling through a loop. Example:: @@ -90,9 +90,9 @@ The following functions are available: .. php:function:: reduce_double_slashes($str) - :param string $str: Input string - :returns: A string with normalized slashes - :rtype: string + :param string $str: Input string + :returns: A string with normalized slashes + :rtype: string Converts double slashes in a string to a single slash, except those found in URL protocol prefixes (e.g., http://). @@ -104,9 +104,9 @@ The following functions are available: .. php:function:: strip_slashes($data) - :param mixed $data: Input string or an array of strings - :returns: String(s) with stripped slashes - :rtype: mixed + :param mixed $data: Input string or an array of strings + :returns: String(s) with stripped slashes + :rtype: mixed Removes any slashes from an array of strings. @@ -132,11 +132,11 @@ The following functions are available: .. php:function:: reduce_multiples($str[, $character = ''[, $trim = false]]) - :param string $str: Text to search in - :param string $character: Character to reduce - :param bool $trim: Whether to also trim the specified character - :returns: Reduced string - :rtype: string + :param string $str: Text to search in + :param string $character: Character to reduce + :param bool $trim: Whether to also trim the specified character + :returns: Reduced string + :rtype: string Reduces multiple instances of a particular character occurring directly after each other. Example:: @@ -152,9 +152,9 @@ The following functions are available: .. php:function:: quotes_to_entities($str) - :param string $str: Input string - :returns: String with quotes converted to HTML entities - :rtype: string + :param string $str: Input string + :returns: String with quotes converted to HTML entities + :rtype: string Converts single and double quotes in a string to the corresponding HTML entities. Example:: @@ -164,9 +164,9 @@ The following functions are available: .. php:function:: strip_quotes($str) - :param string $str: Input string - :returns: String with quotes stripped - :rtype: string + :param string $str: Input string + :returns: String with quotes stripped + :rtype: string Removes single and double quotes from a string. Example:: @@ -175,11 +175,11 @@ The following functions are available: .. php:function:: word_limiter($str[, $limit = 100[, $end_char = '…']]) - :param string $str: Input string - :param int $limit: Limit - :param string $end_char: End character (usually an ellipsis) - :returns: Word-limited string - :rtype: string + :param string $str: Input string + :param int $limit: Limit + :param string $end_char: End character (usually an ellipsis) + :returns: Word-limited string + :rtype: string Truncates a string to the number of *words* specified. Example:: @@ -192,11 +192,11 @@ The following functions are available: .. php:function:: character_limiter($str[, $n = 500[, $end_char = '…']]) - :param string $str: Input string - :param int $n: Number of characters - :param string $end_char: End character (usually an ellipsis) - :returns: Character-limited string - :rtype: string + :param string $str: Input string + :param int $n: Number of characters + :param string $end_char: End character (usually an ellipsis) + :returns: Character-limited string + :rtype: string Truncates a string to the number of *characters* specified. It maintains the integrity of words so the character count may be slightly @@ -216,9 +216,9 @@ The following functions are available: .. php:function:: ascii_to_entities($str) - :param string $str: Input string - :returns: A string with ASCII values converted to entities - :rtype: string + :param string $str: Input string + :returns: A string with ASCII values converted to entities + :rtype: string Converts ASCII values to character entities, including high ASCII and MS Word characters that can cause problems when used in a web page, so that @@ -234,19 +234,19 @@ The following functions are available: .. php:function:: entities_to_ascii($str[, $all = true]) - :param string $str: Input string - :param bool $all: Whether to convert unsafe entities as well - :returns: A string with HTML entities converted to ASCII characters - :rtype: string + :param string $str: Input string + :param bool $all: Whether to convert unsafe entities as well + :returns: A string with HTML entities converted to ASCII characters + :rtype: string This function does the opposite of :php:func:`ascii_to_entities()`. It turns character entities back into ASCII. .. php:function:: convert_accented_characters($str) - :param string $str: Input string - :returns: A string with accented characters converted - :rtype: string + :param string $str: Input string + :returns: A string with accented characters converted + :rtype: string Transliterates high ASCII characters to low ASCII equivalents. Useful when non-English characters need to be used where only standard ASCII @@ -262,11 +262,11 @@ The following functions are available: .. php:function:: word_censor($str, $censored[, $replacement = '']) - :param string $str: Input string - :param array $censored: List of bad words to censor - :param string $replacement: What to replace bad words with - :returns: Censored string - :rtype: string + :param string $str: Input string + :param array $censored: List of bad words to censor + :param string $replacement: What to replace bad words with + :returns: Censored string + :rtype: string Enables you to censor words within a text string. The first parameter will contain the original string. The second will contain an array of @@ -281,9 +281,9 @@ The following functions are available: .. php:function:: highlight_code($str) - :param string $str: Input string - :returns: String with code highlighted via HTML - :rtype: string + :param string $str: Input string + :returns: String with code highlighted via HTML + :rtype: string Colorizes a string of code (PHP, HTML, etc.). Example:: @@ -294,12 +294,12 @@ The following functions are available: .. php:function:: highlight_phrase($str, $phrase[, $tag_open = ''[, $tag_close = '']]) - :param string $str: Input string - :param string $phrase: Phrase to highlight - :param string $tag_open: Opening tag used for the highlight - :param string $tag_close: Closing tag for the highlight - :returns: String with a phrase highlighted via HTML - :rtype: string + :param string $str: Input string + :param string $phrase: Phrase to highlight + :param string $tag_open: Opening tag used for the highlight + :param string $tag_close: Closing tag for the highlight + :returns: String with a phrase highlighted via HTML + :rtype: string Will highlight a phrase within a text string. The first parameter will contain the original string, the second will contain the phrase you wish @@ -327,10 +327,10 @@ The following functions are available: .. php:function:: word_wrap($str[, $charlim = 76]) - :param string $str: Input string - :param int $charlim: Character limit - :returns: Word-wrapped string - :rtype: string + :param string $str: Input string + :param int $charlim: Character limit + :returns: Word-wrapped string + :rtype: string Wraps text at the specified *character* count while maintaining complete words. @@ -350,12 +350,12 @@ The following functions are available: .. php:function:: ellipsize($str, $max_length[, $position = 1[, $ellipsis = '…']]) - :param string $str: Input string - :param int $max_length: String length limit - :param mixed $position: Position to split at (int or float) - :param string $ellipsis: What to use as the ellipsis character - :returns: Ellipsized string - :rtype: string + :param string $str: Input string + :param int $max_length: String length limit + :param mixed $position: Position to split at (int or float) + :param string $ellipsis: What to use as the ellipsis character + :returns: Ellipsized string + :rtype: string This function will strip tags from a string, split it at a defined maximum length, and insert an ellipsis. @@ -380,12 +380,12 @@ The following functions are available: .. php:function:: excerpt($text, $phrase = false, $radius = 100, $ellipsis = '...') - :param string $text: Text to extract an excerpt - :param string $phrase: Phrase or word to extract the text around - :param int $radius: Number of characters before and after $phrase - :param string $ellipsis: What to use as the ellipsis character - :returns: Excerpt. - :rtype: string + :param string $text: Text to extract an excerpt + :param string $phrase: Phrase or word to extract the text around + :param int $radius: Number of characters before and after $phrase + :param string $ellipsis: What to use as the ellipsis character + :returns: Excerpt. + :rtype: string This function will extract $radius number of characters before and after the central $phrase with an ellipsis before and after. diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index 55604ad6bbee..f57f3cf93d8d 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -32,17 +32,17 @@ set your preferences in the **app/Config/Email.php** file. Here is a basic example demonstrating how you might send email:: - $email = \Config\Services::email(); + $email = \Config\Services::email(); - $email->setFrom('your@example.com', 'Your Name'); - $email->setTo('someone@example.com'); - $email->setCC('another@another-example.com'); - $email->setBCC('them@their-example.com'); + $email->setFrom('your@example.com', 'Your Name'); + $email->setTo('someone@example.com'); + $email->setCC('another@another-example.com'); + $email->setBCC('them@their-example.com'); - $email->setSubject('Email Test'); - $email->setMessage('Testing the email class.'); + $email->setSubject('Email Test'); + $email->setMessage('Testing the email class.'); - $email->send(); + $email->send(); Setting Email Preferences ========================= @@ -56,15 +56,15 @@ Preferences are set by passing an array of preference values to the email initialize method. Here is an example of how you might set some preferences:: - $config['protocol'] = 'sendmail'; - $config['mailPath'] = '/usr/sbin/sendmail'; - $config['charset'] = 'iso-8859-1'; - $config['wordWrap'] = true; + $config['protocol'] = 'sendmail'; + $config['mailPath'] = '/usr/sbin/sendmail'; + $config['charset'] = 'iso-8859-1'; + $config['wordWrap'] = true; - $email->initialize($config); + $email->initialize($config); .. note:: Most of the preferences have default values that will be used - if you do not set them. + if you do not set them. Setting Email Preferences in a Config File ------------------------------------------ @@ -157,13 +157,13 @@ causing it to become un-clickable by the person receiving it. CodeIgniter lets you manually override word wrapping within part of your message like this:: - The text of your email that - gets wrapped normally. + The text of your email that + gets wrapped normally. - {unwrap}http://example.com/a_long_link_that_should_not_be_wrapped.html{/unwrap} + {unwrap}http://example.com/a_long_link_that_should_not_be_wrapped.html{/unwrap} - More text that will be - wrapped normally. + More text that will be + wrapped normally. Place the item you do not want word-wrapped between: {unwrap} {/unwrap} @@ -174,266 +174,266 @@ Class Reference .. php:class:: CodeIgniter\\Email\\Email - .. php:method:: setFrom($from[, $name = ''[, $returnPath = null]]) + .. php:method:: setFrom($from[, $name = ''[, $returnPath = null]]) - :param string $from: "From" e-mail address - :param string $name: "From" display name - :param string $returnPath: Optional email address to redirect undelivered e-mail to - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $from: "From" e-mail address + :param string $name: "From" display name + :param string $returnPath: Optional email address to redirect undelivered e-mail to + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the email address and name of the person sending the email:: + Sets the email address and name of the person sending the email:: - $email->setFrom('you@example.com', 'Your Name'); + $email->setFrom('you@example.com', 'Your Name'); - You can also set a Return-Path, to help redirect undelivered mail:: + You can also set a Return-Path, to help redirect undelivered mail:: - $email->setFrom('you@example.com', 'Your Name', 'returned_emails@example.com'); + $email->setFrom('you@example.com', 'Your Name', 'returned_emails@example.com'); - .. note:: Return-Path can't be used if you've configured 'smtp' as - your protocol. + .. note:: Return-Path can't be used if you've configured 'smtp' as + your protocol. - .. php:method:: setReplyTo($replyto[, $name = '']) + .. php:method:: setReplyTo($replyto[, $name = '']) - :param string $replyto: E-mail address for replies - :param string $name: Display name for the reply-to e-mail address - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $replyto: E-mail address for replies + :param string $name: Display name for the reply-to e-mail address + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the reply-to address. If the information is not provided the - information in the `setFrom <#setFrom>`_ method is used. Example:: + Sets the reply-to address. If the information is not provided the + information in the `setFrom <#setFrom>`_ method is used. Example:: - $email->setReplyTo('you@example.com', 'Your Name'); + $email->setReplyTo('you@example.com', 'Your Name'); - .. php:method:: setTo($to) + .. php:method:: setTo($to) - :param mixed $to: Comma-delimited string or an array of e-mail addresses - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param mixed $to: Comma-delimited string or an array of e-mail addresses + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the email address(s) of the recipient(s). Can be a single e-mail, - a comma-delimited list or an array:: + Sets the email address(s) of the recipient(s). Can be a single e-mail, + a comma-delimited list or an array:: - $email->setTo('someone@example.com'); + $email->setTo('someone@example.com'); - :: + :: - $email->setTo('one@example.com, two@example.com, three@example.com'); + $email->setTo('one@example.com, two@example.com, three@example.com'); - :: + :: - $email->setTo(['one@example.com', 'two@example.com', 'three@example.com']); + $email->setTo(['one@example.com', 'two@example.com', 'three@example.com']); - .. php:method:: setCC($cc) + .. php:method:: setCC($cc) - :param mixed $cc: Comma-delimited string or an array of e-mail addresses - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param mixed $cc: Comma-delimited string or an array of e-mail addresses + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the CC email address(s). Just like the "to", can be a single e-mail, - a comma-delimited list or an array. + Sets the CC email address(s). Just like the "to", can be a single e-mail, + a comma-delimited list or an array. - .. php:method:: setBCC($bcc[, $limit = '']) + .. php:method:: setBCC($bcc[, $limit = '']) - :param mixed $bcc: Comma-delimited string or an array of e-mail addresses - :param int $limit: Maximum number of e-mails to send per batch - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param mixed $bcc: Comma-delimited string or an array of e-mail addresses + :param int $limit: Maximum number of e-mails to send per batch + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the BCC email address(s). Just like the ``setTo()`` method, can be a single - e-mail, a comma-delimited list or an array. + Sets the BCC email address(s). Just like the ``setTo()`` method, can be a single + e-mail, a comma-delimited list or an array. - If ``$limit`` is set, "batch mode" will be enabled, which will send - the emails to batches, with each batch not exceeding the specified - ``$limit``. + If ``$limit`` is set, "batch mode" will be enabled, which will send + the emails to batches, with each batch not exceeding the specified + ``$limit``. - .. php:method:: setSubject($subject) + .. php:method:: setSubject($subject) - :param string $subject: E-mail subject line - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $subject: E-mail subject line + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the email subject:: + Sets the email subject:: - $email->setSubject('This is my subject'); + $email->setSubject('This is my subject'); - .. php:method:: setMessage($body) + .. php:method:: setMessage($body) - :param string $body: E-mail message body - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $body: E-mail message body + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the e-mail message body:: + Sets the e-mail message body:: - $email->setMessage('This is my message'); + $email->setMessage('This is my message'); - .. php:method:: setAltMessage($str) + .. php:method:: setAltMessage($str) - :param string $str: Alternative e-mail message body - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $str: Alternative e-mail message body + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Sets the alternative e-mail message body:: + Sets the alternative e-mail message body:: - $email->setAltMessage('This is the alternative message'); + $email->setAltMessage('This is the alternative message'); - This is an optional message string which can be used if you send - HTML formatted email. It lets you specify an alternative message - with no HTML formatting which is added to the header string for - people who do not accept HTML email. If you do not set your own - message CodeIgniter will extract the message from your HTML email - and strip the tags. + This is an optional message string which can be used if you send + HTML formatted email. It lets you specify an alternative message + with no HTML formatting which is added to the header string for + people who do not accept HTML email. If you do not set your own + message CodeIgniter will extract the message from your HTML email + and strip the tags. - .. php:method:: setHeader($header, $value) - :noindex: + .. php:method:: setHeader($header, $value) + :noindex: - :param string $header: Header name - :param string $value: Header value - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $header: Header name + :param string $value: Header value + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Appends additional headers to the e-mail:: + Appends additional headers to the e-mail:: - $email->setHeader('Header1', 'Value1'); - $email->setHeader('Header2', 'Value2'); + $email->setHeader('Header1', 'Value1'); + $email->setHeader('Header2', 'Value2'); - .. php:method:: clear($clearAttachments = false) + .. php:method:: clear($clearAttachments = false) - :param bool $clearAttachments: Whether or not to clear attachments - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param bool $clearAttachments: Whether or not to clear attachments + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Initializes all the email variables to an empty state. This method - is intended for use if you run the email sending method in a loop, - permitting the data to be reset between cycles. + Initializes all the email variables to an empty state. This method + is intended for use if you run the email sending method in a loop, + permitting the data to be reset between cycles. - :: + :: - foreach ($list as $name => $address) - { - $email->clear(); + foreach ($list as $name => $address) + { + $email->clear(); - $email->setTo($address); - $email->setFrom('your@example.com'); - $email->setSubject('Here is your info '.$name); - $email->setMessage('Hi ' . $name . ' Here is the info you requested.'); - $email->send(); - } + $email->setTo($address); + $email->setFrom('your@example.com'); + $email->setSubject('Here is your info '.$name); + $email->setMessage('Hi ' . $name . ' Here is the info you requested.'); + $email->send(); + } - If you set the parameter to true any attachments will be cleared as - well:: + If you set the parameter to true any attachments will be cleared as + well:: - $email->clear(true); + $email->clear(true); - .. php:method:: send($autoClear = true) + .. php:method:: send($autoClear = true) - :param bool $autoClear: Whether to clear message data automatically - :returns: true on success, false on failure - :rtype: bool + :param bool $autoClear: Whether to clear message data automatically + :returns: true on success, false on failure + :rtype: bool - The e-mail sending method. Returns boolean true or false based on - success or failure, enabling it to be used conditionally:: + The e-mail sending method. Returns boolean true or false based on + success or failure, enabling it to be used conditionally:: - if (! $email->send()) - { - // Generate error - } + if (! $email->send()) + { + // Generate error + } - This method will automatically clear all parameters if the request was - successful. To stop this behaviour pass false:: + This method will automatically clear all parameters if the request was + successful. To stop this behaviour pass false:: - if ($email->send(false)) - { - // Parameters won't be cleared - } + if ($email->send(false)) + { + // Parameters won't be cleared + } - .. note:: In order to use the ``printDebugger()`` method, you need - to avoid clearing the email parameters. + .. note:: In order to use the ``printDebugger()`` method, you need + to avoid clearing the email parameters. - .. note:: If ``BCCBatchMode`` is enabled, and there are more than - ``BCCBatchSize`` recipients, this method will always return - boolean ``true``. + .. note:: If ``BCCBatchMode`` is enabled, and there are more than + ``BCCBatchSize`` recipients, this method will always return + boolean ``true``. - .. php:method:: attach($filename[, $disposition = ''[, $newname = null[, $mime = '']]]) + .. php:method:: attach($filename[, $disposition = ''[, $newname = null[, $mime = '']]]) - :param string $filename: File name - :param string $disposition: 'disposition' of the attachment. Most - email clients make their own decision regardless of the MIME - specification used here. https://www.iana.org/assignments/cont-disp/cont-disp.xhtml - :param string $newname: Custom file name to use in the e-mail - :param string $mime: MIME type to use (useful for buffered data) - :returns: CodeIgniter\\Email\\Email instance (method chaining) - :rtype: CodeIgniter\\Email\\Email + :param string $filename: File name + :param string $disposition: 'disposition' of the attachment. Most + email clients make their own decision regardless of the MIME + specification used here. https://www.iana.org/assignments/cont-disp/cont-disp.xhtml + :param string $newname: Custom file name to use in the e-mail + :param string $mime: MIME type to use (useful for buffered data) + :returns: CodeIgniter\\Email\\Email instance (method chaining) + :rtype: CodeIgniter\\Email\\Email - Enables you to send an attachment. Put the file path/name in the first - parameter. For multiple attachments use the method multiple times. - For example:: + Enables you to send an attachment. Put the file path/name in the first + parameter. For multiple attachments use the method multiple times. + For example:: - $email->attach('/path/to/photo1.jpg'); - $email->attach('/path/to/photo2.jpg'); - $email->attach('/path/to/photo3.jpg'); + $email->attach('/path/to/photo1.jpg'); + $email->attach('/path/to/photo2.jpg'); + $email->attach('/path/to/photo3.jpg'); - To use the default disposition (attachment), leave the second parameter blank, - otherwise use a custom disposition:: + To use the default disposition (attachment), leave the second parameter blank, + otherwise use a custom disposition:: - $email->attach('image.jpg', 'inline'); + $email->attach('image.jpg', 'inline'); - You can also use a URL:: + You can also use a URL:: - $email->attach('http://example.com/filename.pdf'); + $email->attach('http://example.com/filename.pdf'); - If you'd like to use a custom file name, you can use the third parameter:: + If you'd like to use a custom file name, you can use the third parameter:: - $email->attach('filename.pdf', 'attachment', 'report.pdf'); + $email->attach('filename.pdf', 'attachment', 'report.pdf'); - If you need to use a buffer string instead of a real - physical - file you can - use the first parameter as buffer, the third parameter as file name and the fourth - parameter as mime-type:: + If you need to use a buffer string instead of a real - physical - file you can + use the first parameter as buffer, the third parameter as file name and the fourth + parameter as mime-type:: - $email->attach($buffer, 'attachment', 'report.pdf', 'application/pdf'); + $email->attach($buffer, 'attachment', 'report.pdf', 'application/pdf'); - .. php:method:: setAttachmentCID($filename) + .. php:method:: setAttachmentCID($filename) - :param string $filename: Existing attachment filename - :returns: Attachment Content-ID or false if not found - :rtype: string + :param string $filename: Existing attachment filename + :returns: Attachment Content-ID or false if not found + :rtype: string - Sets and returns an attachment's Content-ID, which enables your to embed an inline - (picture) attachment into HTML. First parameter must be the already attached file name. - :: + Sets and returns an attachment's Content-ID, which enables your to embed an inline + (picture) attachment into HTML. First parameter must be the already attached file name. + :: - $filename = '/img/photo1.jpg'; - $email->attach($filename); + $filename = '/img/photo1.jpg'; + $email->attach($filename); - foreach ($list as $address) { - $email->setTo($address); - $cid = $email->setAttachmentCID($filename); - $email->setMessage('photo1'); - $email->send(); - } + foreach ($list as $address) { + $email->setTo($address); + $cid = $email->setAttachmentCID($filename); + $email->setMessage('photo1'); + $email->send(); + } - .. note:: Content-ID for each e-mail must be re-created for it to be unique. + .. note:: Content-ID for each e-mail must be re-created for it to be unique. - .. php:method:: printDebugger($include = ['headers', 'subject', 'body']) + .. php:method:: printDebugger($include = ['headers', 'subject', 'body']) - :param array $include: Which parts of the message to print out - :returns: Formatted debug data - :rtype: string + :param array $include: Which parts of the message to print out + :returns: Formatted debug data + :rtype: string - Returns a string containing any server messages, the email headers, and - the email message. Useful for debugging. + Returns a string containing any server messages, the email headers, and + the email message. Useful for debugging. - You can optionally specify which parts of the message should be printed. - Valid options are: **headers**, **subject**, **body**. + You can optionally specify which parts of the message should be printed. + Valid options are: **headers**, **subject**, **body**. - Example:: + Example:: - // You need to pass false while sending in order for the email data - // to not be cleared - if that happens, printDebugger() would have - // nothing to output. - $email->send(false); + // You need to pass false while sending in order for the email data + // to not be cleared - if that happens, printDebugger() would have + // nothing to output. + $email->send(false); - // Will only print the email headers, excluding the message subject and body - $email->printDebugger(['headers']); + // Will only print the email headers, excluding the message subject and body + $email->printDebugger(['headers']); - .. note:: By default, all of the raw data will be printed. + .. note:: By default, all of the raw data will be printed. diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 36185183ca4e..54fb1fb333a7 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -3,9 +3,9 @@ Encryption Service ################## .. important:: DO NOT use this or any other *encryption* library for - password storage! Passwords must be *hashed* instead, and you - should do that through PHP's `Password Hashing extension - `_. + password storage! Passwords must be *hashed* instead, and you + should do that through PHP's `Password Hashing extension + `_. The Encryption Service provides two-way symmetric (secret key) data encryption. The service will instantiate and/or initialize an @@ -47,11 +47,11 @@ Assuming you have set your starting key (see :ref:`configuration`), encrypting and decrypting data is simple - pass the appropriate string to ``encrypt()`` and/or ``decrypt()`` methods:: - $plainText = 'This is a plain-text message!'; - $ciphertext = $encrypter->encrypt($plainText); + $plainText = 'This is a plain-text message!'; + $ciphertext = $encrypter->encrypt($plainText); - // Outputs: This is a plain-text message! - echo $encrypter->decrypt($ciphertext); + // Outputs: This is a plain-text message! + echo $encrypter->decrypt($ciphertext); And that's it! The Encryption library will do everything necessary for the whole process to be cryptographically secure out-of-the-box. @@ -101,12 +101,12 @@ nor the output of a hashing function, etc. To create a proper key, you can use the Encryption library's ``createKey()`` method. :: - // $key will be assigned a 32-byte (256-bit) random key - $key = \CodeIgniter\Encryption\Encryption::createKey(); + // $key will be assigned a 32-byte (256-bit) random key + $key = \CodeIgniter\Encryption\Encryption::createKey(); - // for the SodiumHandler, you can use either: - $key = sodium_crypto_secretbox_keygen(); - $key = \CodeIgniter\Encryption\Encryption::createKey(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); + // for the SodiumHandler, you can use either: + $key = sodium_crypto_secretbox_keygen(); + $key = \CodeIgniter\Encryption\Encryption::createKey(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); The key can be stored in ``app/Config/Encryption.php``, or you can design a storage mechanism of your own and pass the key dynamically when encrypting/decrypting. @@ -114,7 +114,7 @@ a storage mechanism of your own and pass the key dynamically when encrypting/dec To save your key to your ``app/Config/Encryption.php``, open the file and set:: - public $key = 'YOUR KEY'; + public $key = 'YOUR KEY'; Encoding Keys or Results ------------------------ @@ -124,18 +124,18 @@ is hard to deal with (i.e., a copy-paste may damage it), so you may use ``bin2hex()``, or ``base64_encode`` to work with the key in a more friendly manner. For example:: - // Get a hex-encoded representation of the key: - $encoded = bin2hex(\CodeIgniter\Encryption\Encryption::createKey(32)); + // Get a hex-encoded representation of the key: + $encoded = bin2hex(\CodeIgniter\Encryption\Encryption::createKey(32)); - // Put the same value with hex2bin(), - // so that it is still passed as binary to the library: - $key = hex2bin('your-hex-encoded-key'); + // Put the same value with hex2bin(), + // so that it is still passed as binary to the library: + $key = hex2bin('your-hex-encoded-key'); You might find the same technique useful for the results of encryption:: - // Encrypt some text & make the results text - $encoded = base64_encode($encrypter->encrypt($plaintext)); + // Encrypt some text & make the results text + $encoded = base64_encode($encrypter->encrypt($plaintext)); Using Prefixes in Storing Keys ------------------------------ @@ -147,20 +147,20 @@ intelligently parse the key and still pass a binary string to the library. :: - // In Encryption, you may use - public $key = 'hex2bin:' + // In Encryption, you may use + public $key = 'hex2bin:' - // or - public $key = 'base64:' + // or + public $key = 'base64:' Similarly, you can use these prefixes in your ``.env`` file, too! :: - // For hex2bin - encryption.key = hex2bin: + // For hex2bin + encryption.key = hex2bin: - // or - encryption.key = base64: + // or + encryption.key = base64: Padding ======= @@ -177,11 +177,11 @@ message prior to encryption, and removed after decryption. Padding is configurab ``$blockSize`` property of ``Config\Encryption``. This value should be greater than zero. .. important:: You are advised not to devise your own padding implementation. You must always use - the more secure implementation of a library. Also, passwords should not be padded. Usage of - padding in order to hide the length of a password is not recommended. A client willing to send - a password to a server should hash it instead (even with a single iteration of the hash function). - This ensures that the length of the transmitted data is constant, and that the server doesn't - effortlessly get a copy of the password. + the more secure implementation of a library. Also, passwords should not be padded. Usage of + padding in order to hide the length of a password is not recommended. A client willing to send + a password to a server should hash it instead (even with a single iteration of the hash function). + This ensures that the length of the transmitted data is constant, and that the server doesn't + effortlessly get a copy of the password. Encryption Handler Notes ======================== @@ -209,8 +209,8 @@ a shared-key, such as symmetric encryption, Sodium uses the XSalsa20 algorithm t HMAC-SHA512 for the authentication. .. note:: CodeIgniter's ``SodiumHandler`` uses ``sodium_memzero`` in every encryption or decryption - session. After each session, the message (whether plaintext or ciphertext) and starter key are - wiped out from the buffers. You may need to provide again the key before starting a new session. + session. After each session, the message (whether plaintext or ciphertext) and starter key are + wiped out from the buffers. You may need to provide again the key before starting a new session. Message Length ============== @@ -246,78 +246,78 @@ Class Reference .. php:class:: CodeIgniter\\Encryption\\Encryption - .. php:staticmethod:: createKey([$length = 32]) + .. php:staticmethod:: createKey([$length = 32]) - :param int $length: Output length - :returns: A pseudo-random cryptographic key with the specified length, or ``false`` on failure - :rtype: string + :param int $length: Output length + :returns: A pseudo-random cryptographic key with the specified length, or ``false`` on failure + :rtype: string - Creates a cryptographic key by fetching random data from - the operating system's sources (*i.e.* ``/dev/urandom``). + Creates a cryptographic key by fetching random data from + the operating system's sources (*i.e.* ``/dev/urandom``). - .. php:method:: initialize([Encryption $config = null]) + .. php:method:: initialize([Encryption $config = null]) - :param Config\\Encryption $config: Configuration parameters - :returns: ``CodeIgniter\Encryption\EncrypterInterface`` instance - :rtype: ``CodeIgniter\Encryption\EncrypterInterface`` - :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` + :param Config\\Encryption $config: Configuration parameters + :returns: ``CodeIgniter\Encryption\EncrypterInterface`` instance + :rtype: ``CodeIgniter\Encryption\EncrypterInterface`` + :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` - Initializes (configures) the library to use different settings. + Initializes (configures) the library to use different settings. - Example:: + Example:: - $encrypter = $encryption->initialize(['cipher' => '3des']); + $encrypter = $encryption->initialize(['cipher' => '3des']); - Please refer to the :ref:`configuration` section for detailed info. + Please refer to the :ref:`configuration` section for detailed info. .. php:interface:: CodeIgniter\\Encryption\\EncrypterInterface - .. php:method:: encrypt($data[, $params = null]) + .. php:method:: encrypt($data[, $params = null]) - :param string $data: Data to encrypt - :param array|string|null $params: Configuration parameters (key) - :returns: Encrypted data - :rtype: string - :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` + :param string $data: Data to encrypt + :param array|string|null $params: Configuration parameters (key) + :returns: Encrypted data + :rtype: string + :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` - Encrypts the input data and returns its ciphertext. + Encrypts the input data and returns its ciphertext. - If you pass parameters as the second argument, the ``key`` element - will be used as the starting key for this operation if ``$params`` - is an array; or the starting key may be passed as a string. + If you pass parameters as the second argument, the ``key`` element + will be used as the starting key for this operation if ``$params`` + is an array; or the starting key may be passed as a string. - If you are using the SodiumHandler and want to pass a different ``blockSize`` - on runtime, pass the ``blockSize`` key in the ``$params`` array. + If you are using the SodiumHandler and want to pass a different ``blockSize`` + on runtime, pass the ``blockSize`` key in the ``$params`` array. - Examples:: + Examples:: - $ciphertext = $encrypter->encrypt('My secret message'); - $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']); - $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]); - $ciphertext = $encrypter->encrypt('My secret message', 'New secret key'); - $ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]); + $ciphertext = $encrypter->encrypt('My secret message'); + $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']); + $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]); + $ciphertext = $encrypter->encrypt('My secret message', 'New secret key'); + $ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]); - .. php:method:: decrypt($data[, $params = null]) + .. php:method:: decrypt($data[, $params = null]) - :param string $data: Data to decrypt - :param array|string|null $params: Configuration parameters (key) - :returns: Decrypted data - :rtype: string - :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` + :param string $data: Data to decrypt + :param array|string|null $params: Configuration parameters (key) + :returns: Decrypted data + :rtype: string + :throws: ``CodeIgniter\Encryption\Exceptions\EncryptionException`` - Decrypts the input data and returns it in plain-text. + Decrypts the input data and returns it in plain-text. - If you pass parameters as the second argument, the ``key`` element - will be used as the starting key for this operation if ``$params`` - is an array; or the starting key may be passed as a string. + If you pass parameters as the second argument, the ``key`` element + will be used as the starting key for this operation if ``$params`` + is an array; or the starting key may be passed as a string. - If you are using the SodiumHandler and want to pass a different ``blockSize`` - on runtime, pass the ``blockSize`` key in the ``$params`` array. + If you are using the SodiumHandler and want to pass a different ``blockSize`` + on runtime, pass the ``blockSize`` key in the ``$params`` array. - Examples:: + Examples:: - echo $encrypter->decrypt($ciphertext); - echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']); - echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]); - echo $encrypter->decrypt($ciphertext, 'New secret key'); - echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]); + echo $encrypter->decrypt($ciphertext); + echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']); + echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]); + echo $encrypter->decrypt($ciphertext, 'New secret key'); + echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]); diff --git a/user_guide_src/source/libraries/images.rst b/user_guide_src/source/libraries/images.rst index d22f3eba9af6..bd71be9657f2 100644 --- a/user_guide_src/source/libraries/images.rst +++ b/user_guide_src/source/libraries/images.rst @@ -24,7 +24,7 @@ Initializing the Class Like most other classes in CodeIgniter, the image class is initialized in your controller by calling the Services class:: - $image = \Config\Services::image(); + $image = \Config\Services::image(); You can pass the alias for the image library you wish to use into the Service function:: @@ -52,10 +52,10 @@ identical. You will set some preferences corresponding to the action you intend to perform, then call one of the available processing functions. For example, to create an image thumbnail you'll do this:: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->fit(100, 100, 'center') - ->save('/path/to/image/mypic_thumb.jpg'); + $image = \Config\Services::image() + ->withFile('/path/to/image/mypic.jpg') + ->fit(100, 100, 'center') + ->save('/path/to/image/mypic_thumb.jpg'); The above code tells the library to look for an image called *mypic.jpg* located in the source_image folder, then create a @@ -69,25 +69,25 @@ needed before saving. The original image is left untouched, and a new image is used and passed through each method, applying the results on top of the previous results:: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->reorient() - ->rotate(90) - ->crop(100, 100, 0, 0) - ->save('/path/to/image/mypic_thumb.jpg'); + $image = \Config\Services::image() + ->withFile('/path/to/image/mypic.jpg') + ->reorient() + ->rotate(90) + ->crop(100, 100, 0, 0) + ->save('/path/to/image/mypic_thumb.jpg'); This example would take the same image and first fix any mobile phone orientation issues, rotate the image by 90 degrees, and then crop the result into a 100x100 pixel image, starting at the top left corner. The result would be saved as the thumbnail. .. note:: In order for the image class to be allowed to do any - processing, the folder containing the image files must have write - permissions. + processing, the folder containing the image files must have write + permissions. .. note:: Image processing can require a considerable amount of server - memory for some operations. If you are experiencing out of memory errors - while processing images you may need to limit their maximum size, and/or - adjust PHP memory limits. + memory for some operations. If you are experiencing out of memory errors + while processing images you may need to limit their maximum size, and/or + adjust PHP memory limits. Image Quality ============= @@ -96,20 +96,20 @@ Image Quality quality. Values range from 0 to 100 with 90 being the framework default. This parameter only applies to JPEG images and will be ignored otherwise:: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - // processing methods - ->save('/path/to/image/my_low_quality_pic.jpg', 10); + $image = \Config\Services::image() + ->withFile('/path/to/image/mypic.jpg') + // processing methods + ->save('/path/to/image/my_low_quality_pic.jpg', 10); .. note:: Higher quality will result in larger file sizes. See also https://www.php.net/manual/en/function.imagejpeg.php If you are only interested in changing the image quality without doing any processing. You will need to include the image resource or you will end up with an exact copy:: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->withResource() - ->save('/path/to/image/my_low_quality_pic.jpg', 10); + $image = \Config\Services::image() + ->withFile('/path/to/image/mypic.jpg') + ->withResource() + ->save('/path/to/image/my_low_quality_pic.jpg', 10); Processing Methods ================== @@ -130,14 +130,14 @@ If they fail they will throw a ``CodeIgniter\Images\ImageException`` that contai the error message. A good practice is to catch the exceptions, showing an error upon failure, like this:: - try { + try { $image = \Config\Services::image() ->withFile('/path/to/image/mypic.jpg') ->fit(100, 100, 'center') ->save('/path/to/image/mypic_thumb.jpg'); - } catch (CodeIgniter\Images\ImageException $e) { - echo $e->getMessage(); - } + } catch (CodeIgniter\Images\ImageException $e) { + echo $e->getMessage(); + } Cropping Images --------------- @@ -158,34 +158,34 @@ To take a 50x50 pixel square out of the center of an image, you would need to fi offset values:: $info = \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->getFile() - ->getProperties(true); + ->withFile('/path/to/image/mypic.jpg') + ->getFile() + ->getProperties(true); $xOffset = ($info['width'] / 2) - 25; $yOffset = ($info['height'] / 2) - 25; \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->crop(50, 50, $xOffset, $yOffset) - ->save('/path/to/new/image.jpg'); + ->withFile('/path/to/image/mypic.jpg') + ->crop(50, 50, $xOffset, $yOffset) + ->save('/path/to/new/image.jpg'); Converting Images ----------------- The ``convert()`` method changes the library's internal indicator for the desired file format. This doesn't touch the actual image resource, but indicates to ``save()`` what format to use:: - convert(int $imageType) + convert(int $imageType) - **$imageType** is one of PHP's image type constants (see for example https://www.php.net/manual/en/function.image-type-to-mime-type.php):: - \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->convert(IMAGETYPE_PNG) - ->save('/path/to/new/image.png'); + \Config\Services::image() + ->withFile('/path/to/image/mypic.jpg') + ->convert(IMAGETYPE_PNG) + ->save('/path/to/new/image.png'); .. note:: ImageMagick already saves files in the type - indicated by their extension, ignoring **$imageType** + indicated by their extension, ignoring **$imageType** Fitting Images -------------- @@ -206,10 +206,10 @@ The ``fit()`` method aims to help simplify cropping a portion of an image in a " This provides a much simpler way to crop that will always maintain the aspect ratio:: - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->fit(100, 150, 'left') - ->save('/path/to/new/image.jpg'); + \Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.jpg') + ->fit(100, 150, 'left') + ->save('/path/to/new/image.jpg'); Flattening Images ----------------- @@ -228,15 +228,15 @@ The ``flatten()`` method aims to add a background color behind transparent image :: - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.png') - ->flatten() - ->save('/path/to/new/image.jpg'); + \Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.png') + ->flatten() + ->save('/path/to/new/image.jpg'); - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.png') - ->flatten(25,25,112) - ->save('/path/to/new/image.jpg'); + \Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.png') + ->flatten(25,25,112) + ->save('/path/to/new/image.jpg'); Flipping Images --------------- @@ -249,17 +249,17 @@ Images can be flipped along either their horizontal or vertical axis:: :: - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->flip('horizontal') - ->save('/path/to/new/image.jpg'); + \Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.jpg') + ->flip('horizontal') + ->save('/path/to/new/image.jpg'); Resizing Images --------------- Images can be resized to fit any dimension you require with the resize() method:: - resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto') + resize(int $width, int $height, bool $maintainRatio = false, string $masterDim = 'auto') - **$width** is the desired width of the new image in pixels - **$height** is the desired height of the new image in pixels @@ -272,22 +272,22 @@ while the other dimension will be altered to match the original image's aspect r :: - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->resize(200, 100, true, 'height') - ->save('/path/to/new/image.jpg'); + \Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.jpg') + ->resize(200, 100, true, 'height') + ->save('/path/to/new/image.jpg'); Rotating Images --------------- The rotate() method allows you to rotate an image in 90 degree increments:: - rotate(float $angle) + rotate(float $angle) - **$angle** is the number of degrees to rotate. One of '90', '180', '270'. .. note:: While the $angle parameter accepts a float, it will convert it to an integer during the process. - If the value is any other than the three values listed above, it will throw a CodeIgniter\Images\ImageException. + If the value is any other than the three values listed above, it will throw a CodeIgniter\Images\ImageException. Adding a Text Watermark ----------------------- @@ -298,36 +298,36 @@ products. :: - text(string $text, array $options = []) + text(string $text, array $options = []) The first parameter is the string of text that you wish to display. The second parameter is an array of options that allow you to specify how the text should be displayed:: - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->text('Copyright 2017 My Photo Co', [ - 'color' => '#fff', - 'opacity' => 0.5, - 'withShadow' => true, - 'hAlign' => 'center', - 'vAlign' => 'bottom', - 'fontSize' => 20 - ]) - ->save('/path/to/new/image.jpg'); + \Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.jpg') + ->text('Copyright 2017 My Photo Co', [ + 'color' => '#fff', + 'opacity' => 0.5, + 'withShadow' => true, + 'hAlign' => 'center', + 'vAlign' => 'bottom', + 'fontSize' => 20 + ]) + ->save('/path/to/new/image.jpg'); The possible options that are recognized are as follows: - color Text Color (hex number), i.e., #ff0000 -- opacity A number between 0 and 1 that represents the opacity of the text. -- withShadow Boolean value whether to display a shadow or not. +- opacity A number between 0 and 1 that represents the opacity of the text. +- withShadow Boolean value whether to display a shadow or not. - shadowColor Color of the shadow (hex number) -- shadowOffset How many pixels to offset the shadow. Applies to both the vertical and horizontal values. +- shadowOffset How many pixels to offset the shadow. Applies to both the vertical and horizontal values. - hAlign Horizontal alignment: left, center, right - vAlign Vertical alignment: top, middle, bottom -- hOffset Additional offset on the x axis, in pixels -- vOffset Additional offset on the y axis, in pixels -- fontPath The full server path to the TTF font you wish to use. System font will be used if none is given. -- fontSize The font size to use. When using the GD handler with the system font, valid values are between 1-5. +- hOffset Additional offset on the x axis, in pixels +- vOffset Additional offset on the y axis, in pixels +- fontPath The full server path to the TTF font you wish to use. System font will be used if none is given. +- fontSize The font size to use. When using the GD handler with the system font, valid values are between 1-5. .. note:: The ImageMagick driver does not recognize full server path for fontPath. Instead, simply provide the - name of one of the installed system fonts that you wish to use, i.e., Calibri. + name of one of the installed system fonts that you wish to use, i.e., Calibri. diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index dc2ec08347a8..fd75c09e99e4 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -15,7 +15,7 @@ Loading the Library Because Publisher instances are specific to their source and destination this library is not available through ``Services`` but should be instantiated or extended directly. E.g. - $publisher = new \CodeIgniter\Publisher\Publisher(); + $publisher = new \CodeIgniter\Publisher\Publisher(); ***************** Concept and Usage @@ -38,41 +38,41 @@ On Demand Access ``Publisher`` directly by instantiating a new instance of the class:: - $publisher = new \CodeIgniter\Publisher\Publisher(); + $publisher = new \CodeIgniter\Publisher\Publisher(); By default the source and destination will be set to ``ROOTPATH`` and ``FCPATH`` respectively, giving ``Publisher`` easy access to take any file from your project and make it web-accessible. Alternatively you may pass a new source or source and destination into the constructor:: - use CodeIgniter\Publisher\Publisher; - - $vendorPublisher = new Publisher(ROOTPATH . 'vendor'); - $filterPublisher = new Publisher('/path/to/module/Filters', APPPATH . 'Filters'); + use CodeIgniter\Publisher\Publisher; + + $vendorPublisher = new Publisher(ROOTPATH . 'vendor'); + $filterPublisher = new Publisher('/path/to/module/Filters', APPPATH . 'Filters'); - // Once the source and destination are set you may start adding relative input files - $frameworkPublisher = new Publisher(ROOTPATH . 'vendor/codeigniter4/codeigniter4'); + // Once the source and destination are set you may start adding relative input files + $frameworkPublisher = new Publisher(ROOTPATH . 'vendor/codeigniter4/codeigniter4'); - // All "path" commands are relative to $source - $frameworkPublisher->addPath('app/Config/Cookie.php'); + // All "path" commands are relative to $source + $frameworkPublisher->addPath('app/Config/Cookie.php'); - // You may also add from outside the source, but the files will not be merged into subdirectories - $frameworkPublisher->addFiles([ - '/opt/mail/susan', - '/opt/mail/ubuntu', - ]); - $frameworkPublisher->addDirectory(SUPPORTPATH . 'Images'); + // You may also add from outside the source, but the files will not be merged into subdirectories + $frameworkPublisher->addFiles([ + '/opt/mail/susan', + '/opt/mail/ubuntu', + ]); + $frameworkPublisher->addDirectory(SUPPORTPATH . 'Images'); Once all the files are staged use one of the output commands (**copy()** or **merge()**) to process the staged files to their destination(s):: - // Place all files into $destination - $frameworkPublisher->copy(); + // Place all files into $destination + $frameworkPublisher->copy(); - // Place all files into $destination, overwriting existing files - $frameworkPublisher->copy(true); + // Place all files into $destination, overwriting existing files + $frameworkPublisher->copy(true); - // Place files into their relative $destination directories, overwriting and saving the boolean result - $result = $frameworkPublisher->merge(true); + // Place files into their relative $destination directories, overwriting and saving the boolean result + $result = $frameworkPublisher->merge(true); See the :ref:`reference` for a full description of available methods. @@ -82,27 +82,27 @@ Automation and Discovery You may have regular publication tasks embedded as part of your application deployment or upkeep. ``Publisher`` leverages the powerful ``Autoloader`` to locate any child classes primed for publication:: - use CodeIgniter\CLI\CLI; - use CodeIgniter\Publisher\Publisher; - - foreach (Publisher::discover() as $publisher) - { - $result = $publisher->publish(); + use CodeIgniter\CLI\CLI; + use CodeIgniter\Publisher\Publisher; + + foreach (Publisher::discover() as $publisher) + { + $result = $publisher->publish(); - if ($result === false) - { - CLI::error(get_class($publisher) . ' failed to publish!', 'red'); - } - } + if ($result === false) + { + CLI::error(get_class($publisher) . ' failed to publish!', 'red'); + } + } By default ``discover()`` will search for the "Publishers" directory across all namespaces, but you may specify a different directory and it will return any child classes found:: - $memePublishers = Publisher::discover('CatGIFs'); + $memePublishers = Publisher::discover('CatGIFs'); Most of the time you will not need to handle your own discovery, just use the provided "publish" command:: - > php spark publish + > php spark publish By default on your class extension ``publish()`` will add all files from your ``$source`` and merge them out to your destination, overwriting on collision. @@ -134,40 +134,40 @@ You want to display a "photo of the day" image on your homepage. You have a feed need to get the actual file into a browsable location in your project at **public/images/daily_photo.jpg**. You can set up :doc:`Custom Command ` to run daily that will handle this for you:: - addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites - } - catch (Throwable $e) - { - $this->showError($e); - } - } - } + try + { + $publisher->addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites + } + catch (Throwable $e) + { + $this->showError($e); + } + } + } Now running ``spark publish:daily`` will keep your homepage's image up-to-date. What if the photo is coming from an external API? You can use ``addUri()`` in place of ``addPath()`` to download the remote resource and publish it out instead:: - $publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy(true); + $publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy(true); Asset Dependencies Example ========================== @@ -176,82 +176,82 @@ You want to integrate the frontend library "Bootstrap" into your project, but th to keep up with. You can create a publication definition in your project to sync frontend assets by extending ``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this:: - addPath('dist') - - // Indicate we only want the minimized versions - ->retainPattern('*.min.*') - - // Merge-and-replace to retain the original directory structure - ->merge(true); - } - } + addPath('dist') + + // Indicate we only want the minimized versions + ->retainPattern('*.min.*') + + // Merge-and-replace to retain the original directory structure + ->merge(true); + } + } Now add the dependency via Composer and call ``spark publish`` to run the publication:: - > composer require twbs/bootstrap - > php spark publish + > composer require twbs/bootstrap + > php spark publish ... and you'll end up with something like this:: - public/.htaccess - public/favicon.ico - public/index.php - public/robots.txt - public/ - bootstrap/ - css/ - bootstrap.min.css - bootstrap-utilities.min.css.map - bootstrap-grid.min.css - bootstrap.rtl.min.css - bootstrap.min.css.map - bootstrap-reboot.min.css - bootstrap-utilities.min.css - bootstrap-reboot.rtl.min.css - bootstrap-grid.min.css.map - js/ - bootstrap.esm.min.js - bootstrap.bundle.min.js.map - bootstrap.bundle.min.js - bootstrap.min.js - bootstrap.esm.min.js.map - bootstrap.min.js.map + public/.htaccess + public/favicon.ico + public/index.php + public/robots.txt + public/ + bootstrap/ + css/ + bootstrap.min.css + bootstrap-utilities.min.css.map + bootstrap-grid.min.css + bootstrap.rtl.min.css + bootstrap.min.css.map + bootstrap-reboot.min.css + bootstrap-utilities.min.css + bootstrap-reboot.rtl.min.css + bootstrap-grid.min.css.map + js/ + bootstrap.esm.min.js + bootstrap.bundle.min.js.map + bootstrap.bundle.min.js + bootstrap.min.js + bootstrap.esm.min.js.map + bootstrap.min.js.map Module Deployment Example ========================= @@ -260,59 +260,59 @@ You want to allow developers using your popular authentication module the abilit of your Migration, Controller, and Model. You can create your own module "publish" command to inject these components into an application for use:: - getNamespace('Math\\Auth'); - - $publisher = new Publisher($source, APPATH); - - try - { - // Add only the desired components - $publisher->addPaths([ - 'Controllers', - 'Database/Migrations', - 'Models', - ])->merge(false); // Be careful not to overwrite anything - } - catch (Throwable $e) - { - $this->showError($e); - return; - } - - // If publication succeeded then update namespaces - foreach ($publisher->getPublished() as $file) - { - // Replace the namespace - $contents = file_get_contents($file); - $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, ); - file_put_contents($file, $contents); - } - } - } + getNamespace('Math\\Auth'); + + $publisher = new Publisher($source, APPATH); + + try + { + // Add only the desired components + $publisher->addPaths([ + 'Controllers', + 'Database/Migrations', + 'Models', + ])->merge(false); // Be careful not to overwrite anything + } + catch (Throwable $e) + { + $this->showError($e); + return; + } + + // If publication succeeded then update namespaces + foreach ($publisher->getPublished() as $file) + { + // Replace the namespace + $contents = file_get_contents($file); + $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, ); + file_put_contents($file, $contents); + } + } + } Now when your module users run ``php spark auth:publish`` they will have the following added to their project:: - app/Controllers/AuthController.php - app/Database/Migrations/2017-11-20-223112_create_auth_tables.php.php - app/Models/LoginModel.php - app/Models/UserModel.php + app/Controllers/AuthController.php + app/Database/Migrations/2017-11-20-223112_create_auth_tables.php.php + app/Models/LoginModel.php + app/Models/UserModel.php .. _reference: @@ -361,7 +361,7 @@ Downloads the contents of a URI using ``CURLRequest`` into the scratch workspace file to the list. .. note:: The CURL request made is a simple ``GET`` and uses the response body for the file contents. Some - remote files may need a custom request to be handled properly. + remote files may need a custom request to be handled properly. Outputting Files ================ @@ -380,14 +380,14 @@ to overwrite when there is already an existing file. Returns success or failure, and ``getErrors()`` to troubleshoot failures. Be mindful of duplicate basename collisions, for example:: - $publisher = new Publisher('/home/source', '/home/destination'); - $publisher->addPaths([ - 'pencil/lead.png', - 'metal/lead.png', - ]); + $publisher = new Publisher('/home/source', '/home/destination'); + $publisher->addPaths([ + 'pencil/lead.png', + 'metal/lead.png', + ]); - // This is bad! Only one file will remain at /home/destination/lead.png - $publisher->copy(true); + // This is bad! Only one file will remain at /home/destination/lead.png + $publisher->copy(true); **merge(bool $replace = true): bool** @@ -400,11 +400,11 @@ affect other files in the destination. Returns success or failure, use ``getPubl Example:: - $publisher = new Publisher('/home/source', '/home/destination'); - $publisher->addPaths([ - 'pencil/lead.png', - 'metal/lead.png', - ]); + $publisher = new Publisher('/home/source', '/home/destination'); + $publisher->addPaths([ + 'pencil/lead.png', + 'metal/lead.png', + ]); - // Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png" - $publisher->merge(); + // Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png" + $publisher->merge(); diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 1472afa4000c..b2efd60b7025 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -23,7 +23,7 @@ class should be magically initialized. To access and initialize the session:: - $session = \Config\Services::session($config); + $session = \Config\Services::session($config); The ``$config`` parameter is optional - your application configuration. If not provided, the services register will instantiate your default @@ -31,14 +31,14 @@ one. Once loaded, the Sessions library object will be available using:: - $session + $session Alternatively, you can use the helper function that will use the default configuration options. This version is a little friendlier to read, but does not take any configuration options. :: - $session = session(); + $session = session(); How do Sessions work? ===================== @@ -58,7 +58,7 @@ data, but the process of reading, writing, and updating a session is automatic. .. note:: Under CLI, the Session library will automatically halt itself, - as this is a concept based entirely on the HTTP protocol. + as this is a concept based entirely on the HTTP protocol. A note about concurrency ------------------------ @@ -117,45 +117,45 @@ Retrieving Session Data Any piece of information from the session array is available through the ``$_SESSION`` superglobal:: - $_SESSION['item'] + $_SESSION['item'] Or through the conventional accessor method:: - $session->get('item'); + $session->get('item'); Or through the magic getter:: - $session->item + $session->item Or even through the session helper method:: - session('item'); + session('item'); Where ``item`` is the array key corresponding to the item you wish to fetch. For example, to assign a previously stored 'name' item to the ``$name`` variable, you will do this:: - $name = $_SESSION['name']; + $name = $_SESSION['name']; - // or: + // or: - $name = $session->name + $name = $session->name - // or: + // or: - $name = $session->get('name'); + $name = $session->get('name'); .. note:: The ``get()`` method returns null if the item you are trying - to access does not exist. + to access does not exist. If you want to retrieve all of the existing userdata, you can simply omit the item key (magic getter only works for single property values):: - $_SESSION + $_SESSION - // or: + // or: - $session->get(); + $session->get(); Adding Session Data =================== @@ -172,34 +172,34 @@ The former userdata method is deprecated, but you can pass an array containing your new session data to the ``set()`` method:: - $session->set($array); + $session->set($array); Where ``$array`` is an associative array containing your new data. Here's an example:: - $newdata = [ - 'username' => 'johndoe', - 'email' => 'johndoe@some-site.com', - 'logged_in' => true, - ]; + $newdata = [ + 'username' => 'johndoe', + 'email' => 'johndoe@some-site.com', + 'logged_in' => true, + ]; - $session->set($newdata); + $session->set($newdata); If you want to add session data one value at a time, ``set()`` also supports this syntax:: - $session->set('some_name', 'some_value'); + $session->set('some_name', 'some_value'); If you want to verify that a session value exists, simply check with ``isset()``:: - // returns false if the 'some_name' item doesn't exist or is null, - // true otherwise: - isset($_SESSION['some_name']) + // returns false if the 'some_name' item doesn't exist or is null, + // true otherwise: + isset($_SESSION['some_name']) Or you can call ``has()``:: - $session->has('some_name'); + $session->has('some_name'); Pushing new value to session data ================================= @@ -215,26 +215,26 @@ Removing Session Data Just as with any other variable, unsetting a value in ``$_SESSION`` can be done through ``unset()``:: - unset($_SESSION['some_name']); + unset($_SESSION['some_name']); - // or multiple values: + // or multiple values: - unset( - $_SESSION['some_name'], - $_SESSION['another_name'] - ); + unset( + $_SESSION['some_name'], + $_SESSION['another_name'] + ); Also, just as ``set()`` can be used to add information to a session, ``remove()`` can be used to remove it, by passing the session key. For example, if you wanted to remove 'some_name' from your session data array:: - $session->remove('some_name'); + $session->remove('some_name'); This method also accepts an array of item keys to unset:: - $array_items = ['username', 'email']; - $session->remove($array_items); + $array_items = ['username', 'email']; + $session->remove($array_items); Flashdata ========= @@ -250,21 +250,21 @@ managed inside the CodeIgniter session handler. To mark an existing item as "flashdata":: - $session->markAsFlashdata('item'); + $session->markAsFlashdata('item'); If you want to mark multiple items as flashdata, simply pass the keys as an array:: - $session->markAsFlashdata(['item', 'item2']); + $session->markAsFlashdata(['item', 'item2']); To add flashdata:: - $_SESSION['item'] = 'value'; - $session->markAsFlashdata('item'); + $_SESSION['item'] = 'value'; + $session->markAsFlashdata('item'); Or alternatively, using the ``setFlashdata()`` method:: - $session->setFlashdata('item', 'value'); + $session->setFlashdata('item', 'value'); You can also pass an array to ``setFlashdata()``, in the same manner as ``set()``. @@ -272,23 +272,23 @@ You can also pass an array to ``setFlashdata()``, in the same manner as Reading flashdata variables is the same as reading regular session data through ``$_SESSION``:: - $_SESSION['item'] + $_SESSION['item'] .. important:: The ``get()`` method WILL return flashdata items when - retrieving a single item by key. It will not return flashdata when - grabbing all userdata from the session, however. + retrieving a single item by key. It will not return flashdata when + grabbing all userdata from the session, however. However, if you want to be sure that you're reading "flashdata" (and not any other kind), you can also use the ``getFlashdata()`` method:: - $session->getFlashdata('item'); + $session->getFlashdata('item'); Or to get an array with all flashdata, simply omit the key parameter:: - $session->getFlashdata(); + $session->getFlashdata(); .. note:: The ``getFlashdata()`` method returns null if the item cannot be - found. + found. If you find that you need to preserve a flashdata variable through an additional request, you can do so using the ``keepFlashdata()`` method. @@ -296,8 +296,8 @@ You can either pass a single item or an array of flashdata items to keep. :: - $session->keepFlashdata('item'); - $session->keepFlashdata(['item1', 'item2', 'item3']); + $session->keepFlashdata('item'); + $session->keepFlashdata(['item1', 'item2', 'item3']); Tempdata ======== @@ -312,71 +312,71 @@ CodeIgniter session handler. To mark an existing item as "tempdata", simply pass its key and expiry time (in seconds!) to the ``markAsTempdata()`` method:: - // 'item' will be erased after 300 seconds - $session->markAsTempdata('item', 300); + // 'item' will be erased after 300 seconds + $session->markAsTempdata('item', 300); You can mark multiple items as tempdata in two ways, depending on whether you want them all to have the same expiry time or not:: - // Both 'item' and 'item2' will expire after 300 seconds - $session->markAsTempdata(['item', 'item2'], 300); + // Both 'item' and 'item2' will expire after 300 seconds + $session->markAsTempdata(['item', 'item2'], 300); - // 'item' will be erased after 300 seconds, while 'item2' - // will do so after only 240 seconds - $session->markAsTempdata([ - 'item' => 300, - 'item2' => 240, - ]); + // 'item' will be erased after 300 seconds, while 'item2' + // will do so after only 240 seconds + $session->markAsTempdata([ + 'item' => 300, + 'item2' => 240, + ]); To add tempdata:: - $_SESSION['item'] = 'value'; - $session->markAsTempdata('item', 300); // Expire in 5 minutes + $_SESSION['item'] = 'value'; + $session->markAsTempdata('item', 300); // Expire in 5 minutes Or alternatively, using the ``setTempdata()`` method:: - $session->setTempdata('item', 'value', 300); + $session->setTempdata('item', 'value', 300); You can also pass an array to ``setTempdata()``:: - $tempdata = ['newuser' => true, 'message' => 'Thanks for joining!']; - $session->setTempdata($tempdata, null, $expire); + $tempdata = ['newuser' => true, 'message' => 'Thanks for joining!']; + $session->setTempdata($tempdata, null, $expire); .. note:: If the expiration is omitted or set to 0, the default - time-to-live value of 300 seconds (or 5 minutes) will be used. + time-to-live value of 300 seconds (or 5 minutes) will be used. To read a tempdata variable, again you can just access it through the ``$_SESSION`` superglobal array:: - $_SESSION['item'] + $_SESSION['item'] .. important:: The ``get()`` method WILL return tempdata items when - retrieving a single item by key. It will not return tempdata when - grabbing all userdata from the session, however. + retrieving a single item by key. It will not return tempdata when + grabbing all userdata from the session, however. Or if you want to be sure that you're reading "tempdata" (and not any other kind), you can also use the ``getTempdata()`` method:: - $session->getTempdata('item'); + $session->getTempdata('item'); And of course, if you want to retrieve all existing tempdata:: - $session->getTempdata(); + $session->getTempdata(); .. note:: The ``getTempdata()`` method returns null if the item cannot be - found. + found. If you need to remove a tempdata value before it expires, you can directly unset it from the ``$_SESSION`` array:: - unset($_SESSION['item']); + unset($_SESSION['item']); However, this won't remove the marker that makes this specific item to be tempdata (it will be invalidated on the next HTTP request), so if you intend to reuse that same key in the same request, you'd want to use ``removeTempdata()``:: - $session->removeTempdata('item'); + $session->removeTempdata('item'); Destroying a Session ==================== @@ -386,16 +386,16 @@ simply use either PHP's `session_destroy() function, or the library's ``destroy()`` method. Both will work in exactly the same way:: - session_destroy(); + session_destroy(); - // or + // or - $session->destroy(); + $session->destroy(); .. note:: This must be the last session-related operation that you do - during the same request. All session data (including flashdata and - tempdata) will be destroyed permanently and functions will be - unusable during the same request after you destroy the session. + during the same request. All session data (including flashdata and + tempdata) will be destroyed permanently and functions will be + unusable during the same request after you destroy the session. You may also use the ``stop()`` method to completely kill the session by removing the old session_id, destroying all data, and destroying @@ -452,11 +452,11 @@ Preference Default Opti ============================== ============================================ ================================================= ============================================================================================ .. note:: As a last resort, the Session library will try to fetch PHP's - session related INI settings, as well as legacy CI settings such as - 'sess_expire_on_close' when any of the above is not configured. - However, you should never rely on this behavior as it can cause - unexpected results or be changed in the future. Please configure - everything properly. + session related INI settings, as well as legacy CI settings such as + 'sess_expire_on_close' when any of the above is not configured. + However, you should never rely on this behavior as it can cause + unexpected results or be changed in the future. Please configure + everything properly. In addition to the values above, the cookie and native drivers apply the following configuration values shared by the :doc:`IncomingRequest ` and @@ -472,9 +472,9 @@ Preference Default Description ==================== =============== =========================================================================== .. note:: The 'cookieHTTPOnly' setting doesn't have an effect on sessions. - Instead the HttpOnly parameter is always enabled, for security - reasons. Additionally, the 'cookiePrefix' setting is completely - ignored. + Instead the HttpOnly parameter is always enabled, for security + reasons. Additionally, the 'cookiePrefix' setting is completely + ignored. Session Drivers *************** @@ -533,9 +533,9 @@ permissions will probably break your application. Instead, you should do something like this, depending on your environment :: - mkdir //Writable/sessions/ - chmod 0700 //Writable/sessions/ - chown www-data //Writable/sessions/ + mkdir //Writable/sessions/ + chmod 0700 //Writable/sessions/ + chown www-data //Writable/sessions/ Bonus Tip --------- @@ -571,43 +571,43 @@ table that we already mentioned and then set it as your For example, if you would like to use 'ci_sessions' as your table name, you would do this:: - public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; - public $sessionSavePath = 'ci_sessions'; + public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; + public $sessionSavePath = 'ci_sessions'; And then of course, create the database table ... For MySQL:: - CREATE TABLE IF NOT EXISTS `ci_sessions` ( - `id` varchar(128) NOT null, - `ip_address` varchar(45) NOT null, - `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP NOT null, - `data` blob NOT null, - KEY `ci_sessions_timestamp` (`timestamp`) - ); + CREATE TABLE IF NOT EXISTS `ci_sessions` ( + `id` varchar(128) NOT null, + `ip_address` varchar(45) NOT null, + `timestamp` timestamp DEFAULT CURRENT_TIMESTAMP NOT null, + `data` blob NOT null, + KEY `ci_sessions_timestamp` (`timestamp`) + ); For PostgreSQL:: - CREATE TABLE "ci_sessions" ( - "id" varchar(128) NOT NULL, - "ip_address" inet NOT NULL, - "timestamp" timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, - "data" bytea DEFAULT '' NOT NULL - ); + CREATE TABLE "ci_sessions" ( + "id" varchar(128) NOT NULL, + "ip_address" inet NOT NULL, + "timestamp" timestamptz DEFAULT CURRENT_TIMESTAMP NOT NULL, + "data" bytea DEFAULT '' NOT NULL + ); - CREATE INDEX "ci_sessions_timestamp" ON "ci_sessions" ("timestamp"); + CREATE INDEX "ci_sessions_timestamp" ON "ci_sessions" ("timestamp"); You will also need to add a PRIMARY KEY **depending on your 'sessionMatchIP' setting**. The examples below work both on MySQL and PostgreSQL:: - // When sessionMatchIP = true - ALTER TABLE ci_sessions ADD PRIMARY KEY (id, ip_address); + // When sessionMatchIP = true + ALTER TABLE ci_sessions ADD PRIMARY KEY (id, ip_address); - // When sessionMatchIP = false - ALTER TABLE ci_sessions ADD PRIMARY KEY (id); + // When sessionMatchIP = false + ALTER TABLE ci_sessions ADD PRIMARY KEY (id); - // To drop a previously created primary key (use when changing the setting) - ALTER TABLE ci_sessions DROP PRIMARY KEY; + // To drop a previously created primary key (use when changing the setting) + ALTER TABLE ci_sessions DROP PRIMARY KEY; You can choose the Database group to use by adding a new line to the **app/Config/App.php** file with the name of the group to use:: @@ -624,19 +624,19 @@ This command will take the **sessionSavePath** and **sessionMatchIP** settings i when it generates the code. .. important:: Only MySQL and PostgreSQL databases are officially - supported, due to lack of advisory locking mechanisms on other - platforms. Using sessions without locks can cause all sorts of - problems, especially with heavy usage of AJAX, and we will not - support such cases. Use ``session_write_close()`` after you've - done processing session data if you're having performance - issues. + supported, due to lack of advisory locking mechanisms on other + platforms. Using sessions without locks can cause all sorts of + problems, especially with heavy usage of AJAX, and we will not + support such cases. Use ``session_write_close()`` after you've + done processing session data if you're having performance + issues. RedisHandler Driver =================== .. note:: Since Redis doesn't have a locking mechanism exposed, locks for - this driver are emulated by a separate value that is kept for up - to 300 seconds. + this driver are emulated by a separate value that is kept for up + to 300 seconds. Redis is a storage engine typically used for caching and popular because of its high performance, which is also probably your reason to use the @@ -656,24 +656,24 @@ The format here is a bit different and complicated at the same time. It is best explained by the *phpredis* extension's README file, so we'll simply link you to it: - https://github.com/phpredis/phpredis + https://github.com/phpredis/phpredis .. warning:: CodeIgniter's Session library does NOT use the actual 'redis' - ``session.save_handler``. Take note **only** of the path format in - the link above. + ``session.save_handler``. Take note **only** of the path format in + the link above. For the most common case however, a simple ``host:port`` pair should be sufficient:: - public $sessionDiver = 'CodeIgniter\Session\Handlers\RedisHandler'; - public $sessionSavePath = 'tcp://localhost:6379'; + public $sessionDiver = 'CodeIgniter\Session\Handlers\RedisHandler'; + public $sessionSavePath = 'tcp://localhost:6379'; MemcachedHandler Driver ======================= .. note:: Since Memcached doesn't have a locking mechanism exposed, locks - for this driver are emulated by a separate value that is kept for - up to 300 seconds. + for this driver are emulated by a separate value that is kept for + up to 300 seconds. The 'MemcachedHandler' driver is very similar to the 'RedisHandler' one in all of its properties, except perhaps for availability, because PHP's `Memcached @@ -693,8 +693,8 @@ considered as it may result in loss of sessions. The ``$sessionSavePath`` format is fairly straightforward here, being just a ``host:port`` pair:: - public $sessionDriver = 'CodeIgniter\Session\Handlers\MemcachedHandler'; - public $sessionSavePath = 'localhost:11211'; + public $sessionDriver = 'CodeIgniter\Session\Handlers\MemcachedHandler'; + public $sessionSavePath = 'localhost:11211'; Bonus Tip --------- @@ -706,6 +706,6 @@ to note that we haven't tested if that is reliable. If you want to experiment with this feature (on your own risk), simply separate the multiple server paths with commas:: - // localhost will be given higher priority (5) here, - // compared to 192.0.2.1 with a weight of 1. - public $sessionSavePath = 'localhost:11211:5,192.0.2.1:11211:1'; + // localhost will be given higher priority (5) here, + // compared to 192.0.2.1 with a weight of 1. + public $sessionSavePath = 'localhost:11211:5,192.0.2.1:11211:1'; diff --git a/user_guide_src/source/libraries/user_agent.rst b/user_guide_src/source/libraries/user_agent.rst index f8cf92f72064..327a943f9749 100644 --- a/user_guide_src/source/libraries/user_agent.rst +++ b/user_guide_src/source/libraries/user_agent.rst @@ -20,7 +20,7 @@ The User Agent class is always available directly from the current :doc:`Incomin By default, you will have a request instance in your controller that you can retrieve the User Agent class from:: - $agent = $this->request->getUserAgent(); + $agent = $this->request->getUserAgent(); User Agent Definitions ====================== @@ -37,21 +37,21 @@ whether the user agent browsing your site is a web browser, a mobile device, or a robot. It will also gather the platform information if it is available:: - $agent = $this->request->getUserAgent(); + $agent = $this->request->getUserAgent(); - if ($agent->isBrowser()) { - $currentAgent = $agent->getBrowser().' '.$agent->getVersion(); - } elseif ($agent->isRobot()) { - $currentAgent = $this->agent->robot(); - } elseif ($agent->isMobile()) { - $currentAgent = $agent->getMobile(); - } else { - $currentAgent = 'Unidentified User Agent'; - } + if ($agent->isBrowser()) { + $currentAgent = $agent->getBrowser().' '.$agent->getVersion(); + } elseif ($agent->isRobot()) { + $currentAgent = $this->agent->robot(); + } elseif ($agent->isMobile()) { + $currentAgent = $agent->getMobile(); + } else { + $currentAgent = 'Unidentified User Agent'; + } - echo $currentAgent; + echo $currentAgent; - echo $agent->getPlatform(); // Platform info (Windows, Linux, Mac, etc.) + echo $agent->getPlatform(); // Platform info (Windows, Linux, Mac, etc.) *************** Class Reference @@ -59,120 +59,120 @@ Class Reference .. php:class:: CodeIgniter\\HTTP\\UserAgent - .. php:method:: isBrowser([$key = null]) + .. php:method:: isBrowser([$key = null]) - :param string $key: Optional browser name - :returns: true if the user agent is a (specified) browser, false if not - :rtype: bool + :param string $key: Optional browser name + :returns: true if the user agent is a (specified) browser, false if not + :rtype: bool - Returns true/false (boolean) if the user agent is a known web browser. - :: + Returns true/false (boolean) if the user agent is a known web browser. + :: - if ($agent->isBrowser('Safari')) { - echo 'You are using Safari.'; - } elseif ($agent->isBrowser()) { - echo 'You are using a browser.'; - } + if ($agent->isBrowser('Safari')) { + echo 'You are using Safari.'; + } elseif ($agent->isBrowser()) { + echo 'You are using a browser.'; + } - .. note:: The string "Safari" in this example is an array key in the list of browser definitions. - You can find this list in **app/Config/UserAgents.php** if you want to add new - browsers or change the strings. + .. note:: The string "Safari" in this example is an array key in the list of browser definitions. + You can find this list in **app/Config/UserAgents.php** if you want to add new + browsers or change the strings. - .. php:method:: isMobile([$key = null]) + .. php:method:: isMobile([$key = null]) - :param string $key: Optional mobile device name - :returns: true if the user agent is a (specified) mobile device, false if not - :rtype: bool + :param string $key: Optional mobile device name + :returns: true if the user agent is a (specified) mobile device, false if not + :rtype: bool - Returns true/false (boolean) if the user agent is a known mobile device. - :: + Returns true/false (boolean) if the user agent is a known mobile device. + :: - if ($agent->isMobile('iphone')) { - echo view('iphone/home'); - } elseif ($agent->isMobile()) { - echo view('mobile/home'); - } else { - echo view('web/home'); - } + if ($agent->isMobile('iphone')) { + echo view('iphone/home'); + } elseif ($agent->isMobile()) { + echo view('mobile/home'); + } else { + echo view('web/home'); + } - .. php:method:: isRobot([$key = null]) + .. php:method:: isRobot([$key = null]) - :param string $key: Optional robot name - :returns: true if the user agent is a (specified) robot, false if not - :rtype: bool + :param string $key: Optional robot name + :returns: true if the user agent is a (specified) robot, false if not + :rtype: bool - Returns true/false (boolean) if the user agent is a known robot. + Returns true/false (boolean) if the user agent is a known robot. - .. note:: The user agent library only contains the most common robot definitions. It is not a complete list of bots. - There are hundreds of them so searching for each one would not be very efficient. If you find that some bots - that commonly visit your site are missing from the list you can add them to your - **app/Config/UserAgents.php** file. + .. note:: The user agent library only contains the most common robot definitions. It is not a complete list of bots. + There are hundreds of them so searching for each one would not be very efficient. If you find that some bots + that commonly visit your site are missing from the list you can add them to your + **app/Config/UserAgents.php** file. - .. php:method:: isReferral() + .. php:method:: isReferral() - :returns: true if the user agent is a referral, false if not - :rtype: bool + :returns: true if the user agent is a referral, false if not + :rtype: bool - Returns true/false (boolean) if the user agent was referred from another site. + Returns true/false (boolean) if the user agent was referred from another site. - .. php:method:: getBrowser() + .. php:method:: getBrowser() - :returns: Detected browser or an empty string - :rtype: string + :returns: Detected browser or an empty string + :rtype: string - Returns a string containing the name of the web browser viewing your site. + Returns a string containing the name of the web browser viewing your site. - .. php:method:: getVersion() + .. php:method:: getVersion() - :returns: Detected browser version or an empty string - :rtype: string + :returns: Detected browser version or an empty string + :rtype: string - Returns a string containing the version number of the web browser viewing your site. + Returns a string containing the version number of the web browser viewing your site. - .. php:method:: getMobile() + .. php:method:: getMobile() - :returns: Detected mobile device brand or an empty string - :rtype: string + :returns: Detected mobile device brand or an empty string + :rtype: string - Returns a string containing the name of the mobile device viewing your site. + Returns a string containing the name of the mobile device viewing your site. - .. php:method:: getRobot() + .. php:method:: getRobot() - :returns: Detected robot name or an empty string - :rtype: string + :returns: Detected robot name or an empty string + :rtype: string - Returns a string containing the name of the robot viewing your site. + Returns a string containing the name of the robot viewing your site. - .. php:method:: getPlatform() + .. php:method:: getPlatform() - :returns: Detected operating system or an empty string - :rtype: string + :returns: Detected operating system or an empty string + :rtype: string - Returns a string containing the platform viewing your site (Linux, Windows, OS X, etc.). + Returns a string containing the platform viewing your site (Linux, Windows, OS X, etc.). - .. php:method:: getReferrer() + .. php:method:: getReferrer() - :returns: Detected referrer or an empty string - :rtype: string + :returns: Detected referrer or an empty string + :rtype: string - The referrer, if the user agent was referred from another site. Typically you'll test for this as follows:: + The referrer, if the user agent was referred from another site. Typically you'll test for this as follows:: - if ($agent->isReferral()) { - echo $agent->referrer(); - } + if ($agent->isReferral()) { + echo $agent->referrer(); + } - .. php:method:: getAgentString() + .. php:method:: getAgentString() - :returns: Full user agent string or an empty string - :rtype: string + :returns: Full user agent string or an empty string + :rtype: string - Returns a string containing the full user agent string. Typically it will be something like this:: + Returns a string containing the full user agent string. Typically it will be something like this:: - Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2 + Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.0.4) Gecko/20060613 Camino/1.0.2 - .. php:method:: parse($string) + .. php:method:: parse($string) - :param string $string: A custom user-agent string - :rtype: void + :param string $string: A custom user-agent string + :rtype: void - Parses a custom user-agent string, different from the one reported by the current visitor. + Parses a custom user-agent string, different from the one reported by the current visitor. diff --git a/user_guide_src/source/outgoing/table.rst b/user_guide_src/source/outgoing/table.rst index 334658d08380..0c8810fdb277 100644 --- a/user_guide_src/source/outgoing/table.rst +++ b/user_guide_src/source/outgoing/table.rst @@ -18,7 +18,7 @@ Initializing the Class The Table class is not provided as a service, and should be instantiated "normally", for instance:: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); Examples ======== @@ -30,16 +30,16 @@ method described in the function reference below). :: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); - $data = [ - ['Name', 'Color', 'Size'], - ['Fred', 'Blue', 'Small'], - ['Mary', 'Red', 'Large'], - ['John', 'Green', 'Medium'], - ]; + $data = [ + ['Name', 'Color', 'Size'], + ['Fred', 'Blue', 'Small'], + ['Mary', 'Red', 'Large'], + ['John', 'Green', 'Medium'], + ]; - echo $table->generate($data); + echo $table->generate($data); Here is an example of a table created from a database query result. The table class will automatically generate the headings based on the table @@ -48,37 +48,37 @@ method described in the class reference below). :: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); - $query = $db->query('SELECT * FROM my_table'); + $query = $db->query('SELECT * FROM my_table'); - echo $table->generate($query); + echo $table->generate($query); Here is an example showing how you might create a table using discrete parameters:: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); - $table->setHeading('Name', 'Color', 'Size'); + $table->setHeading('Name', 'Color', 'Size'); - $table->addRow('Fred', 'Blue', 'Small'); - $table->addRow('Mary', 'Red', 'Large'); - $table->addRow('John', 'Green', 'Medium'); + $table->addRow('Fred', 'Blue', 'Small'); + $table->addRow('Mary', 'Red', 'Large'); + $table->addRow('John', 'Green', 'Medium'); - echo $table->generate(); + echo $table->generate(); Here is the same example, except instead of individual parameters, arrays are used:: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); - $table->setHeading(array('Name', 'Color', 'Size')); + $table->setHeading(array('Name', 'Color', 'Size')); - $table->addRow(['Fred', 'Blue', 'Small']); - $table->addRow(['Mary', 'Red', 'Large']); - $table->addRow(['John', 'Green', 'Medium']); + $table->addRow(['Fred', 'Blue', 'Small']); + $table->addRow(['Mary', 'Red', 'Large']); + $table->addRow(['John', 'Green', 'Medium']); - echo $table->generate(); + echo $table->generate(); Changing the Look of Your Table =============================== @@ -86,65 +86,65 @@ Changing the Look of Your Table The Table Class permits you to set a table template with which you can specify the design of your layout. Here is the template prototype:: - $template = [ - 'table_open' => '
    {$row['name']}{$row['component']}" . number_format($row['duration'] * 1000, 2) . ' ms
    ' . ($hasChildren ? '' : '') . $row['name'] . '' . $row['component'] . '' . number_format($row['duration'] * 1000, 2) . ' ms"; $offset = ((((float) $row['start'] - $startTime) * 1000) / $displayTime) * 100; @@ -189,6 +210,19 @@ protected function renderTimeline(array $collectors, float $startTime, int $segm $output .= '
    '; + $output .= ''; + $output .= ''; + $output .= $this->renderTimelineRecursive($row['children'], $startTime, $segmentCount, $segmentDuration, $styles, $styleCount, $level + 1, true); + $output .= ''; + $output .= '
    '; + $output .= '
    ', + $template = [ + 'table_open' => '
    ', - 'thead_open' => '', - 'thead_close' => '', + 'thead_open' => '', + 'thead_close' => '', - 'heading_row_start' => '', - 'heading_row_end' => '', - 'heading_cell_start' => '', + 'heading_row_start' => '', + 'heading_row_end' => '', + 'heading_cell_start' => '', - 'tfoot_open' => '', - 'tfoot_close' => '', + 'tfoot_open' => '', + 'tfoot_close' => '', - 'footing_row_start' => '', - 'footing_row_end' => '', - 'footing_cell_start' => '', + 'footing_row_start' => '', + 'footing_row_end' => '', + 'footing_cell_start' => '', - 'tbody_open' => '', - 'tbody_close' => '', + 'tbody_open' => '', + 'tbody_close' => '', - 'row_start' => '', - 'row_end' => '', - 'cell_start' => '', + 'row_start' => '', + 'row_end' => '', + 'cell_start' => '', - 'row_alt_start' => '', - 'row_alt_end' => '', - 'cell_alt_start' => '', + 'row_alt_start' => '', + 'row_alt_end' => '', + 'cell_alt_start' => '', - 'table_close' => '
    ', - 'heading_cell_end' => '
    ', + 'heading_cell_end' => '
    ', - 'footing_cell_end' => '
    ', + 'footing_cell_end' => '
    ', - 'cell_end' => '
    ', + 'cell_end' => '
    ', - 'cell_alt_end' => '
    ', + 'cell_alt_end' => '
    ' - ]; + 'table_close' => '' + ]; - $table->setTemplate($template); + $table->setTemplate($template); .. note:: You'll notice there are two sets of "row" blocks in the - template. These permit you to create alternating row colors or design - elements that alternate with each iteration of the row data. + template. These permit you to create alternating row colors or design + elements that alternate with each iteration of the row data. You are NOT required to submit a complete template. If you only need to change parts of the layout you can simply submit those elements. In this example, only the table opening tag is being changed:: - $template = [ - 'table_open' => '' - ]; + $template = [ + 'table_open' => '
    ' + ]; - $table->setTemplate($template); + $table->setTemplate($template); You can also set defaults for these by passing an array of template settings to the Table constructor.:: - $customSettings = [ - 'table_open' => '
    ' - ]; + $customSettings = [ + 'table_open' => '
    ' + ]; - $table = new \CodeIgniter\View\Table($customSettings); + $table = new \CodeIgniter\View\Table($customSettings); *************** @@ -153,171 +153,171 @@ Class Reference .. php:class:: Table - .. attribute:: $function = null + .. attribute:: $function = null - Allows you to specify a native PHP function or a valid function array object to be applied to all cell data. - :: + Allows you to specify a native PHP function or a valid function array object to be applied to all cell data. + :: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); - $table->setHeading('Name', 'Color', 'Size'); - $table->addRow('Fred', 'Blue', 'Small'); + $table->setHeading('Name', 'Color', 'Size'); + $table->addRow('Fred', 'Blue', 'Small'); - $table->function = 'htmlspecialchars'; - echo $table->generate(); + $table->function = 'htmlspecialchars'; + echo $table->generate(); - In the above example, all cell data would be run through PHP's :php:func:`htmlspecialchars()` function, resulting in:: + In the above example, all cell data would be run through PHP's :php:func:`htmlspecialchars()` function, resulting in:: - + - .. php:method:: generate([$tableData = null]) + .. php:method:: generate([$tableData = null]) - :param mixed $tableData: Data to populate the table rows with - :returns: HTML table - :rtype: string + :param mixed $tableData: Data to populate the table rows with + :returns: HTML table + :rtype: string - Returns a string containing the generated table. Accepts an optional parameter which can be an array or a database result object. + Returns a string containing the generated table. Accepts an optional parameter which can be an array or a database result object. - .. php:method:: setCaption($caption) + .. php:method:: setCaption($caption) - :param string $caption: Table caption - :returns: Table instance (method chaining) - :rtype: Table + :param string $caption: Table caption + :returns: Table instance (method chaining) + :rtype: Table - Permits you to add a caption to the table. - :: + Permits you to add a caption to the table. + :: - $table->setCaption('Colors'); + $table->setCaption('Colors'); - .. php:method:: setHeading([$args = [] [, ...]]) + .. php:method:: setHeading([$args = [] [, ...]]) - :param mixed $args: An array or multiple strings containing the table column titles - :returns: Table instance (method chaining) - :rtype: Table + :param mixed $args: An array or multiple strings containing the table column titles + :returns: Table instance (method chaining) + :rtype: Table - Permits you to set the table heading. You can submit an array or discrete params:: + Permits you to set the table heading. You can submit an array or discrete params:: - $table->setHeading('Name', 'Color', 'Size'); // or + $table->setHeading('Name', 'Color', 'Size'); // or - $table->setHeading(['Name', 'Color', 'Size']); + $table->setHeading(['Name', 'Color', 'Size']); - .. php:method:: setFooting([$args = [] [, ...]]) + .. php:method:: setFooting([$args = [] [, ...]]) - :param mixed $args: An array or multiple strings containing the table footing values - :returns: Table instance (method chaining) - :rtype: Table + :param mixed $args: An array or multiple strings containing the table footing values + :returns: Table instance (method chaining) + :rtype: Table - Permits you to set the table footing. You can submit an array or discrete params:: + Permits you to set the table footing. You can submit an array or discrete params:: - $table->setFooting('Subtotal', $subtotal, $notes); // or + $table->setFooting('Subtotal', $subtotal, $notes); // or - $table->setFooting(['Subtotal', $subtotal, $notes]); + $table->setFooting(['Subtotal', $subtotal, $notes]); - .. php:method:: addRow([$args = [] [, ...]]) + .. php:method:: addRow([$args = [] [, ...]]) - :param mixed $args: An array or multiple strings containing the row values - :returns: Table instance (method chaining) - :rtype: Table + :param mixed $args: An array or multiple strings containing the row values + :returns: Table instance (method chaining) + :rtype: Table - Permits you to add a row to your table. You can submit an array or discrete params:: + Permits you to add a row to your table. You can submit an array or discrete params:: - $table->addRow('Blue', 'Red', 'Green'); // or + $table->addRow('Blue', 'Red', 'Green'); // or - $table->addRow(['Blue', 'Red', 'Green']); + $table->addRow(['Blue', 'Red', 'Green']); - If you would like to set an individual cell's tag attributes, you can use an associative array for that cell. - The associative key **data** defines the cell's data. Any other key => val pairs are added as key='val' attributes to the tag:: + If you would like to set an individual cell's tag attributes, you can use an associative array for that cell. + The associative key **data** defines the cell's data. Any other key => val pairs are added as key='val' attributes to the tag:: - $cell = ['data' => 'Blue', 'class' => 'highlight', 'colspan' => 2]; - $table->addRow($cell, 'Red', 'Green'); + $cell = ['data' => 'Blue', 'class' => 'highlight', 'colspan' => 2]; + $table->addRow($cell, 'Red', 'Green'); - // generates - // + // generates + // - .. php:method:: makeColumns([$array = [] [, $columnLimit = 0]]) + .. php:method:: makeColumns([$array = [] [, $columnLimit = 0]]) - :param array $array: An array containing multiple rows' data - :param int $columnLimit: Count of columns in the table - :returns: An array of HTML table columns - :rtype: array + :param array $array: An array containing multiple rows' data + :param int $columnLimit: Count of columns in the table + :returns: An array of HTML table columns + :rtype: array - This method takes a one-dimensional array as input and creates a multi-dimensional array with a depth equal to the number of columns desired. - This allows a single array with many elements to be displayed in a table that has a fixed column count. Consider this example:: + This method takes a one-dimensional array as input and creates a multi-dimensional array with a depth equal to the number of columns desired. + This allows a single array with many elements to be displayed in a table that has a fixed column count. Consider this example:: - $list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve']; + $list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve']; - $newList = $table->makeColumns($list, 3); + $newList = $table->makeColumns($list, 3); - $table->generate($newList); + $table->generate($newList); - // Generates a table with this prototype + // Generates a table with this prototype -
    Fred<strong>Blue</strong>SmallFred<strong>Blue</strong>SmallBlueRedGreenBlueRedGreen
    - - - - - - - - -
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    + + + + + + + + + +
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    - .. php:method:: setTemplate($template) + .. php:method:: setTemplate($template) - :param array $template: An associative array containing template values - :returns: true on success, false on failure - :rtype: bool + :param array $template: An associative array containing template values + :returns: true on success, false on failure + :rtype: bool - Permits you to set your template. You can submit a full or partial template. - :: + Permits you to set your template. You can submit a full or partial template. + :: - $template = [ - 'table_open' => '' - ]; + $template = [ + 'table_open' => '
    ' + ]; - $table->setTemplate($template); + $table->setTemplate($template); - .. php:method:: setEmpty($value) + .. php:method:: setEmpty($value) - :param mixed $value: Value to put in empty cells - :returns: Table instance (method chaining) - :rtype: Table + :param mixed $value: Value to put in empty cells + :returns: Table instance (method chaining) + :rtype: Table - Lets you set a default value for use in any table cells that are empty. - You might, for example, set a non-breaking space:: + Lets you set a default value for use in any table cells that are empty. + You might, for example, set a non-breaking space:: - $table->setEmpty(" "); + $table->setEmpty(" "); - .. php:method:: clear() + .. php:method:: clear() - :returns: Table instance (method chaining) - :rtype: Table + :returns: Table instance (method chaining) + :rtype: Table - Lets you clear the table heading, row data and caption. If - you need to show multiple tables with different data you - should to call this method after each table has been - generated to clear the previous table information. + Lets you clear the table heading, row data and caption. If + you need to show multiple tables with different data you + should to call this method after each table has been + generated to clear the previous table information. - Example :: + Example :: - $table = new \CodeIgniter\View\Table(); + $table = new \CodeIgniter\View\Table(); - $table->setCaption('Preferences') - ->setHeading('Name', 'Color', 'Size') - ->addRow('Fred', 'Blue', 'Small') - ->addRow('Mary', 'Red', 'Large') - ->addRow('John', 'Green', 'Medium'); + $table->setCaption('Preferences') + ->setHeading('Name', 'Color', 'Size') + ->addRow('Fred', 'Blue', 'Small') + ->addRow('Mary', 'Red', 'Large') + ->addRow('John', 'Green', 'Medium'); - echo $table->generate(); + echo $table->generate(); - $table->clear(); + $table->clear(); - $table->setCaption('Shipping') - ->setHeading('Name', 'Day', 'Delivery') - ->addRow('Fred', 'Wednesday', 'Express') - ->addRow('Mary', 'Monday', 'Air') - ->addRow('John', 'Saturday', 'Overnight'); + $table->setCaption('Shipping') + ->setHeading('Name', 'Day', 'Delivery') + ->addRow('Fred', 'Wednesday', 'Express') + ->addRow('Mary', 'Monday', 'Air') + ->addRow('John', 'Saturday', 'Overnight'); - echo $table->generate(); + echo $table->generate(); diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 0ea2001fe724..19121c98b86a 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -21,14 +21,14 @@ Creating a View Using your text editor, create a file called ``BlogView.php`` and put this in it:: - + My Blog

    Welcome to my Blog!

    - + Then save the file in your **app/Views** directory. @@ -37,7 +37,7 @@ Displaying a View To load and display a particular view file you will use the following function:: - echo view('name'); + echo view('name'); Where *name* is the name of your view file. @@ -45,21 +45,21 @@ Where *name* is the name of your view file. Now, open the controller file you made earlier called ``Blog.php``, and replace the echo statement with the view function:: - 'Your title', - ]; + class Page extends \CodeIgniter\Controller + { + public function index() + { + $data = [ + 'page_title' => 'Your title', + ]; - echo view('header'); - echo view('menu'); - echo view('content', $data); - echo view('footer'); - } - } + echo view('header'); + echo view('menu'); + echo view('content', $data); + echo view('footer'); + } + } In the example above, we are using "dynamically added data", which you will see below. @@ -98,7 +98,7 @@ Storing Views within Sub-directories Your view files can also be stored within sub-directories if you prefer that type of organization. When doing so you will need to include the directory name loading the view. Example:: - echo view('directory_name/file_name'); + echo view('directory_name/file_name'); Namespaced Views ================ @@ -134,41 +134,41 @@ Adding Dynamic Data to the View Data is passed from the controller to the view by way of an array in the second parameter of the view function. Here's an example:: - $data = [ - 'title' => 'My title', - 'heading' => 'My Heading', - 'message' => 'My Message', - ]; + $data = [ + 'title' => 'My title', + 'heading' => 'My Heading', + 'message' => 'My Message', + ]; - echo view('blogview', $data); + echo view('blogview', $data); Let's try it with your controller file. Open it and add this code:: - + <?= $title ?>

    - + Then load the page at the URL you've been using and you should see the variables replaced. @@ -178,13 +178,13 @@ other views, potentially causing issues. If you would prefer the data to persist into the `$option` array in the third parameter. :: - $data = [ - 'title' => 'My title', - 'heading' => 'My Heading', - 'message' => 'My Message', - ]; + $data = [ + 'title' => 'My title', + 'heading' => 'My Heading', + 'message' => 'My Message', + ]; - echo view('blogview', $data, ['saveData' => true]); + echo view('blogview', $data, ['saveData' => true]); Additionally, if you would like the default functionality of the view function to be that it does save the data between calls, you can set ``$saveData`` to **true** in **app/Config/Views.php**. @@ -198,42 +198,42 @@ typically be in the form of a multi-dimensional array. Here’s a simple example. Add this to your controller:: - ['Clean House', 'Call Mom', 'Run Errands'], - 'title' => 'My Real Title', - 'heading' => 'My Real Heading', - ]; + class Blog extends \CodeIgniter\Controller + { + public function index() + { + $data = [ + 'todo_list' => ['Clean House', 'Call Mom', 'Run Errands'], + 'title' => 'My Real Title', + 'heading' => 'My Real Heading', + ]; - echo view('blogview', $data); - } - } + echo view('blogview', $data); + } + } Now open your view file and create a loop:: - - - <?= $title ?> - - -

    + + + <?= $title ?> + + +

    -

    My Todo List

    +

    My Todo List

    -
      - +
        + -
      • +
      • - -
      + +
    - - + + From ec5a92540fe674afbca9253aa2056fd479456b14 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Sep 2021 20:10:58 +0900 Subject: [PATCH 0288/2325] docs: replace tabs with spaces --- user_guide_src/ghpages.rst | 10 +- .../source/database/query_builder.rst | 280 +++++++++--------- user_guide_src/source/helpers/form_helper.rst | 220 +++++++------- 3 files changed, 255 insertions(+), 255 deletions(-) diff --git a/user_guide_src/ghpages.rst b/user_guide_src/ghpages.rst index 1d7719c1193c..4699d38f978d 100644 --- a/user_guide_src/ghpages.rst +++ b/user_guide_src/ghpages.rst @@ -26,19 +26,19 @@ Re-generating the User Guide In the ``user_guide_src`` folder, you generate a conventional user guide, for testing, using the command:: - make html + make html An additional target has been configured, which will generate the same HTML but inside the ``html`` folder of the second repo clone:: - make ghpages + make ghpages After making this target, update the online user guide by switching to the ``CodeIgniter4-guide/html`` folder, and then:: - git add . - git commit -S -m "Suitable comment" - git push origin gh-pages + git add . + git commit -S -m "Suitable comment" + git push origin gh-pages Process ======= diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 45380416fdac..26fcba73e4ee 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -627,7 +627,7 @@ searches. $builder->havingLike('title', 'match', 'before'); // Produces: HAVING `title` LIKE '%match' ESCAPE '!' $builder->havingLike('title', 'match', 'after'); // Produces: HAVING `title` LIKE 'match%' ESCAPE '!' - $builder->havingLike('title', 'match', 'both'); // Produces: HAVING `title` LIKE '%match%' ESCAPE '!' + $builder->havingLike('title', 'match', 'both'); // Produces: HAVING `title` LIKE '%match%' ESCAPE '!' #. **Associative array method:** @@ -1046,9 +1046,9 @@ is an example using an array:: $builder->update($data); // Produces: // - // UPDATE mytable - // SET title = '{$title}', name = '{$name}', date = '{$date}' - // WHERE id = $id + // UPDATE mytable + // SET title = '{$title}', name = '{$name}', date = '{$date}' + // WHERE id = $id Or you can supply an object:: @@ -1238,8 +1238,8 @@ Class Reference .. php:method:: db() - :returns: The database connection in use - :rtype: ``ConnectionInterface`` + :returns: The database connection in use + :rtype: ``ConnectionInterface`` Returns the current database connection from ``$db``. Useful for accessing ``ConnectionInterface`` methods that are not directly @@ -1247,8 +1247,8 @@ Class Reference .. php:method:: resetQuery() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Resets the current Query Builder state. Useful when you want to build a query that can be canceled under certain conditions. @@ -1256,8 +1256,8 @@ Class Reference .. php:method:: countAllResults([$reset = true]) :param bool $reset: Whether to reset values for SELECTs - :returns: Number of rows in the query result - :rtype: int + :returns: Number of rows in the query result + :rtype: int Generates a platform-specific query string that counts all records returned by an Query Builder query. @@ -1265,8 +1265,8 @@ Class Reference .. php:method:: countAll([$reset = true]) :param bool $reset: Whether to reset values for SELECTs - :returns: Number of rows in the query result - :rtype: int + :returns: Number of rows in the query result + :rtype: int Generates a platform-specific query string that counts all records in the particular table. @@ -1277,7 +1277,7 @@ Class Reference :param int $offset: The OFFSET clause :param bool $reset: Do we want to clear query builder values? :returns: ``\CodeIgniter\Database\ResultInterface`` instance (method chaining) - :rtype: ``\CodeIgniter\Database\ResultInterface`` + :rtype: ``\CodeIgniter\Database\ResultInterface`` Compiles and runs ``SELECT`` statement based on the already called Query Builder methods. @@ -1288,8 +1288,8 @@ Class Reference :param int $limit: The LIMIT clause :param int $offset: The OFFSET clause :param bool $reset: Do we want to clear query builder values? - :returns: ``\CodeIgniter\Database\ResultInterface`` instance (method chaining) - :rtype: ``\CodeIgniter\Database\ResultInterface`` + :returns: ``\CodeIgniter\Database\ResultInterface`` instance (method chaining) + :rtype: ``\CodeIgniter\Database\ResultInterface`` Same as ``get()``, but also allows the WHERE to be added directly. @@ -1297,8 +1297,8 @@ Class Reference :param string $select: The SELECT portion of a query :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``SELECT`` clause to a query. @@ -1306,8 +1306,8 @@ Class Reference :param string $select: Field to compute the average of :param string $alias: Alias for the resulting value name - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``SELECT AVG(field)`` clause to a query. @@ -1315,8 +1315,8 @@ Class Reference :param string $select: Field to compute the maximum of :param string $alias: Alias for the resulting value name - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``SELECT MAX(field)`` clause to a query. @@ -1324,8 +1324,8 @@ Class Reference :param string $select: Field to compute the minimum of :param string $alias: Alias for the resulting value name - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``SELECT MIN(field)`` clause to a query. @@ -1333,8 +1333,8 @@ Class Reference :param string $select: Field to compute the sum of :param string $alias: Alias for the resulting value name - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``SELECT SUM(field)`` clause to a query. @@ -1342,16 +1342,16 @@ Class Reference :param string $select: Field to compute the average of :param string $alias: Alias for the resulting value name - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``SELECT COUNT(field)`` clause to a query. .. php:method:: distinct([$val = true]) :param bool $val: Desired value of the "distinct" flag - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Sets a flag which tells the query builder to add a ``DISTINCT`` clause to the ``SELECT`` portion of the query. @@ -1359,9 +1359,9 @@ Class Reference .. php:method:: from($from[, $overwrite = false]) :param mixed $from: Table name(s); string or array - :param bool $overwrite: Should we remove the first table existing? - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $overwrite: Should we remove the first table existing? + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Specifies the ``FROM`` clause of a query. @@ -1370,9 +1370,9 @@ Class Reference :param string $table: Table name to join :param string $cond: The JOIN ON condition :param string $type: The JOIN type - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``JOIN`` clause to a query. @@ -1380,9 +1380,9 @@ Class Reference :param mixed $key: Name of field to compare, or associative array :param mixed $value: If a single key, compared to this value - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates the ``WHERE`` portion of the query. Separates multiple calls with ``AND``. @@ -1391,8 +1391,8 @@ Class Reference :param mixed $key: Name of field to compare, or associative array :param mixed $value: If a single key, compared to this value :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates the ``WHERE`` portion of the query. Separates multiple calls with ``OR``. @@ -1401,8 +1401,8 @@ Class Reference :param string $key: The field to search :param array|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``WHERE`` field ``IN('item', 'item')`` SQL query, joined with ``OR`` if appropriate. @@ -1411,8 +1411,8 @@ Class Reference :param string $key: The field to search :param array|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``WHERE`` field ``NOT IN('item', 'item')`` SQL query, joined with ``OR`` if appropriate. @@ -1421,8 +1421,8 @@ Class Reference :param string $key: Name of field to examine :param array|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``WHERE`` field ``IN('item', 'item')`` SQL query, joined with ``AND`` if appropriate. @@ -1430,44 +1430,44 @@ Class Reference :param string $key: Name of field to examine :param array|Closure $values: Array of target values, or anonymous function for subquery - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``WHERE`` field ``NOT IN('item', 'item')`` SQL query, joined with ``AND`` if appropriate. .. php:method:: groupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression, using ``AND`` for the conditions inside it. .. php:method:: orGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression, using ``OR`` for the conditions inside it. .. php:method:: notGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression, using ``AND NOT`` for the conditions inside it. .. php:method:: orNotGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression, using ``OR NOT`` for the conditions inside it. .. php:method:: groupEnd() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Ends a group expression. @@ -1476,10 +1476,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``LIKE`` clause to a query, separating multiple calls with ``AND``. @@ -1488,10 +1488,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``LIKE`` clause to a query, separating multiple class with ``OR``. @@ -1500,10 +1500,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``NOT LIKE`` clause to a query, separating multiple calls with ``AND``. @@ -1512,10 +1512,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``NOT LIKE`` clause to a query, separating multiple calls with ``OR``. @@ -1524,8 +1524,8 @@ Class Reference :param mixed $key: Identifier (string) or associative array of field/value pairs :param string $value: Value sought if $key is an identifier :param string $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``HAVING`` clause to a query, separating multiple calls with ``AND``. @@ -1534,8 +1534,8 @@ Class Reference :param mixed $key: Identifier (string) or associative array of field/value pairs :param string $value: Value sought if $key is an identifier :param string $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``HAVING`` clause to a query, separating multiple calls with ``OR``. @@ -1543,9 +1543,9 @@ Class Reference :param string $key: The field to search :param array|Closure $values: Array of target values, or anonymous function for subquery - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``HAVING`` field IN('item', 'item') SQL query, joined with ``OR`` if appropriate. @@ -1553,9 +1553,9 @@ Class Reference :param string $key: The field to search :param array|Closure $values: Array of target values, or anonymous function for subquery - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``HAVING`` field ``NOT IN('item', 'item')`` SQL query, joined with ``OR`` if appropriate. @@ -1564,8 +1564,8 @@ Class Reference :param string $key: Name of field to examine :param array|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``HAVING`` field ``IN('item', 'item')`` SQL query, joined with ``AND`` if appropriate. @@ -1575,8 +1575,8 @@ Class Reference :param array|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Generates a ``HAVING`` field ``NOT IN('item', 'item')`` SQL query, joined with ``AND`` if appropriate. @@ -1585,10 +1585,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``LIKE`` clause to a ``HAVING`` part of the query, separating multiple calls with ``AND``. @@ -1597,10 +1597,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :rtype: ``BaseBuilder`` Adds a ``LIKE`` clause to a ``HAVING`` part of the query, separating multiple class with ``OR``. @@ -1609,10 +1609,10 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers + :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``NOT LIKE`` clause to a ``HAVING`` part of the query, separating multiple calls with ``AND``. @@ -1621,52 +1621,52 @@ Class Reference :param string $field: Field name :param string $match: Text portion to match :param string $side: Which side of the expression to put the '%' wildcard on - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``NOT LIKE`` clause to a ``HAVING`` part of the query, separating multiple calls with ``OR``. .. php:method:: havingGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression for ``HAVING`` clause, using ``AND`` for the conditions inside it. .. php:method:: orHavingGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression for ``HAVING`` clause, using ``OR`` for the conditions inside it. .. php:method:: notHavingGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression for ``HAVING`` clause, using ``AND NOT`` for the conditions inside it. .. php:method:: orNotHavingGroupStart() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Starts a group expression for ``HAVING`` clause, using ``OR NOT`` for the conditions inside it. .. php:method:: havingGroupEnd() - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Ends a group expression for ``HAVING`` clause. .. php:method:: groupBy($by[, $escape = null]) :param mixed $by: Field(s) to group by; string or array - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds a ``GROUP BY`` clause to a query. @@ -1674,9 +1674,9 @@ Class Reference :param string $orderby: Field to order by :param string $direction: The order requested - ASC, DESC or random - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds an ``ORDER BY`` clause to a query. @@ -1684,16 +1684,16 @@ Class Reference :param int $value: Number of rows to limit the results to :param int $offset: Number of rows to skip - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds ``LIMIT`` and ``OFFSET`` clauses to a query. .. php:method:: offset($offset) :param int $offset: Number of rows to skip - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds an ``OFFSET`` clause to a query. @@ -1701,9 +1701,9 @@ Class Reference :param mixed $key: Field name, or an array of field/value pairs :param mixed $value: Field value, if $key is a single field - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds field/value pairs to be passed later to ``insert()``, ``update()`` or ``replace()``. @@ -1711,8 +1711,8 @@ Class Reference :param array $set: An associative array of field/value pairs :param bool $escape: Whether to escape values and identifiers - :returns: ``true`` on success, ``false`` on failure - :rtype: bool + :returns: ``true`` on success, ``false`` on failure + :rtype: bool Compiles and executes an ``INSERT`` statement. @@ -1722,7 +1722,7 @@ Class Reference :param bool $escape: Whether to escape values and identifiers :param int $batch_size: Count of rows to insert at once :returns: Number of rows inserted or ``false`` on failure - :rtype: int|false + :rtype: int|false Compiles and executes batch ``INSERT`` statements. @@ -1735,8 +1735,8 @@ Class Reference :param mixed $key: Field name or an array of field/value pairs :param string $value: Field value, if $key is a single field :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds field/value pairs to be inserted in a table later via ``insertBatch()``. @@ -1745,8 +1745,8 @@ Class Reference :param array $set: An associative array of field/value pairs :param string $where: The WHERE clause :param int $limit: The LIMIT clause - :returns: ``true`` on success, ``false`` on failure - :rtype: bool + :returns: ``true`` on success, ``false`` on failure + :rtype: bool Compiles and executes an ``UPDATE`` statement. @@ -1755,8 +1755,8 @@ Class Reference :param array $set: Field name, or an associative array of field/value pairs :param string $value: Field value, if $set is a single field :param int $batch_size: Count of conditions to group in a single query - :returns: Number of rows updated or ``false`` on failure - :rtype: int|false + :returns: Number of rows updated or ``false`` on failure + :rtype: int|false Compiles and executes batch ``UPDATE`` statements. @@ -1768,9 +1768,9 @@ Class Reference :param mixed $key: Field name or an array of field/value pairs :param string $value: Field value, if $key is a single field - :param bool $escape: Whether to escape values and identifiers - :returns: ``BaseBuilder`` instance (method chaining) - :rtype: ``BaseBuilder`` + :param bool $escape: Whether to escape values and identifiers + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` Adds field/value pairs to be updated in a table later via ``updateBatch()``. @@ -1778,7 +1778,7 @@ Class Reference :param array $set: An associative array of field/value pairs :returns: ``true`` on success, ``false`` on failure - :rtype: bool + :rtype: bool Compiles and executes a ``REPLACE`` statement. @@ -1787,8 +1787,8 @@ Class Reference :param string $where: The WHERE clause :param int $limit: The LIMIT clause :param bool $reset_data: true to reset the query "write" clause - :returns: ``BaseBuilder`` instance (method chaining) or ``false`` on failure - :rtype: ``BaseBuilder|false`` + :returns: ``BaseBuilder`` instance (method chaining) or ``false`` on failure + :rtype: ``BaseBuilder|false`` Compiles and executes a ``DELETE`` query. @@ -1812,8 +1812,8 @@ Class Reference .. php:method:: truncate() - :returns: ``true`` on success, ``false`` on failure, string on test mode - :rtype: bool|string + :returns: ``true`` on success, ``false`` on failure, string on test mode + :rtype: bool|string Executes a ``TRUNCATE`` statement on a table. @@ -1823,7 +1823,7 @@ Class Reference .. php:method:: emptyTable() :returns: ``true`` on success, ``false`` on failure - :rtype: bool + :rtype: bool Deletes all records from a table via a ``DELETE`` statement. @@ -1831,7 +1831,7 @@ Class Reference :param bool $reset: Whether to reset the current QB values or not :returns: The compiled SQL statement as a string - :rtype: string + :rtype: string Compiles a ``SELECT`` statement and returns it as a string. @@ -1839,7 +1839,7 @@ Class Reference :param bool $reset: Whether to reset the current QB values or not :returns: The compiled SQL statement as a string - :rtype: string + :rtype: string Compiles an ``INSERT`` statement and returns it as a string. @@ -1847,7 +1847,7 @@ Class Reference :param bool $reset: Whether to reset the current QB values or not :returns: The compiled SQL statement as a string - :rtype: string + :rtype: string Compiles an ``UPDATE`` statement and returns it as a string. @@ -1855,6 +1855,6 @@ Class Reference :param bool $reset: Whether to reset the current QB values or not :returns: The compiled SQL statement as a string - :rtype: string + :rtype: string Compiles a ``DELETE`` statement and returns it as a string. diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index f54b1166a05e..685c7e7041ea 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -48,11 +48,11 @@ The following functions are available: .. php:function:: form_open([$action = ''[, $attributes = ''[, $hidden = []]]]) - :param string $action: Form action/target URI string - :param mixed $attributes: HTML attributes, as an array or escaped string - :param array $hidden: An array of hidden fields' definitions - :returns: An HTML form opening tag - :rtype: string + :param string $action: Form action/target URI string + :param mixed $attributes: HTML attributes, as an array or escaped string + :param array $hidden: An array of hidden fields' definitions + :returns: An HTML form opening tag + :rtype: string Creates an opening form tag with a site URL **built from your config preferences**. It will optionally let you add form attributes and hidden input fields, and @@ -123,11 +123,11 @@ The following functions are available: .. php:function:: form_open_multipart([$action = ''[, $attributes = ''[, $hidden = []]]]) - :param string $action: Form action/target URI string - :param mixed $attributes: HTML attributes, as an array or escaped string - :param array $hidden: An array of hidden fields' definitions - :returns: An HTML multipart form opening tag - :rtype: string + :param string $action: Form action/target URI string + :param mixed $attributes: HTML attributes, as an array or escaped string + :param array $hidden: An array of hidden fields' definitions + :returns: An HTML multipart form opening tag + :rtype: string This function is identical to :php:func:`form_open()` above, except that it adds a *multipart* attribute, which is necessary if you @@ -135,10 +135,10 @@ The following functions are available: .. php:function:: form_hidden($name[, $value = '']) - :param string $name: Field name - :param string $value: Field value - :returns: An HTML hidden input field tag - :rtype: string + :param string $name: Field name + :param string $value: Field value + :returns: An HTML hidden input field tag + :rtype: string Lets you generate hidden input fields. You can either submit a name/value string to create one field:: @@ -202,12 +202,12 @@ The following functions are available: .. php:function:: form_input([$data = ''[, $value = ''[, $extra = ''[, $type = 'text']]]]) - :param array $data: Field attributes data - :param string $value: Field value - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :param array $data: Field attributes data + :param string $value: Field value + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string :param string $type: The type of input field. i.e., 'text', 'email', 'number', etc. - :returns: An HTML text input field tag - :rtype: string + :returns: An HTML text input field tag + :rtype: string Lets you generate a standard text input field. You can minimally pass the field name and value in the first and second parameter:: @@ -257,22 +257,22 @@ The following functions are available: .. php:function:: form_password([$data = ''[, $value = ''[, $extra = '']]]) - :param array $data: Field attributes data - :param string $value: Field value - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML password input field tag - :rtype: string + :param array $data: Field attributes data + :param string $value: Field value + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML password input field tag + :rtype: string This function is identical in all respects to the :php:func:`form_input()` function above except that it uses the "password" input type. .. php:function:: form_upload([$data = ''[, $value = ''[, $extra = '']]]) - :param array $data: Field attributes data - :param string $value: Field value - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML file upload input field tag - :rtype: string + :param array $data: Field attributes data + :param string $value: Field value + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML file upload input field tag + :rtype: string This function is identical in all respects to the :php:func:`form_input()` function above except that it uses the "file" input type, allowing it to @@ -280,11 +280,11 @@ The following functions are available: .. php:function:: form_textarea([$data = ''[, $value = ''[, $extra = '']]]) - :param array $data: Field attributes data - :param string $value: Field value - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML textarea tag - :rtype: string + :param array $data: Field attributes data + :param string $value: Field value + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML textarea tag + :rtype: string This function is identical in all respects to the :php:func:`form_input()` function above except that it generates a "textarea" type. @@ -294,12 +294,12 @@ The following functions are available: .. php:function:: form_dropdown([$name = ''[, $options = [][, $selected = [][, $extra = '']]]]) - :param string $name: Field name - :param array $options: An associative array of options to be listed - :param array $selected: List of fields to mark with the *selected* attribute - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML dropdown select field tag - :rtype: string + :param string $name: Field name + :param array $options: An associative array of options to be listed + :param array $selected: List of fields to mark with the *selected* attribute + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML dropdown select field tag + :rtype: string Lets you create a standard drop-down field. The first parameter will contain the name of the field, the second parameter will contain an @@ -365,12 +365,12 @@ The following functions are available: .. php:function:: form_multiselect([$name = ''[, $options = [][, $selected = [][, $extra = '']]]]) - :param string $name: Field name - :param array $options: An associative array of options to be listed - :param array $selected: List of fields to mark with the *selected* attribute - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML dropdown multiselect field tag - :rtype: string + :param string $name: Field name + :param array $options: An associative array of options to be listed + :param array $selected: List of fields to mark with the *selected* attribute + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML dropdown multiselect field tag + :rtype: string Lets you create a standard multiselect field. The first parameter will contain the name of the field, the second parameter will contain an @@ -383,10 +383,10 @@ The following functions are available: .. php:function:: form_fieldset([$legend_text = ''[, $attributes = []]]) - :param string $legend_text: Text to put in the tag - :param array $attributes: Attributes to be set on the
    tag - :returns: An HTML fieldset opening tag - :rtype: string + :param string $legend_text: Text to put in the tag + :param array $attributes: Attributes to be set on the
    tag + :returns: An HTML fieldset opening tag + :rtype: string Lets you generate fieldset/legend fields. @@ -409,8 +409,8 @@ The following functions are available: second parameter if you prefer to set additional attributes:: $attributes = [ - 'id' => 'address_info', - 'class' => 'address_info' + 'id' => 'address_info', + 'class' => 'address_info' ]; echo form_fieldset('Address Information', $attributes); @@ -428,9 +428,9 @@ The following functions are available: .. php:function:: form_fieldset_close([$extra = '']) - :param string $extra: Anything to append after the closing tag, *as is* - :returns: An HTML fieldset closing tag - :rtype: string + :param string $extra: Anything to append after the closing tag, *as is* + :returns: An HTML fieldset closing tag + :rtype: string Produces a closing
    tag. The only advantage to using this function is it permits you to pass data to it which will be added below @@ -444,12 +444,12 @@ The following functions are available: .. php:function:: form_checkbox([$data = ''[, $value = ''[, $checked = false[, $extra = '']]]]) - :param array $data: Field attributes data - :param string $value: Field value - :param bool $checked: Whether to mark the checkbox as being *checked* - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML checkbox input tag - :rtype: string + :param array $data: Field attributes data + :param string $value: Field value + :param bool $checked: Whether to mark the checkbox as being *checked* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML checkbox input tag + :rtype: string Lets you generate a checkbox field. Simple example:: @@ -487,23 +487,23 @@ The following functions are available: .. php:function:: form_radio([$data = ''[, $value = ''[, $checked = false[, $extra = '']]]]) - :param array $data: Field attributes data - :param string $value: Field value - :param bool $checked: Whether to mark the radio button as being *checked* - :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string - :returns: An HTML radio input tag - :rtype: string + :param array $data: Field attributes data + :param string $value: Field value + :param bool $checked: Whether to mark the radio button as being *checked* + :param mixed $extra: Extra attributes to be added to the tag either as an array or a literal string + :returns: An HTML radio input tag + :rtype: string This function is identical in all respects to the :php:func:`form_checkbox()` function above except that it uses the "radio" input type. .. php:function:: form_label([$label_text = ''[, $id = ''[, $attributes = []]]]) - :param string $label_text: Text to put in the
    {queries} - + From 027e41ba4a7441c201c368cafba67f937262a35f Mon Sep 17 00:00:00 2001 From: Daniel Tiringer Date: Fri, 8 Oct 2021 13:47:48 +0200 Subject: [PATCH 0436/2325] Add css class to mark duplicates --- system/Debug/Toolbar/Views/toolbar.css | 67 ++++++++------------------ 1 file changed, 20 insertions(+), 47 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 7382f4d7e60a..f0a5271535d4 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -1,10 +1,9 @@ -/** - * This file is part of the CodeIgniter 4 framework. - * - * (c) CodeIgniter Foundation - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. +/*! CodeIgniter 4 - Debug bar + * ============================================================================ + * Forum: https://forum.codeigniter.com + * Github: https://github.com/codeigniter4/codeigniter4 + * Slack: https://codeigniterchat.slack.com + * Website: https://codeigniter.com */ #debug-icon { bottom: 0; @@ -118,6 +117,7 @@ overflow: hidden; overflow-y: auto; padding: 0 12px 0 12px; + /* give room for OS X scrollbar */ white-space: nowrap; z-index: 10000; } #debug-bar.fixed-top { @@ -200,14 +200,7 @@ padding: 5px; position: relative; } #debug-bar .timeline td:first-child { - border-left: 0; - max-width: none; } - #debug-bar .timeline td.child-container { - padding: 0px; } - #debug-bar .timeline td.child-container .timeline { - margin: 0px; } - #debug-bar .timeline td.child-container .timeline td:first-child:not(.child-container) { - padding-left: calc(5px + 10px * var(--level)); } + border-left: 0; } #debug-bar .timeline .timer { border-radius: 4px; -moz-border-radius: 4px; @@ -216,22 +209,6 @@ padding: 5px; position: absolute; top: 30%; } - #debug-bar .timeline .timeline-parent { - cursor: pointer; } - #debug-bar .timeline .timeline-parent td:first-child nav { - background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; - background-position: 0 25%; - display: inline-block; - height: 15px; - width: 15px; - margin-right: 3px; - vertical-align: middle; } - #debug-bar .timeline .timeline-parent-open { - background-color: #DFDFDF; } - #debug-bar .timeline .timeline-parent-open td:first-child nav { - background-position: 0 75%; } - #debug-bar .timeline .child-row:hover { - background: transparent; } #debug-bar .route-params, #debug-bar .route-params-item { vertical-align: top; } @@ -267,9 +244,7 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, - #debug-icon a:link, - #debug-icon a:visited { + #debug-icon a:active, #debug-icon a:link, #debug-icon a:visited { color: #DD8615; } #debug-bar { @@ -292,7 +267,7 @@ #debug-bar button { background-color: #FFFFFF; } #debug-bar table strong { - color: #DD8615; } + color: #FDC894; } #debug-bar table tbody tr:hover { background-color: #DFDFDF; } #debug-bar table tbody tr.current { @@ -355,9 +330,7 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, - #debug-icon a:link, - #debug-icon a:visited { + #debug-icon a:active, #debug-icon a:link, #debug-icon a:visited { color: #DD8615; } #debug-bar { background-color: #252525; @@ -379,7 +352,7 @@ #debug-bar button { background-color: #252525; } #debug-bar table strong { - color: #DD8615; } + color: #FDC894; } #debug-bar table tbody tr:hover { background-color: #434343; } #debug-bar table tbody tr.current { @@ -441,9 +414,7 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.dark #debug-icon a:active, - #toolbarContainer.dark #debug-icon a:link, - #toolbarContainer.dark #debug-icon a:visited { + #toolbarContainer.dark #debug-icon a:active, #toolbarContainer.dark #debug-icon a:link, #toolbarContainer.dark #debug-icon a:visited { color: #DD8615; } #toolbarContainer.dark #debug-bar { @@ -466,7 +437,7 @@ #toolbarContainer.dark #debug-bar button { background-color: #252525; } #toolbarContainer.dark #debug-bar table strong { - color: #DD8615; } + color: #FDC894; } #toolbarContainer.dark #debug-bar table tbody tr:hover { background-color: #434343; } #toolbarContainer.dark #debug-bar table tbody tr.current { @@ -534,9 +505,7 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.light #debug-icon a:active, - #toolbarContainer.light #debug-icon a:link, - #toolbarContainer.light #debug-icon a:visited { + #toolbarContainer.light #debug-icon a:active, #toolbarContainer.light #debug-icon a:link, #toolbarContainer.light #debug-icon a:visited { color: #DD8615; } #toolbarContainer.light #debug-bar { @@ -559,7 +528,7 @@ #toolbarContainer.light #debug-bar button { background-color: #FFFFFF; } #toolbarContainer.light #debug-bar table strong { - color: #DD8615; } + color: #FDC894; } #toolbarContainer.light #debug-bar table tbody tr:hover { background-color: #DFDFDF; } #toolbarContainer.light #debug-bar table tbody tr.current { @@ -645,3 +614,7 @@ .debug-bar-noverflow { overflow: hidden; } + +#ci-database table tbody tr.duplicate { + background-color: #DD4814; +} From 4ea6493f4cd41b459419528056ebd86c0cb8b029 Mon Sep 17 00:00:00 2001 From: Daniel Tiringer Date: Fri, 8 Oct 2021 13:56:41 +0200 Subject: [PATCH 0437/2325] Correct the accidentally modified css --- system/Debug/Toolbar/Views/toolbar.css | 66 +++++++++++++++++++------- 1 file changed, 48 insertions(+), 18 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index f0a5271535d4..5f971ba7172a 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -1,9 +1,10 @@ -/*! CodeIgniter 4 - Debug bar - * ============================================================================ - * Forum: https://forum.codeigniter.com - * Github: https://github.com/codeigniter4/codeigniter4 - * Slack: https://codeigniterchat.slack.com - * Website: https://codeigniter.com +/** + * This file is part of the CodeIgniter 4 framework. + * + * (c) CodeIgniter Foundation + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. */ #debug-icon { bottom: 0; @@ -117,7 +118,6 @@ overflow: hidden; overflow-y: auto; padding: 0 12px 0 12px; - /* give room for OS X scrollbar */ white-space: nowrap; z-index: 10000; } #debug-bar.fixed-top { @@ -200,7 +200,14 @@ padding: 5px; position: relative; } #debug-bar .timeline td:first-child { - border-left: 0; } + border-left: 0; + max-width: none; } + #debug-bar .timeline td.child-container { + padding: 0px; } + #debug-bar .timeline td.child-container .timeline { + margin: 0px; } + #debug-bar .timeline td.child-container .timeline td:first-child:not(.child-container) { + padding-left: calc(5px + 10px * var(--level)); } #debug-bar .timeline .timer { border-radius: 4px; -moz-border-radius: 4px; @@ -209,6 +216,22 @@ padding: 5px; position: absolute; top: 30%; } + #debug-bar .timeline .timeline-parent { + cursor: pointer; } + #debug-bar .timeline .timeline-parent td:first-child nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; } + #debug-bar .timeline .timeline-parent-open { + background-color: #DFDFDF; } + #debug-bar .timeline .timeline-parent-open td:first-child nav { + background-position: 0 75%; } + #debug-bar .timeline .child-row:hover { + background: transparent; } #debug-bar .route-params, #debug-bar .route-params-item { vertical-align: top; } @@ -244,7 +267,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, #debug-icon a:link, #debug-icon a:visited { + #debug-icon a:active, + #debug-icon a:link, + #debug-icon a:visited { color: #DD8615; } #debug-bar { @@ -267,7 +292,7 @@ #debug-bar button { background-color: #FFFFFF; } #debug-bar table strong { - color: #FDC894; } + color: #DD8615; } #debug-bar table tbody tr:hover { background-color: #DFDFDF; } #debug-bar table tbody tr.current { @@ -330,7 +355,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, #debug-icon a:link, #debug-icon a:visited { + #debug-icon a:active, + #debug-icon a:link, + #debug-icon a:visited { color: #DD8615; } #debug-bar { background-color: #252525; @@ -352,7 +379,7 @@ #debug-bar button { background-color: #252525; } #debug-bar table strong { - color: #FDC894; } + color: #DD8615; } #debug-bar table tbody tr:hover { background-color: #434343; } #debug-bar table tbody tr.current { @@ -414,7 +441,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.dark #debug-icon a:active, #toolbarContainer.dark #debug-icon a:link, #toolbarContainer.dark #debug-icon a:visited { + #toolbarContainer.dark #debug-icon a:active, + #toolbarContainer.dark #debug-icon a:link, + #toolbarContainer.dark #debug-icon a:visited { color: #DD8615; } #toolbarContainer.dark #debug-bar { @@ -437,7 +466,7 @@ #toolbarContainer.dark #debug-bar button { background-color: #252525; } #toolbarContainer.dark #debug-bar table strong { - color: #FDC894; } + color: #DD8615; } #toolbarContainer.dark #debug-bar table tbody tr:hover { background-color: #434343; } #toolbarContainer.dark #debug-bar table tbody tr.current { @@ -505,7 +534,9 @@ box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.light #debug-icon a:active, #toolbarContainer.light #debug-icon a:link, #toolbarContainer.light #debug-icon a:visited { + #toolbarContainer.light #debug-icon a:active, + #toolbarContainer.light #debug-icon a:link, + #toolbarContainer.light #debug-icon a:visited { color: #DD8615; } #toolbarContainer.light #debug-bar { @@ -528,7 +559,7 @@ #toolbarContainer.light #debug-bar button { background-color: #FFFFFF; } #toolbarContainer.light #debug-bar table strong { - color: #FDC894; } + color: #DD8615; } #toolbarContainer.light #debug-bar table tbody tr:hover { background-color: #DFDFDF; } #toolbarContainer.light #debug-bar table tbody tr.current { @@ -616,5 +647,4 @@ overflow: hidden; } #ci-database table tbody tr.duplicate { - background-color: #DD4814; -} + background-color: #DD4814;} From 674af492e9c9d07719fb73f86b984e606a60619f Mon Sep 17 00:00:00 2001 From: Daniel Tiringer Date: Fri, 8 Oct 2021 23:15:49 +0200 Subject: [PATCH 0438/2325] Use the hover colors to highlight duplicates --- system/Debug/Toolbar/Views/toolbar.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 5f971ba7172a..b5a223b55d70 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -471,6 +471,8 @@ background-color: #434343; } #toolbarContainer.dark #debug-bar table tbody tr.current { background-color: #FDC894; } + #toolbarContainer.dark #ci-database table tbody tr.duplicate { + background-color: #434343;} #toolbarContainer.dark #debug-bar table tbody tr.current td { color: #252525; } #toolbarContainer.dark #debug-bar table tbody tr.current:hover td { @@ -564,6 +566,8 @@ background-color: #DFDFDF; } #toolbarContainer.light #debug-bar table tbody tr.current { background-color: #FDC894; } + #toolbarContainer.light #ci-database table tbody tr.duplicate { + background-color: #DFDFDF;} #toolbarContainer.light #debug-bar table tbody tr.current:hover td { background-color: #DD4814; color: #FFFFFF; } @@ -645,6 +649,3 @@ .debug-bar-noverflow { overflow: hidden; } - -#ci-database table tbody tr.duplicate { - background-color: #DD4814;} From b2560d56c5b0b048ba73d872be8340c78285af52 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 10 Oct 2021 22:15:35 +0900 Subject: [PATCH 0439/2325] docs: move PULL_REQUEST_TEMPLATE.md to .github/ --- PULL_REQUEST_TEMPLATE.md => .github/PULL_REQUEST_TEMPLATE.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename PULL_REQUEST_TEMPLATE.md => .github/PULL_REQUEST_TEMPLATE.md (100%) diff --git a/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE.md From 7f88eceabbcf0cb128992ffe27cc77d6abec5deb Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 10 Oct 2021 22:16:54 +0900 Subject: [PATCH 0440/2325] docs: replace PHPdoc with PHPDoc --- .github/PULL_REQUEST_TEMPLATE.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index db5aeb9eca37..eb50d54c4c4f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,7 @@ Explain what you have changed, and why. **Checklist:** - [ ] Securely signed commits -- [ ] Component(s) with PHPdocs +- [ ] Component(s) with PHPDocs - [ ] Unit testing, with >80% coverage - [ ] User guide updated - [ ] Conforms to style guide @@ -19,4 +19,3 @@ Explain what you have changed, and why. - Unsolicited pull requests will be considered, but there is no guarantee of acceptance - Pull requests should be from a feature branch in the contributor's fork of the repository to the develop branch of the project repository - From aaab1bc0509d0677044d8175ed888bb696be515e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 11 Oct 2021 11:29:47 +0900 Subject: [PATCH 0441/2325] docs: update expression Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- .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 eb50d54c4c4f..6204913fd437 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -5,7 +5,7 @@ Explain what you have changed, and why. **Checklist:** - [ ] Securely signed commits -- [ ] Component(s) with PHPDocs +- [ ] Component(s) with PHPDoc blocks, only if necessary or adds value - [ ] Unit testing, with >80% coverage - [ ] User guide updated - [ ] Conforms to style guide From cb714b5b0c8c197e13c0373f5ac1221c549305aa Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Mon, 11 Oct 2021 17:03:05 +0800 Subject: [PATCH 0442/2325] Change behavior of `class_attributes_separation` rule --- .no-header.php-cs-fixer.dist.php | 24 ++++++---- .php-cs-fixer.dist.php | 24 ++++++---- .../tests/_support/Models/ExampleModel.php | 12 ++--- .../tests/_support/Models/ExampleModel.php | 12 ++--- app/Config/Kint.php | 24 +++------- system/Test/Mock/MockAppConfig.php | 44 ++++++++----------- system/Test/Mock/MockAutoload.php | 3 +- system/Test/Mock/MockCLIConfig.php | 40 +++++++---------- system/Test/Mock/MockCURLRequest.php | 1 - system/Test/Mock/MockConnection.php | 2 - system/Test/Mock/MockServices.php | 1 - tests/_support/Models/EntityModel.php | 15 +++---- tests/_support/Models/EventModel.php | 13 ++---- tests/_support/Models/FabricatorModel.php | 15 +++---- tests/_support/Models/JobModel.php | 16 +++---- tests/_support/Models/SecondaryModel.php | 15 +++---- tests/_support/Models/UserModel.php | 19 +++----- tests/_support/Models/ValidErrorsModel.php | 13 ++---- tests/_support/Models/ValidModel.php | 14 ++---- .../Models/WithoutAutoIncrementModel.php | 7 +-- .../Commands/EnvironmentCommandTest.php | 4 +- .../Commands/MigrationIntegrationTest.php | 4 +- tests/system/Config/fixtures/Encryption.php | 1 + tests/system/Config/fixtures/SimpleConfig.php | 4 +- tests/system/ControllerTest.php | 1 + tests/system/Database/BaseConnectionTest.php | 1 - tests/system/Database/ConfigTest.php | 3 -- tests/system/Database/Live/AliasTest.php | 3 +- tests/system/Database/Live/BadQueryTest.php | 3 +- tests/system/Database/Live/ConnectTest.php | 2 - tests/system/Database/Live/CountTest.php | 3 +- .../Live/DatabaseTestTraitCaseTest.php | 3 +- tests/system/Database/Live/DeleteTest.php | 3 +- tests/system/Database/Live/EmptyTest.php | 3 +- tests/system/Database/Live/EscapeTest.php | 1 - tests/system/Database/Live/ForgeTest.php | 3 +- tests/system/Database/Live/FromTest.php | 3 +- tests/system/Database/Live/GetNumRowsTest.php | 3 +- tests/system/Database/Live/GetTest.php | 3 +- tests/system/Database/Live/GroupTest.php | 3 +- tests/system/Database/Live/IncrementTest.php | 3 +- tests/system/Database/Live/InsertTest.php | 3 +- tests/system/Database/Live/JoinTest.php | 3 +- tests/system/Database/Live/LikeTest.php | 3 +- tests/system/Database/Live/LimitTest.php | 4 +- tests/system/Database/Live/OrderTest.php | 3 +- tests/system/Database/Live/SelectTest.php | 3 +- tests/system/Database/Live/UpdateTest.php | 3 +- tests/system/Database/Live/WhereTest.php | 3 +- .../Database/Live/WriteTypeQueryTest.php | 3 +- .../Migrations/MigrationRunnerTest.php | 1 - tests/system/Entity/EntityTest.php | 9 ---- tests/system/HTTP/RedirectResponseTest.php | 1 + tests/system/Models/InsertModelTest.php | 2 - tests/system/Models/SaveModelTest.php | 1 - tests/system/Models/UpdateModelTest.php | 3 -- tests/system/Pager/PagerTest.php | 1 + .../Session/Handlers/DatabaseHandlerTest.php | 3 +- .../system/Validation/CreditCardRulesTest.php | 1 + tests/system/Validation/FileRulesTest.php | 1 + tests/system/Validation/FormatRulesTest.php | 1 + tests/system/Validation/RulesTest.php | 1 + tests/system/Validation/ValidationTest.php | 1 + tests/system/View/ParserPluginTest.php | 1 + 64 files changed, 161 insertions(+), 265 deletions(-) diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php index 6e0a5c09602d..a3030aa98f58 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.no-header.php-cs-fixer.dist.php @@ -30,14 +30,22 @@ $overrides = [ // @TODO Remove once these are live in coding-standard 'assign_null_coalescing_to_coalesce_equal' => false, // requires 7.4+ - 'control_structure_continuation_position' => ['position' => 'same_line'], - 'empty_loop_condition' => ['style' => 'while'], - 'integer_literal_case' => true, - 'modernize_strpos' => false, // requires 8.0+ - 'no_alternative_syntax' => ['fix_non_monolithic_code' => false], - 'no_space_around_double_colon' => true, - 'octal_notation' => false, // requires 8.1+ - 'string_length_to_empty' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'const' => 'none', + 'property' => 'none', + 'method' => 'one', + 'trait_import' => 'none', + ], + ], + 'control_structure_continuation_position' => ['position' => 'same_line'], + 'empty_loop_condition' => ['style' => 'while'], + 'integer_literal_case' => true, + 'modernize_strpos' => false, // requires 8.0+ + 'no_alternative_syntax' => ['fix_non_monolithic_code' => false], + 'no_space_around_double_colon' => true, + 'octal_notation' => false, // requires 8.1+ + 'string_length_to_empty' => true, ]; $options = [ diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 2196640dae93..743062d44a88 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -37,14 +37,22 @@ $overrides = [ // @TODO Remove once these are live in coding-standard 'assign_null_coalescing_to_coalesce_equal' => false, // requires 7.4+ - 'control_structure_continuation_position' => ['position' => 'same_line'], - 'empty_loop_condition' => ['style' => 'while'], - 'integer_literal_case' => true, - 'modernize_strpos' => false, // requires 8.0+ - 'no_alternative_syntax' => ['fix_non_monolithic_code' => false], - 'no_space_around_double_colon' => true, - 'octal_notation' => false, // requires 8.1+ - 'string_length_to_empty' => true, + 'class_attributes_separation' => [ + 'elements' => [ + 'const' => 'none', + 'property' => 'none', + 'method' => 'one', + 'trait_import' => 'none', + ], + ], + 'control_structure_continuation_position' => ['position' => 'same_line'], + 'empty_loop_condition' => ['style' => 'while'], + 'integer_literal_case' => true, + 'modernize_strpos' => false, // requires 8.0+ + 'no_alternative_syntax' => ['fix_non_monolithic_code' => false], + 'no_space_around_double_colon' => true, + 'octal_notation' => false, // requires 8.1+ + 'string_length_to_empty' => true, ]; $options = [ diff --git a/admin/module/tests/_support/Models/ExampleModel.php b/admin/module/tests/_support/Models/ExampleModel.php index a71009e74f8b..f0687e9b1985 100644 --- a/admin/module/tests/_support/Models/ExampleModel.php +++ b/admin/module/tests/_support/Models/ExampleModel.php @@ -6,22 +6,18 @@ class ExampleModel extends Model { - protected $table = 'factories'; - protected $primaryKey = 'id'; - + protected $table = 'factories'; + protected $primaryKey = 'id'; protected $returnType = 'object'; protected $useSoftDeletes = false; - - protected $allowedFields = [ + protected $allowedFields = [ 'name', 'uid', 'class', 'icon', 'summary', ]; - - protected $useTimestamps = true; - + protected $useTimestamps = true; protected $validationRules = []; protected $validationMessages = []; protected $skipValidation = false; diff --git a/admin/starter/tests/_support/Models/ExampleModel.php b/admin/starter/tests/_support/Models/ExampleModel.php index a71009e74f8b..f0687e9b1985 100644 --- a/admin/starter/tests/_support/Models/ExampleModel.php +++ b/admin/starter/tests/_support/Models/ExampleModel.php @@ -6,22 +6,18 @@ class ExampleModel extends Model { - protected $table = 'factories'; - protected $primaryKey = 'id'; - + protected $table = 'factories'; + protected $primaryKey = 'id'; protected $returnType = 'object'; protected $useSoftDeletes = false; - - protected $allowedFields = [ + protected $allowedFields = [ 'name', 'uid', 'class', 'icon', 'summary', ]; - - protected $useTimestamps = true; - + protected $useTimestamps = true; protected $validationRules = []; protected $validationMessages = []; protected $skipValidation = false; diff --git a/app/Config/Kint.php b/app/Config/Kint.php index 4b52422af7d7..b1016ed57923 100644 --- a/app/Config/Kint.php +++ b/app/Config/Kint.php @@ -24,26 +24,19 @@ class Kint extends BaseConfig */ public $plugins; - - public $maxDepth = 6; - + public $maxDepth = 6; public $displayCalledFrom = true; - - public $expanded = false; + public $expanded = false; /* |-------------------------------------------------------------------------- | RichRenderer Settings |-------------------------------------------------------------------------- */ - public $richTheme = 'aante-light.css'; - + public $richTheme = 'aante-light.css'; public $richFolder = false; - - public $richSort = Renderer::SORT_FULL; - + public $richSort = Renderer::SORT_FULL; public $richObjectPlugins; - public $richTabPlugins; /* @@ -51,11 +44,8 @@ class Kint extends BaseConfig | CLI Settings |-------------------------------------------------------------------------- */ - public $cliColors = true; - - public $cliForceUTF8 = false; - + public $cliColors = true; + public $cliForceUTF8 = false; public $cliDetectWidth = true; - - public $cliMinWidth = 40; + public $cliMinWidth = 40; } diff --git a/system/Test/Mock/MockAppConfig.php b/system/Test/Mock/MockAppConfig.php index 26fb350db12c..fe51c4d3202f 100644 --- a/system/Test/Mock/MockAppConfig.php +++ b/system/Test/Mock/MockAppConfig.php @@ -15,31 +15,25 @@ class MockAppConfig extends App { - public $baseURL = 'http://example.com/'; - - public $uriProtocol = 'REQUEST_URI'; - - public $cookiePrefix = ''; - public $cookieDomain = ''; - public $cookiePath = '/'; - public $cookieSecure = false; - public $cookieHTTPOnly = false; - public $cookieSameSite = 'Lax'; - - public $proxyIPs = ''; - - public $CSRFProtection = false; - public $CSRFTokenName = 'csrf_test_name'; - public $CSRFHeaderName = 'X-CSRF-TOKEN'; - public $CSRFCookieName = 'csrf_cookie_name'; - public $CSRFExpire = 7200; - public $CSRFRegenerate = true; - public $CSRFExcludeURIs = ['http://example.com']; - public $CSRFRedirect = false; - public $CSRFSameSite = 'Lax'; - - public $CSPEnabled = false; - + public $baseURL = 'http://example.com/'; + public $uriProtocol = 'REQUEST_URI'; + public $cookiePrefix = ''; + public $cookieDomain = ''; + public $cookiePath = '/'; + public $cookieSecure = false; + public $cookieHTTPOnly = false; + public $cookieSameSite = 'Lax'; + public $proxyIPs = ''; + public $CSRFProtection = false; + public $CSRFTokenName = 'csrf_test_name'; + public $CSRFHeaderName = 'X-CSRF-TOKEN'; + public $CSRFCookieName = 'csrf_cookie_name'; + public $CSRFExpire = 7200; + public $CSRFRegenerate = true; + public $CSRFExcludeURIs = ['http://example.com']; + public $CSRFRedirect = false; + public $CSRFSameSite = 'Lax'; + public $CSPEnabled = false; public $defaultLocale = 'en'; public $negotiateLocale = false; public $supportedLocales = [ diff --git a/system/Test/Mock/MockAutoload.php b/system/Test/Mock/MockAutoload.php index 26a92b2f811c..291974c65be3 100644 --- a/system/Test/Mock/MockAutoload.php +++ b/system/Test/Mock/MockAutoload.php @@ -15,8 +15,7 @@ class MockAutoload extends Autoload { - public $psr4 = []; - + public $psr4 = []; public $classmap = []; public function __construct() diff --git a/system/Test/Mock/MockCLIConfig.php b/system/Test/Mock/MockCLIConfig.php index 5c6e6b5db195..0e5f9c8dd64e 100644 --- a/system/Test/Mock/MockCLIConfig.php +++ b/system/Test/Mock/MockCLIConfig.php @@ -15,29 +15,23 @@ class MockCLIConfig extends App { - public $baseURL = 'http://example.com/'; - - public $uriProtocol = 'REQUEST_URI'; - - public $cookiePrefix = ''; - public $cookieDomain = ''; - public $cookiePath = '/'; - public $cookieSecure = false; - public $cookieHTTPOnly = false; - public $cookieSameSite = 'Lax'; - - public $proxyIPs = ''; - - public $CSRFProtection = false; - public $CSRFTokenName = 'csrf_test_name'; - public $CSRFCookieName = 'csrf_cookie_name'; - public $CSRFExpire = 7200; - public $CSRFRegenerate = true; - public $CSRFExcludeURIs = ['http://example.com']; - public $CSRFSameSite = 'Lax'; - - public $CSPEnabled = false; - + public $baseURL = 'http://example.com/'; + public $uriProtocol = 'REQUEST_URI'; + public $cookiePrefix = ''; + public $cookieDomain = ''; + public $cookiePath = '/'; + public $cookieSecure = false; + public $cookieHTTPOnly = false; + public $cookieSameSite = 'Lax'; + public $proxyIPs = ''; + public $CSRFProtection = false; + public $CSRFTokenName = 'csrf_test_name'; + public $CSRFCookieName = 'csrf_cookie_name'; + public $CSRFExpire = 7200; + public $CSRFRegenerate = true; + public $CSRFExcludeURIs = ['http://example.com']; + public $CSRFSameSite = 'Lax'; + public $CSPEnabled = false; public $defaultLocale = 'en'; public $negotiateLocale = false; public $supportedLocales = [ diff --git a/system/Test/Mock/MockCURLRequest.php b/system/Test/Mock/MockCURLRequest.php index 5b7344fe13e5..635db366234c 100644 --- a/system/Test/Mock/MockCURLRequest.php +++ b/system/Test/Mock/MockCURLRequest.php @@ -23,7 +23,6 @@ class MockCURLRequest extends CURLRequest { public $curl_options; - protected $output = ''; public function setOutput($output) diff --git a/system/Test/Mock/MockConnection.php b/system/Test/Mock/MockConnection.php index 099a8b735d20..78bd405babad 100644 --- a/system/Test/Mock/MockConnection.php +++ b/system/Test/Mock/MockConnection.php @@ -19,9 +19,7 @@ class MockConnection extends BaseConnection { protected $returnValues = []; - public $database; - public $lastQuery; public function shouldReturn(string $method, $return) diff --git a/system/Test/Mock/MockServices.php b/system/Test/Mock/MockServices.php index f02404a1b74e..f18700426811 100644 --- a/system/Test/Mock/MockServices.php +++ b/system/Test/Mock/MockServices.php @@ -19,7 +19,6 @@ class MockServices extends BaseService public $psr4 = [ 'Tests/Support' => TESTPATH . '_support/', ]; - public $classmap = []; public function __construct() diff --git a/tests/_support/Models/EntityModel.php b/tests/_support/Models/EntityModel.php index fb53549e8fa6..f2bbe35ccfd1 100644 --- a/tests/_support/Models/EntityModel.php +++ b/tests/_support/Models/EntityModel.php @@ -15,17 +15,12 @@ class EntityModel extends Model { - protected $table = 'job'; - - protected $returnType = '\Tests\Support\Models\SimpleEntity'; - + protected $table = 'job'; + protected $returnType = '\Tests\Support\Models\SimpleEntity'; protected $useSoftDeletes = false; - - protected $dateFormat = 'int'; - - protected $deletedField = 'deleted_at'; - - protected $allowedFields = [ + protected $dateFormat = 'int'; + protected $deletedField = 'deleted_at'; + protected $allowedFields = [ 'name', 'description', 'created_at', diff --git a/tests/_support/Models/EventModel.php b/tests/_support/Models/EventModel.php index 8b8a947efcc6..c3e0a145509b 100644 --- a/tests/_support/Models/EventModel.php +++ b/tests/_support/Models/EventModel.php @@ -15,21 +15,16 @@ class EventModel extends Model { - protected $table = 'user'; - - protected $returnType = 'array'; - + protected $table = 'user'; + protected $returnType = 'array'; protected $useSoftDeletes = false; - - protected $dateFormat = 'datetime'; - - protected $allowedFields = [ + protected $dateFormat = 'datetime'; + protected $allowedFields = [ 'name', 'email', 'country', 'deleted_at', ]; - protected $beforeInsert = ['beforeInsertMethod']; protected $afterInsert = ['afterInsertMethod']; protected $beforeUpdate = ['beforeUpdateMethod']; diff --git a/tests/_support/Models/FabricatorModel.php b/tests/_support/Models/FabricatorModel.php index 1c40e7e1464e..70efeeb5c942 100644 --- a/tests/_support/Models/FabricatorModel.php +++ b/tests/_support/Models/FabricatorModel.php @@ -16,17 +16,12 @@ class FabricatorModel extends Model { - protected $table = 'job'; - - protected $returnType = 'object'; - + protected $table = 'job'; + protected $returnType = 'object'; protected $useSoftDeletes = true; - - protected $useTimestamps = true; - - protected $dateFormat = 'int'; - - protected $allowedFields = [ + protected $useTimestamps = true; + protected $dateFormat = 'int'; + protected $allowedFields = [ 'name', 'description', ]; diff --git a/tests/_support/Models/JobModel.php b/tests/_support/Models/JobModel.php index 06b967af7a89..7f5044dddc61 100644 --- a/tests/_support/Models/JobModel.php +++ b/tests/_support/Models/JobModel.php @@ -15,20 +15,14 @@ class JobModel extends Model { - protected $table = 'job'; - - protected $returnType = 'object'; - + protected $table = 'job'; + protected $returnType = 'object'; protected $useSoftDeletes = false; - - protected $dateFormat = 'int'; - - protected $allowedFields = [ + protected $dateFormat = 'int'; + protected $allowedFields = [ 'name', 'description', ]; - - public $name = ''; - + public $name = ''; public $description = ''; } diff --git a/tests/_support/Models/SecondaryModel.php b/tests/_support/Models/SecondaryModel.php index b4ef155a5aa9..aff1c2646e14 100644 --- a/tests/_support/Models/SecondaryModel.php +++ b/tests/_support/Models/SecondaryModel.php @@ -15,17 +15,12 @@ class SecondaryModel extends Model { - protected $table = 'secondary'; - - protected $primaryKey = 'id'; - - protected $returnType = 'object'; - + protected $table = 'secondary'; + protected $primaryKey = 'id'; + protected $returnType = 'object'; protected $useSoftDeletes = false; - - protected $dateFormat = 'int'; - - protected $allowedFields = [ + protected $dateFormat = 'int'; + protected $allowedFields = [ 'key', 'value', ]; diff --git a/tests/_support/Models/UserModel.php b/tests/_support/Models/UserModel.php index 7e68c3441803..07c678fb5db5 100644 --- a/tests/_support/Models/UserModel.php +++ b/tests/_support/Models/UserModel.php @@ -15,24 +15,17 @@ class UserModel extends Model { - protected $table = 'user'; - + protected $table = 'user'; protected $allowedFields = [ 'name', 'email', 'country', 'deleted_at', ]; - - protected $returnType = 'object'; - + protected $returnType = 'object'; protected $useSoftDeletes = true; - - protected $dateFormat = 'datetime'; - - public $name = ''; - - public $email = ''; - - public $country = ''; + protected $dateFormat = 'datetime'; + public $name = ''; + public $email = ''; + public $country = ''; } diff --git a/tests/_support/Models/ValidErrorsModel.php b/tests/_support/Models/ValidErrorsModel.php index 04ff1a98f715..e05f801a6983 100644 --- a/tests/_support/Models/ValidErrorsModel.php +++ b/tests/_support/Models/ValidErrorsModel.php @@ -15,19 +15,14 @@ class ValidErrorsModel extends Model { - protected $table = 'job'; - - protected $returnType = 'object'; - + protected $table = 'job'; + protected $returnType = 'object'; protected $useSoftDeletes = false; - - protected $dateFormat = 'int'; - - protected $allowedFields = [ + protected $dateFormat = 'int'; + protected $allowedFields = [ 'name', 'description', ]; - protected $validationRules = [ 'name' => [ 'required', diff --git a/tests/_support/Models/ValidModel.php b/tests/_support/Models/ValidModel.php index 730985ad8142..216f80cc3f87 100644 --- a/tests/_support/Models/ValidModel.php +++ b/tests/_support/Models/ValidModel.php @@ -15,19 +15,14 @@ class ValidModel extends Model { - protected $table = 'job'; - - protected $returnType = 'object'; - + protected $table = 'job'; + protected $returnType = 'object'; protected $useSoftDeletes = false; - - protected $dateFormat = 'int'; - - protected $allowedFields = [ + protected $dateFormat = 'int'; + protected $allowedFields = [ 'name', 'description', ]; - protected $validationRules = [ 'name' => [ 'required', @@ -35,7 +30,6 @@ class ValidModel extends Model ], 'token' => 'permit_empty|in_list[{id}]', ]; - protected $validationMessages = [ 'name' => [ 'required' => 'You forgot to name the baby.', diff --git a/tests/_support/Models/WithoutAutoIncrementModel.php b/tests/_support/Models/WithoutAutoIncrementModel.php index 248fd3af1134..dcbb8c4aba3c 100644 --- a/tests/_support/Models/WithoutAutoIncrementModel.php +++ b/tests/_support/Models/WithoutAutoIncrementModel.php @@ -15,14 +15,11 @@ class WithoutAutoIncrementModel extends Model { - protected $table = 'without_auto_increment'; - - protected $primaryKey = 'key'; - + protected $table = 'without_auto_increment'; + protected $primaryKey = 'key'; protected $allowedFields = [ 'key', 'value', ]; - protected $useAutoIncrement = false; } diff --git a/tests/system/Commands/EnvironmentCommandTest.php b/tests/system/Commands/EnvironmentCommandTest.php index bd7f04ff3121..e81fe65ec622 100644 --- a/tests/system/Commands/EnvironmentCommandTest.php +++ b/tests/system/Commands/EnvironmentCommandTest.php @@ -20,9 +20,7 @@ final class EnvironmentCommandTest extends CIUnitTestCase { private $streamFilter; - - private $envPath = ROOTPATH . '.env'; - + private $envPath = ROOTPATH . '.env'; private $backupEnvPath = ROOTPATH . '.env.backup'; protected function setUp(): void diff --git a/tests/system/Commands/MigrationIntegrationTest.php b/tests/system/Commands/MigrationIntegrationTest.php index 77c047ef82ae..f2fca3405354 100644 --- a/tests/system/Commands/MigrationIntegrationTest.php +++ b/tests/system/Commands/MigrationIntegrationTest.php @@ -20,10 +20,8 @@ final class MigrationIntegrationTest extends CIUnitTestCase { private $streamFilter; - private $migrationFileFrom = SUPPORTPATH . 'Database/Migrations/20160428212500_Create_test_tables.php'; - - private $migrationFileTo = APPPATH . 'Database/Migrations/20160428212500_Create_test_tables.php'; + private $migrationFileTo = APPPATH . 'Database/Migrations/20160428212500_Create_test_tables.php'; protected function setUp(): void { diff --git a/tests/system/Config/fixtures/Encryption.php b/tests/system/Config/fixtures/Encryption.php index 2793795f56ff..7a8a00bc03fe 100644 --- a/tests/system/Config/fixtures/Encryption.php +++ b/tests/system/Config/fixtures/Encryption.php @@ -15,6 +15,7 @@ class Encryption extends EncryptionConfig { private const HEX2BIN = 'hex2bin:84cf2c0811d5daf9e1c897825a3debce91f9a33391e639f72f7a4740b30675a2'; private const BASE64 = 'base64:Psf8bUHRh1UJYG2M7e+5ec3MdjpKpzAr0twamcAvOcI='; + public $key; public $driver = 'MCrypt'; diff --git a/tests/system/Config/fixtures/SimpleConfig.php b/tests/system/Config/fixtures/SimpleConfig.php index d5d2665f657e..69f5590e90f1 100644 --- a/tests/system/Config/fixtures/SimpleConfig.php +++ b/tests/system/Config/fixtures/SimpleConfig.php @@ -25,7 +25,8 @@ class SimpleConfig extends \CodeIgniter\Config\BaseConfig public $simple = [ 'name' => null, ]; - // properties for environment over-ride testing + + // properties for environment override testing public $alpha = 'one'; public $bravo = 'two'; public $charlie = 'three'; @@ -41,7 +42,6 @@ class SimpleConfig extends \CodeIgniter\Config\BaseConfig 'doctor' => 'Bones', 'comms' => 'Uhuru', ]; - public $shortie; public $longie; public $onedeep_value; diff --git a/tests/system/ControllerTest.php b/tests/system/ControllerTest.php index 3d7c205eec0b..d4be0c503b7a 100644 --- a/tests/system/ControllerTest.php +++ b/tests/system/ControllerTest.php @@ -56,6 +56,7 @@ final class ControllerTest extends CIUnitTestCase * @var Response */ protected $response; + /** * @var LoggerInterface */ diff --git a/tests/system/Database/BaseConnectionTest.php b/tests/system/Database/BaseConnectionTest.php index 85126836650f..7d2352a0e9b2 100644 --- a/tests/system/Database/BaseConnectionTest.php +++ b/tests/system/Database/BaseConnectionTest.php @@ -39,7 +39,6 @@ final class BaseConnectionTest extends CIUnitTestCase 'strictOn' => true, 'failover' => [], ]; - protected $failoverOptions = [ 'DSN' => '', 'hostname' => 'localhost', diff --git a/tests/system/Database/ConfigTest.php b/tests/system/Database/ConfigTest.php index d4f795dcc26b..0dc9a1619485 100644 --- a/tests/system/Database/ConfigTest.php +++ b/tests/system/Database/ConfigTest.php @@ -40,7 +40,6 @@ final class ConfigTest extends CIUnitTestCase 'failover' => [], 'port' => 3306, ]; - protected $dsnGroup = [ 'DSN' => 'MySQLi://user:pass@localhost:3306/dbname?DBPrefix=test_&pConnect=true&charset=latin1&DBCollat=latin1_swedish_ci', 'hostname' => '', @@ -60,7 +59,6 @@ final class ConfigTest extends CIUnitTestCase 'failover' => [], 'port' => 3306, ]; - protected $dsnGroupPostgre = [ 'DSN' => 'Postgre://user:pass@localhost:5432/dbname?DBPrefix=test_&connect_timeout=5&sslmode=1', 'hostname' => '', @@ -80,7 +78,6 @@ final class ConfigTest extends CIUnitTestCase 'failover' => [], 'port' => 5432, ]; - protected $dsnGroupPostgreNative = [ 'DSN' => 'pgsql:host=localhost;port=5432;dbname=database_name', 'hostname' => '', diff --git a/tests/system/Database/Live/AliasTest.php b/tests/system/Database/Live/AliasTest.php index 0024625ce5b5..c032cd1b6546 100644 --- a/tests/system/Database/Live/AliasTest.php +++ b/tests/system/Database/Live/AliasTest.php @@ -24,8 +24,7 @@ final class AliasTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testAlias() { diff --git a/tests/system/Database/Live/BadQueryTest.php b/tests/system/Database/Live/BadQueryTest.php index 44a2adb0a391..b7d7840525c6 100644 --- a/tests/system/Database/Live/BadQueryTest.php +++ b/tests/system/Database/Live/BadQueryTest.php @@ -25,8 +25,7 @@ final class BadQueryTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; protected static $origDebug; /** diff --git a/tests/system/Database/Live/ConnectTest.php b/tests/system/Database/Live/ConnectTest.php index 680f03c94ca7..5ee18a6f25eb 100644 --- a/tests/system/Database/Live/ConnectTest.php +++ b/tests/system/Database/Live/ConnectTest.php @@ -27,9 +27,7 @@ final class ConnectTest extends CIUnitTestCase use DatabaseTestTrait; protected $group1; - protected $group2; - protected $tests; protected function setUp(): void diff --git a/tests/system/Database/Live/CountTest.php b/tests/system/Database/Live/CountTest.php index bfe917cb2adc..d87833759f24 100644 --- a/tests/system/Database/Live/CountTest.php +++ b/tests/system/Database/Live/CountTest.php @@ -24,8 +24,7 @@ final class CountTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testCountReturnsZeroWithNoResults() { diff --git a/tests/system/Database/Live/DatabaseTestTraitCaseTest.php b/tests/system/Database/Live/DatabaseTestTraitCaseTest.php index 8e917a7d30e9..3e9267b2b05d 100644 --- a/tests/system/Database/Live/DatabaseTestTraitCaseTest.php +++ b/tests/system/Database/Live/DatabaseTestTraitCaseTest.php @@ -24,8 +24,7 @@ final class DatabaseTestTraitCaseTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testHasInDatabase() { diff --git a/tests/system/Database/Live/DeleteTest.php b/tests/system/Database/Live/DeleteTest.php index bd3cd7d6d05c..31b89412e78a 100644 --- a/tests/system/Database/Live/DeleteTest.php +++ b/tests/system/Database/Live/DeleteTest.php @@ -25,8 +25,7 @@ final class DeleteTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testDeleteThrowExceptionWithNoCriteria() { diff --git a/tests/system/Database/Live/EmptyTest.php b/tests/system/Database/Live/EmptyTest.php index 5dfcec87e418..912f627911c6 100644 --- a/tests/system/Database/Live/EmptyTest.php +++ b/tests/system/Database/Live/EmptyTest.php @@ -24,8 +24,7 @@ final class EmptyTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testEmpty() { diff --git a/tests/system/Database/Live/EscapeTest.php b/tests/system/Database/Live/EscapeTest.php index f5c3ff8b59c1..08265788d00e 100644 --- a/tests/system/Database/Live/EscapeTest.php +++ b/tests/system/Database/Live/EscapeTest.php @@ -24,7 +24,6 @@ final class EscapeTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = false; - protected $char; protected function setUp(): void diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index d459bc92e391..1f8d8108d42d 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -29,8 +29,7 @@ final class ForgeTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; /** * @var Forge diff --git a/tests/system/Database/Live/FromTest.php b/tests/system/Database/Live/FromTest.php index 6a17f800e55a..5037dd717f71 100644 --- a/tests/system/Database/Live/FromTest.php +++ b/tests/system/Database/Live/FromTest.php @@ -24,8 +24,7 @@ final class FromTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testFromCanAddTables() { diff --git a/tests/system/Database/Live/GetNumRowsTest.php b/tests/system/Database/Live/GetNumRowsTest.php index bfa982d5d6a5..791fef5acf39 100644 --- a/tests/system/Database/Live/GetNumRowsTest.php +++ b/tests/system/Database/Live/GetNumRowsTest.php @@ -22,8 +22,7 @@ final class GetNumRowsTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; /** * Added as instructed at https://codeigniter4.github.io/userguide/testing/database.html#the-test-class diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index a2f1aa4f9b89..2682f12e57ca 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -25,8 +25,7 @@ final class GetTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testGet() { diff --git a/tests/system/Database/Live/GroupTest.php b/tests/system/Database/Live/GroupTest.php index 9ef9da758fff..705172ac97f0 100644 --- a/tests/system/Database/Live/GroupTest.php +++ b/tests/system/Database/Live/GroupTest.php @@ -24,8 +24,7 @@ final class GroupTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testGroupBy() { diff --git a/tests/system/Database/Live/IncrementTest.php b/tests/system/Database/Live/IncrementTest.php index d53732464f56..bb5faccf4e15 100644 --- a/tests/system/Database/Live/IncrementTest.php +++ b/tests/system/Database/Live/IncrementTest.php @@ -24,8 +24,7 @@ final class IncrementTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testIncrement() { diff --git a/tests/system/Database/Live/InsertTest.php b/tests/system/Database/Live/InsertTest.php index 8ca40e2309ef..a5bd090b7578 100644 --- a/tests/system/Database/Live/InsertTest.php +++ b/tests/system/Database/Live/InsertTest.php @@ -24,8 +24,7 @@ final class InsertTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testInsert() { diff --git a/tests/system/Database/Live/JoinTest.php b/tests/system/Database/Live/JoinTest.php index 7e35effcc852..b30c8ac8b9bb 100644 --- a/tests/system/Database/Live/JoinTest.php +++ b/tests/system/Database/Live/JoinTest.php @@ -24,8 +24,7 @@ final class JoinTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testSimpleJoin() { diff --git a/tests/system/Database/Live/LikeTest.php b/tests/system/Database/Live/LikeTest.php index 999539e488fc..65261f2372fb 100644 --- a/tests/system/Database/Live/LikeTest.php +++ b/tests/system/Database/Live/LikeTest.php @@ -24,8 +24,7 @@ final class LikeTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testLikeDefault() { diff --git a/tests/system/Database/Live/LimitTest.php b/tests/system/Database/Live/LimitTest.php index ee3f8c475b79..8673b5bc486d 100644 --- a/tests/system/Database/Live/LimitTest.php +++ b/tests/system/Database/Live/LimitTest.php @@ -22,9 +22,9 @@ final class LimitTest extends CIUnitTestCase { use DatabaseTestTrait; - protected $refresh = true; - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $refresh = true; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testLimit() { diff --git a/tests/system/Database/Live/OrderTest.php b/tests/system/Database/Live/OrderTest.php index 9d87089b5e79..76f7e8374f32 100644 --- a/tests/system/Database/Live/OrderTest.php +++ b/tests/system/Database/Live/OrderTest.php @@ -24,8 +24,7 @@ final class OrderTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testOrderAscending() { diff --git a/tests/system/Database/Live/SelectTest.php b/tests/system/Database/Live/SelectTest.php index 6224633847d6..fbfa3ca97052 100644 --- a/tests/system/Database/Live/SelectTest.php +++ b/tests/system/Database/Live/SelectTest.php @@ -24,8 +24,7 @@ final class SelectTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testSelectAllByDefault() { diff --git a/tests/system/Database/Live/UpdateTest.php b/tests/system/Database/Live/UpdateTest.php index c0f1bd3575d4..f7e2fb5e4b32 100644 --- a/tests/system/Database/Live/UpdateTest.php +++ b/tests/system/Database/Live/UpdateTest.php @@ -25,8 +25,7 @@ final class UpdateTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testUpdateSetsAllWithoutWhere() { diff --git a/tests/system/Database/Live/WhereTest.php b/tests/system/Database/Live/WhereTest.php index ce87bbd3c7f4..76756e19a219 100644 --- a/tests/system/Database/Live/WhereTest.php +++ b/tests/system/Database/Live/WhereTest.php @@ -24,8 +24,7 @@ final class WhereTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testWhereSimpleKeyValue() { diff --git a/tests/system/Database/Live/WriteTypeQueryTest.php b/tests/system/Database/Live/WriteTypeQueryTest.php index 31dd848c41a2..9ec6c1c1dbe3 100644 --- a/tests/system/Database/Live/WriteTypeQueryTest.php +++ b/tests/system/Database/Live/WriteTypeQueryTest.php @@ -25,8 +25,7 @@ final class WriteTypeQueryTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; public function testSet() { diff --git a/tests/system/Database/Migrations/MigrationRunnerTest.php b/tests/system/Database/Migrations/MigrationRunnerTest.php index fa867c7e1f0e..27e14c51c0f7 100644 --- a/tests/system/Database/Migrations/MigrationRunnerTest.php +++ b/tests/system/Database/Migrations/MigrationRunnerTest.php @@ -33,7 +33,6 @@ final class MigrationRunnerTest extends CIUnitTestCase use DatabaseTestTrait; protected $refresh = true; - protected $root; protected $start; protected $config; diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index c995f5d7c191..94d71849c679 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -930,14 +930,12 @@ protected function getEntity() 'default' => 'sumfin', 'created_at' => null, ]; - protected $original = [ 'foo' => null, 'bar' => null, 'default' => 'sumfin', 'created_at' => null, ]; - protected $datamap = [ 'createdAt' => 'created_at', ]; @@ -968,7 +966,6 @@ protected function getMappedEntity() 'foo' => null, 'simple' => null, ]; - protected $_original = [ 'foo' => null, 'simple' => null, @@ -999,12 +996,10 @@ protected function getSwappedEntity() 'foo' => 'foo', 'bar' => 'bar', ]; - protected $_original = [ 'foo' => 'foo', 'bar' => 'bar', ]; - protected $datamap = [ 'bar' => 'foo', 'foo' => 'bar', @@ -1031,7 +1026,6 @@ protected function getCastEntity($data = null): Entity 'twelfth' => null, 'thirteenth' => null, ]; - protected $_original = [ 'first' => null, 'second' => null, @@ -1082,7 +1076,6 @@ protected function getCastNullableEntity() 'integer_0' => null, 'string_value_not_null' => 'value', ]; - protected $_original = [ 'string_null' => null, 'string_empty' => null, @@ -1111,7 +1104,6 @@ protected function getCustomCastEntity() 'third' => null, 'fourth' => null, ]; - protected $_original = [ 'first' => null, 'second' => null, @@ -1126,7 +1118,6 @@ protected function getCustomCastEntity() 'third' => 'type[param1, param2,param3]', 'fourth' => '?type', ]; - protected $castHandlers = [ 'base64' => CastBase64::class, 'someType' => NotExtendsBaseCast::class, diff --git a/tests/system/HTTP/RedirectResponseTest.php b/tests/system/HTTP/RedirectResponseTest.php index 0e8e49a74588..ac2e8abaaba9 100644 --- a/tests/system/HTTP/RedirectResponseTest.php +++ b/tests/system/HTTP/RedirectResponseTest.php @@ -30,6 +30,7 @@ final class RedirectResponseTest extends CIUnitTestCase * @var RouteCollection */ protected $routes; + protected $request; protected $config; diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 38b86eb67e30..521dec8fbadd 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -165,7 +165,6 @@ public function testInsertBatchNewEntityWithDateTime(): void protected $deleted; protected $created_at; protected $updated_at; - protected $_options = [ 'datamap' => [], 'dates' => [ @@ -223,7 +222,6 @@ public function testInsertEntityWithNoDataExceptionNoAllowedData(): void protected $deleted; protected $created_at; protected $updated_at; - protected $_options = [ 'datamap' => [], 'dates' => [ diff --git a/tests/system/Models/SaveModelTest.php b/tests/system/Models/SaveModelTest.php index 17f56a4cb88c..48b63c14b211 100644 --- a/tests/system/Models/SaveModelTest.php +++ b/tests/system/Models/SaveModelTest.php @@ -216,7 +216,6 @@ public function testSaveNewEntityWithDateTime(): void protected $deleted; protected $created_at; protected $updated_at; - protected $_options = [ 'datamap' => [], 'dates' => [ diff --git a/tests/system/Models/UpdateModelTest.php b/tests/system/Models/UpdateModelTest.php index 619028a748aa..888c019eca1e 100644 --- a/tests/system/Models/UpdateModelTest.php +++ b/tests/system/Models/UpdateModelTest.php @@ -166,7 +166,6 @@ public function testUpdateBatchWithEntity(): void protected $deleted; protected $created_at; protected $updated_at; - protected $_options = [ 'datamap' => [], 'dates' => [ @@ -186,7 +185,6 @@ public function testUpdateBatchWithEntity(): void protected $deleted; protected $created_at; protected $updated_at; - protected $_options = [ 'datamap' => [], 'dates' => [ @@ -315,7 +313,6 @@ public function testUpdateWithEntityNoAllowedFields(): void protected $deleted; protected $created_at; protected $updated_at; - protected $_options = [ 'datamap' => [], 'dates' => [ diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 72deb09c2c4c..05b069d83c21 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -29,6 +29,7 @@ final class PagerTest extends CIUnitTestCase * @var \CodeIgniter\Pager\Pager */ protected $pager; + protected $config; protected function setUp(): void diff --git a/tests/system/Session/Handlers/DatabaseHandlerTest.php b/tests/system/Session/Handlers/DatabaseHandlerTest.php index e001af8eeec8..2349bc292bd8 100644 --- a/tests/system/Session/Handlers/DatabaseHandlerTest.php +++ b/tests/system/Session/Handlers/DatabaseHandlerTest.php @@ -26,8 +26,7 @@ final class DatabaseHandlerTest extends CIUnitTestCase use ReflectionHelper; protected $refresh = true; - - protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; + protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; protected function setUp(): void { diff --git a/tests/system/Validation/CreditCardRulesTest.php b/tests/system/Validation/CreditCardRulesTest.php index a1e8f74d8a27..7610ea4ee966 100644 --- a/tests/system/Validation/CreditCardRulesTest.php +++ b/tests/system/Validation/CreditCardRulesTest.php @@ -24,6 +24,7 @@ final class CreditCardRulesTest extends CIUnitTestCase * @var Validation */ protected $validation; + protected $config = [ 'ruleSets' => [ Rules::class, diff --git a/tests/system/Validation/FileRulesTest.php b/tests/system/Validation/FileRulesTest.php index 0e4e70ec537f..e8da364367a7 100644 --- a/tests/system/Validation/FileRulesTest.php +++ b/tests/system/Validation/FileRulesTest.php @@ -24,6 +24,7 @@ final class FileRulesTest extends CIUnitTestCase * @var Validation */ protected $validation; + protected $config = [ 'ruleSets' => [ Rules::class, diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index 725824607748..eb457a0c3a2f 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -27,6 +27,7 @@ final class FormatRulesTest extends CIUnitTestCase * @var Validation */ protected $validation; + protected $config = [ 'ruleSets' => [ Rules::class, diff --git a/tests/system/Validation/RulesTest.php b/tests/system/Validation/RulesTest.php index f4f171b87bbb..7fe8469fcbeb 100644 --- a/tests/system/Validation/RulesTest.php +++ b/tests/system/Validation/RulesTest.php @@ -31,6 +31,7 @@ final class RulesTest extends CIUnitTestCase * @var Validation */ protected $validation; + protected $config = [ 'ruleSets' => [ Rules::class, diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index ccbff3358f42..8b77686fc3b5 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -29,6 +29,7 @@ final class ValidationTest extends CIUnitTestCase * @var Validation */ protected $validation; + protected $config = [ 'ruleSets' => [ Rules::class, diff --git a/tests/system/View/ParserPluginTest.php b/tests/system/View/ParserPluginTest.php index df773a375df8..85de3e7898fa 100644 --- a/tests/system/View/ParserPluginTest.php +++ b/tests/system/View/ParserPluginTest.php @@ -24,6 +24,7 @@ final class ParserPluginTest extends CIUnitTestCase * @var Parser */ protected $parser; + /** * @var Validation */ From abe42861f6c4267f7b72082cac59a3a8023a16f1 Mon Sep 17 00:00:00 2001 From: Tetsuro Yoshikawa Date: Mon, 11 Oct 2021 22:15:09 +0900 Subject: [PATCH 0443/2325] fix: fieldName -> keyName --- system/Database/Forge.php | 6 +++--- system/Database/MySQLi/Forge.php | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/system/Database/Forge.php b/system/Database/Forge.php index c4bd082b73c4..8e0b7e43c7f3 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -433,13 +433,13 @@ public function addForeignKey($fieldName = '', string $tableName = '', $tableFie * * @throws DatabaseException * - * @return BaseResult|bool|false|mixed|Query + * @return bool */ - public function dropKey(string $table, string $fieldName) + public function dropKey(string $table, string $keyName) { $sql = sprintf( $this->dropIndexStr, - $this->db->escapeIdentifiers($this->db->DBPrefix . $fieldName), + $this->db->escapeIdentifiers($this->db->DBPrefix . $keyName), $this->db->escapeIdentifiers($this->db->DBPrefix . $table), ); diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index 3038f8a9165f..d00c26dd1ca7 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -224,13 +224,13 @@ protected function _processIndexes(string $table): string /** * Drop Key * - * @return BaseResult|bool|false|mixed|Query + * @return bool */ - public function dropKey(string $table, string $fieldName) + public function dropKey(string $table, string $keyName) { $sql = sprintf( $this->dropIndexStr, - $this->db->escapeIdentifiers($fieldName), + $this->db->escapeIdentifiers($keyName), $this->db->escapeIdentifiers($this->db->DBPrefix . $table), ); From eda426ddd9df34bb9ed3b49f3c534d446af65674 Mon Sep 17 00:00:00 2001 From: Tetsuro Yoshikawa Date: Mon, 11 Oct 2021 22:15:27 +0900 Subject: [PATCH 0444/2325] docs: remove unnecessary escape. --- user_guide_src/source/dbmgmt/forge.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index d9b3bd631dbf..d7b3c4546825 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -312,7 +312,7 @@ Execute a DROP KEY. :: - // Produces: DROP INDEX 'users_index' ON 'tablename' + // Produces: DROP INDEX users_index ON tablename $forge->dropKey('tablename','users_index'); Renaming a table From 2126376e8998732fc7341517fe9e11ea39b788c0 Mon Sep 17 00:00:00 2001 From: Tetsuro Yoshikawa Date: Mon, 11 Oct 2021 22:27:25 +0900 Subject: [PATCH 0445/2325] docs: remove single-quote escaping. --- user_guide_src/source/dbmgmt/forge.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index 6cbdfe506e8a..a0c677d3162b 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -301,7 +301,7 @@ Execute a DROP FOREIGN KEY. :: - // Produces: ALTER TABLE 'tablename' DROP FOREIGN KEY 'users_foreign' + // Produces: ALTER TABLE tablename DROP FOREIGN KEY users_foreign $forge->dropForeignKey('tablename','users_foreign'); Renaming a table From 1d091fab3bdd259e9ace6327db0b2d03a90fcd28 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Tue, 12 Oct 2021 00:43:31 +0200 Subject: [PATCH 0446/2325] Add formatted query string to timeline. Co-Authored-By: Daniel Tiringer <53534182+danielTiringer@users.noreply.github.com> --- system/Debug/Toolbar.php | 11 +++++++++++ system/Debug/Toolbar/Collectors/Database.php | 1 + 2 files changed, 12 insertions(+) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index b59666aacc4c..2f2e7d0d92b4 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -273,6 +273,17 @@ protected function structureTimelineData(array $elements): array // We define ourselves as the first element of the array $element = array_shift($elements); + // If we are a query, add the formatted query string as our first child + if (array_key_exists('query', $element) && $element['query']) { + $element['children'][] = [ + 'name' => $element['query'], + 'component' => 'Query', + 'start' => $element['start'], + 'duration' => $element['duration'], + 'end' => $element['end'], + ]; + } + // If we have children behind us, collect and attach them to us while (! empty($elements) && $elements[array_key_first($elements)]['end'] <= $element['end']) { $element['children'][] = array_shift($elements); diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index c093068a9342..d8445b80364f 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -118,6 +118,7 @@ protected function formatTimelineData(): array 'component' => 'Database', 'start' => $query['query']->getStartTime(true), 'duration' => $query['query']->getDuration(), + 'query' => $query['query']->debugToolbarDisplay(), ]; } From d02c38071f45d4d891624b7a4e9d931a7eaf4ab9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 09:17:08 +0900 Subject: [PATCH 0447/2325] docs: move contributing related contents from README.md to contributing/README.md --- README.md | 8 +------- contributing/README.md | 6 ++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5d9d007b91e2..1bcfdfcb922d 100644 --- a/README.md +++ b/README.md @@ -71,13 +71,7 @@ to optional packages, with their own repository. We **are** accepting contributions from the community! -We will try to manage the process somewhat, by adding a ["help wanted" label](https://github.com/codeigniter4/CodeIgniter4/labels/help%20wanted) to those that we are -specifically interested in at any point in time. Join the discussion for those issues and let us know -if you want to take the lead on one of them. - -At this time, we are not looking for out-of-scope contributions, only those that would be considered part of our controlled evolution! - -Please read the [*Contributing to CodeIgniter*](https://github.com/codeigniter4/CodeIgniter4/blob/develop/CONTRIBUTING.md) section in the user guide. +Please read the [*Contributing to CodeIgniter*](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/README.md). ## Server Requirements diff --git a/contributing/README.md b/contributing/README.md index 2df6e0870ebc..7277eb1dc25d 100644 --- a/contributing/README.md +++ b/contributing/README.md @@ -7,6 +7,12 @@ Requests](https://help.github.com/articles/using-pull-requests/) on the [CodeIgniter4 repository](https://github.com/codeigniter4/CodeIgniter4) on GitHub. +We will try to manage the process somewhat, by adding a ["help wanted" label](https://github.com/codeigniter4/CodeIgniter4/labels/help%20wanted) to those that we are +specifically interested in at any point in time. Join the discussion for those issues and let us know +if you want to take the lead on one of them. + +At this time, we are not looking for out-of-scope contributions, only those that would be considered part of our controlled evolution! + - [Contributor Covenant Code of Conduct](../CODE_OF_CONDUCT.md) - [Reporting a Bug](./bug_report.md) - [Sending a Pull Request](./pull_request.md) From 99a1a53905f7fc6b599fb6b6ee6f8e94cc8f9d0b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 09:18:54 +0900 Subject: [PATCH 0448/2325] docs: remove "we are not looking for out-of-scope contributions" It seems it is out-of-dated. --- contributing/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/contributing/README.md b/contributing/README.md index 7277eb1dc25d..40796df376b3 100644 --- a/contributing/README.md +++ b/contributing/README.md @@ -11,8 +11,6 @@ We will try to manage the process somewhat, by adding a ["help wanted" label](ht specifically interested in at any point in time. Join the discussion for those issues and let us know if you want to take the lead on one of them. -At this time, we are not looking for out-of-scope contributions, only those that would be considered part of our controlled evolution! - - [Contributor Covenant Code of Conduct](../CODE_OF_CONDUCT.md) - [Reporting a Bug](./bug_report.md) - [Sending a Pull Request](./pull_request.md) From c1f72de2af3a2bfeb5fdd9fcc815cfdb2866cb1b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 12:46:22 +0900 Subject: [PATCH 0449/2325] docs: remove unnecessary indentation --- user_guide_src/source/helpers/form_helper.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index 685c7e7041ea..be36f9c9dd09 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -103,7 +103,7 @@ The following functions are available: will return::
    - + **Adding Hidden Input Fields** From 205cdfb2e707863138af0248446aa55d455ca3f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 12:47:56 +0900 Subject: [PATCH 0450/2325] docs: add note to CSRF filter and HTTP method --- user_guide_src/source/helpers/form_helper.rst | 2 ++ user_guide_src/source/libraries/security.rst | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index be36f9c9dd09..f4e5b09c1af1 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -105,6 +105,8 @@ The following functions are available: + .. note:: To use auto generation of CSRF field, you need to turn CSRF filter on to the form page. In most cases it is requested using the `GET` method. + **Adding Hidden Input Fields** Hidden fields can be added by passing an associative array to the diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 0a16f99e022a..2d16a2a5b53a 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -53,7 +53,12 @@ Regular expressions are also supported (case-insensitive):: If you use the :doc:`form helper <../helpers/form_helper>`, then :func:`form_open()` will automatically insert a hidden csrf field in -your forms. If not, then you can use the always available ``csrf_token()`` +your forms. + +.. note:: To use auto generation of CSRF field, you need to turn CSRF filter on to the form page. + In most cases it is requested using the `GET` method. + +If not, then you can use the always available ``csrf_token()`` and ``csrf_hash()`` functions :: From f562184c051fa7becc822b3995a2a9e76dbe3035 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 12:48:43 +0900 Subject: [PATCH 0451/2325] docs: fix typo --- user_guide_src/source/installation/upgrade_security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 4f2b8107a96b..61cf699658b2 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -30,7 +30,7 @@ Upgrade Guide ] ]; -2. Within you html forms you have to remove the csrf input which looks similar to ````. +2. Within your html forms you have to remove the csrf input which looks similar to ````. 3. Now within your html forms you have to add ```` somewhere in the form body, unless you are using ``form_open()``. Code Example From 33f4635244541a1b285a1bd93aad340e2fec3d97 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 12:49:35 +0900 Subject: [PATCH 0452/2325] docs: add headings There are a lot of contents. --- user_guide_src/source/libraries/security.rst | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 2d16a2a5b53a..758d16b54173 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -23,6 +23,9 @@ If you find a case where you do need direct access though, you may load it throu Cross-site request forgery (CSRF) ********************************* +Enable CSRF Protection +====================== + You can enable CSRF protection by altering your **app/Config/Filters.php** and enabling the `csrf` filter globally:: @@ -51,6 +54,9 @@ Regular expressions are also supported (case-insensitive):: ], ]; +HTML Forms +========== + If you use the :doc:`form helper <../helpers/form_helper>`, then :func:`form_open()` will automatically insert a hidden csrf field in your forms. @@ -80,12 +86,18 @@ meta tag for you:: // Generates: +The Order of Token Sent by Users +================================ + The order of checking the availability of the CSRF token is as follows: 1. ``$_POST`` array -2. Http header +2. HTTP header 3. ``php://input`` (JSON request) - bare in mind that this approach is the slowest one since we have to decode JSON and then encode it again +Tokens Regeneration +=================== + Tokens may be either regenerated on every submission (default) or kept the same throughout the life of the CSRF cookie. The default regeneration of tokens provides stricter security, but may result @@ -96,6 +108,9 @@ may alter this behavior by editing the following config parameter value in public $regenerate = true; +Redirection on Failure +====================== + When a request fails the CSRF validation check, it will redirect to the previous page by default, setting an ``error`` flash message that you can display to the end user. This provides a nicer experience than simply crashing. This can be turned off by editing the following config parameter value in From 69fbed9a5969a80bb17ffecf36272e19dd0496dd Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 13:39:31 +0900 Subject: [PATCH 0453/2325] docs: remove unnecessary blank lines --- admin/README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/admin/README.md b/admin/README.md index 52747ca3eeaa..9f36d2d72a48 100644 --- a/admin/README.md +++ b/admin/README.md @@ -9,7 +9,6 @@ This folder contains tools or docs useful for project maintainers. In addition to the framework source, it includes unit testing and documentation source. The three repositories following are built from this one as part of the release workflow. This repo is meant to be forked by contributors. - - **framework** is the released developer repository. It contains all the main pieces of the framework that developers would use to build their apps, but not the framework unit testing or the user guide source. @@ -25,7 +24,6 @@ This folder contains tools or docs useful for project maintainers. framework releases. It could be downloaded, forked or potentially composer-installed. This is a read-only repository. - - **coding-standard** is the coding style standards repository. It contains PHP CodeSniffer rules to ensure consistent code style within the framework itself. From aa81929094ebf4210154ebc2e1ed3f993ccd9a44 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 13:39:57 +0900 Subject: [PATCH 0454/2325] docs: update about coding-standard repository --- admin/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/README.md b/admin/README.md index 9f36d2d72a48..1f5dd89bfcd1 100644 --- a/admin/README.md +++ b/admin/README.md @@ -24,8 +24,8 @@ This folder contains tools or docs useful for project maintainers. framework releases. It could be downloaded, forked or potentially composer-installed. This is a read-only repository. -- **coding-standard** is the coding style standards repository. - It contains PHP CodeSniffer rules to ensure consistent code style +- **coding-standard** is the coding style standards repository. + It contains PHP-CS-Fixer rules to ensure consistent code style within the framework itself. It is meant to be composer-installed. - **translations** is the repository holding official translations of From cc0b7e996951d32b53874d81be8b90b6eb05e064 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Tue, 12 Oct 2021 09:41:44 +0200 Subject: [PATCH 0455/2325] Simplify query string output in timeline. --- system/Debug/Toolbar.php | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 2f2e7d0d92b4..491be10e5af6 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -185,16 +185,18 @@ protected function renderTimelineRecursive(array $rows, float $startTime, int $s foreach ($rows as $row) { $hasChildren = isset($row['children']) && ! empty($row['children']); + $isQuery = isset($row['query']) && ! empty($row['query']); + // Open controller timeline by default $open = $row['name'] === 'Controller'; - if ($hasChildren) { + if ($hasChildren || $isQuery) { $output .= '
    '; } else { $output .= ''; } - $output .= ''; + $output .= ''; $output .= ''; $output .= ''; $output .= "'; $output .= ''; @@ -273,17 +285,6 @@ protected function structureTimelineData(array $elements): array // We define ourselves as the first element of the array $element = array_shift($elements); - // If we are a query, add the formatted query string as our first child - if (array_key_exists('query', $element) && $element['query']) { - $element['children'][] = [ - 'name' => $element['query'], - 'component' => 'Query', - 'start' => $element['start'], - 'duration' => $element['duration'], - 'end' => $element['end'], - ]; - } - // If we have children behind us, collect and attach them to us while (! empty($elements) && $elements[array_key_first($elements)]['end'] <= $element['end']) { $element['children'][] = array_shift($elements); From 8d2678f0cd47789eac4162b052882c5deb1bfb08 Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Wed, 13 Oct 2021 07:25:43 +0200 Subject: [PATCH 0456/2325] Remove duplicate parentheses. Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/Debug/Toolbar.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 491be10e5af6..2199559d362d 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -196,7 +196,7 @@ protected function renderTimelineRecursive(array $rows, float $startTime, int $s $output .= ''; } - $output .= ''; + $output .= ''; $output .= ''; $output .= ''; $output .= " {queries} - + + + + + + {/queries} diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index b5a223b55d70..50ec4bff9e28 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -344,6 +344,8 @@ .debug-view.show-view { border-color: #DD8615; } +#debug-bar tr[data-toggle] { + cursor: pointer; } .debug-view-path { background-color: #FDC894; @@ -407,7 +409,7 @@ #debug-bar .muted { color: #DFDFDF; } #debug-bar .muted td { - color: #434343; } + color: #797979; } #debug-bar .muted:hover td { color: #DFDFDF; } #debug-bar #toolbar-position, diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index 690535f2de0d..b6883d4b9f3b 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -58,6 +58,13 @@ var ciDebugBar = { { buttons[i].addEventListener('click', ciDebugBar.showTab, true); } + + // Hook up generic toggle via data attributes `data-toggle="foo"` + var links = document.querySelectorAll('[data-toggle]'); + for (var i = 0; i < links.length; i++) + { + links[i].addEventListener('click', ciDebugBar.toggleRows, true); + } }, showTab: function () { @@ -124,6 +131,21 @@ var ciDebugBar = { } }, + /** + * Toggle display of another object based on + * the data-toggle value of this object + * + * @param event + */ + toggleRows : function(event) { + if(event.target) + { + let row = event.target.closest('tr'); + let target = document.getElementById(row.getAttribute('data-toggle')); + target.style.display = target.style.display === 'none' ? 'table-row' : 'none'; + } + }, + /** * Toggle display of a data table * @@ -137,7 +159,7 @@ var ciDebugBar = { if (obj) { - obj.style.display = obj.style.display == 'none' ? 'block' : 'none'; + obj.style.display = obj.style.display === 'none' ? 'block' : 'none'; } }, @@ -155,7 +177,7 @@ var ciDebugBar = { if (par && obj) { - obj.style.display = obj.style.display == 'none' ? '' : 'none'; + obj.style.display = obj.style.display === 'none' ? '' : 'none'; par.classList.toggle('timeline-parent-open'); } }, From 0ff83f2863c7d35638db4d003e4624ed60dc5de0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:18:24 +0900 Subject: [PATCH 0751/2325] docs: decorate variable names with '``' --- user_guide_src/source/models/model.rst | 30 +++++++++++++------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 18545f92f1bf..32fe2cf207c9 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -100,7 +100,7 @@ Connecting to the Database When the class is first instantiated, if no database connection instance is passed to the constructor, it will automatically connect to the default database group, as set in the configuration. You can -modify which group is used on a per-model basis by adding the DBGroup property to your class. +modify which group is used on a per-model basis by adding the ``$DBGroup`` property to your class. This ensures that within the model any references to ``$this->db`` are made through the appropriate connection. :: @@ -221,11 +221,11 @@ Leave it empty to avoid updating it (even if ``$useTimestamps`` is enabled) **$updatedField** Specifies which database field should use for keep data record update timestamp. -Leave it empty to avoid update it (even useTimestamps is enabled) +Leave it empty to avoid update it (even ``$useTimestamps`` is enabled). **$dateFormat** -This value works with $useTimestamps and $useSoftDeletes to ensure that the correct type of +This value works with ``$useTimestamps`` and ``$useSoftDeletes`` to ensure that the correct type of date value gets inserted into the database. By default, this creates DATETIME values, but valid options are: datetime, date, or int (a PHP timestamp). Using 'useSoftDeletes' or 'useTimestamps' with an invalid or missing dateFormat will cause an exception. @@ -277,7 +277,7 @@ Returns a single row where the primary key matches the value passed in as the fi $user = $userModel->find($user_id); -The value is returned in the format specified in $returnType. +The value is returned in the format specified in ``$returnType``. You can specify more than one row to return by passing an array of primaryKey values instead of just one:: @@ -293,7 +293,7 @@ Returns null or an indexed array of column values:: $user = $userModel->findColumn($column_name); -$column_name should be a name of single column else you will get the DataException. +``$column_name`` should be a name of single column else you will get the DataException. **findAll()** @@ -344,7 +344,7 @@ Saving Data **insert()** An associative array of data is passed into this method as the only parameter to create a new -row of data in the database. The array's keys must match the name of the columns in a $table, while +row of data in the database. The array's keys must match the name of the columns in a ``$table``, while the array's values are the values to save for that key:: $data = [ @@ -476,7 +476,7 @@ Takes a primary key value as the first parameter and deletes the matching record $userModel->delete(12); -If the model's $useSoftDeletes value is true, this will update the row to set ``deleted_at`` to the current +If the model's ``$useSoftDeletes`` value is true, this will update the row to set ``deleted_at`` to the current date and time. You can force a permanent delete by setting the second parameter as true. An array of primary keys can be passed in as the first parameter to delete multiple records at once:: @@ -642,7 +642,7 @@ Validation Placeholders The model provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply -the name of the field (or array key) that was passed in as $data surrounded by curly brackets. It will be +the name of the field (or array key) that was passed in as ``$data`` surrounded by curly brackets. It will be replaced by the **value** of the matched incoming field. An example should clarify this:: protected $validationRules = [ @@ -694,7 +694,7 @@ need it:: $builder = $userModel->builder(); -This builder is already set up with the model's $table. If you need access to another table +This builder is already set up with the model's ``$table``. If you need access to another table you can pass it in as a parameter, but be aware that this will not return a shared instance:: $groupBuilder = $userModel->builder('groups'); @@ -757,14 +757,14 @@ Model Events There are several points within the model's execution that you can specify multiple callback methods to run. These methods can be used to normalize data, hash passwords, save related entities, and much more. The following -points in the model's execution can be affected, each through a class property: **$beforeInsert**, **$afterInsert**, -**$beforeUpdate**, **$afterUpdate**, **$afterFind**, and **$afterDelete**. +points in the model's execution can be affected, each through a class property: ``$beforeInsert``, ``$afterInsert``, +``$beforeUpdate``, ``$afterUpdate``, ``$afterFind``, and ``$afterDelete``. Defining Callbacks ------------------ You specify the callbacks by first creating a new class method in your model to use. This class will always -receive a $data array as its only parameter. The exact contents of the $data array will vary between events, but +receive a ``$data`` array as its only parameter. The exact contents of the ``$data`` array will vary between events, but will always contain a key named **data** that contains the primary data passed to the original method. In the case of the insert* or update* methods, that will be the key/value pairs that are being inserted into the database. The main array will also contain the other values passed to the method, and be detailed later. The callback method @@ -785,14 +785,14 @@ must return the original $data array so other callbacks have the full informatio Specifying Callbacks To Run --------------------------- -You specify when to run the callbacks by adding the method name to the appropriate class property (beforeInsert, afterUpdate, +You specify when to run the callbacks by adding the method name to the appropriate class property (``$beforeInsert``, ``$afterUpdate``, etc). Multiple callbacks can be added to a single event and they will be processed one after the other. You can use the same callback in multiple events:: protected $beforeInsert = ['hashPassword']; protected $beforeUpdate = ['hashPassword']; -Additionally, each model may allow (default) or deny callbacks class-wide by setting its $allowCallbacks property:: +Additionally, each model may allow (default) or deny callbacks class-wide by setting its ``$allowCallbacks`` property:: protected $allowCallbacks = false; @@ -804,7 +804,7 @@ You may also change this setting temporarily for a single model call sing the `` Event Parameters ---------------- -Since the exact data passed to each callback varies a bit, here are the details on what is in the $data parameter +Since the exact data passed to each callback varies a bit, here are the details on what is in the ``$data`` parameter passed to each event: ================ ========================================================================================================= From e21445f737df749cbef80a8642dec275b105d03a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:19:16 +0900 Subject: [PATCH 0752/2325] docs: fix coding style --- user_guide_src/source/models/model.rst | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 32fe2cf207c9..ca020ca686a4 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -591,17 +591,16 @@ The other way to set the validation message to fields by functions, Now, whenever you call the ``insert()``, ``update()``, or ``save()`` methods, the data will be validated. If it fails, the model will return boolean **false**. You can use the ``errors()`` method to retrieve the validation errors:: - if ($model->save($data) === false) - { + if ($model->save($data) === false) { return view('updateUser', ['errors' => $model->errors()]); } This returns an array with the field names and their associated errors that can be used to either show all of the errors at the top of the form, or to display them individually:: - +
    - $error) : ?> + $error): ?>

    @@ -774,7 +773,9 @@ must return the original $data array so other callbacks have the full informatio protected function hashPassword(array $data) { - if (! isset($data['data']['password'])) return $data; + if (! isset($data['data']['password'])) { + return $data; + } $data['data']['password_hash'] = password_hash($data['data']['password'], PASSWORD_DEFAULT); unset($data['data']['password']); From 00480eb7c1ac94f8ac9a93963fd287c384e5caf8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:23:17 +0900 Subject: [PATCH 0753/2325] docs: decorate method names with '``' --- user_guide_src/source/models/model.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index ca020ca686a4..97045ceb3787 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -201,8 +201,8 @@ configured to any name of your choice by using $deletedField property. **$allowedFields** -This array should be updated with the field names that can be set during save, insert, or -update methods. Any field names other than these will be discarded. This helps to protect +This array should be updated with the field names that can be set during ``save()``, ``insert()``, or +``update()`` methods. Any field names other than these will be discarded. This helps to protect against just taking input from a form and throwing it all at the model, resulting in potential mass assignment vulnerabilities. @@ -268,8 +268,8 @@ Working With Data Finding Data ------------ -Several functions are provided for doing basic CRUD work on your tables, including find(), -insert(), update(), delete() and more. +Several functions are provided for doing basic CRUD work on your tables, including ``find()``, +``insert()``, ``update()``, ``delete()`` and more. **find()** @@ -285,7 +285,7 @@ of just one:: $users = $userModel->find([1,2,3]); If no parameters are passed in, will return all rows in that model's table, effectively acting -like findAll(), though less explicit. +like ``findAll()``, though less explicit. **findColumn()** From 38047b5f23a102e16d48b8b264a02ca755bfe8e9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:30:13 +0900 Subject: [PATCH 0754/2325] docs: replace find*() with **find*()** --- user_guide_src/source/models/model.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 97045ceb3787..bbb0d029f833 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -716,18 +716,18 @@ You can specify the format that data should be returned as when using the find*( $returnType. There may be times that you would like the data back in a different format, though. The Model provides methods that allow you to do just that. -.. note:: These methods only change the return type for the next find*() method call. After that, +.. note:: These methods only change the return type for the next **find*()** method call. After that, it is reset to its default value. **asArray()** -Returns data from the next find*() method as associative arrays:: +Returns data from the next **find*()** method as associative arrays:: $users = $userModel->asArray()->where('status', 'active')->findAll(); **asObject()** -Returns data from the next find*() method as standard objects or custom class intances:: +Returns data from the next **find*()** method as standard objects or custom class intances:: // Return as standard objects $users = $userModel->asObject()->where('status', 'active')->findAll(); From c80adce3bc0b5d7a35cec9ccf6eb4996bb5b5f82 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:31:48 +0900 Subject: [PATCH 0755/2325] docs: add comma --- 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 bbb0d029f833..2018f735f3c9 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -175,7 +175,7 @@ Specifies if the table uses an auto-increment feature for ``$primaryKey``. If se then you are responsible for providing primary key value for every record in the table. This feature may be handy when we want to implement 1:1 relation or use UUIDs for our model. -.. note:: If you set ``$useAutoIncrement`` to ``false`` then make sure to set your primary +.. note:: If you set ``$useAutoIncrement`` to ``false``, then make sure to set your primary key in the database to ``unique``. This way you will make sure that all of Model's features will still work the same as before. From 96664fead007f921c5bf6d9f5086e3b6e8cb381a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:32:20 +0900 Subject: [PATCH 0756/2325] docs: add period --- 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 2018f735f3c9..f94a76d416de 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -216,7 +216,7 @@ data type. **$createdField** Specifies which database field to use for data record create timestamp. -Leave it empty to avoid updating it (even if ``$useTimestamps`` is enabled) +Leave it empty to avoid updating it (even if ``$useTimestamps`` is enabled). **$updatedField** From 57dc194602d5e0d1d335b8b6580cad7513442831 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:34:45 +0900 Subject: [PATCH 0757/2325] docs: emphasize table A Model is for a specific table. --- 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 f94a76d416de..2e592106ad92 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -9,7 +9,7 @@ Using CodeIgniter's Model Models ====== -Models provide a way to interact with a specific table in your database. They come out of the box with helper +Models provide a way to interact with a specific **table** in your database. They come out of the box with helper methods for much of the standard ways you would need to interact with a database table, including finding records, updating records, deleting records, and more. From e5519e48956fbf58ef1550091798060b84a6cf06 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:35:54 +0900 Subject: [PATCH 0758/2325] docs: fix delete* with delete() There is only one delete() method in the Model. --- 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 2e592106ad92..5198818d0ec9 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -189,7 +189,7 @@ method. **$useSoftDeletes** -If true, then any delete* method calls will set ``deleted_at`` in the database, instead of +If true, then any ``delete()`` method calls will set ``deleted_at`` in the database, instead of actually deleting the row. This can preserve data when it might be referenced elsewhere, or can maintain a "recycle bin" of objects that can be restored, or even simply preserve it as part of a security trail. If true, the find* methods will only return non-deleted rows, unless From ab03da999e48312721643284b03e070a33572c0d Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 16 Nov 2021 15:38:04 +0900 Subject: [PATCH 0759/2325] docs: decorate variable names, method names, etc --- user_guide_src/source/models/model.rst | 44 +++++++++++++------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 5198818d0ec9..f3a75ef41056 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -183,8 +183,8 @@ feature may be handy when we want to implement 1:1 relation or use UUIDs for our The Model's CRUD methods will take a step of work away from you and automatically return 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', 'object', or the fully -qualified name of a class that can be used with the Result object's getCustomResultObject() +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. **$useSoftDeletes** @@ -192,12 +192,12 @@ method. If true, then any ``delete()`` method calls will set ``deleted_at`` in the database, instead of actually deleting the row. This can preserve data when it might be referenced elsewhere, or can maintain a "recycle bin" of objects that can be restored, or even simply preserve it as -part of a security trail. If true, the find* methods will only return non-deleted rows, unless -the withDeleted() method is called prior to calling the find* method. +part of a security trail. If true, the **find*()** methods will only return non-deleted rows, unless +the ``withDeleted()`` method is called prior to calling the **find*()** method. This requires either a DATETIME or INTEGER field in the database as per the model's -$dateFormat setting. The default field name is ``deleted_at`` however this name can be -configured to any name of your choice by using $deletedField property. +``$dateFormat`` setting. The default field name is ``deleted_at`` however this name can be +configured to any name of your choice by using ``$deletedField`` property. **$allowedFields** @@ -209,8 +209,8 @@ potential mass assignment vulnerabilities. **$useTimestamps** This boolean value determines whether the current date is automatically added to all inserts -and updates. If true, will set the current time in the format specified by $dateFormat. This -requires that the table have columns named 'created_at' and 'updated_at' in the appropriate +and updates. If true, will set the current time in the format specified by ``$dateFormat``. This +requires that the table have columns named **created_at** and **updated_at** in the appropriate data type. **$createdField** @@ -227,8 +227,8 @@ Leave it empty to avoid update it (even ``$useTimestamps`` is enabled). This value works with ``$useTimestamps`` and ``$useSoftDeletes`` to ensure that the correct type of date value gets inserted into the database. By default, this creates DATETIME values, but -valid options are: datetime, date, or int (a PHP timestamp). Using 'useSoftDeletes' or -'useTimestamps' with an invalid or missing dateFormat will cause an exception. +valid options are: ``'datetime'``, ``'date'``, or ``'int'`` (a PHP timestamp). Using **useSoftDeletes** or +**useTimestamps** with an invalid or missing dateFormat will cause an exception. **$validationRules** @@ -243,7 +243,7 @@ described in :ref:`validation-custom-errors`. Described in more detail below. **$skipValidation** -Whether validation should be skipped during all ``inserts`` and ``updates``. The default +Whether validation should be skipped during all **inserts** and **updates**. The default value is false, meaning that data will always attempt to be validated. This is primarily used by the ``skipValidation()`` method, but may be changed to ``true`` so this model will never validate. @@ -321,8 +321,8 @@ Returns the first row in the result set. This is best used in combination with t **withDeleted()** -If $useSoftDeletes is true, then the find* methods will not return any rows where 'deleted_at IS NOT null'. -To temporarily override this, you can use the withDeleted() method prior to calling the find* method. +If ``$useSoftDeletes`` is true, then the **find*()** methods will not return any rows where 'deleted_at IS NOT NULL'. +To temporarily override this, you can use the ``withDeleted()`` method prior to calling the **find*()** method. :: // Only gets non-deleted rows (deleted = 0) @@ -333,8 +333,8 @@ To temporarily override this, you can use the withDeleted() method prior to call **onlyDeleted()** -Whereas withDeleted() will return both deleted and not-deleted rows, this method modifies -the next find* methods to return only soft deleted rows:: +Whereas ``withDeleted()`` will return both deleted and not-deleted rows, this method modifies +the next **find*()** methods to return only soft deleted rows:: $deletedUsers = $userModel->onlyDeleted()->findAll(); @@ -356,9 +356,9 @@ the array's values are the values to save for that key:: **update()** -Updates an existing record in the database. The first parameter is the $primaryKey of the record to update. +Updates an existing record in the database. The first parameter is the ``$primaryKey`` of the record to update. An associative array of data is passed into this method as the second parameter. The array's keys must match the name -of the columns in a $table, while the array's values are the values to save for that key:: +of the columns in a ``$table``, while the array's values are the values to save for that key:: $data = [ 'username' => 'darth', @@ -385,8 +385,8 @@ update command, with the added benefit of validation, events, etc:: **save()** -This is a wrapper around the insert() and update() methods that handle inserting or updating the record -automatically, based on whether it finds an array key matching the $primaryKey value:: +This is a wrapper around the ``insert()`` and ``update()`` methods that handle inserting or updating the record +automatically, based on whether it finds an array key matching the **primary key** value:: // Defined as a model property $primaryKey = 'id'; @@ -628,7 +628,7 @@ method directly, with options:: $rules = $model->getValidationRules($options); The ``$options`` parameter is an associative array with one element, -whose key is either "except" or "only", and which has as its +whose key is either ``'except'`` or ``'only'``, and which has as its value an array of fieldnames of interest.:: // get the rules for all but the "username" field @@ -712,8 +712,8 @@ very elegant use:: Runtime Return Type Changes ---------------------------- -You can specify the format that data should be returned as when using the find*() methods as the class property, -$returnType. There may be times that you would like the data back in a different format, though. The Model +You can specify the format that data should be returned as when using the **find*()** methods as the class property, +``$returnType``. There may be times that you would like the data back in a different format, though. The Model provides methods that allow you to do just that. .. note:: These methods only change the return type for the next **find*()** method call. After that, From e78e6c7c6a1241a2a7728ebb024b706d6d5b86d0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 17 Nov 2021 11:44:55 +0900 Subject: [PATCH 0760/2325] docs: fix execute() explanation --- user_guide_src/source/testing/controllers.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst index e99a24d935f9..94ef7dad1135 100644 --- a/user_guide_src/source/testing/controllers.rst +++ b/user_guide_src/source/testing/controllers.rst @@ -69,13 +69,15 @@ Specifies the class name of the controller to test. The first parameter must be $this->controller(\App\Controllers\ForumController::class); -**execute($method)** +**execute(string $method, ...$params)** -Executes the specified method within the controller. The only parameter is the name of the method to run:: +Executes the specified method within the controller. The first parameter is the name of the method to run:: $results = $this->controller(\App\Controllers\ForumController::class) ->execute('showCategories'); +By specifying the second and subsequent parameters, you can pass them to the controller method. + This returns a new helper class that provides a number of routines for checking the response itself. See below for details. From 58644197b6cc4cbcbf94c12f11ead23ddd655042 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 17 Nov 2021 11:45:31 +0900 Subject: [PATCH 0761/2325] docs: fix withURI() signature --- user_guide_src/source/testing/controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst index 94ef7dad1135..1f16cd615fc2 100644 --- a/user_guide_src/source/testing/controllers.rst +++ b/user_guide_src/source/testing/controllers.rst @@ -135,7 +135,7 @@ Allows you to provide a **Logger** instance:: If you do not provide one, a new Logger instance with the default configuration values will be passed into your controller. -**withURI($uri)** +**withURI(string $uri)** Allows you to provide a new URI that simulates the URL the client was visiting when this controller was run. This is helpful if you need to check URI segments within your controller. The only parameter is a string From 2d867408f32f0e033c09904f1adbb232ffe41234 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 17 Nov 2021 11:45:53 +0900 Subject: [PATCH 0762/2325] docs: elaborate on isOK() --- user_guide_src/source/testing/response.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index e5e0f34852ff..c5f7d9c34fbe 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -37,7 +37,7 @@ Checking Response Status **isOK()** Returns a boolean true/false based on whether the response is perceived to be "ok". This is primarily determined by -a response status code in the 200 or 300's. +a response status code in the 200 or 300's. An empty body is not considered valid, unless in redirects. :: if ($result->isOK()) { From 978089a058b4aa18017b0ba5fd7042b156624ee2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 17 Nov 2021 14:53:48 +0900 Subject: [PATCH 0763/2325] test: fix: move loading helper to setUp() If you run one test method, it fails. --- tests/system/Helpers/FilesystemHelperTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index 25a1cb1680bd..6492cab98708 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -37,11 +37,12 @@ protected function setUp(): void 'simpleFile' => 'A tap-tap-tapping upon my door', '.hidden' => 'There is no spoon', ]; + + helper('filesystem'); } public function testDirectoryMapDefaults() { - helper('filesystem'); $this->assertTrue(function_exists('directory_map')); $expected = [ @@ -65,7 +66,6 @@ public function testDirectoryMapDefaults() public function testDirectoryMapShowsHiddenFiles() { - helper('filesystem'); $this->assertTrue(function_exists('directory_map')); $expected = [ From a4a92edfff280d48a64ded19df56941e59ee906a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 17 Nov 2021 14:54:53 +0900 Subject: [PATCH 0764/2325] test: fix: incorrect function name in assertions --- tests/system/Helpers/FilesystemHelperTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index 6492cab98708..c48ccd1ff328 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -257,7 +257,7 @@ public function testDeleteFilesFailure() public function testGetFilenames() { - $this->assertTrue(function_exists('delete_files')); + $this->assertTrue(function_exists('get_filenames')); // Not sure the directory names should actually show up // here but this matches v3.x results. @@ -279,7 +279,7 @@ public function testGetFilenames() public function testGetFilenamesWithHidden() { - $this->assertTrue(function_exists('delete_files')); + $this->assertTrue(function_exists('get_filenames')); // Not sure the directory names should actually show up // here but this matches v3.x results. From e97b95b2ffc8b11a4a97202cab12d6a839ddca93 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Wed, 17 Nov 2021 00:00:12 -0600 Subject: [PATCH 0765/2325] Fix rector error and cleanup up filename displays for Debug toolbar database tab. --- system/Debug/Toolbar/Collectors/Database.php | 15 ++++++++++----- system/Debug/Toolbar/Views/toolbar.css | 6 +++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index 639ba73be3e0..a3fc7e435d56 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -137,12 +137,17 @@ public function display(): array // Find the first line that doesn't include `system` in the backtrace $line = []; - foreach ($query['trace'] as $traceLine) { - if (strpos($traceLine['file'], 'system/') !== false) { + foreach ($query['trace'] as &$traceLine) { + // Clean up the file paths + $traceLine['file'] = str_ireplace(APPPATH, 'APPPATH/', $traceLine['file']); + $traceLine['file'] = str_ireplace(SYSTEMPATH, 'SYSTEMPATH/', $traceLine['file']); + $traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']); + $traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']); + + if (strpos($traceLine['file'], 'APPPATH') === false) { continue; } - $line = $traceLine; - break; + $line = empty($line) ? $traceLine : $line; } return [ @@ -153,7 +158,7 @@ public function display(): array 'trace' => $query['trace'], 'trace-file' => str_replace(ROOTPATH, '/', $line['file'] ?? ''), 'trace-line' => $line['line'] ?? '', - 'qid' => md5((string) $query['query'] . microtime()), + 'qid' => md5($query['query'] . microtime()), ]; }, static::$queries); diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 50ec4bff9e28..ed4230be0988 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -498,7 +498,7 @@ #toolbarContainer.dark #debug-bar .muted { color: #DFDFDF; } #toolbarContainer.dark #debug-bar .muted td { - color: #434343; } + color: #797979; } #toolbarContainer.dark #debug-bar .muted:hover td { color: #DFDFDF; } #toolbarContainer.dark #debug-bar #toolbar-position, @@ -589,9 +589,9 @@ -moz-box-shadow: 0 1px 4px #DFDFDF; -webkit-box-shadow: 0 1px 4px #DFDFDF; } #toolbarContainer.light #debug-bar .muted { - color: #434343; } + color: #797979; } #toolbarContainer.light #debug-bar .muted td { - color: #DFDFDF; } + color: #797979; } #toolbarContainer.light #debug-bar .muted:hover td { color: #434343; } #toolbarContainer.light #debug-bar #toolbar-position, From ccc4a5e8f45072de35b07da9e639f6f120880532 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Wed, 17 Nov 2021 00:02:22 -0600 Subject: [PATCH 0766/2325] Added note to changelog --- system/Debug/Toolbar/Collectors/Database.php | 2 +- user_guide_src/source/changelogs/v4.1.6.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index a3fc7e435d56..db13e14e920e 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -144,7 +144,7 @@ public function display(): array $traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']); $traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']); - if (strpos($traceLine['file'], 'APPPATH') === false) { + if (strpos($traceLine['file'], 'SYSTEMPATH') !== false) { continue; } $line = empty($line) ? $traceLine : $line; diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 80800ecbc94b..093ea6ca8aec 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -14,6 +14,7 @@ BREAKING Enhancements ============ +- Database pane on debug toolbar now displays location where Query was called from. Also displays full backtrace. Changes ======= From 328aa7670c7636db5775f88a6f39d374d098bf6f Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 08:48:44 +0900 Subject: [PATCH 0767/2325] chore: add seach example in Issue Form --- .github/ISSUE_TEMPLATE/bug_report.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 2c28200c36aa..cadb186f71ac 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -13,6 +13,9 @@ body: whether still open or closed, related to your report**. If there is, your report will be closed promptly. + For example, if you get the error "*Undefined property: Config\\Exceptions::$sensitiveDataInTrace*", + you can search the GitHub repository with the keyword "[$sensitiveDataInTrace](https://github.com/codeigniter4/CodeIgniter4/search?q=%24sensitiveDataInTrace&type=issues)". + --- - type: dropdown From e8db9099c65e0ac8cf81f81730a54d10a00ee8ad Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 08:49:31 +0900 Subject: [PATCH 0768/2325] chore: add codeigniter-installation in Issue Form --- .github/ISSUE_TEMPLATE/bug_report.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index cadb186f71ac..9dc91d2cc42a 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -43,6 +43,19 @@ body: validations: required: true + - type: dropdown + id: codeigniter-installation + attributes: + label: CodeIgniter4 Installation + multiple: false + options: + - Composer; appstarter + - Composer; Adding CI4 to an Existing Project + - Manual (zip or tar.gz) + - Git + validations: + required: true + - type: dropdown id: operating-systems attributes: From 431546710ee21b8c409c78a48d9fe54b4f3da3b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 09:35:32 +0900 Subject: [PATCH 0769/2325] docs: add @TODO See #5344 --- system/HTTP/IncomingRequest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 128d6ee1c432..3ac25b6df5fd 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -64,6 +64,8 @@ class IncomingRequest extends Request * AFTER the script name. So, if hosted in a sub-folder this will * appear different than actual URL. If you need that use getPath(). * + * @TODO should be protected. Use getUri() instead. + * * @var URI */ public $uri; From 05ce6cb92a6822177a50f479620c6dd276c15ce7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 09:36:14 +0900 Subject: [PATCH 0770/2325] docs: don't use $request->uri See #5344 --- user_guide_src/source/concepts/http.rst | 2 +- user_guide_src/source/incoming/incomingrequest.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/concepts/http.rst b/user_guide_src/source/concepts/http.rst index 2696c91223d3..8ae030fc1811 100644 --- a/user_guide_src/source/concepts/http.rst +++ b/user_guide_src/source/concepts/http.rst @@ -75,7 +75,7 @@ is an object-oriented representation of the HTTP request. It provides everything $request = service('request'); // the URI being requested (i.e., /about) - $request->uri->getPath(); + $request->getUri()->getPath(); // Retrieve $_GET and $_POST variables $request->getGet('foo'); diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index e9f494961233..d08bf8470f70 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -249,13 +249,13 @@ The Request URL --------------- You can retrieve a :doc:`URI ` object that represents the current URI for this request through the -``$request->uri`` property. You can cast this object as a string to get a full URL for the current request:: +``$request->getUri()`` method. You can cast this object as a string to get a full URL for the current request:: - $uri = (string)$request->uri; + $uri = (string) $request->getUri(); The object gives you full abilities to grab any part of the request on it's own:: - $uri = $request->uri; + $uri = $request->getUri(); echo $uri->getScheme(); // http echo $uri->getAuthority(); // snoopy:password@example.com:88 From 19454015570810287529b88ef2dcf73ab2409e77 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 10:00:25 +0900 Subject: [PATCH 0771/2325] refactor: replace $request->uri with $request->getUri() See #5344 --- app/Views/errors/html/error_exception.php | 2 +- system/Common.php | 6 +++--- tests/system/HTTP/IncomingRequestTest.php | 2 +- tests/system/HTTP/URITest.php | 14 +++++++------- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 4477ee08ff8b..693afed491f5 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -195,7 +195,7 @@
    - + diff --git a/system/Common.php b/system/Common.php index 7c150a01c1d4..32943189b56b 100644 --- a/system/Common.php +++ b/system/Common.php @@ -480,9 +480,9 @@ function force_https(int $duration = 31536000, ?RequestInterface $request = null $uri = URI::createURIString( 'https', $baseURL, - $request->uri->getPath(), // Absolute URIs should use a "/" for an empty path - $request->uri->getQuery(), - $request->uri->getFragment() + $request->getUri()->getPath(), // Absolute URIs should use a "/" for an empty path + $request->getUri()->getQuery(), + $request->getUri()->getFragment() ); // Set an HSTS header diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index b467c9ca3e1a..3b14c6a03357 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -650,6 +650,6 @@ public function testSetPathUpdatesURI() $request->setPath('apples'); - $this->assertSame('apples', $request->uri->getPath()); + $this->assertSame('apples', $request->getUri()->getPath()); } } diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index acd491bccb9d..0438505aea2e 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -876,14 +876,14 @@ public function testBasedNoIndex() // going through request $this->assertSame('http://example.com/ci/v4/controller/method', (string) $request->uri); - $this->assertSame('/ci/v4/controller/method', $request->uri->getPath()); + $this->assertSame('/ci/v4/controller/method', $request->getUri()->getPath()); // standalone $uri = new URI('http://example.com/ci/v4/controller/method'); $this->assertSame('http://example.com/ci/v4/controller/method', (string) $uri); $this->assertSame('/ci/v4/controller/method', $uri->getPath()); - $this->assertSame($uri->getPath(), $request->uri->getPath()); + $this->assertSame($uri->getPath(), $request->getUri()->getPath()); } public function testBasedWithIndex() @@ -902,15 +902,15 @@ public function testBasedWithIndex() Services::injectMock('request', $request); // going through request - $this->assertSame('http://example.com/ci/v4/index.php/controller/method', (string) $request->uri); - $this->assertSame('/ci/v4/index.php/controller/method', $request->uri->getPath()); + $this->assertSame('http://example.com/ci/v4/index.php/controller/method', (string) $request->getUri()); + $this->assertSame('/ci/v4/index.php/controller/method', $request->getUri()->getPath()); // standalone $uri = new URI('http://example.com/ci/v4/index.php/controller/method'); $this->assertSame('http://example.com/ci/v4/index.php/controller/method', (string) $uri); $this->assertSame('/ci/v4/index.php/controller/method', $uri->getPath()); - $this->assertSame($uri->getPath(), $request->uri->getPath()); + $this->assertSame($uri->getPath(), $request->getUri()->getPath()); } public function testForceGlobalSecureRequests() @@ -933,13 +933,13 @@ public function testForceGlobalSecureRequests() Services::injectMock('request', $request); // Detected by request - $this->assertSame('https://example.com/ci/v4/controller/method', (string) $request->uri); + $this->assertSame('https://example.com/ci/v4/controller/method', (string) $request->getUri()); // Standalone $uri = new URI('http://example.com/ci/v4/controller/method'); $this->assertSame('https://example.com/ci/v4/controller/method', (string) $uri); - $this->assertSame(trim($uri->getPath(), '/'), trim($request->uri->getPath(), '/')); + $this->assertSame(trim($uri->getPath(), '/'), trim($request->getUri()->getPath(), '/')); } public function testZeroAsURIPath() From f4eed93bb01bf64b733c0d9afbae75be0592cf76 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 11:46:42 +0900 Subject: [PATCH 0772/2325] docs: remove /docs, because no such directory --- user_guide_src/source/concepts/structure.rst | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/concepts/structure.rst b/user_guide_src/source/concepts/structure.rst index 14bb3a59304b..b55a3eac9ff1 100644 --- a/user_guide_src/source/concepts/structure.rst +++ b/user_guide_src/source/concepts/structure.rst @@ -8,8 +8,8 @@ can change to meet the needs of your application. Default Directories =================== -A fresh install has six directories: ``/app``, ``/system``, ``/public``, -``/writable``, ``/tests`` and possibly ``/docs``. +A fresh install has five directories: ``/app``, ``/public``, +``/writable``, ``/tests`` and ``/system`` or ``/vendor``. Each of these directories has a very specific part to play. app @@ -75,11 +75,6 @@ This directory is set up to hold your test files. The ``_support`` directory hol utilities that you can use while writing your tests. This directory does not need to be transferred to your production servers. -docs ----- -If this directory is part of your project, it holds a local copy of the CodeIgniter4 -User Guide. - Modifying Directory Locations ----------------------------- From ee08712be5b78f8ce0961b1615088821e2a9e7f8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 11:47:26 +0900 Subject: [PATCH 0773/2325] docs: add note when composer installation --- user_guide_src/source/concepts/structure.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/concepts/structure.rst b/user_guide_src/source/concepts/structure.rst index b55a3eac9ff1..5c94b8542758 100644 --- a/user_guide_src/source/concepts/structure.rst +++ b/user_guide_src/source/concepts/structure.rst @@ -44,6 +44,9 @@ All files in this directory live under the ``App`` namespace, though you are fre system ------ + +.. note:: If you install CodeIgniter with Composer, the ``system`` is located in ``vendor/codeigniter4/framework/system``. + This directory stores the files that make up the framework, itself. While you have a lot of flexibility in how you use the application directory, the files in the system directory should never be modified. Instead, you should extend the classes, or create new classes, to provide the desired functionality. From 73371c46ac43828703c8d990d4a79656ed2c6f6c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 11:55:47 +0900 Subject: [PATCH 0774/2325] docs: update sample code It is recommended to use BaseController instead of Controller. --- user_guide_src/source/tutorial/static_pages.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index d6874bc9fbe9..1763d1fae624 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -39,9 +39,7 @@ code. namespace App\Controllers; - use CodeIgniter\Controller; - - class Pages extends Controller + class Pages extends BaseController { public function index() { @@ -66,7 +64,7 @@ displays the CodeIgniter welcome page. Both are *technically* a function. But when you create a function in a class, it's called a method. -The ``Pages`` class is extending the +The ``Pages`` class is extending the ``BaseController`` class that extends the ``CodeIgniter\Controller`` class. This means that the new Pages class can access the methods and variables defined in the ``CodeIgniter\Controller`` class (**system/Controller.php**). From c0fedce2429ff332316f330c4c89bf8710cbe35b Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 11:56:45 +0900 Subject: [PATCH 0775/2325] docs: add CSRF error display in sample code --- .../source/tutorial/create_news_items.rst | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index b4506b4dc322..604c2373314e 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -33,6 +33,7 @@ the slug from our title in the model. Create a new view at

    + getFlashdata('error') ?> listErrors() ?>
    @@ -47,10 +48,15 @@ the slug from our title in the model. Create a new view at -There are probably only two things here that look unfamiliar. The -``service('validation')->listErrors()`` function is used to report -errors related to form validation. The ``csrf_field()`` function creates -a hidden input with a CSRF token that helps protect against some common attacks. +There are probably only three things here that look unfamiliar. + +The ``getFlashdata('error') ?>`` function is used to report +errors related to CSRF protection. + +The ``service('validation')->listErrors()`` function is used to report +errors related to form validation. + +The ``csrf_field()`` function creates a hidden input with a CSRF token that helps protect against some common attacks. Go back to your ``News`` controller. You're going to do two things here, check whether the form was submitted and whether the submitted data From 88c4968fb3147cd33613d7cafaa31084e2d9a907 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 13:20:08 +0900 Subject: [PATCH 0776/2325] chore: fix script to copy tests directory --- .github/scripts/deploy-framework | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/scripts/deploy-framework b/.github/scripts/deploy-framework index c3f7e39fa1b7..9396ed88aa04 100644 --- a/.github/scripts/deploy-framework +++ b/.github/scripts/deploy-framework @@ -28,6 +28,8 @@ done # Copy repo-specific files cp -Rf ${SOURCE}/admin/framework/. ./ +# Copy tests files +cp -Rf ${SOURCE}/admin/starter/tests/. ./tests/ # Commit the changes git add . From d5c90f1668eafc4baa857f304668458526ec6c78 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 17:20:57 +0900 Subject: [PATCH 0777/2325] docs: make view filename lowercase Capital letters can also be used, but they are often lowercased. --- user_guide_src/source/outgoing/views.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 19121c98b86a..4f865f6aaecb 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -19,7 +19,7 @@ Using the example controller you created in the controller page, let’s add a v Creating a View =============== -Using your text editor, create a file called ``BlogView.php`` and put this in it:: +Using your text editor, create a file called ``blogview.php`` and put this in it:: @@ -53,7 +53,7 @@ Now, open the controller file you made earlier called ``Blog.php``, and replace { public function index() { - echo view('BlogView'); + echo view('blogview'); } } @@ -111,7 +111,7 @@ If you have ``Blog`` directory that has a PSR-4 mapping set up in the :doc:`Auto under the namespace ``Example\Blog``, you could retrieve view files as if they were namespaced also. Following this example, you could load the **BlogView** file from **/blog/views** by prepending the namespace to the view name:: - echo view('Example\Blog\Views\BlogView'); + echo view('Example\Blog\Views\blogview'); Caching Views ============= From 05ce8a5142dc3f4ecb72427eeedc5c5959f75e22 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 17:23:39 +0900 Subject: [PATCH 0778/2325] docs: fix directory name Saying that "If you have ``Blog`` directory", the directory name must be Blog, not blog. --- user_guide_src/source/outgoing/views.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 4f865f6aaecb..b01466ce40da 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -109,7 +109,7 @@ to package your views together in a module-like fashion for easy re-use or distr If you have ``Blog`` directory that has a PSR-4 mapping set up in the :doc:`Autoloader ` living under the namespace ``Example\Blog``, you could retrieve view files as if they were namespaced also. Following this -example, you could load the **BlogView** file from **/blog/views** by prepending the namespace to the view name:: +example, you could load the **blogview.php** file from **Blog/Views** by prepending the namespace to the view name:: echo view('Example\Blog\Views\blogview'); From 5a3ba8012e09c060ca595b0c705e2229d722d426 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 17:29:12 +0900 Subject: [PATCH 0779/2325] docs: fix incorrect method name --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 5dade8d13f3d..9778307bc4fa 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -330,7 +330,7 @@ Command-Line only Routes You can create routes that work only from the command-line, and are inaccessible from the web browser, with the ``cli()`` method. This is great for building cronjobs or CLI-only tools. Any route created by any of the HTTP-verb-based -route methods will also be inaccessible from the CLI, but routes created by the ``any()`` method will still be +route methods will also be inaccessible from the CLI, but routes created by the ``add()`` method will still be available from the command line:: $routes->cli('migrate', 'App\Database::migrate'); From b4da1c1629350bf04bd8e5eefe78a97908b3c35f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 19 Nov 2021 13:53:30 +0900 Subject: [PATCH 0780/2325] chore: fix by review Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index 9dc91d2cc42a..cbc27bc81a22 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -46,7 +46,7 @@ body: - type: dropdown id: codeigniter-installation attributes: - label: CodeIgniter4 Installation + label: CodeIgniter4 Installation Method multiple: false options: - Composer; appstarter From b31256fc03bccd8d0bfb8c43f40d9745c56e7bbd Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 19 Nov 2021 13:53:38 +0900 Subject: [PATCH 0781/2325] chore: fix by review Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- .github/ISSUE_TEMPLATE/bug_report.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index cbc27bc81a22..975c611a61c3 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -49,8 +49,8 @@ body: label: CodeIgniter4 Installation Method multiple: false options: - - Composer; appstarter - - Composer; Adding CI4 to an Existing Project + - Composer (using `codeigniter4/appstarter`) + - Composer (as dependency to an existing project) - Manual (zip or tar.gz) - Git validations: From 27d216b62db26246fa08eb686347b11670dd9c77 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 10 Nov 2021 11:22:36 +0900 Subject: [PATCH 0782/2325] fix: UploadedFile::hasMoved() may return incorrect value --- system/HTTP/Files/UploadedFile.php | 13 ++++-- tests/system/HTTP/Files/FileMovingTest.php | 52 +++++++++++++++++++++- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 6455a5106d8d..42bb9891f90b 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -141,7 +141,7 @@ public function move(string $targetPath, ?string $name = null, bool $overwrite = $destination = $overwrite ? $targetPath . $name : $this->getDestination($targetPath . $name); try { - move_uploaded_file($this->path, $destination); + $this->hasMoved = move_uploaded_file($this->path, $destination); } catch (Exception $e) { $error = error_get_last(); $message = isset($error['message']) ? strip_tags($error['message']) : ''; @@ -149,12 +149,17 @@ public function move(string $targetPath, ?string $name = null, bool $overwrite = throw HTTPException::forMoveFailed(basename($this->path), $targetPath, $message); } + if ($this->hasMoved === false) { + $message = 'move_uploaded_file() returned false'; + + throw HTTPException::forMoveFailed(basename($this->path), $targetPath, $message); + } + @chmod($targetPath, 0777 & ~umask()); // Success, so store our new information - $this->path = $targetPath; - $this->name = basename($destination); - $this->hasMoved = true; + $this->path = $targetPath; + $this->name = basename($destination); return true; } diff --git a/tests/system/HTTP/Files/FileMovingTest.php b/tests/system/HTTP/Files/FileMovingTest.php index 9797ca46c301..c9234a82dc6b 100644 --- a/tests/system/HTTP/Files/FileMovingTest.php +++ b/tests/system/HTTP/Files/FileMovingTest.php @@ -35,6 +35,9 @@ protected function setUp(): void } $_FILES = []; + + // Set the mock's return value to true + move_uploaded_file('', '', true); } protected function tearDown(): void @@ -262,7 +265,7 @@ public function testInvalidFile() $file->move($destination, $file->getName(), false); } - public function testFailedMove() + public function testFailedMoveBecauseOfWarning() { $_FILES = [ 'userfile' => [ @@ -287,6 +290,41 @@ public function testFailedMove() $this->expectException(HTTPException::class); $file->move($destination, $file->getName(), false); } + + public function testFailedMoveBecauseOfFalseReturned() + { + $finalFilename = 'fileA'; + + $_FILES = [ + 'userfile1' => [ + 'name' => $finalFilename . '.txt', + 'type' => 'text/plain', + 'size' => 124, + 'tmp_name' => '/tmp/fileA.txt', + 'error' => 0, + ], + ]; + + $collection = new FileCollection(); + + $this->assertTrue($collection->hasFile('userfile1')); + + $destination = $this->destination; + + // Create the destination if not exists + if (! is_dir($destination)) { + mkdir($destination, 0777, true); + } + + $file = $collection->getFile('userfile1'); + + // Set the mock's return value to false + move_uploaded_file('', '', false); + + $this->expectException(HTTPException::class); + + $file->move($destination, $file->getName(), false); + } } /* @@ -311,10 +349,20 @@ function is_uploaded_file($filename) * This overwrite is for testing the move operation. */ -function move_uploaded_file($filename, $destination) +function move_uploaded_file($filename, $destination, ?bool $setReturnValue = null) { + static $return = true; + + if ($setReturnValue !== null) { + $return = $setReturnValue; + + return true; + } + copy($filename, $destination); unlink($filename); + + return $return; } function rrmdir($src) From 2425b291c333c1265ce4a44c5206bb8419c028d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 20 Nov 2021 11:47:15 +0900 Subject: [PATCH 0783/2325] docs: fix incorrect namespace in sample code --- user_guide_src/source/general/helpers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/helpers.rst b/user_guide_src/source/general/helpers.rst index 65d63d942631..51deea953590 100644 --- a/user_guide_src/source/general/helpers.rst +++ b/user_guide_src/source/general/helpers.rst @@ -78,7 +78,7 @@ code into its own namespace, ``Example\Blog``. The files exist on our server at **/Modules/Blog/Helpers/blog_helper.php**. Within our controller we could use the following command to load the helper for us:: - helper('Modules\Blog\blog'); + helper('Example\Blog\blog'); .. note:: The functions within files loaded this way are not truly namespaced. The namespace is simply used as a convenient way to locate the files. From 843ddb96846029c8814c121e5ae5de6394584368 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 20 Nov 2021 13:13:38 +0900 Subject: [PATCH 0784/2325] test: add test for table alias and table prefix --- tests/system/Database/Builder/AliasTest.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/system/Database/Builder/AliasTest.php b/tests/system/Database/Builder/AliasTest.php index b6789d987708..d6d2c8618741 100644 --- a/tests/system/Database/Builder/AliasTest.php +++ b/tests/system/Database/Builder/AliasTest.php @@ -84,4 +84,20 @@ public function testAliasLeftJoinWithLongTableName() $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5360 + */ + public function testAliasSimpleLikeWithDBPrefix() + { + $this->setPrivateProperty($this->db, 'DBPrefix', 'db_'); + $builder = $this->db->table('jobs j'); + + $builder->like('j.name', 'veloper'); + + $expectedSQL = <<<'SQL' + SELECT * FROM "db_jobs" "j" WHERE "j"."name" LIKE '%veloper%' ESCAPE '!' + SQL; + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + } } From 20411e61851493f210db2877ede2603f8000f467 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 20 Nov 2021 15:20:02 +0900 Subject: [PATCH 0785/2325] fix: if condition where the first segment is one of the aliases previously identified Fixes #5360 --- system/Database/BaseConnection.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index ebb63b7f5827..c7f4e124d507 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1012,7 +1012,8 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro // // NOTE: The ! empty() condition prevents this method // from breaking when QB isn't enabled. - if (! empty($this->aliasedTables) && in_array($parts[0], $this->aliasedTables, true)) { + $firstSegment = trim($parts[0], $this->escapeChar); + if (! empty($this->aliasedTables) && in_array($firstSegment, $this->aliasedTables, true)) { if ($protectIdentifiers === true) { foreach ($parts as $key => $val) { if (! in_array($val, $this->reservedIdentifiers, true)) { From 7f0e921dfe32a42b38c1b2490a624b50d1a3d0ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 2 Nov 2021 16:28:18 +0900 Subject: [PATCH 0786/2325] fix: Query builder escapes negative integers Fixes #4973 --- system/Database/BaseConnection.php | 2 +- tests/system/Database/BaseQueryTest.php | 18 ++++++++++++++++++ tests/system/Database/Live/EscapeTest.php | 2 +- 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index ebb63b7f5827..6279e822a10c 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1201,7 +1201,7 @@ public function escape($str) } if (is_numeric($str) && $str < 0) { - return "'{$str}'"; + return "{$str}"; } return $str ?? 'NULL'; diff --git a/tests/system/Database/BaseQueryTest.php b/tests/system/Database/BaseQueryTest.php index fe942ffeb187..a279e01dd444 100644 --- a/tests/system/Database/BaseQueryTest.php +++ b/tests/system/Database/BaseQueryTest.php @@ -345,6 +345,24 @@ public function testSetQueryBindsWithSetEscapeFalse() $this->assertSame($expected, $query->getQuery()); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4973 + */ + public function testSetQueryBindsWithSetEscapeNegativeIntegers() + { + $query = new Query($this->db); + + $query->setQuery( + 'SELECT * FROM product WHERE date_pickup < DateAdd(month, ?, Convert(date, GetDate())', + [-6], + true + ); + + $expected = 'SELECT * FROM product WHERE date_pickup < DateAdd(month, -6, Convert(date, GetDate())'; + + $this->assertSame($expected, $query->getQuery()); + } + /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/2762 */ diff --git a/tests/system/Database/Live/EscapeTest.php b/tests/system/Database/Live/EscapeTest.php index 08265788d00e..9099115e45d0 100644 --- a/tests/system/Database/Live/EscapeTest.php +++ b/tests/system/Database/Live/EscapeTest.php @@ -40,7 +40,7 @@ protected function setUp(): void */ public function testEscapeProtectsNegativeNumbers() { - $this->assertSame("'-100'", $this->db->escape(-100)); + $this->assertSame('-100', $this->db->escape(-100)); } public function testEscape() From 034b1332a09ab876f8922b62e57c122ccf89ba53 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 2 Nov 2021 16:29:07 +0900 Subject: [PATCH 0787/2325] docs: add PHPDoc --- system/Database/BaseConnection.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 6279e822a10c..6902490dea1c 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -565,7 +565,7 @@ abstract protected function execute(string $sql); * * @param mixed ...$binds * - * @return BaseResult|bool|Query + * @return BaseResult|bool|Query BaseResult when “read” type query, bool when “write” type query, Query when prepared query * * @todo BC set $queryClass default as null in 4.1 */ @@ -955,6 +955,8 @@ public function getConnectDuration(int $decimals = 6): string * the correct identifiers. * * @param array|string $item + * @param bool $prefixSingle Prefix an item with no segments? + * @param bool $fieldExists Supplied $item contains a field name? * * @return array|string */ From 69e79fbe8be7eb1d4a371d051a2d5cfa2575d81b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 2 Nov 2021 19:50:34 +0900 Subject: [PATCH 0788/2325] fix: remove escaping code for negative integer It is inconsistent, with negative numbers we get a string. For positive, we get numbers. --- system/Database/BaseConnection.php | 4 ---- tests/system/Database/BaseQueryTest.php | 14 ++++++++++++++ tests/system/Database/Live/EscapeTest.php | 2 +- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 6902490dea1c..44654e4423a0 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1202,10 +1202,6 @@ public function escape($str) return ($str === false) ? 0 : 1; } - if (is_numeric($str) && $str < 0) { - return "{$str}"; - } - return $str ?? 'NULL'; } diff --git a/tests/system/Database/BaseQueryTest.php b/tests/system/Database/BaseQueryTest.php index a279e01dd444..d7fe4bca2819 100644 --- a/tests/system/Database/BaseQueryTest.php +++ b/tests/system/Database/BaseQueryTest.php @@ -363,6 +363,20 @@ public function testSetQueryBindsWithSetEscapeNegativeIntegers() $this->assertSame($expected, $query->getQuery()); } + public function testSetQueryNamedBindsWithNegativeIntegers() + { + $query = new Query($this->db); + + $query->setQuery( + 'SELECT * FROM product WHERE date_pickup < DateAdd(month, :num:, Convert(date, GetDate())', + ['num' => -6] + ); + + $expected = 'SELECT * FROM product WHERE date_pickup < DateAdd(month, -6, Convert(date, GetDate())'; + + $this->assertSame($expected, $query->getQuery()); + } + /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/2762 */ diff --git a/tests/system/Database/Live/EscapeTest.php b/tests/system/Database/Live/EscapeTest.php index 9099115e45d0..f0586fd820cb 100644 --- a/tests/system/Database/Live/EscapeTest.php +++ b/tests/system/Database/Live/EscapeTest.php @@ -40,7 +40,7 @@ protected function setUp(): void */ public function testEscapeProtectsNegativeNumbers() { - $this->assertSame('-100', $this->db->escape(-100)); + $this->assertSame(-100, $this->db->escape(-100)); } public function testEscape() From 127b9cf9a373be3eaf10af27cabbde96d00bebf0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 20 Nov 2021 15:41:11 +0900 Subject: [PATCH 0789/2325] test: fix test method name --- tests/system/Database/Live/EscapeTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Database/Live/EscapeTest.php b/tests/system/Database/Live/EscapeTest.php index f0586fd820cb..1260badcee77 100644 --- a/tests/system/Database/Live/EscapeTest.php +++ b/tests/system/Database/Live/EscapeTest.php @@ -38,7 +38,7 @@ protected function setUp(): void * * @see https://github.com/codeigniter4/CodeIgniter4/issues/606 */ - public function testEscapeProtectsNegativeNumbers() + public function testDoesNotEscapeNegativeNumbers() { $this->assertSame(-100, $this->db->escape(-100)); } From 955100eb01c99823d24e1a3e78641f6e338e2616 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 09:52:19 +0900 Subject: [PATCH 0790/2325] refactor: use ?? Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/HTTP/Files/UploadedFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/Files/UploadedFile.php b/system/HTTP/Files/UploadedFile.php index 42bb9891f90b..b9a672921b94 100644 --- a/system/HTTP/Files/UploadedFile.php +++ b/system/HTTP/Files/UploadedFile.php @@ -144,7 +144,7 @@ public function move(string $targetPath, ?string $name = null, bool $overwrite = $this->hasMoved = move_uploaded_file($this->path, $destination); } catch (Exception $e) { $error = error_get_last(); - $message = isset($error['message']) ? strip_tags($error['message']) : ''; + $message = strip_tags($error['message'] ?? ''); throw HTTPException::forMoveFailed(basename($this->path), $targetPath, $message); } From 5bf3492d74fa1ca85b7b5b3b350990915593ba56 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 09:55:24 +0900 Subject: [PATCH 0791/2325] test: add expectExceptionMessage() --- tests/system/HTTP/Files/FileMovingTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/HTTP/Files/FileMovingTest.php b/tests/system/HTTP/Files/FileMovingTest.php index c9234a82dc6b..67be3a5a310e 100644 --- a/tests/system/HTTP/Files/FileMovingTest.php +++ b/tests/system/HTTP/Files/FileMovingTest.php @@ -322,6 +322,7 @@ public function testFailedMoveBecauseOfFalseReturned() move_uploaded_file('', '', false); $this->expectException(HTTPException::class); + $this->expectExceptionMessage('move_uploaded_file() returned false'); $file->move($destination, $file->getName(), false); } From 3a7722c1fd7d1432dcc94d9a4b5a0e0e99ae4646 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 10:08:04 +0900 Subject: [PATCH 0792/2325] test: refactor: remove unneeded variable --- tests/system/HTTP/Files/FileMovingTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/system/HTTP/Files/FileMovingTest.php b/tests/system/HTTP/Files/FileMovingTest.php index 67be3a5a310e..90ba938de396 100644 --- a/tests/system/HTTP/Files/FileMovingTest.php +++ b/tests/system/HTTP/Files/FileMovingTest.php @@ -293,11 +293,9 @@ public function testFailedMoveBecauseOfWarning() public function testFailedMoveBecauseOfFalseReturned() { - $finalFilename = 'fileA'; - $_FILES = [ 'userfile1' => [ - 'name' => $finalFilename . '.txt', + 'name' => 'fileA.txt', 'type' => 'text/plain', 'size' => 124, 'tmp_name' => '/tmp/fileA.txt', From c0a8005a62df48841c9ffdccabbfedea39662a01 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 10:11:51 +0900 Subject: [PATCH 0793/2325] test: refactor: separate arrange, act, assert code --- tests/system/HTTP/Files/FileMovingTest.php | 39 +++++++++------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/tests/system/HTTP/Files/FileMovingTest.php b/tests/system/HTTP/Files/FileMovingTest.php index 90ba938de396..9eac8e51f1e7 100644 --- a/tests/system/HTTP/Files/FileMovingTest.php +++ b/tests/system/HTTP/Files/FileMovingTest.php @@ -55,8 +55,7 @@ protected function tearDown(): void public function testMove() { $finalFilename = 'fileA'; - - $_FILES = [ + $_FILES = [ 'userfile1' => [ 'name' => $finalFilename . '.txt', 'type' => 'text/plain', @@ -79,7 +78,6 @@ public function testMove() $this->assertTrue($collection->hasFile('userfile2')); $destination = $this->destination; - // Create the destination if not exists if (! is_dir($destination)) { mkdir($destination, 0777, true); @@ -97,8 +95,7 @@ public function testMove() public function testMoveOverwriting() { $finalFilename = 'file_with_delimiters_underscore'; - - $_FILES = [ + $_FILES = [ 'userfile1' => [ 'name' => $finalFilename . '.txt', 'type' => 'text/plain', @@ -129,7 +126,6 @@ public function testMoveOverwriting() $this->assertTrue($collection->hasFile('userfile3')); $destination = $this->destination; - // Create the destination if not exists if (! is_dir($destination)) { mkdir($destination, 0777, true); @@ -149,8 +145,7 @@ public function testMoveOverwriting() public function testMoved() { $finalFilename = 'fileA'; - - $_FILES = [ + $_FILES = [ 'userfile1' => [ 'name' => $finalFilename . '.txt', 'type' => 'text/plain', @@ -165,7 +160,6 @@ public function testMoved() $this->assertTrue($collection->hasFile('userfile1')); $destination = $this->destination; - // Create the destination if not exists if (! is_dir($destination)) { mkdir($destination, 0777, true); @@ -175,15 +169,16 @@ public function testMoved() $this->assertInstanceOf(UploadedFile::class, $file); $this->assertFalse($file->hasMoved()); + $file->move($destination, $file->getName(), false); + $this->assertTrue($file->hasMoved()); } public function testStore() { $finalFilename = 'fileA'; - - $_FILES = [ + $_FILES = [ 'userfile1' => [ 'name' => $finalFilename . '.txt', 'type' => 'text/plain', @@ -198,7 +193,6 @@ public function testStore() $this->assertTrue($collection->hasFile('userfile1')); $destination = $this->destination; - // Create the destination if not exists if (! is_dir($destination)) { mkdir($destination, 0777, true); @@ -207,15 +201,16 @@ public function testStore() $file = $collection->getFile('userfile1'); $this->assertInstanceOf(UploadedFile::class, $file); + $path = $file->store($destination, $file->getName()); + $this->assertSame($destination . '/fileA.txt', $path); } public function testAlreadyMoved() { $finalFilename = 'fileA'; - - $_FILES = [ + $_FILES = [ 'userfile1' => [ 'name' => $finalFilename . '.txt', 'type' => 'text/plain', @@ -230,7 +225,6 @@ public function testAlreadyMoved() $this->assertTrue($collection->hasFile('userfile1')); $destination = $this->destination; - // Create the destination if not exists if (! is_dir($destination)) { mkdir($destination, 0777, true); @@ -257,11 +251,11 @@ public function testInvalidFile() ]; $destination = $this->destination; - - $collection = new FileCollection(); - $file = $collection->getFile('userfile'); + $collection = new FileCollection(); $this->expectException(HTTPException::class); + + $file = $collection->getFile('userfile'); $file->move($destination, $file->getName(), false); } @@ -278,16 +272,16 @@ public function testFailedMoveBecauseOfWarning() ]; $destination = $this->destination; - // Create the destination and make it read only if (! is_dir($destination)) { mkdir($destination, 0400, true); } $collection = new FileCollection(); - $file = $collection->getFile('userfile'); $this->expectException(HTTPException::class); + + $file = $collection->getFile('userfile'); $file->move($destination, $file->getName(), false); } @@ -308,20 +302,17 @@ public function testFailedMoveBecauseOfFalseReturned() $this->assertTrue($collection->hasFile('userfile1')); $destination = $this->destination; - // Create the destination if not exists if (! is_dir($destination)) { mkdir($destination, 0777, true); } - - $file = $collection->getFile('userfile1'); - // Set the mock's return value to false move_uploaded_file('', '', false); $this->expectException(HTTPException::class); $this->expectExceptionMessage('move_uploaded_file() returned false'); + $file = $collection->getFile('userfile1'); $file->move($destination, $file->getName(), false); } } From ae6db974ba58d54b895847e6be4574d2686a3d86 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 10:37:18 +0900 Subject: [PATCH 0794/2325] docs: add about config() preferApp and Registrars --- user_guide_src/source/general/modules.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 91ec5554c955..150ddcfe3f60 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -191,6 +191,11 @@ with the ``new`` command:: Config files are automatically discovered whenever using the **config()** function that is always available. +.. note:: **config()** finds the file in **app/Config/** when there is a class with the same shortname, + even if you specify a full qualified class name like ``config(\Acme\Blog\Config\Blog::class)``. + +.. note:: Modules that need to override or add to known configurations in **app/Config/** should use :ref:`registrars`. + Migrations ========== From 525e2d95fa3e2991ab1cafade96822944b05caaa Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 11:17:01 +0900 Subject: [PATCH 0795/2325] docs: fix page links Do not use link like "`Feature Testing tools `_". --- user_guide_src/source/concepts/security.rst | 8 ++++---- user_guide_src/source/concepts/structure.rst | 2 +- user_guide_src/source/incoming/routing.rst | 10 ++++++---- user_guide_src/source/installation/upgrade_415.rst | 2 +- user_guide_src/source/libraries/curlrequest.rst | 2 ++ user_guide_src/source/testing/controllers.rst | 4 ++-- user_guide_src/source/testing/feature.rst | 2 +- user_guide_src/source/testing/overview.rst | 2 +- user_guide_src/source/testing/response.rst | 2 +- 9 files changed, 19 insertions(+), 15 deletions(-) diff --git a/user_guide_src/source/concepts/security.rst b/user_guide_src/source/concepts/security.rst index 63581c9510dd..9bca73026eba 100644 --- a/user_guide_src/source/concepts/security.rst +++ b/user_guide_src/source/concepts/security.rst @@ -34,7 +34,7 @@ OWASP recommendations CodeIgniter provisions ---------------------- -- `HTTP library <../incoming/incomingrequest.html>`_ provides for input field filtering & content metadata +- :doc:`HTTP library <../incoming/incomingrequest>` provides for input field filtering & content metadata - Form validation library ********************************************* @@ -56,7 +56,7 @@ OWASP recommendations CodeIgniter provisions ---------------------- -- `Session <../libraries/sessions.html>`_ library +- :doc:`Session <../libraries/sessions>` library - :doc:`Security ` library provides for CSRF validation - Easy to add third party authentication @@ -217,5 +217,5 @@ OWASP recommendations CodeIgniter provisions ---------------------- -- `HTTP library <../incoming/incomingrequest.html>`_ provides for ... -- `Session <../libraries/sessions.html>`_ library provides flashdata +- :doc:`HTTP library <../incoming/incomingrequest>` provides for ... +- :doc:`Session <../libraries/sessions>` library provides flashdata diff --git a/user_guide_src/source/concepts/structure.rst b/user_guide_src/source/concepts/structure.rst index 5c94b8542758..561cbb28f97d 100644 --- a/user_guide_src/source/concepts/structure.rst +++ b/user_guide_src/source/concepts/structure.rst @@ -84,4 +84,4 @@ Modifying Directory Locations If you've relocated any of the main directories, you can change the configuration settings inside **app/Config/Paths.php**. -Please read `Managing your Applications <../general/managing_apps.html>`_ +Please read :doc:`Managing your Applications <../general/managing_apps>`. diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 9778307bc4fa..5f18fb4960d8 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -228,7 +228,7 @@ extensive set of routes that all share the opening string, like when building an This would prefix the 'users' and 'blog" URIs with "admin", handling URLs like ``/admin/users`` and ``/admin/blog``. -If you need to assign options to a group, like a `namespace <#assigning-namespace>`_, do it before the callback:: +If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback:: $routes->group('api', ['namespace' => 'App\API\v1'], function ($routes) { $routes->resource('users'); @@ -236,7 +236,7 @@ If you need to assign options to a group, like a `namespace <#assigning-namespac This would handle a resource route to the ``App\API\v1\Users`` controller with the ``/api/users`` URI. -You can also use a specific `filter `_ for a group of routes. This will always +You can also use a specific :doc:`filter ` for a group of routes. This will always run the filter before or after the controller. This is especially handy during authentication or api logging:: $routes->group('api', ['filter' => 'api-auth'], function ($routes) { @@ -338,7 +338,7 @@ available from the command line:: Global Options ============== -All of the methods for creating a route (add, get, post, `resource `_ etc) can take an array of options that +All of the methods for creating a route (add, get, post, :doc:`resource ` etc) can take an array of options that can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter:: $routes->add('from', 'to', $options); @@ -363,7 +363,7 @@ The value for the filter can be a string or an array of strings: * matching the aliases defined in **app/Config/Filters.php**. * filter classnames -See `Controller filters `_ for more information on setting up filters. +See :doc:`Controller filters ` for more information on setting up filters. .. Warning:: If you set filters to routes in **app/Config/Routes.php** (not in **app/Config/Filters.php**), it is recommended to disable auto-routing. @@ -396,6 +396,8 @@ You specify an array for the filter value:: $routes->add('admin',' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); +.. _assigning-namespace: + Assigning Namespace ------------------- diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst index 3f7c7226ea0b..c7b885efa40a 100644 --- a/user_guide_src/source/installation/upgrade_415.rst +++ b/user_guide_src/source/installation/upgrade_415.rst @@ -59,7 +59,7 @@ CURLRequest header change In the previous version, if you didn't provide your own headers, ``CURLRequest`` would send the request-headers from the browser. The bug was fixed. If your requests depend on the headers, your requests might fail after upgrading. In this case, add the necessary headers manually. -See `CURLRequest Class <../libraries/curlrequest.html#headers>`_ for how to add. +See :ref:`CURLRequest Class ` for how to add. Query Builder changes --------------------- diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index 0074523d79fd..e7163133d5bc 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -299,6 +299,8 @@ if it's not already set:: Use ``form_params`` for ``application/x-www-form-urlencoded`` request, and ``multipart`` for ``multipart/form-data`` requests. +.. _curlrequest-request-options-headers: + headers ======= diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst index 1f16cd615fc2..d5dd2d379b8b 100644 --- a/user_guide_src/source/testing/controllers.rst +++ b/user_guide_src/source/testing/controllers.rst @@ -4,7 +4,7 @@ Testing Controllers Testing your controllers is made convenient with a couple of new helper classes and traits. When testing controllers, you can execute the code within a controller, without first running through the entire application bootstrap process. -Often times, using the `Feature Testing tools `_ will be simpler, but this functionality is here in +Often times, using the :doc:`Feature Testing tools ` will be simpler, but this functionality is here in case you need it. .. note:: Because the entire framework has not been bootstrapped, there will be times when you cannot test a controller @@ -161,7 +161,7 @@ you need to set a JSON value as the body. The only parameter is a string that re Checking the Response ===================== -``ControllerTestTrait::execute()`` returns an instance of a ``TestResponse``. See `Testing Responses `_ on +``ControllerTestTrait::execute()`` returns an instance of a ``TestResponse``. See :doc:`Testing Responses ` on how to use this class to perform additional assertions and verification in your test cases. Filter Testing diff --git a/user_guide_src/source/testing/feature.rst b/user_guide_src/source/testing/feature.rst index 79d0b9d51c76..2a9eb96a348a 100644 --- a/user_guide_src/source/testing/feature.rst +++ b/user_guide_src/source/testing/feature.rst @@ -157,5 +157,5 @@ the Content-Type header for you so if you need that, you can set it with the ``w Checking the Response ===================== -``FeatureTestTrait::call()`` returns an instance of a ``TestResponse``. See `Testing Responses `_ on +``FeatureTestTrait::call()`` returns an instance of a ``TestResponse``. See :doc:`Testing Responses ` on how to use this class to perform additional assertions and verification in your test cases. diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 0a16a07b34ac..7cfcdcb69d54 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -103,7 +103,7 @@ have the correct namespace relative to ``App``. .. note:: Namespaces are not strictly required for test classes, but they are helpful to ensure no class names collide. -When testing database results, you must use the `DatabaseTestTrait `_ in your class. +When testing database results, you must use the :doc:`DatabaseTestTrait ` in your class. Staging ------- diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index c5f7d9c34fbe..db709e415fff 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -4,7 +4,7 @@ Testing Responses The ``TestResponse`` class provides a number of helpful functions for parsing and testing responses from your test cases. Usually a ``TestResponse`` will be provided for you as a result of your -`Controller Tests `_ or `HTTP Feature Tests `_, but you can always +:doc:`Controller Tests ` or :doc:`HTTP Feature Tests `, but you can always create your own directly using any ``ResponseInterface``:: $result = new \CodeIgniter\Test\TestResponse($response); From c057adea785539ede98f7ecb2220078e132a25e2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 11:20:00 +0900 Subject: [PATCH 0796/2325] docs: update external URLs --- user_guide_src/source/installation/installing_manual.rst | 2 +- user_guide_src/source/testing/overview.rst | 4 ++-- user_guide_src/source/testing/response.rst | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/installation/installing_manual.rst b/user_guide_src/source/installation/installing_manual.rst index 1224e84d2830..c64f7dc5b212 100644 --- a/user_guide_src/source/installation/installing_manual.rst +++ b/user_guide_src/source/installation/installing_manual.rst @@ -10,7 +10,7 @@ will be your public-facing document root. Do not change anything inside the ``sy folder! .. note:: This is the installation technique closest to that described - for `CodeIgniter 3 `_. + for `CodeIgniter 3 `_. Installation ============ diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 7cfcdcb69d54..4b4cdce7beed 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -216,7 +216,7 @@ Ensure that a header or cookie was actually emitted:: $this->assertHeaderEmitted("Set-Cookie: foo=bar"); Note: the test case with this should be `run as a separate process -in PHPunit `_. +in PHPunit `_. **assertHeaderNotEmitted($header, $ignoreCase = false)** @@ -231,7 +231,7 @@ Ensure that a header or cookie was not emitted:: $this->assertHeaderNotEmitted("Set-Cookie: banana"); Note: the test case with this should be `run as a separate process -in PHPunit `_. +in PHPunit `_. **assertCloseEnough($expected, $actual, $message = '', $tolerance = 1)** diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index db709e415fff..6c22e7e9cbdb 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -10,6 +10,10 @@ create your own directly using any ``ResponseInterface``:: $result = new \CodeIgniter\Test\TestResponse($response); $result->assertOK(); +.. contents:: + :local: + :depth: 2 + Testing the Response ==================== From c802bd88c5a979a04e08288cd4869614fe4b156c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 17:20:39 +0900 Subject: [PATCH 0797/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/general/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 150ddcfe3f60..c9a5607df1f2 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -192,7 +192,7 @@ with the ``new`` command:: Config files are automatically discovered whenever using the **config()** function that is always available. .. note:: **config()** finds the file in **app/Config/** when there is a class with the same shortname, - even if you specify a full qualified class name like ``config(\Acme\Blog\Config\Blog::class)``. + even if you specify a fully qualified class name like ``config(\Acme\Blog\Config\Blog::class)``. .. note:: Modules that need to override or add to known configurations in **app/Config/** should use :ref:`registrars`. From b367e05a3f37db4377efd5ae576e2f9e6a772256 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 21 Nov 2021 19:37:47 +0900 Subject: [PATCH 0798/2325] fix: unexpected array structure causes Type Error Fixes #5369 --- system/Helpers/array_helper.php | 4 ++++ tests/system/Helpers/ArrayHelperTest.php | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php index a06d4bb96c6e..423f9c266dd5 100644 --- a/system/Helpers/array_helper.php +++ b/system/Helpers/array_helper.php @@ -53,6 +53,10 @@ function _array_search_dot(array $indexes, array $array) $answer = []; foreach ($array as $value) { + if (! is_array($value)) { + return null; + } + $answer[] = _array_search_dot($indexes, $value); } diff --git a/tests/system/Helpers/ArrayHelperTest.php b/tests/system/Helpers/ArrayHelperTest.php index f6ae751e1bda..68941d670ce9 100644 --- a/tests/system/Helpers/ArrayHelperTest.php +++ b/tests/system/Helpers/ArrayHelperTest.php @@ -46,6 +46,18 @@ public function testArrayDotTooManyLevels() $this->assertSame(23, dot_array_search('foo.bar.baz', $data)); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5369 + */ + public function testArrayDotValueIsListArray() + { + $data = [ + 'arr' => [1, 2, 3], + ]; + + $this->assertNull(dot_array_search('arr.*.index', $data)); + } + public function testArrayDotEscape() { $data = [ From a2fc131e2c60605c801fb0886620361056b77e6e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 09:09:02 +0900 Subject: [PATCH 0799/2325] docs: add more explanation and link --- user_guide_src/source/concepts/factories.rst | 2 ++ user_guide_src/source/general/modules.rst | 6 ++++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 2c5c9ea84c3d..96bf0e39a4a5 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -58,6 +58,8 @@ to access user records always go through that connection:: Now any time the ``UserModel`` is loaded from ``Factories`` it will in fact be returning a class instance that uses the alternate database connection. +.. _factories-options: + Factories Options ================== diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index c9a5607df1f2..85a1d4ae82f8 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -191,10 +191,12 @@ with the ``new`` command:: Config files are automatically discovered whenever using the **config()** function that is always available. +.. note:: We don't recommend you use the same short classname in modules. + Modules that need to override or add to known configurations in **app/Config/** should use :ref:`registrars`. + .. note:: **config()** finds the file in **app/Config/** when there is a class with the same shortname, even if you specify a fully qualified class name like ``config(\Acme\Blog\Config\Blog::class)``. - -.. note:: Modules that need to override or add to known configurations in **app/Config/** should use :ref:`registrars`. + This is because ``Factories``'s the default configuration. See :ref:`factories-options` for more information. Migrations ========== From 2c668d4e7552e95f43b9ab03668be8a04e06a77a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 09:09:52 +0900 Subject: [PATCH 0800/2325] docs: shorten the width of the table It is too long and difficult to see. --- user_guide_src/source/concepts/factories.rst | 22 ++++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 96bf0e39a4a5..978c6bc26fe9 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -67,15 +67,19 @@ The default behavior might not work for every component. For example, say your c name and its path do not align, or you need to limit instances to a certain type of class. Each component takes a set of options to direct discovery and instantiation. -========== ============== ==================================================================================================================== =================================================== -Key Type Description Default -========== ============== ==================================================================================================================== =================================================== -component string or null The name of the component (if different than the static method). This can be used to alias one component to another. ``null`` (defaults to the component name) -path string or null The relative path within the namespace/folder to look for classes. ``null`` (defaults to the component name) -instanceOf string or null A required class name to match on the returned instance. ``null`` (no filtering) -getShared boolean Whether to return a shared instance of the class or load a fresh one. ``true`` -preferApp boolean Whether a class with the same basename in the App namespace overrides other explicit class requests. ``true`` -========== ============== ==================================================================================================================== =================================================== +========== ============== ============================================================ =================================================== +Key Type Description Default +========== ============== ============================================================ =================================================== +component string or null The name of the component (if different than the static ``null`` (defaults to the component name) + method). This can be used to alias one component to another. +path string or null The relative path within the namespace/folder to look for ``null`` (defaults to the component name) + classes. +instanceOf string or null A required class name to match on the returned instance. ``null`` (no filtering) +getShared boolean Whether to return a shared instance of the class or load a ``true`` + fresh one. +preferApp boolean Whether a class with the same basename in the App namespace ``true`` + overrides other explicit class requests. +========== ============== ============================================================ =================================================== Factories Behavior ================== From cb64680cd30a6b9764e435c62682aae52eb8186a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 10:41:26 +0900 Subject: [PATCH 0801/2325] docs: replace blogview with blog_view We use snake_case view filename, e.g. welcome_message, error_404. --- user_guide_src/source/outgoing/views.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index b01466ce40da..604f38731e85 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -19,7 +19,7 @@ Using the example controller you created in the controller page, let’s add a v Creating a View =============== -Using your text editor, create a file called ``blogview.php`` and put this in it:: +Using your text editor, create a file called ``blog_view.php`` and put this in it:: @@ -53,7 +53,7 @@ Now, open the controller file you made earlier called ``Blog.php``, and replace { public function index() { - echo view('blogview'); + echo view('blog_view'); } } @@ -109,9 +109,9 @@ to package your views together in a module-like fashion for easy re-use or distr If you have ``Blog`` directory that has a PSR-4 mapping set up in the :doc:`Autoloader ` living under the namespace ``Example\Blog``, you could retrieve view files as if they were namespaced also. Following this -example, you could load the **blogview.php** file from **Blog/Views** by prepending the namespace to the view name:: +example, you could load the **blog_view.php** file from **Blog/Views** by prepending the namespace to the view name:: - echo view('Example\Blog\Views\blogview'); + echo view('Example\Blog\Views\blog_view'); Caching Views ============= @@ -140,7 +140,7 @@ Here's an example:: 'message' => 'My Message', ]; - echo view('blogview', $data); + echo view('blog_view', $data); Let's try it with your controller file. Open it and add this code:: @@ -155,7 +155,7 @@ Let's try it with your controller file. Open it and add this code:: $data['title'] = "My Real Title"; $data['heading'] = "My Real Heading"; - echo view('blogview', $data); + echo view('blog_view', $data); } } @@ -184,7 +184,7 @@ into the `$option` array in the third parameter. 'message' => 'My Message', ]; - echo view('blogview', $data, ['saveData' => true]); + echo view('blog_view', $data, ['saveData' => true]); Additionally, if you would like the default functionality of the view function to be that it does save the data between calls, you can set ``$saveData`` to **true** in **app/Config/Views.php**. @@ -212,7 +212,7 @@ Here’s a simple example. Add this to your controller:: 'heading' => 'My Real Heading', ]; - echo view('blogview', $data); + echo view('blog_view', $data); } } From 7d15138f7d79eb21898ddd7b3ec06591d82b1c5c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 10:50:48 +0900 Subject: [PATCH 0802/2325] docs: fix namespace directory explanation --- user_guide_src/source/outgoing/views.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 604f38731e85..533e3c9bead5 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -107,9 +107,9 @@ You can store views under a **View** directory that is namespaced, and load that PHP does not support loading non-class files from a namespace, CodeIgniter provides this feature to make it possible to package your views together in a module-like fashion for easy re-use or distribution. -If you have ``Blog`` directory that has a PSR-4 mapping set up in the :doc:`Autoloader ` living +If you have ``example/blog`` directory that has a PSR-4 mapping set up in the :doc:`Autoloader ` living under the namespace ``Example\Blog``, you could retrieve view files as if they were namespaced also. Following this -example, you could load the **blog_view.php** file from **Blog/Views** by prepending the namespace to the view name:: +example, you could load the **blog_view.php** file from **example/blog/Views** by prepending the namespace to the view name:: echo view('Example\Blog\Views\blog_view'); From 29047e92d7dcb02300ac258e039470ffe98e48d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 18 Nov 2021 16:58:51 +0900 Subject: [PATCH 0803/2325] chore: add script to add "Edit this page" button in User Guide --- user_guide_src/add-edit-this-page | 62 +++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) create mode 100755 user_guide_src/add-edit-this-page diff --git a/user_guide_src/add-edit-this-page b/user_guide_src/add-edit-this-page new file mode 100755 index 000000000000..cb036524369d --- /dev/null +++ b/user_guide_src/add-edit-this-page @@ -0,0 +1,62 @@ +#!/usr/bin/env php +' . PHP_EOL; + echo ' e.g: ' . $argv[0] . ' user_guide_src/build/html/' . PHP_EOL; + + exit(1); +} + +$dir = realpath($argv[1]); + +if ($dir === false || ! is_dir($dir)) { + throw new RuntimeException('Cannot find directory: ' . $dir); +} + +$iterator = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator( + $dir, + FilesystemIterator::CURRENT_AS_FILEINFO | + FilesystemIterator::KEY_AS_PATHNAME | + FilesystemIterator::SKIP_DOTS + ) +); + +$files = new RegexIterator( + $iterator, + '/\A.+\.html\z/', + RecursiveRegexIterator::MATCH +); + +foreach ($files as $filePath => $fileInfo) { + echo 'processing... ' . PHP_EOL; + + $uriPath = str_replace('.html', '.rst', str_replace($dir, '', $filePath)); + $gitHubLink = 'Edit this page'; + + $content = file_get_contents($filePath); + + $pattern = '!">Edit this page!u'; + if (preg_match($pattern, $content) === 1) { + // Move the cursor up 1 line + echo "\033[1A"; + echo 'skip: ' . $filePath . PHP_EOL; + + continue; + } + + $pattern = '/
    /u'; + $content = preg_replace( + $pattern, + $gitHubLink . PHP_EOL . '
    ', + $content + ); + + file_put_contents($filePath, $content, LOCK_EX); + + // Move the cursor up 1 line + echo "\033[1A"; + echo 'done: ' . $filePath . PHP_EOL; +} From 414ca7718ac0525de86095a4fed8d0f143b40806 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 14:23:49 +0900 Subject: [PATCH 0804/2325] feat: add controller filter to check invalid chars in user input --- system/Filters/InvalidChars.php | 120 ++++++++++++++++ tests/system/Filters/InvalidCharsTest.php | 158 ++++++++++++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 system/Filters/InvalidChars.php create mode 100644 tests/system/Filters/InvalidCharsTest.php diff --git a/system/Filters/InvalidChars.php b/system/Filters/InvalidChars.php new file mode 100644 index 000000000000..34368b0c5380 --- /dev/null +++ b/system/Filters/InvalidChars.php @@ -0,0 +1,120 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Filters; + +use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\ResponseInterface; +use RuntimeException; + +/** + * InvalidChars filter. + * + * Check if user input data ($_GET, $_POST, $_COOKIE, php://input) do not contain + * invalid characters: + * - invalid UTF-8 characters + * - control characters except line break and tab code + */ +class InvalidChars implements FilterInterface +{ + /** + * Data source + * + * @var string + */ + protected $source; + + /** + * Check invalid characters. + * + * @param array|null $arguments + * + * @return void + */ + public function before(RequestInterface $request, $arguments = null) + { + if ($request->isCLI()) { + return; + } + + $data = [ + 'get' => $request->getGet(), + 'post' => $request->getPost(), + 'cookie' => $request->getCookie(), + 'rawInput' => $request->getRawInput(), + ]; + + foreach ($data as $source => $values) { + $this->source = $source; + $this->checkEncoding($values); + $this->checkControl($values); + } + } + + /** + * We don't have anything to do here. + * + * @param array|null $arguments + * + * @return void + */ + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + } + + /** + * Check the character encoding is valid UTF-8. + * + * @param array|string $value + * + * @return array|string + */ + protected function checkEncoding($value) + { + if (is_array($value)) { + array_map([$this, 'checkEncoding'], $value); + + return $value; + } + + if (mb_check_encoding($value, 'UTF-8')) { + return $value; + } + + throw new RuntimeException( + 'Invalid UTF-8 characters in ' . $this->source . ': ' . $value + ); + } + + /** + * Check for the presence of control characters except line breaks and tabs. + * + * @param array|string $value + * + * @return array|string + */ + protected function checkControl($value) + { + if (is_array($value)) { + array_map([$this, 'checkControl'], $value); + + return $value; + } + + if (preg_match('/\A[\r\n\t[:^cntrl:]]*\z/u', $value) === 1) { + return $value; + } + + throw new RuntimeException( + 'Invalid Control characters in ' . $this->source . ': ' . $value + ); + } +} diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php new file mode 100644 index 000000000000..85048f1a0df8 --- /dev/null +++ b/tests/system/Filters/InvalidCharsTest.php @@ -0,0 +1,158 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Filters; + +use CodeIgniter\HTTP\CLIRequest; +use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\UserAgent; +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\Mock\MockAppConfig; +use RuntimeException; + +/** + * @internal + */ +final class InvalidCharsTest extends CIUnitTestCase +{ + /** + * @var InvalidChars + */ + private $invalidChars; + + /** + * @var IncomingRequest + */ + private $request; + + protected function setUp(): void + { + parent::setUp(); + + $_GET = []; + $_POST = []; + $_COOKIE = []; + + $this->request = $this->createRequest(); + $this->invalidChars = new InvalidChars(); + } + + private function createRequest(): IncomingRequest + { + $config = new MockAppConfig(); + $uri = new URI(); + $userAgent = new UserAgent(); + $request = $this->getMockBuilder(IncomingRequest::class) + ->setConstructorArgs([$config, $uri, null, $userAgent]) + ->onlyMethods(['isCLI']) + ->getMock(); + $request->method('isCLI')->willReturn(false); + + return $request; + } + + public function testBeforeDoNothingWhenCLIRequest() + { + $cliRequest = new CLIRequest(new MockAppConfig()); + + $ret = $this->invalidChars->before($cliRequest); + + $this->assertNull($ret); + } + + public function testBeforeValidString() + { + $_POST['val'] = [ + 'valid string', + ]; + $_COOKIE['val'] = 'valid string'; + + $ret = $this->invalidChars->before($this->request); + + $this->assertNull($ret); + } + + public function testBeforeInvalidUTF8StringCausesException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Invalid UTF-8 characters in post:'); + + $sjisString = mb_convert_encoding('SJISの文字列です。', 'SJIS'); + $_POST['val'] = [ + 'valid string', + $sjisString, + ]; + + $this->invalidChars->before($this->request); + } + + public function testBeforeInvalidControllCharCausesException() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Invalid Control characters in cookie:'); + + $stringWithNullChar = "String contains null char and line break.\0\n"; + $_COOKIE['val'] = $stringWithNullChar; + + $this->invalidChars->before($this->request); + } + + /** + * @dataProvider stringWithLineBreakAndTabProvider + * + * @param string $input + */ + public function testCheckControlStringWithLineBreakAndTabReturnsTheString($input) + { + $_GET['val'] = $input; + + $ret = $this->invalidChars->before($this->request); + + $this->assertNull($ret); + } + + public function stringWithLineBreakAndTabProvider() + { + return [ + ["String contains \n line break."], + ["String contains \r line break."], + ["String contains \r\n line break."], + ["String contains \t tab."], + ["String contains \t and \r line \n break."], + ]; + } + + /** + * @dataProvider stringWithControlCharsProvider + * + * @param string $input + */ + public function testCheckControlStringWithControlCharsCausesException($input) + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Invalid Control characters in get:'); + + $_GET['val'] = $input; + + $ret = $this->invalidChars->before($this->request); + + $this->assertNull($ret); + } + + public function stringWithControlCharsProvider() + { + return [ + ["String contains null char.\0"], + ["String contains null char and line break.\0\n"], + ]; + } +} From 9a67840c43dcc97c8d3123f619fbbe6450d3d752 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 17:06:51 +0900 Subject: [PATCH 0805/2325] test: clear super globals after testing The following test failed. It depends global state. 1) CodeIgniter\HTTP\ResponseTest::testSetLink Failed asserting that two strings are identical. --- tests/system/Filters/InvalidCharsTest.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 85048f1a0df8..3346b1adad18 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -46,6 +46,15 @@ protected function setUp(): void $this->invalidChars = new InvalidChars(); } + protected function tearDown(): void + { + parent::tearDown(); + + $_GET = []; + $_POST = []; + $_COOKIE = []; + } + private function createRequest(): IncomingRequest { $config = new MockAppConfig(); From 1e3a30cb6709634e4147a16f9326574b53df3a79 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 5 Nov 2021 11:37:39 +0900 Subject: [PATCH 0806/2325] feat: add SecurityException static consructors --- system/Filters/InvalidChars.php | 10 +++------- system/Security/Exceptions/SecurityException.php | 16 ++++++++++++++++ tests/system/Filters/InvalidCharsTest.php | 8 ++++---- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/system/Filters/InvalidChars.php b/system/Filters/InvalidChars.php index 34368b0c5380..ab5a2fef9ca4 100644 --- a/system/Filters/InvalidChars.php +++ b/system/Filters/InvalidChars.php @@ -13,7 +13,7 @@ use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\HTTP\ResponseInterface; -use RuntimeException; +use CodeIgniter\Security\Exceptions\SecurityException; /** * InvalidChars filter. @@ -89,9 +89,7 @@ protected function checkEncoding($value) return $value; } - throw new RuntimeException( - 'Invalid UTF-8 characters in ' . $this->source . ': ' . $value - ); + throw SecurityException::forInvalidUTF8Chars($this->source, $value); } /** @@ -113,8 +111,6 @@ protected function checkControl($value) return $value; } - throw new RuntimeException( - 'Invalid Control characters in ' . $this->source . ': ' . $value - ); + throw SecurityException::forInvalidControlChars($this->source, $value); } } diff --git a/system/Security/Exceptions/SecurityException.php b/system/Security/Exceptions/SecurityException.php index 254f3ec345f5..ed118d95d5dd 100644 --- a/system/Security/Exceptions/SecurityException.php +++ b/system/Security/Exceptions/SecurityException.php @@ -20,6 +20,22 @@ public static function forDisallowedAction() return new static(lang('Security.disallowedAction'), 403); } + public static function forInvalidUTF8Chars(string $source, string $string) + { + return new static( + 'Invalid UTF-8 characters in ' . $source . ': ' . $string, + 400 + ); + } + + public static function forInvalidControlChars(string $source, string $string) + { + return new static( + 'Invalid Control characters in ' . $source . ': ' . $string, + 400 + ); + } + /** * @deprecated Use `CookieException::forInvalidSameSite()` instead. * diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 3346b1adad18..85fa6b91425a 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -15,9 +15,9 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; +use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockAppConfig; -use RuntimeException; /** * @internal @@ -92,7 +92,7 @@ public function testBeforeValidString() public function testBeforeInvalidUTF8StringCausesException() { - $this->expectException(RuntimeException::class); + $this->expectException(SecurityException::class); $this->expectExceptionMessage('Invalid UTF-8 characters in post:'); $sjisString = mb_convert_encoding('SJISの文字列です。', 'SJIS'); @@ -106,7 +106,7 @@ public function testBeforeInvalidUTF8StringCausesException() public function testBeforeInvalidControllCharCausesException() { - $this->expectException(RuntimeException::class); + $this->expectException(SecurityException::class); $this->expectExceptionMessage('Invalid Control characters in cookie:'); $stringWithNullChar = "String contains null char and line break.\0\n"; @@ -147,7 +147,7 @@ public function stringWithLineBreakAndTabProvider() */ public function testCheckControlStringWithControlCharsCausesException($input) { - $this->expectException(RuntimeException::class); + $this->expectException(SecurityException::class); $this->expectExceptionMessage('Invalid Control characters in get:'); $_GET['val'] = $input; From 991f9537bf41d58a232e1eb749b9d4dd904007a4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 5 Nov 2021 11:39:01 +0900 Subject: [PATCH 0807/2325] test: fix test code --- tests/system/Filters/InvalidCharsTest.php | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 85fa6b91425a..95725de07323 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -69,15 +69,19 @@ private function createRequest(): IncomingRequest return $request; } + /** + * @doesNotPerformAssertions + */ public function testBeforeDoNothingWhenCLIRequest() { $cliRequest = new CLIRequest(new MockAppConfig()); - $ret = $this->invalidChars->before($cliRequest); - - $this->assertNull($ret); + $this->invalidChars->before($cliRequest); } + /** + * @doesNotPerformAssertions + */ public function testBeforeValidString() { $_POST['val'] = [ @@ -85,9 +89,7 @@ public function testBeforeValidString() ]; $_COOKIE['val'] = 'valid string'; - $ret = $this->invalidChars->before($this->request); - - $this->assertNull($ret); + $this->invalidChars->before($this->request); } public function testBeforeInvalidUTF8StringCausesException() @@ -104,7 +106,7 @@ public function testBeforeInvalidUTF8StringCausesException() $this->invalidChars->before($this->request); } - public function testBeforeInvalidControllCharCausesException() + public function testBeforeInvalidControlCharCausesException() { $this->expectException(SecurityException::class); $this->expectExceptionMessage('Invalid Control characters in cookie:'); @@ -116,6 +118,8 @@ public function testBeforeInvalidControllCharCausesException() } /** + * @doesNotPerformAssertions + * * @dataProvider stringWithLineBreakAndTabProvider * * @param string $input @@ -124,9 +128,7 @@ public function testCheckControlStringWithLineBreakAndTabReturnsTheString($input { $_GET['val'] = $input; - $ret = $this->invalidChars->before($this->request); - - $this->assertNull($ret); + $this->invalidChars->before($this->request); } public function stringWithLineBreakAndTabProvider() @@ -152,9 +154,7 @@ public function testCheckControlStringWithControlCharsCausesException($input) $_GET['val'] = $input; - $ret = $this->invalidChars->before($this->request); - - $this->assertNull($ret); + $this->invalidChars->before($this->request); } public function stringWithControlCharsProvider() From 871e4996da7c57900df021f5e4a20fe56b818308 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 11:32:22 +0900 Subject: [PATCH 0808/2325] config: add invalidchars to Filter.php as comment --- app/Config/Filters.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/Config/Filters.php b/app/Config/Filters.php index df90270a6480..02aaec533c17 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -6,6 +6,7 @@ use CodeIgniter\Filters\CSRF; use CodeIgniter\Filters\DebugToolbar; use CodeIgniter\Filters\Honeypot; +use CodeIgniter\Filters\InvalidChars; class Filters extends BaseConfig { @@ -16,9 +17,10 @@ class Filters extends BaseConfig * @var array */ public $aliases = [ - 'csrf' => CSRF::class, - 'toolbar' => DebugToolbar::class, - 'honeypot' => Honeypot::class, + 'csrf' => CSRF::class, + 'toolbar' => DebugToolbar::class, + 'honeypot' => Honeypot::class, + 'invalidchars' => InvalidChars::class, ]; /** @@ -31,6 +33,7 @@ class Filters extends BaseConfig 'before' => [ // 'honeypot', // 'csrf', + // 'invalidchars', ], 'after' => [ 'toolbar', From 97be0378e2579a7e206d531f0fba1f583fabc459 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 11:37:05 +0900 Subject: [PATCH 0809/2325] docs: add InvalidChars in Provided Filters --- user_guide_src/source/incoming/filters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 259bb496e0b7..334edf188fee 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -193,6 +193,6 @@ In this example, the array ``['dual', 'noreturn']`` will be passed in ``$argumen Provided Filters **************** -Three filters are bundled with CodeIgniter4: ``Honeypot``, ``CSRF``, and ``DebugToolbar``. +These filters are bundled with CodeIgniter4: ``Honeypot``, ``CSRF``, ``DebugToolbar`` and ``InvalidChars``. .. note:: The filters are executed in the declared order that is defined in the config file, but there is one exception to this and it concerns the ``DebugToolbar``, which is always executed last. This is because ``DebugToolbar`` should be able to register everything that happens in other filters. From fb9f6ec24f99ff8f30e6aa27ac9433f7b1fbe90f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 22 Nov 2021 11:38:38 +0900 Subject: [PATCH 0810/2325] refactor: add property for control code regex Users could override the property. --- system/Filters/InvalidChars.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/system/Filters/InvalidChars.php b/system/Filters/InvalidChars.php index ab5a2fef9ca4..4b1d8f7f9b6b 100644 --- a/system/Filters/InvalidChars.php +++ b/system/Filters/InvalidChars.php @@ -32,6 +32,13 @@ class InvalidChars implements FilterInterface */ protected $source; + /** + * Regular expressions for valid control codes + * + * @var string + */ + protected $controlCodeRegex = '/\A[\r\n\t[:^cntrl:]]*\z/u'; + /** * Check invalid characters. * @@ -107,7 +114,7 @@ protected function checkControl($value) return $value; } - if (preg_match('/\A[\r\n\t[:^cntrl:]]*\z/u', $value) === 1) { + if (preg_match($this->controlCodeRegex, $value) === 1) { return $value; } From 867322868e08e671d74c349eae7a8d30a2b638d4 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 21 Nov 2021 18:32:55 +0800 Subject: [PATCH 0811/2325] Fix deprecated usage of `null` on `string` params of internal functions --- app/Config/Mimes.php | 2 +- system/CLI/CLI.php | 8 ++-- system/Database/BaseUtils.php | 4 +- system/Database/Forge.php | 2 +- system/Database/Postgre/Connection.php | 7 +++- system/Filters/Filters.php | 7 +--- system/HTTP/CLIRequest.php | 8 ++-- system/HTTP/CURLRequest.php | 2 +- system/HTTP/ResponseTrait.php | 2 +- system/I18n/Time.php | 18 ++++---- system/Security/Security.php | 7 ++-- system/Validation/FormatRules.php | 56 ++++++++++++------------- system/Validation/Rules.php | 58 ++++++-------------------- system/Validation/Validation.php | 20 +++------ tests/system/I18n/TimeTest.php | 3 +- 15 files changed, 82 insertions(+), 122 deletions(-) diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index 973fb3984901..786bc6a1e5c7 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -509,7 +509,7 @@ public static function guessExtensionFromType(string $type, ?string $proposedExt { $type = trim(strtolower($type), '. '); - $proposedExtension = trim(strtolower($proposedExtension)); + $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)) { diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index ea1e1ad85611..347a894f7578 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -865,10 +865,12 @@ public static function getOptionString(bool $useLongOpts = false, bool $trim = f $out .= "-{$name} "; } - // If there's a space, we need to group - // so it will pass correctly. + if ($value === null) { + continue; + } + if (mb_strpos($value, ' ') !== false) { - $out .= '"' . $value . '" '; + $out .= "\"{$value}\" "; } elseif ($value !== null) { $out .= "{$value} "; } diff --git a/system/Database/BaseUtils.php b/system/Database/BaseUtils.php index 5af2b54dbad7..7848ae75ecf0 100644 --- a/system/Database/BaseUtils.php +++ b/system/Database/BaseUtils.php @@ -200,7 +200,7 @@ public function repairTable(string $tableName) public function getCSVFromResult(ResultInterface $query, string $delim = ',', string $newline = "\n", string $enclosure = '"') { $out = ''; - // First generate the headings from the table column names + foreach ($query->getFieldNames() as $name) { $out .= $enclosure . str_replace($enclosure, $enclosure . $enclosure, $name) . $enclosure . $delim; } @@ -212,7 +212,7 @@ public function getCSVFromResult(ResultInterface $query, string $delim = ',', st $line = []; foreach ($row as $item) { - $line[] = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $item) . $enclosure; + $line[] = $enclosure . str_replace($enclosure, $enclosure . $enclosure, $item ?? '') . $enclosure; } $out .= implode($delim, $line) . $newline; diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 8e0b7e43c7f3..d07675401df8 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -462,7 +462,7 @@ public function dropKey(string $table, string $keyName) public function dropForeignKey(string $table, string $foreignName) { $sql = sprintf( - $this->dropConstraintStr, + (string) $this->dropConstraintStr, $this->db->escapeIdentifiers($this->db->DBPrefix . $table), $this->db->escapeIdentifiers($this->db->DBPrefix . $foreignName) ); diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index a768e0ecf432..d39587821036 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -433,8 +433,11 @@ protected function buildDSN() $this->DSN = "host={$this->hostname} "; } - if (! empty($this->port) && ctype_digit($this->port)) { - $this->DSN .= "port={$this->port} "; + // ctype_digit only accepts strings + $port = (string) $this->port; + + if ($port !== '' && ctype_digit($port)) { + $this->DSN .= "port={$port} "; } if ($this->username !== '') { diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index faa1df358cb4..edeb8b0571c5 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -397,13 +397,10 @@ protected function processGlobals(?string $uri = null) return; } - $uri = strtolower(trim($uri, '/ ')); + $uri = strtolower(trim($uri ?? '', '/ ')); // Add any global filters, unless they are excluded for this URI - $sets = [ - 'before', - 'after', - ]; + $sets = ['before', 'after']; foreach ($sets as $set) { if (isset($this->config->globals[$set])) { diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php index b10d41884733..11bf598fd36c 100644 --- a/system/HTTP/CLIRequest.php +++ b/system/HTTP/CLIRequest.php @@ -139,11 +139,13 @@ public function getOptionString(bool $useLongOpts = false): string $out .= "-{$name} "; } - // If there's a space, we need to group - // so it will pass correctly. + if ($value === null) { + continue; + } + if (mb_strpos($value, ' ') !== false) { $out .= '"' . $value . '" '; - } elseif ($value !== null) { + } else { $out .= "{$value} "; } } diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index fffe57258a54..9a66e632783b 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -424,7 +424,7 @@ protected function applyMethod(string $method, array $curlOptions): array $this->method = $method; $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - $size = strlen($this->body); + $size = strlen($this->body ?? ''); // Have content? if ($size > 0) { diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 2b1205a5d47a..7ec5f1e69e6b 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -435,7 +435,7 @@ public function send() if ($this->CSPEnabled === true) { $this->CSP->finalize($this); } else { - $this->body = str_replace(['{csp-style-nonce}', '{csp-script-nonce}'], '', $this->body); + $this->body = str_replace(['{csp-style-nonce}', '{csp-script-nonce}'], '', $this->body ?? ''); } $this->sendHeaders(); diff --git a/system/I18n/Time.php b/system/I18n/Time.php index 919a5a391534..ca8ffc3dc72e 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -75,25 +75,23 @@ class Time extends DateTime */ public function __construct(?string $time = null, $timezone = null, ?string $locale = null) { - // If no locale was provided, grab it from Locale (set by IncomingRequest for web requests) - $this->locale = ! empty($locale) ? $locale : Locale::getDefault(); + $this->locale = $locale ?: Locale::getDefault(); - // If a test instance has been provided, use it instead. - if ($time === null && static::$testNow instanceof self) { - if (empty($timezone)) { - $timezone = static::$testNow->getTimezone(); - } + $time = $time ?? ''; - $time = static::$testNow->toDateTimeString(); + // 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(); } - $timezone = ! empty($timezone) ? $timezone : date_default_timezone_get(); + $timezone = $timezone ?: date_default_timezone_get(); $this->timezone = $timezone instanceof DateTimeZone ? $timezone : new DateTimeZone($timezone); // If the time string was a relative string (i.e. 'next Tuesday') // then we need to adjust the time going in so that we have a current // timezone to work with. - if (! empty($time) && (is_string($time) && static::hasRelativeKeywords($time))) { + if ($time !== '' && static::hasRelativeKeywords($time)) { $instance = new DateTime('now', $this->timezone); $instance->modify($time); $time = $instance->format('Y-m-d H:i:s'); diff --git a/system/Security/Security.php b/system/Security/Security.php index fc8c1ac334c8..35e889a85d69 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -288,7 +288,7 @@ public function verify(RequestInterface $request) throw SecurityException::forDisallowedAction(); } - $json = json_decode($request->getBody()); + $json = json_decode($request->getBody() ?? ''); if (isset($_POST[$this->tokenName])) { // We kill this since we're done and we don't want to pollute the POST array. @@ -323,9 +323,10 @@ private function getPostedToken(RequestInterface $request): ?string if ($request->hasHeader($this->headerName) && ! empty($request->header($this->headerName)->getValue())) { $tokenName = $request->header($this->headerName)->getValue(); } else { - $json = json_decode($request->getBody()); + $body = (string) $request->getBody(); + $json = json_decode($body); - if (! empty($request->getBody()) && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { + if ($body !== '' && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { $tokenName = $json->{$this->tokenName} ?? null; } else { $tokenName = null; diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index 2167e28cba79..e28f6d6af13d 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -23,7 +23,7 @@ class FormatRules */ public function alpha(?string $str = null): bool { - return ctype_alpha($str); + return ctype_alpha($str ?? ''); } /** @@ -74,7 +74,7 @@ public function alpha_numeric_punct($str) */ public function alpha_numeric(?string $str = null): bool { - return ctype_alnum($str); + return ctype_alnum($str ?? ''); } /** @@ -83,7 +83,7 @@ public function alpha_numeric(?string $str = null): bool public function alpha_numeric_space(?string $str = null): bool { // @see https://regex101.com/r/0AZDME/1 - return (bool) preg_match('/\A[A-Z0-9 ]+\z/i', $str); + return (bool) preg_match('/\A[A-Z0-9 ]+\z/i', $str ?? ''); } /** @@ -105,7 +105,7 @@ public function string($str = null): bool public function decimal(?string $str = null): bool { // @see https://regex101.com/r/HULifl/2/ - return (bool) preg_match('/\A[-+]?\d{0,}\.?\d+\z/', $str); + return (bool) preg_match('/\A[-+]?\d{0,}\.?\d+\z/', $str ?? ''); } /** @@ -113,7 +113,7 @@ public function decimal(?string $str = null): bool */ public function hex(?string $str = null): bool { - return ctype_xdigit($str); + return ctype_xdigit($str ?? ''); } /** @@ -121,7 +121,7 @@ public function hex(?string $str = null): bool */ public function integer(?string $str = null): bool { - return (bool) preg_match('/\A[\-+]?\d+\z/', $str); + return (bool) preg_match('/\A[\-+]?\d+\z/', $str ?? ''); } /** @@ -129,7 +129,7 @@ public function integer(?string $str = null): bool */ public function is_natural(?string $str = null): bool { - return ctype_digit($str); + return ctype_digit($str ?? ''); } /** @@ -137,7 +137,7 @@ public function is_natural(?string $str = null): bool */ public function is_natural_no_zero(?string $str = null): bool { - return $str !== '0' && ctype_digit($str); + return $str !== '0' && ctype_digit($str ?? ''); } /** @@ -146,7 +146,7 @@ public function is_natural_no_zero(?string $str = null): bool public function numeric(?string $str = null): bool { // @see https://regex101.com/r/bb9wtr/2 - return (bool) preg_match('/\A[\-+]?\d*\.?\d+\z/', $str); + return (bool) preg_match('/\A[\-+]?\d*\.?\d+\z/', $str ?? ''); } /** @@ -158,7 +158,7 @@ public function regex_match(?string $str, string $pattern): bool $pattern = "/{$pattern}/"; } - return (bool) preg_match($pattern, $str); + return (bool) preg_match($pattern, $str ?? ''); } /** @@ -171,7 +171,7 @@ public function regex_match(?string $str, string $pattern): bool */ public function timezone(?string $str = null): bool { - return in_array($str, timezone_identifiers_list(), true); + return in_array($str ?? '', timezone_identifiers_list(), true); } /** @@ -184,6 +184,10 @@ public function timezone(?string $str = null): bool */ public function valid_base64(?string $str = null): bool { + if ($str === null) { + return false; + } + return base64_encode(base64_decode($str, true)) === $str; } @@ -194,7 +198,7 @@ public function valid_base64(?string $str = null): bool */ public function valid_json(?string $str = null): bool { - json_decode($str); + json_decode($str ?? ''); return json_last_error() === JSON_ERROR_NONE; } @@ -207,7 +211,7 @@ public function valid_json(?string $str = null): bool public function valid_email(?string $str = null): bool { // @see https://regex101.com/r/wlJG1t/1/ - if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str, $matches)) { + if (function_exists('idn_to_ascii') && defined('INTL_IDNA_VARIANT_UTS46') && preg_match('#\A([^@]+)@(.+)\z#', $str ?? '', $matches)) { $str = $matches[1] . '@' . idn_to_ascii($matches[2], 0, INTL_IDNA_VARIANT_UTS46); } @@ -224,8 +228,9 @@ public function valid_email(?string $str = null): bool */ public function valid_emails(?string $str = null): bool { - foreach (explode(',', $str) as $email) { + foreach (explode(',', $str ?? '') as $email) { $email = trim($email); + if ($email === '') { return false; } @@ -241,8 +246,7 @@ public function valid_emails(?string $str = null): bool /** * Validate an IP address (human readable format or binary string - inet_pton) * - * @param string $ip IP Address - * @param string $which IP protocol: 'ipv4' or 'ipv6' + * @param string|null $which IP protocol: 'ipv4' or 'ipv6' */ public function valid_ip(?string $ip = null, ?string $which = null): bool { @@ -250,7 +254,7 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool return false; } - switch (strtolower($which)) { + switch (strtolower($which ?? '')) { case 'ipv4': $which = FILTER_FLAG_IPV4; break; @@ -260,11 +264,11 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool break; default: - $which = null; - break; + $which = 0; } - return (bool) filter_var($ip, FILTER_VALIDATE_IP, $which) || (! ctype_print($ip) && (bool) filter_var(inet_ntop($ip), FILTER_VALIDATE_IP, $which)); + return filter_var($ip, FILTER_VALIDATE_IP, $which) !== false + || (! ctype_print($ip) && filter_var(inet_ntop($ip), FILTER_VALIDATE_IP, $which) !== false); } /** @@ -272,8 +276,6 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool * * Warning: this rule will pass basic strings like * "banana"; use valid_url_strict for a stricter rule. - * - * @param string $str */ public function valid_url(?string $str = null): bool { @@ -317,18 +319,16 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu /** * Checks for a valid date and matches a given date format - * - * @param string $str - * @param string $format */ public function valid_date(?string $str = null, ?string $format = null): bool { if (empty($format)) { - return (bool) strtotime($str); + return strtotime($str) !== false; } - $date = DateTime::createFromFormat($format, $str); + $date = DateTime::createFromFormat($format, $str); + $errors = DateTime::getLastErrors(); - return (bool) $date && DateTime::getLastErrors()['warning_count'] === 0 && DateTime::getLastErrors()['error_count'] === 0; + return $date !== false && $errors !== false && $errors['warning_count'] === 0 && $errors['error_count'] === 0; } } diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 20f558e52be2..367915ebae35 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -22,8 +22,7 @@ class Rules /** * The value does not match another field in $data. * - * @param string $str - * @param array $data Other field/value pairs + * @param array $data Other field/value pairs */ public function differs(?string $str, string $field, array $data): bool { @@ -36,8 +35,6 @@ public function differs(?string $str, string $field, array $data): bool /** * Equals the static value provided. - * - * @param string $str */ public function equals(?string $str, string $val): bool { @@ -47,15 +44,13 @@ public function equals(?string $str, string $val): bool /** * Returns true if $str is $val characters long. * $val = "5" (one) | "5,8,12" (multiple values) - * - * @param string $str */ public function exact_length(?string $str, string $val): bool { $val = explode(',', $val); foreach ($val as $tmp) { - if (is_numeric($tmp) && (int) $tmp === mb_strlen($str)) { + if (is_numeric($tmp) && (int) $tmp === mb_strlen($str ?? '')) { return true; } } @@ -65,8 +60,6 @@ public function exact_length(?string $str, string $val): bool /** * Greater than - * - * @param string $str */ public function greater_than(?string $str, string $min): bool { @@ -75,8 +68,6 @@ public function greater_than(?string $str, string $min): bool /** * Equal to or Greater than - * - * @param string $str */ public function greater_than_equal_to(?string $str, string $min): bool { @@ -91,8 +82,6 @@ public function greater_than_equal_to(?string $str, string $min): bool * Example: * is_not_unique[table.field,where_field,where_value] * is_not_unique[menu.id,active,1] - * - * @param string $str */ public function is_not_unique(?string $str, string $field, array $data): bool { @@ -102,9 +91,8 @@ public function is_not_unique(?string $str, string $field, array $data): bool // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); - $db = Database::connect($data['DBGroup'] ?? null); - - $row = $db->table($table) + $row = Database::connect($data['DBGroup'] ?? null) + ->table($table) ->select('1') ->where($field, $str) ->limit(1); @@ -118,8 +106,6 @@ public function is_not_unique(?string $str, string $field, array $data): bool /** * Value should be within an array of values - * - * @param string $value */ public function in_list(?string $value, string $list): bool { @@ -136,20 +122,15 @@ public function in_list(?string $value, string $list): bool * Example: * is_unique[table.field,ignore_field,ignore_value] * is_unique[users.email,id,5] - * - * @param string $str */ public function is_unique(?string $str, string $field, array $data): bool { - // Grab any data for exclusion of a single row. [$field, $ignoreField, $ignoreValue] = array_pad(explode(',', $field), 3, null); - // Break the table and field apart sscanf($field, '%[^.].%[^.]', $table, $field); - $db = Database::connect($data['DBGroup'] ?? null); - - $row = $db->table($table) + $row = Database::connect($data['DBGroup'] ?? null) + ->table($table) ->select('1') ->where($field, $str) ->limit(1); @@ -163,8 +144,6 @@ public function is_unique(?string $str, string $field, array $data): bool /** * Less than - * - * @param string $str */ public function less_than(?string $str, string $max): bool { @@ -173,8 +152,6 @@ public function less_than(?string $str, string $max): bool /** * Equal to or Less than - * - * @param string $str */ public function less_than_equal_to(?string $str, string $max): bool { @@ -184,8 +161,7 @@ public function less_than_equal_to(?string $str, string $max): bool /** * Matches the value of another field in $data. * - * @param string $str - * @param array $data Other field/value pairs + * @param array $data Other field/value pairs */ public function matches(?string $str, string $field, array $data): bool { @@ -198,22 +174,18 @@ public function matches(?string $str, string $field, array $data): bool /** * Returns true if $str is $val or fewer characters in length. - * - * @param string $str */ public function max_length(?string $str, string $val): bool { - return is_numeric($val) && $val >= mb_strlen($str); + return is_numeric($val) && $val >= mb_strlen($str ?? ''); } /** * Returns true if $str is at least $val length. - * - * @param string $str */ public function min_length(?string $str, string $val): bool { - return is_numeric($val) && $val <= mb_strlen($str); + return is_numeric($val) && $val <= mb_strlen($str ?? ''); } /** @@ -237,11 +209,7 @@ public function not_in_list(?string $value, string $list): bool } /** - * Required - * - * @param mixed $str Value - * - * @return bool True if valid, false if not + * @param mixed $str */ public function required($str = null): bool { @@ -270,11 +238,10 @@ public function required_with($str = null, ?string $fields = null, array $data = throw new InvalidArgumentException('You must supply the parameters: fields, data.'); } - $fields = explode(',', $fields); - // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. + $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { @@ -311,11 +278,10 @@ public function required_without($str = null, ?string $fields = null, array $dat throw new InvalidArgumentException('You must supply the parameters: fields, data.'); } - $fields = explode(',', $fields); - // If the field is present we can safely assume that // the field is here, no matter whether the corresponding // search field is present or not. + $fields = explode(',', $fields); $present = $this->required($str ?? ''); if ($present) { diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 8bd14817e79d..876ab3caffa0 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -215,7 +215,7 @@ protected function processRules(string $field, ?string $label, $value, $rules = } if (in_array('permit_empty', $rules, true)) { - if (! in_array('required', $rules, true) && (is_array($value) ? empty($value) : (trim($value) === ''))) { + if (! in_array('required', $rules, true) && (is_array($value) ? $value === [] : trim($value ?? '') === '')) { $passed = true; foreach ($rules as $rule) { @@ -570,13 +570,13 @@ protected function fillPlaceholders(array $rules, array $data): array continue; } - $row = strtr($row, $replacements); + $row = strtr($row ?? '', $replacements); } continue; } - $rule = strtr($rule, $replacements); + $rule = strtr($rule ?? '', $replacements); } } @@ -594,10 +594,6 @@ public function hasError(string $field): bool /** * Returns the error(s) for a specified $field (or empty string if not * set). - * - * @param string $field Field. - * - * @return string Error(s). */ public function getError(?string $field = null): string { @@ -617,9 +613,7 @@ public function getError(?string $field = null): string * 'field2' => 'error message', * ] * - * @return array - * - * Excluded from code coverage because that it always run as cli + * @return array * * @codeCoverageIgnore */ @@ -648,12 +642,10 @@ public function setError(string $field, string $error): ValidationInterface /** * Attempts to find the appropriate error message * - * @param string $param - * @param string $value The value that caused the validation to fail. + * @param string|null $value The value that caused the validation to fail. */ protected function getErrorMessage(string $rule, string $field, ?string $label = null, ?string $param = null, ?string $value = null): string { - // Check if custom message has been defined by user if (isset($this->customErrors[$field][$rule])) { $message = lang($this->customErrors[$field][$rule]); } else { @@ -666,7 +658,7 @@ protected function getErrorMessage(string $rule, string $field, ?string $label = $message = str_replace('{field}', empty($label) ? $field : lang($label), $message); $message = str_replace('{param}', empty($this->rules[$param]['label']) ? $param : lang($this->rules[$param]['label']), $message); - return str_replace('{value}', $value, $message); + return str_replace('{value}', $value ?? '', $message); } /** diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index 205a98098724..75f4416676fc 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -42,8 +42,7 @@ public function testNewTimeNow() 'yyyy-MM-dd HH:mm:ss' ); - $time = new Time(null, 'America/Chicago'); - + $time = new Time('', 'America/Chicago'); $this->assertSame($formatter->format($time), (string) $time); } From d4d3316909476cab57474d77c4cebc753f328cc2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 10:16:37 +0900 Subject: [PATCH 0812/2325] docs: fix by proofreading Co-authored-by: MGatner --- user_guide_src/source/general/modules.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 85a1d4ae82f8..581b2617aabb 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -196,7 +196,7 @@ Config files are automatically discovered whenever using the **config()** functi .. note:: **config()** finds the file in **app/Config/** when there is a class with the same shortname, even if you specify a fully qualified class name like ``config(\Acme\Blog\Config\Blog::class)``. - This is because ``Factories``'s the default configuration. See :ref:`factories-options` for more information. + This is because ``config()`` is a wrapper for the ``Factories`` class which uses ``preferApp`` by default. See :ref:`factories-options` for more information. Migrations ========== From 09147bb716ea7599cbf0e8bc67a52aa07b89ea7b Mon Sep 17 00:00:00 2001 From: vlakoff Date: Sun, 26 Sep 2021 09:49:18 +0200 Subject: [PATCH 0813/2325] Determine if binds are simple or named by looking at the $binds array --- system/Database/Query.php | 34 +++++++++++++------------ tests/system/Database/BaseQueryTest.php | 26 ++++++++++++++++++- 2 files changed, 43 insertions(+), 17 deletions(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index a4bb1b2b9de5..aaf6b6cb9671 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -275,14 +275,7 @@ protected function compileBinds() { $sql = $this->finalQueryString; - $hasBinds = strpos($sql, $this->bindMarker) !== false; - $hasNamedBinds = ! $hasBinds - && preg_match('/:(?!=).+:/', $sql) === 1; - - if (empty($this->binds) - || empty($this->bindMarker) - || (! $hasNamedBinds && ! $hasBinds) - ) { + if (empty($this->binds)) { return; } @@ -294,16 +287,25 @@ protected function compileBinds() $bindCount = count($binds); } - // Reverse the binds so that duplicate named binds - // will be processed prior to the original binds. - if (! is_numeric(key(array_slice($binds, 0, 1)))) { - $binds = array_reverse($binds); - } + if (is_numeric(key(array_slice($binds, 0, 1)))) { + if (empty($this->bindMarker) || strpos($sql, $this->bindMarker) === false) { + return; + } - $ml = strlen($this->bindMarker); - $sql = $hasNamedBinds ? $this->matchNamedBinds($sql, $binds) : $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); + $ml = strlen($this->bindMarker); - $this->finalQueryString = $sql; + $this->finalQueryString = $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); + } else { + if (! preg_match('/:(?!=).+:/', $sql)) { + return; + } + + // Reverse the binds so that duplicate named binds + // will be processed prior to the original binds. + $binds = array_reverse($binds); + + $this->finalQueryString = $this->matchNamedBinds($sql, $binds); + } } /** diff --git a/tests/system/Database/BaseQueryTest.php b/tests/system/Database/BaseQueryTest.php index fe942ffeb187..cebbe47163ec 100644 --- a/tests/system/Database/BaseQueryTest.php +++ b/tests/system/Database/BaseQueryTest.php @@ -269,7 +269,7 @@ public function testNamedBinds() /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/3566 */ - public function testNamedBindsWithColonElseWhere() + public function testNamedBindsWithColonElsewhere() { $query = new Query($this->db); $query->setQuery('SELECT `email`, @total:=(total+1) FROM `users` WHERE `id` = :id:', ['id' => 10]); @@ -278,6 +278,30 @@ public function testNamedBindsWithColonElseWhere() $this->assertSame($sql, $query->getQuery()); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/pull/5138 + */ + public function testNamedBindsWithBindMarkerElsewhere() + { + $query = new Query($this->db); + $query->setQuery('SELECT * FROM posts WHERE id = :id: AND title = \'The default bind marker is "?"\'', ['id' => 10]); + + $sql = 'SELECT * FROM posts WHERE id = 10 AND title = \'The default bind marker is "?"\''; + $this->assertSame($sql, $query->getQuery()); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/pull/5138 + */ + public function testSimpleBindsWithNamedBindPlaceholderElsewhere() + { + $query = new Query($this->db); + $query->setQuery('SELECT * FROM posts WHERE id = ? AND title = \'A named bind placeholder looks like ":foobar:"\'', 10); + + $sql = 'SELECT * FROM posts WHERE id = 10 AND title = \'A named bind placeholder looks like ":foobar:"\''; + $this->assertSame($sql, $query->getQuery()); + } + /** * @group single * From a8e549b355fb6e17dac11de6b5e5cc1911fb7974 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Sun, 26 Sep 2021 10:16:41 +0200 Subject: [PATCH 0814/2325] Remove tests that are now superfluous MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Simple binds: matchSimpleBinds() also handles the bind marker, and more elaborately: handles enclosing quotes, checks the number of markers… * Named binds: there just won't be replacements for matchNamedBinds() to make. --- system/Database/Query.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index aaf6b6cb9671..1892781e44c0 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -288,7 +288,7 @@ protected function compileBinds() } if (is_numeric(key(array_slice($binds, 0, 1)))) { - if (empty($this->bindMarker) || strpos($sql, $this->bindMarker) === false) { + if (empty($this->bindMarker)) { return; } @@ -296,10 +296,6 @@ protected function compileBinds() $this->finalQueryString = $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); } else { - if (! preg_match('/:(?!=).+:/', $sql)) { - return; - } - // Reverse the binds so that duplicate named binds // will be processed prior to the original binds. $binds = array_reverse($binds); From d1a973869bcc9cfd1b386201c1940ed03a5cfcc0 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Fri, 1 Oct 2021 22:23:49 +0200 Subject: [PATCH 0815/2325] Remove another superfluous test It's very unlikely that the bindMarker property would be empty. --- system/Database/Query.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index 1892781e44c0..64264bf70635 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -288,10 +288,6 @@ protected function compileBinds() } if (is_numeric(key(array_slice($binds, 0, 1)))) { - if (empty($this->bindMarker)) { - return; - } - $ml = strlen($this->bindMarker); $this->finalQueryString = $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); From 211f713f7ac9bc91ebbf734ffe21e923ad272073 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Fri, 1 Oct 2021 22:24:59 +0200 Subject: [PATCH 0816/2325] Some refinement / optimization Considering that $binds is usually an array, and that only matchSimpleBinds() needs the count. --- system/Database/Query.php | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index 64264bf70635..021a360d85c9 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -279,16 +279,11 @@ protected function compileBinds() return; } - if (! is_array($this->binds)) { - $binds = [$this->binds]; - $bindCount = 1; - } else { - $binds = $this->binds; - $bindCount = count($binds); - } + $binds = (array) $this->binds; if (is_numeric(key(array_slice($binds, 0, 1)))) { - $ml = strlen($this->bindMarker); + $bindCount = count($binds); + $ml = strlen($this->bindMarker); $this->finalQueryString = $this->matchSimpleBinds($sql, $binds, $bindCount, $ml); } else { From 2a08bc7a0dc5a7b688fa40a86b43fa745ed7d995 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Tue, 16 Nov 2021 15:25:49 +0100 Subject: [PATCH 0817/2325] Make the test "array is a list" a bit more robust We are looking for an integer, excluding other numeric values (decimals, etc). As a reminder: for array keys, PHP automatically casts strings representing integers to regular integers. --- system/Database/Query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index 021a360d85c9..a2f65f629f8a 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -281,7 +281,7 @@ protected function compileBinds() $binds = (array) $this->binds; - if (is_numeric(key(array_slice($binds, 0, 1)))) { + if (is_int(key(array_slice($binds, 0, 1)))) { $bindCount = count($binds); $ml = strlen($this->bindMarker); From 9d92d56d6401f12bfe2780a6f56886155076bd71 Mon Sep 17 00:00:00 2001 From: vlakoff Date: Tue, 23 Nov 2021 03:04:12 +0100 Subject: [PATCH 0818/2325] Use array_key_first() Same results, but simpler and faster code. Note array_key_first() is available on PHP 7.3+, which is thankfully the minimum PHP version required by CodeIgniter. --- system/Database/Query.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index a2f65f629f8a..f1ec562034c7 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -281,7 +281,7 @@ protected function compileBinds() $binds = (array) $this->binds; - if (is_int(key(array_slice($binds, 0, 1)))) { + if (is_int(array_key_first($binds))) { $bindCount = count($binds); $ml = strlen($this->bindMarker); From 147fc9d8f6cc449c2fd56eb3c9022c43c3dd19e3 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 21 Nov 2021 18:36:02 +0800 Subject: [PATCH 0819/2325] Fix precision loss deprecation on float to int conversion --- system/Images/Handlers/GDHandler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Images/Handlers/GDHandler.php b/system/Images/Handlers/GDHandler.php index 02d61c40a007..ab8e0b7e3dd3 100644 --- a/system/Images/Handlers/GDHandler.php +++ b/system/Images/Handlers/GDHandler.php @@ -188,7 +188,7 @@ protected function process(string $action) imagesavealpha($dest, true); } - $copy($dest, $src, 0, 0, $this->xAxis, $this->yAxis, $this->width, $this->height, $origWidth, $origHeight); + $copy($dest, $src, 0, 0, (int) $this->xAxis, (int) $this->yAxis, $this->width, $this->height, $origWidth, $origHeight); imagedestroy($src); $this->resource = $dest; @@ -472,9 +472,9 @@ protected function textOverlay(string $text, array $options = [], bool $isShadow // Add the shadow to the source image if (! empty($options['fontPath'])) { // We have to add fontheight because imagettftext locates the bottom left corner, not top-left corner. - imagettftext($src, $options['fontSize'], 0, $xAxis, $yAxis + $options['fontheight'], $color, $options['fontPath'], $text); + imagettftext($src, $options['fontSize'], 0, (int) $xAxis, (int) ($yAxis + $options['fontheight']), $color, $options['fontPath'], $text); } else { - imagestring($src, $options['fontSize'], $xAxis, $yAxis, $text, $color); + imagestring($src, (int) $options['fontSize'], (int) $xAxis, (int) $yAxis, $text, $color); } $this->resource = $src; From abab12128ecf8fe1f8920550048d6f064dc862fe Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 14:31:34 +0900 Subject: [PATCH 0820/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/incoming/filters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 334edf188fee..ef2b1991004c 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -193,6 +193,6 @@ In this example, the array ``['dual', 'noreturn']`` will be passed in ``$argumen Provided Filters **************** -These filters are bundled with CodeIgniter4: ``Honeypot``, ``CSRF``, ``DebugToolbar`` and ``InvalidChars``. +The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``DebugToolbar``, and ``InvalidChars``. .. note:: The filters are executed in the declared order that is defined in the config file, but there is one exception to this and it concerns the ``DebugToolbar``, which is always executed last. This is because ``DebugToolbar`` should be able to register everything that happens in other filters. From fe3ab5eb9551fa4445e3bc8c54e8e1dab6fe4bee Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 14:32:54 +0900 Subject: [PATCH 0821/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/incoming/filters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index ef2b1991004c..60e2ea90cc76 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -195,4 +195,4 @@ Provided Filters The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``DebugToolbar``, and ``InvalidChars``. -.. note:: The filters are executed in the declared order that is defined in the config file, but there is one exception to this and it concerns the ``DebugToolbar``, which is always executed last. This is because ``DebugToolbar`` should be able to register everything that happens in other filters. +.. note:: The filters are executed in the order defined in the config file. However, if enabled, ``DebugToolbar`` is always executed last because it should be able to capture everything that happens in the other filters. From e7e492fe6d7cf2a9253d0a918360b415b9447533 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 14:33:36 +0900 Subject: [PATCH 0822/2325] test: add param type Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- tests/system/Filters/InvalidCharsTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 95725de07323..5bfe9268795c 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -144,10 +144,8 @@ public function stringWithLineBreakAndTabProvider() /** * @dataProvider stringWithControlCharsProvider - * - * @param string $input */ - public function testCheckControlStringWithControlCharsCausesException($input) + public function testCheckControlStringWithControlCharsCausesException(string $input) { $this->expectException(SecurityException::class); $this->expectExceptionMessage('Invalid Control characters in get:'); From 70424d61d5b4d00e0b475b49d36a04a29aa2034c Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 14:33:58 +0900 Subject: [PATCH 0823/2325] test: add param type Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- tests/system/Filters/InvalidCharsTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 5bfe9268795c..fb487c7939dc 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -121,10 +121,8 @@ public function testBeforeInvalidControlCharCausesException() * @doesNotPerformAssertions * * @dataProvider stringWithLineBreakAndTabProvider - * - * @param string $input */ - public function testCheckControlStringWithLineBreakAndTabReturnsTheString($input) + public function testCheckControlStringWithLineBreakAndTabReturnsTheString(string $input) { $_GET['val'] = $input; From 72aa844b5c9ba2adb9d2c326e7a2380d85d9285d Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 14:40:36 +0900 Subject: [PATCH 0824/2325] test: replace return with yield from Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- tests/system/Filters/InvalidCharsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index fb487c7939dc..90e106eec97d 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -131,7 +131,7 @@ public function testCheckControlStringWithLineBreakAndTabReturnsTheString(string public function stringWithLineBreakAndTabProvider() { - return [ + yield from [ ["String contains \n line break."], ["String contains \r line break."], ["String contains \r\n line break."], From 9d7e0389a981f0c8e4650fc4c61d8414bd88aa1a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 23 Nov 2021 14:40:43 +0900 Subject: [PATCH 0825/2325] test: replace return with yield from Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- tests/system/Filters/InvalidCharsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Filters/InvalidCharsTest.php b/tests/system/Filters/InvalidCharsTest.php index 90e106eec97d..8724413120b5 100644 --- a/tests/system/Filters/InvalidCharsTest.php +++ b/tests/system/Filters/InvalidCharsTest.php @@ -155,7 +155,7 @@ public function testCheckControlStringWithControlCharsCausesException(string $in public function stringWithControlCharsProvider() { - return [ + yield from [ ["String contains null char.\0"], ["String contains null char and line break.\0\n"], ]; From b8fe16d2ff708971693a5e3325b74447ffb93fdd Mon Sep 17 00:00:00 2001 From: Katherine Date: Tue, 23 Nov 2021 11:49:00 +0000 Subject: [PATCH 0826/2325] fix: BaseModel::insert() may not pass all the values from Entity (#4980) * Update of BaseModel.php to fix INSERT issue Applied the fix that enables the INSERT to work correctly when inserting a row that already contains data. * Update BaseModel.php * Added tests for fix. User.php is an Entity UserObjModel.php returns an entity not StdObj * Updated to simplify usings. * Updated to cleanup test code. * Update tests/system/Models/InsertModelTest.php Co-authored-by: kenjis * Update tests/_support/Entity/User.php Co-authored-by: kenjis Co-authored-by: Katherine Co-authored-by: kenjis --- system/BaseModel.php | 2 +- tests/_support/Entity/User.php | 21 +++++++++++++++++++ tests/_support/Models/UserObjModel.php | 28 +++++++++++++++++++++++++ tests/system/Models/InsertModelTest.php | 22 +++++++++++++++++++ 4 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/_support/Entity/User.php create mode 100644 tests/_support/Models/UserObjModel.php diff --git a/system/BaseModel.php b/system/BaseModel.php index 6b9ef3687817..971303664a8e 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1578,7 +1578,7 @@ protected function transformDataToArray($data, string $type): array // properties representing the collection elements, we need to grab // them as an array. if (is_object($data) && ! $data instanceof stdClass) { - $data = $this->objectToArray($data, true, true); + $data = $this->objectToArray($data, ($type === 'update'), true); } // If it's still a stdClass, go ahead and convert to diff --git a/tests/_support/Entity/User.php b/tests/_support/Entity/User.php new file mode 100644 index 000000000000..dc8a3954341d --- /dev/null +++ b/tests/_support/Entity/User.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Entity; + +use CodeIgniter\Entity\Entity; + +class User extends Entity +{ + protected $attributes = [ + 'country' => 'India', + ]; +} diff --git a/tests/_support/Models/UserObjModel.php b/tests/_support/Models/UserObjModel.php new file mode 100644 index 000000000000..ea461ec64fb3 --- /dev/null +++ b/tests/_support/Models/UserObjModel.php @@ -0,0 +1,28 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace Tests\Support\Models; + +use CodeIgniter\Model; + +class UserObjModel extends Model +{ + protected $table = 'user'; + protected $allowedFields = [ + 'name', + 'email', + 'country', + 'deleted_at', + ]; + protected $returnType = \Tests\Support\Entity\User::class; + protected $useSoftDeletes = true; + protected $dateFormat = 'datetime'; +} diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index d08db6f87ac8..2bcc912e3d80 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -15,8 +15,10 @@ use CodeIgniter\Entity\Entity; use CodeIgniter\I18n\Time; use stdClass; +use Tests\Support\Entity\User; use Tests\Support\Models\JobModel; use Tests\Support\Models\UserModel; +use Tests\Support\Models\UserObjModel; use Tests\Support\Models\WithoutAutoIncrementModel; /** @@ -286,4 +288,24 @@ public function testInsertWithSetAndEscape(): void $this->assertCloseEnough(time(), strtotime($result->created_at)); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/4247 + */ + public function testInsertWithDefaultValue(): void + { + $this->createModel(UserObjModel::class); + + $entity = new User(); + $entity->name = 'Mark'; + $entity->email = 'mark@example.com'; + $entity->country = 'India'; // same as the default + $entity->deleted = 0; + $entity->created_at = new Time('now'); + + $this->model->insert($entity); + + $id = $this->model->getInsertID(); + $this->assertSame($entity->country, $this->model->find($id)->country); + } } From 3497170a595f99238ce50bd8381cb94258591535 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 09:53:25 +0900 Subject: [PATCH 0827/2325] fix: make sure $this->tableName is string --- system/Database/BaseBuilder.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index b0ea12416683..0d7ca807a036 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -158,6 +158,9 @@ class BaseBuilder * Tracked separately because $QBFrom gets escaped * and prefixed. * + * When $tableName to the constructor has multiple tables, + * the value is empty string. + * * @var string */ protected $tableName; @@ -276,7 +279,13 @@ public function __construct($tableName, ConnectionInterface &$db, ?array $option */ $this->db = $db; - $this->tableName = $tableName; + // If it contains `,`, it has multiple tables + if (is_string($tableName) && strpos($tableName, ',') === false) { + $this->tableName = $tableName; // @TODO remove alias if exists + } else { + $this->tableName = ''; + } + $this->from($tableName); if (! empty($options)) { From 82e27ba2eb20892b0133645a44f9d349f5cc5430 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 09:55:47 +0900 Subject: [PATCH 0828/2325] docs: make comment more detailed --- system/Database/BaseBuilder.php | 4 +++- system/Database/BaseConnection.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 0d7ca807a036..fecf3e10718f 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -264,7 +264,9 @@ class BaseBuilder /** * Constructor * - * @param array|string $tableName + * @param array|string $tableName tablename or tablenames with or without aliases + * + * Examples of $tableName: `mytable`, `jobs j`, `jobs j, users u`, `['jobs j','users u']` * * @throws DatabaseException */ diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index b7168259e631..f2ceb5a0f907 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -835,7 +835,7 @@ abstract protected function _transCommit(): bool; abstract protected function _transRollback(): bool; /** - * Returns an instance of the query builder for this connection. + * Returns a non-shared new instance of the query builder for this connection. * * @param array|string $tableName * From d22c6f14ece4f603184942c73ff5e26780d6458c Mon Sep 17 00:00:00 2001 From: vlakoff Date: Wed, 24 Nov 2021 04:48:32 +0100 Subject: [PATCH 0829/2325] Remove unneeded cast to array As discussed on GitHub PR #5138, $this->binds is not expected to be something else than an array. --- system/Database/Query.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index f1ec562034c7..91b98c77d2ef 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -273,14 +273,13 @@ public function getOriginalQuery(): string */ protected function compileBinds() { - $sql = $this->finalQueryString; + $sql = $this->finalQueryString; + $binds = $this->binds; - if (empty($this->binds)) { + if (empty($binds)) { return; } - $binds = (array) $this->binds; - if (is_int(array_key_first($binds))) { $bindCount = count($binds); $ml = strlen($this->bindMarker); From 0f3ce86e425847ba3518425000cbe3258cf919c1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 13:22:15 +0900 Subject: [PATCH 0830/2325] docs: fix incorrect explanation on getCompiledInsert() It has only one parameter in CI4. --- user_guide_src/source/database/query_builder.rst | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index a05fb25f8159..7aa8cf69dcdb 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -886,15 +886,15 @@ Example:: 'date' => 'My date', ]; - $sql = $builder->set($data)->getCompiledInsert('mytable'); + $sql = $builder->set($data)->getCompiledInsert(); echo $sql; // Produces string: INSERT INTO mytable (`title`, `name`, `date`) VALUES ('My title', 'My name', 'My date') -The second parameter enables you to set whether or not the query builder query +The first parameter enables you to set whether or not the query builder query will be reset (by default it will be--just like ``$builder->insert()``):: - echo $builder->set('title', 'My Title')->getCompiledInsert('mytable', false); + echo $builder->set('title', 'My Title')->getCompiledInsert(false); // Produces string: INSERT INTO mytable (`title`) VALUES ('My Title') @@ -902,9 +902,7 @@ will be reset (by default it will be--just like ``$builder->insert()``):: // Produces string: INSERT INTO mytable (`title`, `content`) VALUES ('My Title', 'My Content') -The key thing to notice in the above example is that the second query did not -utilize ``$builder->from()`` nor did it pass a table name into the first -parameter. The reason this worked is that the query has not been executed +The reason the second query worked is that the query has not been executed using ``$builder->insert()`` which resets values or reset directly using ``$builder->resetQuery()``. From 81859f2920148fa7e95a0cceadfaf06fa09ee98f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 14:30:14 +0900 Subject: [PATCH 0831/2325] docs: change from important to warning It is security thing. --- user_guide_src/source/general/configuration.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index ac31e6f3241a..7543802f39ad 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -115,7 +115,7 @@ overwritten. The loaded Environment variables are accessed using any of the foll $s3_bucket = $_ENV['S3_BUCKET']; $s3_bucket = $_SERVER['S3_BUCKET']; -.. important:: Note that your settings from the **.env** file are added to Environment Variables. As a side effect, this means that if your CodeIgniter application is (for example) generating a ``var_dump($_ENV)`` or ``phpinfo()`` (for debugging or other valid reasons) **your secure credentials are publicly exposed**. +.. warning:: Note that your settings from the **.env** file are added to Environment Variables. As a side effect, this means that if your CodeIgniter application is (for example) generating a ``var_dump($_ENV)`` or ``phpinfo()`` (for debugging or other valid reasons) **your secure credentials are publicly exposed**. Nesting Variables ================= From 954cc0d8c85e8545b0402156f50bbd632f6db787 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 14:37:04 +0900 Subject: [PATCH 0832/2325] docs: add ::class sample --- user_guide_src/source/general/configuration.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index 7543802f39ad..b1016b939c9b 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -31,7 +31,8 @@ You can access configuration files for your classes in several different ways. $config = config('Pager'); // Access config class with namespace - $config = config( 'Config\\Pager' ); + $config = config('Config\\Pager'); + $config = config(\Config\Pager::class); // Creating a new object with config function $config = config('Pager', false); From e452d510ad374cbb4040018c21af53f80db36f18 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 14:37:37 +0900 Subject: [PATCH 0833/2325] docs: fix RST format --- user_guide_src/source/general/configuration.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index b1016b939c9b..813f523c7fa2 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -122,8 +122,7 @@ Nesting Variables ================= To save on typing, you can reuse variables that you've already specified in the file by wrapping the -variable name within ``${...}`` -:: +variable name within ``${...}``:: BASE_DIR="/var/webroot/project-root" CACHE_DIR="${BASE_DIR}/cache" From f990c7f9be275f054a73426e1cc7993756a1e965 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 14:52:22 +0900 Subject: [PATCH 0834/2325] docs: add reference from Module Routes to Route processing queue --- user_guide_src/source/general/modules.rst | 3 +++ user_guide_src/source/incoming/routing.rst | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 91ec5554c955..19797b099416 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -153,6 +153,9 @@ the **Modules** config file, described above. .. note:: Since the files are being included into the current scope, the ``$routes`` instance is already defined for you. It will cause errors if you attempt to redefine that class. +When working with modules, it can be a problem if the routes in the application contain wildcards. +In that case, see :ref:`routing-priority`. + Filters ======= diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 5f18fb4960d8..be571d34b736 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -456,7 +456,7 @@ be used when the first parameter is a language string:: // Creates: $routes['users/(:num)'] = 'users/show/$2'; -.. _priority: +.. _routing-priority: Route processing queue ---------------------- @@ -590,7 +590,7 @@ Route processing by priority Enables or disables processing of the routes queue by priority. Lowering the priority is defined in the route option. Disabled by default. This functionality affects all routes. -For an example of use lowering the priority see :ref:`priority`:: +For an example of use lowering the priority see :ref:`routing-priority`:: // to enable $routes->setPrioritize(); From dfa5229145de49c9e31556129959e87901c2d262 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 15:25:52 +0900 Subject: [PATCH 0835/2325] docs: replace PSR* with PSR-* --- user_guide_src/source/concepts/autoloader.rst | 4 ++-- user_guide_src/source/general/logging.rst | 4 ++-- user_guide_src/source/general/modules.rst | 6 +++--- user_guide_src/source/installation/upgrade_4xx.rst | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index 543d70323bc6..beb8da256f0b 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -11,7 +11,7 @@ headache and very error-prone. That's where autoloaders come in. CodeIgniter provides a very flexible autoloader that can be used with very little configuration. It can locate individual non-namespaced classes, namespaced classes that adhere to -`PSR4 `_ autoloading +`PSR-4 `_ autoloading directory structures, and will even attempt to locate classes in common directories (like Controllers, Models, etc). @@ -30,7 +30,7 @@ Configuration ============= Initial configuration is done in **/app/Config/Autoload.php**. This file contains two primary -arrays: one for the classmap, and one for PSR4-compatible namespaces. +arrays: one for the classmap, and one for PSR-4 compatible namespaces. Namespaces ========== diff --git a/user_guide_src/source/general/logging.rst b/user_guide_src/source/general/logging.rst index 7fa706ce6a86..761500ac722a 100644 --- a/user_guide_src/source/general/logging.rst +++ b/user_guide_src/source/general/logging.rst @@ -136,8 +136,8 @@ Using Third-Party Loggers ========================= You can use any other logger that you might like as long as it extends from either -``Psr\Log\LoggerInterface`` and is `PSR3 `_ compatible. This means -that you can easily drop in use for any PSR3-compatible logger, or create your own. +``Psr\Log\LoggerInterface`` and is `PSR-3 `_ compatible. This means +that you can easily drop in use for any PSR-3 compatible logger, or create your own. You must ensure that the third-party logger can be found by the system, by adding it to either the **app/Config/Autoload.php** configuration file, or through another autoloader, diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 91ec5554c955..7aea12358fdb 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -15,8 +15,8 @@ language files, etc. Modules may contain as few, or as many, of these as you lik Namespaces ========== -The core element of the modules functionality comes from the :doc:`PSR4-compatible autoloading ` -that CodeIgniter uses. While any code can use the PSR4 autoloader and namespaces, the primary way to take full advantage of +The core element of the modules functionality comes from the :doc:`PSR-4 compatible autoloading ` +that CodeIgniter uses. While any code can use the PSR-4 autoloader and namespaces, the primary way to take full advantage of modules is to namespace your code and add it to **app/Config/Autoload.php**, in the ``psr4`` section. For example, let's say we want to keep a simple blog module that we can re-use between applications. We might create @@ -129,7 +129,7 @@ Discovery and Composer ====================== Packages that were installed via Composer will also be discovered by default. This only requires that the namespace -that Composer knows about is a PSR4 namespace. PSR0 namespaces will not be detected. +that Composer knows about is a PSR-4 namespace. PSR-0 namespaces will not be detected. If you do not want all of Composer's known directories to be scanned when locating files, you can turn this off by editing the ``$discoverInComposer`` variable in ``Config\Modules.php``:: diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index 76fdba16c8e0..ae6bd0188608 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -77,7 +77,7 @@ General Adjustments references magically injected as properties of your controller. - Classes are instantiated where needed, and components are managed by ``Services``. -- The class loader automatically handles PSR4 style class locating, +- The class loader automatically handles PSR-4 style class locating, within the ``App`` (application) and ``CodeIgniter`` (i.e., system) top level namespaces; with composer autoloading support, and even using educated guessing to find your models and libraries if they are in the right From 0ba441a1518d9d80d00cac076f28eb27d670bd38 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 15:38:59 +0900 Subject: [PATCH 0836/2325] docs: change lang file sample filename to uppercase first --- user_guide_src/source/outgoing/localization.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 97d3fbdf6d5e..996224fc2c72 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -20,9 +20,9 @@ supported language:: /app /Language /en - app.php + App.php /fr - app.php + App.php .. important:: Locale detection only works for web-based requests that use the IncomingRequest class. Command-line requests will not have these features. From 025d27a76daeab7e7c0bef2688db8eb7ec103aed Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 15:40:42 +0900 Subject: [PATCH 0837/2325] docs: change lang key to camelCase --- user_guide_src/source/outgoing/localization.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 996224fc2c72..f9e0693abfcb 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -119,11 +119,11 @@ You might name it simply: **Errors.php**. Within the file, you would return an array, where each element in the array has a language key and can have string to return:: - 'language_key' => 'The actual message to be shown.' + 'languageKey' => 'The actual message to be shown.' It also support nested definition:: - 'language_key' => [ + 'languageKey' => [ 'nested' => [ 'key' => 'The actual message to be shown.', ], From a7fc1bed9e4d740cc440e591296c9ef169968e90 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 15:41:09 +0900 Subject: [PATCH 0838/2325] docs: remove out-of-dated note It seems about CI3. --- user_guide_src/source/outgoing/localization.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index f9e0693abfcb..4c78ed39ee44 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -129,10 +129,6 @@ It also support nested definition:: ], ], -.. note:: It's good practice to use a common prefix for all messages in a given file to avoid collisions with - similarly named items in other files. For example, if you are creating error messages you might prefix them - with error\_ - :: return [ From 96381ea4a8cbeff2be980785074ea1b8b0ace478 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 15:41:56 +0900 Subject: [PATCH 0839/2325] docs: replace " with ' in sample code No reason to use `"`. --- user_guide_src/source/outgoing/localization.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 4c78ed39ee44..58b24c48524f 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -170,9 +170,9 @@ You can pass an array of values to replace placeholders in the language string a // The language file, Tests.php: return [ - "apples" => "I have {0, number} apples.", - "men" => "The top {1, number} men out-performed the remaining {0, number}", - "namedApples" => "I have {number_apples, number, integer} apples.", + 'apples' => 'I have {0, number} apples.', + 'men' => 'The top {1, number} men out-performed the remaining {0, number}', + 'namedApples' => 'I have {number_apples, number, integer} apples.', ]; // Displays "I have 3 apples." @@ -186,7 +186,7 @@ The first item in the placeholder corresponds to the index of the item in the ar You can also use named keys to make it easier to keep things straight, if you'd like:: // Displays "I have 3 apples." - echo lang("Tests.namedApples", ['number_apples' => 3]); + echo lang('Tests.namedApples', ['number_apples' => 3]); Obviously, you can do more than just number replacement. According to the `official ICU docs `_ for the underlying From 95a0ed59f17e3d5495bc4ac187b43d9829ae5df1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 24 Nov 2021 18:38:48 +0900 Subject: [PATCH 0840/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index be571d34b736..0e9f3bb4e6be 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -590,7 +590,7 @@ Route processing by priority Enables or disables processing of the routes queue by priority. Lowering the priority is defined in the route option. Disabled by default. This functionality affects all routes. -For an example of use lowering the priority see :ref:`routing-priority`:: +For an example use of lowering the priority see :ref:`routing-priority`:: // to enable $routes->setPrioritize(); From 9edc247dbafae08f5e55c2b0e41ad18175e14afe Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Wed, 24 Nov 2021 20:57:38 +0700 Subject: [PATCH 0841/2325] update line numbers about Paths.php --- user_guide_src/source/general/managing_apps.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index c1781e032fa0..21fcebdf9407 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -14,14 +14,14 @@ Renaming or Relocating the Application Directory If you would like to rename your application directory or even move it to a different location on your server, other than your project root, open your main **app/Config/Paths.php** and set a *full server path* in the -``$appDirectory`` variable (at about line 45):: +``$appDirectory`` variable (at about line 44):: public $appDirectory = '/path/to/your/application'; You will need to modify two additional files in your project root, so that they can find the ``Paths`` configuration file: -- ``/spark`` runs command line apps; the path is specified on or about line 36:: +- ``/spark`` runs command line apps; the path is specified on or about line 35:: $pathsConfig = 'app/Config/Paths.php'; // ^^^ Change this line if you move your application folder From bead7d01437aaef5f22f6e7bc9b8ff078859ae00 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 24 Nov 2021 15:03:44 +0000 Subject: [PATCH 0842/2325] chore(deps-dev): update rector/rector requirement from 0.12.4 to 0.12.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.12.4...0.12.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 4e3ebda66819..064f7b392e05 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.4" + "rector/rector": "0.12.5" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From 9def2430108d867615145e612419f64f7dc8f194 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 15 Nov 2021 13:23:58 +0900 Subject: [PATCH 0843/2325] chore: add PHPUnitSetList::PHPUNIT_80 and remove skip of AssertFalseStrposToContainsRector --- rector.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rector.php b/rector.php index 829ec303e0f4..92636b0bfdd5 100644 --- a/rector.php +++ b/rector.php @@ -42,7 +42,6 @@ use Rector\Php71\Rector\FuncCall\CountOnNullRector; use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; -use Rector\PHPUnit\Rector\MethodCall\AssertFalseStrposToContainsRector; use Rector\PHPUnit\Rector\MethodCall\AssertIssetToSpecificMethodRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\LevelSetList; @@ -57,6 +56,7 @@ $containerConfigurator->import(SetList::DEAD_CODE); $containerConfigurator->import(LevelSetList::UP_TO_PHP_73); $containerConfigurator->import(PHPUnitSetList::PHPUNIT_SPECIFIC_METHOD); + $containerConfigurator->import(PHPUnitSetList::PHPUNIT_80); $parameters = $containerConfigurator->parameters(); @@ -122,9 +122,6 @@ __DIR__ . '/tests/system/Entity/EntityTest.php', __DIR__ . '/tests/system/Session/SessionTest.php', ], - - // assertContains() to string can't be used in PHPUnit 9.1 - AssertFalseStrposToContainsRector::class, ]); // auto import fully qualified class names From 3cf95b599a59a1569378aa20fe944e096bc6ca4a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 15 Nov 2021 13:25:13 +0900 Subject: [PATCH 0844/2325] test: refactor: vendor/bin/rector process tests/system/ --- tests/system/HTTP/ResponseTest.php | 4 ++-- tests/system/View/ViewTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index 64eab48dc0fa..b4eba4c547c9 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -327,7 +327,7 @@ public function testJSONWithArray() $response->setJSON($body); $this->assertSame($expected, $response->getJSON()); - $this->assertNotFalse(strpos($response->getHeaderLine('content-type'), 'application/json')); + $this->assertStringContainsString('application/json', $response->getHeaderLine('content-type')); } public function testJSONGetFromNormalBody() @@ -364,7 +364,7 @@ public function testXMLWithArray() $response->setXML($body); $this->assertSame($expected, $response->getXML()); - $this->assertNotFalse(strpos($response->getHeaderLine('content-type'), 'application/xml')); + $this->assertStringContainsString('application/xml', $response->getHeaderLine('content-type')); } public function testXMLGetFromNormalBody() diff --git a/tests/system/View/ViewTest.php b/tests/system/View/ViewTest.php index 435c4d8f9578..d740e17a4c34 100644 --- a/tests/system/View/ViewTest.php +++ b/tests/system/View/ViewTest.php @@ -316,8 +316,8 @@ public function testRenderLayoutWithInclude() $content = $view->render('extend_include'); - $this->assertNotFalse(strpos($content, '

    Open

    ')); - $this->assertNotFalse(strpos($content, '

    Hello World

    ')); + $this->assertStringContainsString('

    Open

    ', $content); + $this->assertStringContainsString('

    Hello World

    ', $content); $this->assertSame(2, substr_count($content, 'Hello World')); } From 6cd24700ac3be69e776e0d9db1c5df5447299505 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 25 Nov 2021 12:08:40 +0800 Subject: [PATCH 0845/2325] Additional fix for deprecated `null` usage --- system/HTTP/IncomingRequest.php | 2 +- system/Validation/FormatRules.php | 22 ++++++++++++++++------ system/Validation/Rules.php | 10 +++++++++- 3 files changed, 26 insertions(+), 8 deletions(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 3ac25b6df5fd..76b0c1d1c40a 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -565,7 +565,7 @@ public function getJsonVar(string $index, bool $assoc = false, ?int $filter = nu */ public function getRawInput() { - parse_str($this->body, $output); + parse_str($this->body ?? '', $output); return $output; } diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index e28f6d6af13d..4d02f221365d 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -45,11 +45,16 @@ public function alpha_space(?string $value = null): bool /** * Alphanumeric with underscores and dashes + * + * @see https://regex101.com/r/XfVY3d/1 */ public function alpha_dash(?string $str = null): bool { - // @see https://regex101.com/r/XfVY3d/1 - return (bool) preg_match('/\A[a-z0-9_-]+\z/i', $str); + if ($str === null) { + return false; + } + + return preg_match('/\A[a-z0-9_-]+\z/i', $str) === 1; } /** @@ -59,14 +64,19 @@ public function alpha_dash(?string $str = null): bool * _ underscore, + plus, = equals, | vertical bar, : colon, . period * ~ ! # $ % & * - _ + = | : . * - * @param string $str + * @param string|null $str * * @return bool + * + * @see https://regex101.com/r/6N8dDY/1 */ public function alpha_numeric_punct($str) { - // @see https://regex101.com/r/6N8dDY/1 - return (bool) preg_match('/\A[A-Z0-9 ~!#$%\&\*\-_+=|:.]+\z/i', $str); + if ($str === null) { + return false; + } + + return preg_match('/\A[A-Z0-9 ~!#$%\&\*\-_+=|:.]+\z/i', $str) === 1; } /** @@ -307,7 +317,7 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu return false; } - $scheme = strtolower(parse_url($str, PHP_URL_SCHEME)); + $scheme = strtolower(parse_url($str, PHP_URL_SCHEME) ?? ''); // absent scheme gives null $validSchemes = explode( ',', strtolower($validSchemes ?? 'http,https') diff --git a/system/Validation/Rules.php b/system/Validation/Rules.php index 367915ebae35..aba9ff117df6 100644 --- a/system/Validation/Rules.php +++ b/system/Validation/Rules.php @@ -213,11 +213,19 @@ public function not_in_list(?string $value, string $list): bool */ public function required($str = null): bool { + if ($str === null) { + return false; + } + if (is_object($str)) { return true; } - return is_array($str) ? ! empty($str) : (trim($str) !== ''); + if (is_array($str)) { + return $str !== []; + } + + return trim((string) $str) !== ''; } /** From b2f49be433d3c195be5fc3cfd76eb417e1034ca7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 25 Nov 2021 13:28:11 +0900 Subject: [PATCH 0846/2325] docs: improve explanation --- user_guide_src/source/general/modules.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index 0c38a36bb14b..15a4040f020a 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -128,8 +128,8 @@ present, then no auto-discovery will happen for that item, but the others in the Discovery and Composer ====================== -Packages that were installed via Composer will also be discovered by default. This only requires that the namespace -that Composer knows about is a PSR-4 namespace. PSR-0 namespaces will not be detected. +Packages installed via Composer using PSR-4 namespaces will also be discovered by default. +PSR-0 namespaced packages will not be detected. If you do not want all of Composer's known directories to be scanned when locating files, you can turn this off by editing the ``$discoverInComposer`` variable in ``Config\Modules.php``:: From 0a5508202b1c08928c7bcb863837a8a119951b32 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 25 Nov 2021 22:24:19 +0800 Subject: [PATCH 0847/2325] Add support for PHP 8.1 (#4883) --- .github/workflows/test-phpunit.yml | 36 ++++++++++++++---------------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index aa7d584991a6..4583244ed358 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -4,12 +4,7 @@ on: push: branches: - develop - - '4.*' paths: - - 'app/**' - - 'public/**' - - 'system/**' - - 'tests/**' - composer.json - spark - phpunit.xml.dist @@ -18,12 +13,7 @@ on: pull_request: branches: - develop - - '4.*' paths: - - 'app/**' - - 'public/**' - - 'system/**' - - 'tests/**' - composer.json - spark - phpunit.xml.dist @@ -31,22 +21,24 @@ on: - .github/workflows/test-phpunit.yml jobs: - tests: + name: PHP ${{ matrix.php-versions }} - ${{ matrix.db-platforms }} runs-on: ubuntu-20.04 if: "!contains(github.event.head_commit.message, '[ci skip]')" - name: PHP ${{ matrix.php-versions }} - ${{ matrix.db-platforms }} strategy: fail-fast: false matrix: - php-versions: ['7.3', '7.4', '8.0'] + php-versions: ['7.3', '7.4', '8.0', '8.1'] db-platforms: ['MySQLi', 'Postgre', 'SQLite3', 'SQLSRV'] mysql-versions: ['5.7'] include: - php-versions: '7.4' db-platforms: MySQLi mysql-versions: '8.0' + # @todo remove once 8.1 is stable enough + - php-versions: '8.1' + composer-flag: '--ignore-platform-req=php' services: mysql: @@ -57,6 +49,7 @@ jobs: ports: - 3306:3306 options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 + postgres: image: postgres env: @@ -66,6 +59,7 @@ jobs: ports: - 5432:5432 options: --health-cmd=pg_isready --health-interval=10s --health-timeout=5s --health-retries=3 + mssql: image: mcr.microsoft.com/mssql/server:2019-CU10-ubuntu-20.04 env: @@ -75,11 +69,13 @@ jobs: ports: - 1433:1433 options: --health-cmd="/opt/mssql-tools/bin/sqlcmd -S 127.0.0.1 -U sa -P 1Secure*Password1 -Q 'SELECT @@VERSION'" --health-interval=10s --health-timeout=5s --health-retries=3 + redis: image: redis ports: - 6379:6379 options: --health-cmd "redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3 + memcached: image: memcached:1.6-alpine ports: @@ -105,6 +101,7 @@ jobs: - name: Install latest ImageMagick run: | + sudo apt-get update sudo apt-get install --reinstall libgs9-common fonts-noto-mono libgs9:amd64 libijs-0.35:amd64 fonts-urw-base35 ghostscript poppler-data libjbig2dec0:amd64 gsfonts libopenjp2-7:amd64 fonts-droid-fallback ttf-dejavu-core sudo apt-get install -y imagemagick sudo apt-get install --fix-broken @@ -122,13 +119,13 @@ jobs: - name: Install dependencies run: | - composer update --ansi --no-interaction - composer remove --ansi --dev --unused -W rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config codeigniter/coding-standard + composer update --ansi --no-interaction ${{ matrix.composer-flag }} + composer remove --ansi --dev --unused -W ${{ matrix.composer-flag }} -- rector/rector phpstan/phpstan friendsofphp/php-cs-fixer nexusphp/cs-config codeigniter/coding-standard env: COMPOSER_AUTH: ${{ secrets.COMPOSER_AUTH }} - - name: Profile slow tests in PHP 7.4 MySQLi for now - if: matrix.php-versions == '7.4' && matrix.db-platforms == 'MySQLi' + - name: Profile slow tests in PHP 8.0 + if: matrix.php-versions == '8.0' run: echo "TACHYCARDIA_MONITOR_GA=enabled" >> $GITHUB_ENV - name: Test with PHPUnit @@ -137,8 +134,8 @@ jobs: DB: ${{ matrix.db-platforms }} TERM: xterm-256color - - if: github.repository_owner == 'codeigniter4' && matrix.php-versions == '7.4' - name: Run Coveralls + - name: Run Coveralls + if: github.repository_owner == 'codeigniter4' && matrix.php-versions == '8.0' run: | composer global require --ansi php-coveralls/php-coveralls:^2.4 php-coveralls --coverage_clover=build/logs/clover.xml -v @@ -151,6 +148,7 @@ jobs: if: github.repository_owner == 'codeigniter4' needs: [tests] runs-on: ubuntu-20.04 + steps: - name: Coveralls Finished uses: coverallsapp/github-action@master From 567f0c6507941ffbac0cfeb55e2cc19f84ab6944 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 08:53:44 +0900 Subject: [PATCH 0848/2325] fix: IncomingRequest::getJsonVar() may cause TypeError See #5391 [TypeError] dot_array_search(): Argument #2 ($array) must be of type array, null given, called in .../system/HTTP/IncomingRequest.php on line 540 at SYSTEMPATH/Helpers/array_helper.php:21 --- system/HTTP/IncomingRequest.php | 6 +++++- tests/system/HTTP/IncomingRequestTest.php | 23 +++++++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 76b0c1d1c40a..ea5b968a6f79 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -537,7 +537,11 @@ public function getJsonVar(string $index, bool $assoc = false, ?int $filter = nu { helper('array'); - $data = dot_array_search($index, $this->getJSON(true)); + $json = $this->getJSON(true); + if (! is_array($json)) { + return null; + } + $data = dot_array_search($index, $json); if ($data === null) { return null; diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 3b14c6a03357..4229d5d264ec 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -394,6 +394,29 @@ public function testGetVarWorksWithJsonAndGetParams() $this->assertSame('buzz', $all['fizz']); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5391 + */ + public function testGetJsonVarReturnsNullFromNullBody() + { + $config = new App(); + $config->baseURL = 'http://example.com/'; + $json = null; + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + + $this->assertNull($request->getJsonVar('myKey')); + } + + public function testgetJSONReturnsNullFromNullBody() + { + $config = new App(); + $config->baseURL = 'http://example.com/'; + $json = null; + $request = new IncomingRequest($config, new URI(), $json, new UserAgent()); + + $this->assertNull($request->getJSON()); + } + public function testCanGrabGetRawInput() { $rawstring = 'username=admin001&role=administrator&usepass=0'; From 9c9c4d2e15805ecfa0163469021ac49c13ff14f8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 09:24:11 +0900 Subject: [PATCH 0849/2325] fix: passing null to parameter of type string ErrorException: json_decode(): Passing null to parameter #1 ($json) of type string is deprecated --- system/HTTP/IncomingRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index ea5b968a6f79..071b18e97d00 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -520,7 +520,7 @@ public function getVar($index = null, $filter = null, $flags = null) */ public function getJSON(bool $assoc = false, int $depth = 512, int $options = 0) { - return json_decode($this->body, $assoc, $depth, $options); + return json_decode($this->body ?? '', $assoc, $depth, $options); } /** From ed0207d29a86c00c2e1b95ad22b142c0f440c9d1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 14:43:00 +0900 Subject: [PATCH 0850/2325] docs: add space after `//` in sample code --- user_guide_src/source/incoming/incomingrequest.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index d08bf8470f70..63a4aa5266df 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -149,7 +149,7 @@ data that you want or you can use "dot" notation to dig into the JSON to get dat :: - //With a request body of: + // With a request body of: { "foo": "bar", "fizz": { @@ -157,10 +157,10 @@ data that you want or you can use "dot" notation to dig into the JSON to get dat } } $data = $request->getVar('foo'); - //$data = "bar" + // $data = "bar" $data = $request->getVar('fizz.buzz'); - //$data = "baz" + // $data = "baz" If you want the result to be an associative array instead of an object, you can use ``getJsonVar()`` instead and pass @@ -169,12 +169,12 @@ correct ``CONTENT_TYPE`` header. :: - //With the same request as above + // With the same request as above $data = $request->getJsonVar('fizz'); - //$data->buzz = "baz" + // $data->buzz = "baz" $data = $request->getJsonVar('fizz', true); - //$data = ["buzz" => "baz"] + // $data = ["buzz" => "baz"] .. note:: See the documentation for ``dot_array_search()`` in the ``Array`` helper for more information on "dot" notation. From 59d1b74effaa4db8a3faaa8526186d373adce8fb Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 17:13:29 +0900 Subject: [PATCH 0851/2325] docs: fix about class loading Update application folder name. Remove about Legacy Support which was removed in 4.1.0. --- user_guide_src/source/installation/upgrade_4xx.rst | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index ae6bd0188608..6b693b3101cb 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -78,10 +78,8 @@ General Adjustments - Classes are instantiated where needed, and components are managed by ``Services``. - The class loader automatically handles PSR-4 style class locating, - within the ``App`` (application) and ``CodeIgniter`` (i.e., system) top level - namespaces; with composer autoloading support, and even using educated - guessing to find your models and libraries if they are in the right - folder even though not namespaced. + within the ``App`` (**app**) and ``CodeIgniter`` (i.e., **system**) top level + namespaces; with Composer autoloading support. - You can configure the class loading to support whatever application structure you are most comfortable with, including the "HMVC" style. From c28b5d10fc3c2049daaf34f8b703a418e7b89772 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 17:19:31 +0900 Subject: [PATCH 0852/2325] docs: decorate file paths with ** --- .../source/installation/upgrade_4xx.rst | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index 6b693b3101cb..d4f219d4d7a3 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -39,26 +39,26 @@ General Adjustments **Application Structure** -- The ``application`` folder is renamed as ``app`` and the framework still has ``system`` folders, +- The **application** folder is renamed as **app** and the framework still has **system** folders, with the same interpretation as before. -- The framework now provides for a ``public`` folder, intended as the document root for your app. -- There is also a ``writable`` folder, to hold cache data, logs, and session data. -- The ``app`` folder looks very similar to ``application`` for CI3, with some - name changes, and some subfolders moved to the ``writable`` folder. -- There is no longer a nested ``application/core`` folder, as we have +- The framework now provides for a **public** folder, intended as the document root for your app. +- There is also a **writable** folder, to hold cache data, logs, and session data. +- The **app** folder looks very similar to **application** for CI3, with some + name changes, and some subfolders moved to the **writable** folder. +- There is no longer a nested **application/core** folder, as we have a different mechanism for extending framework components (see below). **Model, View and Controller** - CodeIgniter is based on the MVC concept. Thus, the changes on the Model, View and Controller are one of the most important things you have to handle. -- In CodeIgniter 4, models are now located in ``app/Models`` and you have to add the lines +- In CodeIgniter 4, models are now located in **app/Models** and you have to add the lines ``namespace App\Models;`` along with ``use CodeIgniter\Model;`` right after the opening php tag. The last step is to replace ``extends CI_Model`` with ``extends Model``. -- The views of CodeIgniter 4 have been moved ``to app/Views``. Furthermore, you have to change +- The views of CodeIgniter 4 have been moved to **app/Views**. Furthermore, you have to change the syntax of loading views from ``$this->load->view('directory_name/file_name')`` to ``echo view('directory_name/file_name');``. -- Controllers of CodeIgniter 4 have to be moved to ``app/Controllers;``. After that, +- Controllers of CodeIgniter 4 have to be moved to **app/Controllers**. After that, add ``namespace App\Controllers;`` after the opening php tag. Lastly, replace ``extends CI_Controller`` with ``extends BaseController``. - For more information we recommend you the following upgrade guides, which will give @@ -85,7 +85,7 @@ General Adjustments **Libraries** -- Your app classes can still go inside ``app/Libraries``, but they don't have to. +- Your app classes can still go inside **app/Libraries**, but they don't have to. - Instead of CI3's ``$this->load->library(x);`` you can now use ``$this->x = new X();``, following namespaced conventions for your component. @@ -105,18 +105,18 @@ General Adjustments **Extending the framework** -- You don't need a ``core`` folder to hold ``MY_...`` framework +- You don't need a **core** folder to hold ``MY_...`` framework component extensions or replacements. - You don't need ``MY_x`` classes inside your libraries folder to extend or replace CI4 pieces. - Make any such classes where you like, and add appropriate - service methods in ``app/Config/Services.php`` to load + service methods in **app/Config/Services.php** to load your components instead of the default ones. Upgrading Libraries =================== -- Your app classes can still go inside ``app/Libraries``, but they don’t have to. +- Your app classes can still go inside **app/Libraries**, but they don’t have to. - Instead of CI3’s ``$this->load->library(x);`` you can now use ``$this->x = new X();``, following namespaced conventions for your component. - Some libraries from CodeIgniter 3 no longer exists in Version 4. For all these From a467f3a5ea73def182494dbb0a3cc46cfa9f739e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 18:33:50 +0900 Subject: [PATCH 0853/2325] docs: add settings and devkit repositories --- .../source/installation/repositories.rst | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/installation/repositories.rst b/user_guide_src/source/installation/repositories.rst index 9e4e0abc9db9..e35de088e99e 100644 --- a/user_guide_src/source/installation/repositories.rst +++ b/user_guide_src/source/installation/repositories.rst @@ -6,15 +6,21 @@ The CodeIgniter 4 open source project has its own There are several development repositories, of interest to potential contributors: -+---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ -| Repository | Audience | Description | -+=====================================================================+==============+=================================================================+ -| CodeIgniter4 | contributors | Project codebase, including tests & user guide sources | -+---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ -| translations | developers | System message translations | -+---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ -| `coding-standard `_ | contributors | Coding style conventions & rules | -+---------------------------------------------------------------------+--------------+-----------------------------------------------------------------+ ++------------------+--------------+-----------------------------------------------------------------+ +| Repository | Audience | Description | ++==================+==============+=================================================================+ +| CodeIgniter4 | contributors | Project codebase, including tests & user guide sources | ++------------------+--------------+-----------------------------------------------------------------+ +| translations | developers | System message translations | ++------------------+--------------+-----------------------------------------------------------------+ +| coding-standard_ | contributors | Coding style conventions & rules | ++------------------+--------------+-----------------------------------------------------------------+ +| settings | developers | Settings Library for CodeIgniter 4 | ++------------------+--------------+-----------------------------------------------------------------+ +| devkit | developers | Development toolkit for CodeIgniter libraries and projects | ++------------------+--------------+-----------------------------------------------------------------+ + +.. _coding-standard: https://github.com/CodeIgniter/coding-standard There are also several deployment repositories, referenced in the installation directions. The deployment repositories are built automatically when a new version is released, and they From b83d2646c4a4f1847d59b183cd2aa0cd0da4269f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 18:34:35 +0900 Subject: [PATCH 0854/2325] docs: update codeigniter.com repository --- user_guide_src/source/installation/repositories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/repositories.rst b/user_guide_src/source/installation/repositories.rst index e35de088e99e..be7e0863136f 100644 --- a/user_guide_src/source/installation/repositories.rst +++ b/user_guide_src/source/installation/repositories.rst @@ -66,7 +66,7 @@ but which showcase it or make it easier to work with! +------------------+--------------+-----------------------------------------------------------------+ | Repository | Audience | Description | +==================+==============+=================================================================+ -| website2 | developers | The codeigniter.com website, written in CodeIgniter 4 | +| website | developers | The codeigniter.com website, written in CodeIgniter 4 | +------------------+--------------+-----------------------------------------------------------------+ | playground | developers | Basic code examples in project form. Still growing. | +------------------+--------------+-----------------------------------------------------------------+ From 8c638e05c8a7515d1e987ae0fbbac1169f50b751 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 27 Nov 2021 10:55:35 +0900 Subject: [PATCH 0855/2325] docs: add about BaseBuilder::$tableName in changelog --- user_guide_src/source/changelogs/v4.1.6.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 093ea6ca8aec..2bb0f77f9536 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -11,6 +11,7 @@ Release Date: Not released BREAKING ======== +- Multiple table names will no longer be stored in ``BaseBuilder::$tableName`` - an empty string will be used instead. Enhancements ============ From fa1ae6802d8d5fe0981d825563395bf72a6726d6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 27 Nov 2021 11:06:36 +0900 Subject: [PATCH 0856/2325] docs: remove deprecated CodeIgniter\Config\Config::get() usage --- user_guide_src/source/installation/upgrade_configuration.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index 21c309cb34f2..78793439e333 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -31,8 +31,7 @@ Upgrade Guide from the CI3 config into the new CI4 config class as public class properties. 4. Now, you have to change the config fetching syntax everywhere you fetch config values. The CI3 syntax is something like ``$this->config->item('item_name');``. - You have to change this into ``config('MyConfigFile')->item_name;``. Alternatively, - you can use the object-oriented approach: ``CodeIgniter\Config\Config::get('MyConfigFile')->item_name;`` + You have to change this into ``config('MyConfigFile')->item_name;``. Code Example ============ From 748b11a6ae8b35fdcb608ccb6c8c6c45ef65b70c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 27 Nov 2021 11:09:13 +0900 Subject: [PATCH 0857/2325] docs: decorate file paths with ** --- .../source/installation/upgrade_configuration.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index 78793439e333..cad74dc1e713 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -25,7 +25,7 @@ Upgrade Guide 1. You have to change the values in the default CI4 config files according to the changes in the CI3 files. The config names are pretty much the same as in CI3. 2. If you are using custom config files in your CI3 project you have to create those - files as new PHP classes in your CI4 project in ``app/Config/``. These classes + files as new PHP classes in your CI4 project in **app/Config**. These classes should be in the ``Config`` namespace and should extend ``CodeIgniter\Config\BaseConfig``. 3. Once you have created all custom config classes, you have to copy the variables from the CI3 config into the new CI4 config class as public class properties. @@ -39,7 +39,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/models``:: +Path: **application/config**:: Date: Sun, 28 Nov 2021 14:00:57 +0900 Subject: [PATCH 0858/2325] fix: remove dependency on VENDORPATH Fixes #5401 --- system/Debug/Toolbar/Collectors/Database.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/system/Debug/Toolbar/Collectors/Database.php b/system/Debug/Toolbar/Collectors/Database.php index db13e14e920e..520ddc7c5dc6 100644 --- a/system/Debug/Toolbar/Collectors/Database.php +++ b/system/Debug/Toolbar/Collectors/Database.php @@ -141,7 +141,10 @@ public function display(): array // Clean up the file paths $traceLine['file'] = str_ireplace(APPPATH, 'APPPATH/', $traceLine['file']); $traceLine['file'] = str_ireplace(SYSTEMPATH, 'SYSTEMPATH/', $traceLine['file']); - $traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']); + if (defined('VENDORPATH')) { + // VENDORPATH is not defined unless `vendor/autoload.php` exists + $traceLine['file'] = str_ireplace(VENDORPATH, 'VENDORPATH/', $traceLine['file']); + } $traceLine['file'] = str_ireplace(ROOTPATH, 'ROOTPATH/', $traceLine['file']); if (strpos($traceLine['file'], 'SYSTEMPATH') !== false) { From 77e3e6ad8c2770dddcc7d73fa7e6bcf79695897e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 13:43:37 +0900 Subject: [PATCH 0859/2325] docs: add GitHub auto-generated release note for v4.1.4 --- CHANGELOG.md | 145 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 144 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a77c0a4d13a..820ca4069478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,10 +72,153 @@ ## [v4.1.4](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.4) (2021-09-06) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.3...v4.1.4) + This release focuses on code style. All changes (except those noted below) are cosmetic to bring the code in line with the new [CodeIgniter Coding Standard](https://github.com/CodeIgniter/coding-standard) (based on PSR-12). -*Note: Full changelog forthcoming.* +**What's Changed** + +* Use php-cs-fixer as coding style tool by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4770 +* Convert tabs to spaces by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4771 +* Initial rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4774 +* Fixes incorrect release versions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4777 +* [CS Migration]Enable `binary_operator_spaces` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4779 +* Update rector/rector requirement from 0.11.8 to 0.11.14 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4785 +* Remove unused local variables by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4783 +* Use static lambda if a binding to `$this` is not required. by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4784 +* [CS Migration]PSR12 rules starting with "b" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4780 +* Use/Fix `preg_quote()` delimiters by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4789 +* [CS Migration]Update indentation to spaces by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4778 +* Define yoda_style rule and initially apply no_yoda style by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4786 +* Don't override `$path` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4787 +* Don't override `$value` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4788 +* Add brackets to clarify intent and avoid unwanted side-effects by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4791 +* Use constants instead of functions by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4793 +* Replace alias functions with origins by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4794 +* Use null coalescing operator by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4796 +* Remove removed `safe_mode` ini Option by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4795 +* Enable `blank_line_before_statement` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4790 +* Enable `braces` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4792 +* Ensure single space between cast and variable by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4797 +* Update rector/rector requirement from 0.11.14 to 0.11.15 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4803 +* It will fix undefined index cid error when sending emails with embedded images by @mmfarhan in https://github.com/codeigniter4/CodeIgniter4/pull/4798 +* Update rector/rector requirement from 0.11.15 to 0.11.16 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4805 +* Phpdoc param return types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4802 +* [Rector] Apply Rector: SimplifyRegexPatternRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4806 +* Shift binary alignment to `align_single_space_minimal` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4801 +* Enable rules fixing array notations by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4808 +* PSR12: Add visibility identifiers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4809 +* Class, trait and interface elements must be separated with one line by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4810 +* Enable `ordered_imports` by @totoprayogo1916 in https://github.com/codeigniter4/CodeIgniter4/pull/4815 +* Enable `class_definition` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4811 +* Revert Model coalesce by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/4819 +* Define remaining "c" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4817 +* Heredocs-related rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4818 +* Update rector/rector requirement from 0.11.16 to 0.11.20 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4832 +* Initial Phpdoc-related rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4820 +* Phpdoc types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4823 +* Modernize and standardize typecasting by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4824 +* Enforce ordering and trimming of phpdoc elements by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4822 +* Define switch-related rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4835 +* Define rules starting with "L" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4838 +* Define rules on unary operators by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4837 +* Define initial "m" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4839 +* Define rules for ternary operators by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4836 +* Define last "m" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4842 +* PSR12: Enable `method_argument_space` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4840 +* Enable `method_chaining_indentation` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4841 +* Native functions and type hints should be written in correct case by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4845 +* PSR12: All instances created with `new` keyword must be followed by braces. by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4846 +* Master language constructs shall be used instead of aliases. by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4847 +* [Commands] Remove unused $minPHPVersion property at Serve command by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4852 +* Update to latest PHPStan and Rector and Rector config compat by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4861 +* [Rector] Apply Rector: RemoveExtraParametersRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4862 +* [Rector] Apply Rector: RemoveUnusedVariableAssignRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4864 +* Update rector/rector requirement from 0.11.21 to 0.11.23 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4869 +* Test classes should be marked as final and internal by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4870 +* Normalize tests to use dedicated PHPUnit assertions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4868 +* Other PHPUnit-related fixers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4871 +* Configure rules in "d" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4872 +* Defining the trailing "p" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4873 +* Update to latest laminas-escaper ^2.8 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4878 +* Enable `echo_tag_syntax` until `error_suppression` fixers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4879 +* Strive for stricter assertions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4874 +* Convert to explicit those implicit string variables by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4882 +* Enable `explicit_indirect_variable` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4881 +* Update rector/rector requirement from 0.11.23 to 0.11.28 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4889 +* Update to rector 0.11.29 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4893 +* Update rector/rector requirement from 0.11.29 to 0.11.32 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4895 +* Enable remaining rules in "f" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4888 +* Enable `escape_implicit_backslashes` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4880 +* Enable prohibitory rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4900 +* Enable `no_null_property_initialization` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4901 +* Update rector/rector requirement from 0.11.32 to 0.11.35 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4916 +* General phpdocs by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4917 +* Define "i" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4919 +* Define "o" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4921 +* Define "r" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4926 +* [Rector] Re-run InlineIfToExplicitIfRector on Latest Rector 0.11.36 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4930 +* Add `?` to nullable typehints by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4928 +* Define `single_**` rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4924 +* Define last "s" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4925 +* Define initial "s" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4923 +* Define remaining rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4934 +* Remove 'memory_usage' from 'displayPerformanceMetrics()' comment by @Mauricevb in https://github.com/codeigniter4/CodeIgniter4/pull/4939 +* Normalize var and return annotations by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4942 +* Fix tag casing and tag types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4943 +* Change some phpdocs to simple comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4945 +* Remove useless code separator comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4946 +* Normalize and add file-level headers to `system/`, `tests/`, `utils/` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4949 +* [Rector] Update rector to 0.11.37, clean up config by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4954 +* Update to phpdocumentor v3.0 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4773 +* [PHPStan] Using PHPStan ^0.12.91 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4962 +* Add workflow for linting framework by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4958 +* Update pre-commit to lint code by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4960 +* Remove superfluous phpdoc tags by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4941 +* Update to phpdoc v3.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4961 +* [Rector] Apply FuncGetArgsToVariadicParamRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4963 +* Optimize Filters by @mostafakhudair in https://github.com/codeigniter4/CodeIgniter4/pull/4965 +* Update rector/rector requirement from 0.11.37 to 0.11.40 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4967 +* Fix properly the phpstan error in 0.12.93 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4970 +* [Rector] Apply MakeInheritedMethodVisibilitySameAsParentRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4966 +* Fix API repo preparation step by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4969 +* Manual cleanup of docblocks and comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4964 +* Delete `docs` directly, not `api/docs` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4976 +* [Rector] Apply Rector: RemoveDuplicatedArrayKeyRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4978 +* Update rector/rector requirement from 0.11.40 to 0.11.42 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4984 +* Update rector/rector requirement from 0.11.42 to 0.11.43 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4985 +* Remove override by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4991 +* Update rector/rector requirement from 0.11.43 to 0.11.46 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4995 +* Update rector/rector requirement from 0.11.46 to 0.11.47 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4997 +* Add SpaceAfterCommentStartFixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4999 +* [Rector] Apply Rector: RemoveDoubleAssignRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5000 +* [Rector] Apply Rector dead code set list by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5007 +* Make Cookie compatible with ArrayAccess by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5004 +* Replace deprecated FILTER_SANITIZE_STRING by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5005 +* Make CookieStore compatible with IteratorAggregate::getIterator by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5010 +* Make the session handlers all compatible with SessionHandlerInterface by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5012 +* Make CITestStreamFilter compatible with php_user_filter by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5014 +* Update rector/rector requirement from 0.11.48 to 0.11.49 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/5018 +* Make Time compatible with DateTime by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5022 +* Update dependabot config by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5027 +* Add `ReturnTypeWillChange` attribute to Entity by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5028 +* Replace unused Entity private method by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5029 +* Update rector/rector requirement from 0.11.49 to 0.11.52 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/5033 +* Fix broken apt installation by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5037 +* Make File compatible with SplFileInfo by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5040 +* Update documentation code samples by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5039 +* PHP Copy-Paste Detector by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5031 +* Fix key casting in form_dropdown helper. by @sfadschm in https://github.com/codeigniter4/CodeIgniter4/pull/5035 +* [Rector] Apply Rector: FixClassCaseSensitivityNameRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5044 +* Bump to php-cs-fixer v3.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5045 +* Switch to official coding standard by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5038 +* 4.1.4 Ready code by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5058 + +**New Contributors** + +* @mmfarhan made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/4798 +* @Mauricevb made their first contribution in https://github.com/codeigniter4/CodeIgniter4/pull/4939 ## [v4.1.3](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.3) (2021-06-06) From 74d7159ef07cf9378b55b1953c6839da5a2de420 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 14:05:34 +0900 Subject: [PATCH 0860/2325] docs: remove PRs on coding style, rector, phpstan --- CHANGELOG.md | 79 ---------------------------------------------------- 1 file changed, 79 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 820ca4069478..7a62c588d97c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,17 +80,9 @@ This release focuses on code style. All changes (except those noted below) are c **What's Changed** * Use php-cs-fixer as coding style tool by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4770 -* Convert tabs to spaces by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4771 -* Initial rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4774 -* Fixes incorrect release versions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4777 -* [CS Migration]Enable `binary_operator_spaces` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4779 -* Update rector/rector requirement from 0.11.8 to 0.11.14 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4785 * Remove unused local variables by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4783 * Use static lambda if a binding to `$this` is not required. by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4784 -* [CS Migration]PSR12 rules starting with "b" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4780 * Use/Fix `preg_quote()` delimiters by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4789 -* [CS Migration]Update indentation to spaces by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4778 -* Define yoda_style rule and initially apply no_yoda style by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4786 * Don't override `$path` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4787 * Don't override `$value` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4788 * Add brackets to clarify intent and avoid unwanted side-effects by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4791 @@ -98,122 +90,51 @@ This release focuses on code style. All changes (except those noted below) are c * Replace alias functions with origins by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4794 * Use null coalescing operator by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4796 * Remove removed `safe_mode` ini Option by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4795 -* Enable `blank_line_before_statement` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4790 -* Enable `braces` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4792 * Ensure single space between cast and variable by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4797 -* Update rector/rector requirement from 0.11.14 to 0.11.15 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4803 * It will fix undefined index cid error when sending emails with embedded images by @mmfarhan in https://github.com/codeigniter4/CodeIgniter4/pull/4798 -* Update rector/rector requirement from 0.11.15 to 0.11.16 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4805 -* Phpdoc param return types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4802 -* [Rector] Apply Rector: SimplifyRegexPatternRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4806 -* Shift binary alignment to `align_single_space_minimal` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4801 -* Enable rules fixing array notations by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4808 -* PSR12: Add visibility identifiers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4809 * Class, trait and interface elements must be separated with one line by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4810 -* Enable `ordered_imports` by @totoprayogo1916 in https://github.com/codeigniter4/CodeIgniter4/pull/4815 -* Enable `class_definition` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4811 * Revert Model coalesce by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/4819 -* Define remaining "c" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4817 -* Heredocs-related rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4818 -* Update rector/rector requirement from 0.11.16 to 0.11.20 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4832 -* Initial Phpdoc-related rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4820 -* Phpdoc types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4823 * Modernize and standardize typecasting by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4824 * Enforce ordering and trimming of phpdoc elements by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4822 -* Define switch-related rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4835 -* Define rules starting with "L" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4838 -* Define rules on unary operators by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4837 -* Define initial "m" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4839 -* Define rules for ternary operators by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4836 -* Define last "m" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4842 -* PSR12: Enable `method_argument_space` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4840 -* Enable `method_chaining_indentation` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4841 * Native functions and type hints should be written in correct case by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4845 -* PSR12: All instances created with `new` keyword must be followed by braces. by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4846 * Master language constructs shall be used instead of aliases. by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4847 * [Commands] Remove unused $minPHPVersion property at Serve command by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4852 -* Update to latest PHPStan and Rector and Rector config compat by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4861 -* [Rector] Apply Rector: RemoveExtraParametersRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4862 -* [Rector] Apply Rector: RemoveUnusedVariableAssignRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4864 -* Update rector/rector requirement from 0.11.21 to 0.11.23 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4869 * Test classes should be marked as final and internal by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4870 * Normalize tests to use dedicated PHPUnit assertions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4868 -* Other PHPUnit-related fixers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4871 -* Configure rules in "d" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4872 -* Defining the trailing "p" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4873 * Update to latest laminas-escaper ^2.8 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4878 -* Enable `echo_tag_syntax` until `error_suppression` fixers by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4879 * Strive for stricter assertions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4874 * Convert to explicit those implicit string variables by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4882 -* Enable `explicit_indirect_variable` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4881 -* Update rector/rector requirement from 0.11.23 to 0.11.28 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4889 -* Update to rector 0.11.29 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4893 -* Update rector/rector requirement from 0.11.29 to 0.11.32 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4895 -* Enable remaining rules in "f" by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4888 -* Enable `escape_implicit_backslashes` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4880 -* Enable prohibitory rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4900 -* Enable `no_null_property_initialization` fixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4901 -* Update rector/rector requirement from 0.11.32 to 0.11.35 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4916 * General phpdocs by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4917 -* Define "i" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4919 -* Define "o" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4921 -* Define "r" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4926 -* [Rector] Re-run InlineIfToExplicitIfRector on Latest Rector 0.11.36 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4930 * Add `?` to nullable typehints by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4928 -* Define `single_**` rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4924 -* Define last "s" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4925 -* Define initial "s" rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4923 -* Define remaining rules by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4934 * Remove 'memory_usage' from 'displayPerformanceMetrics()' comment by @Mauricevb in https://github.com/codeigniter4/CodeIgniter4/pull/4939 * Normalize var and return annotations by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4942 * Fix tag casing and tag types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4943 * Change some phpdocs to simple comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4945 * Remove useless code separator comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4946 * Normalize and add file-level headers to `system/`, `tests/`, `utils/` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4949 -* [Rector] Update rector to 0.11.37, clean up config by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4954 * Update to phpdocumentor v3.0 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4773 -* [PHPStan] Using PHPStan ^0.12.91 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4962 * Add workflow for linting framework by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4958 * Update pre-commit to lint code by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4960 * Remove superfluous phpdoc tags by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4941 -* Update to phpdoc v3.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4961 -* [Rector] Apply FuncGetArgsToVariadicParamRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4963 * Optimize Filters by @mostafakhudair in https://github.com/codeigniter4/CodeIgniter4/pull/4965 -* Update rector/rector requirement from 0.11.37 to 0.11.40 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4967 * Fix properly the phpstan error in 0.12.93 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4970 -* [Rector] Apply MakeInheritedMethodVisibilitySameAsParentRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4966 * Fix API repo preparation step by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4969 * Manual cleanup of docblocks and comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4964 * Delete `docs` directly, not `api/docs` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4976 -* [Rector] Apply Rector: RemoveDuplicatedArrayKeyRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4978 -* Update rector/rector requirement from 0.11.40 to 0.11.42 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4984 -* Update rector/rector requirement from 0.11.42 to 0.11.43 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4985 -* Remove override by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4991 -* Update rector/rector requirement from 0.11.43 to 0.11.46 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4995 -* Update rector/rector requirement from 0.11.46 to 0.11.47 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/4997 -* Add SpaceAfterCommentStartFixer by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4999 -* [Rector] Apply Rector: RemoveDoubleAssignRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5000 -* [Rector] Apply Rector dead code set list by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5007 * Make Cookie compatible with ArrayAccess by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5004 * Replace deprecated FILTER_SANITIZE_STRING by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5005 * Make CookieStore compatible with IteratorAggregate::getIterator by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5010 * Make the session handlers all compatible with SessionHandlerInterface by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5012 * Make CITestStreamFilter compatible with php_user_filter by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5014 -* Update rector/rector requirement from 0.11.48 to 0.11.49 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/5018 * Make Time compatible with DateTime by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5022 -* Update dependabot config by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5027 * Add `ReturnTypeWillChange` attribute to Entity by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5028 * Replace unused Entity private method by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5029 -* Update rector/rector requirement from 0.11.49 to 0.11.52 by @dependabot in https://github.com/codeigniter4/CodeIgniter4/pull/5033 * Fix broken apt installation by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5037 * Make File compatible with SplFileInfo by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5040 * Update documentation code samples by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5039 * PHP Copy-Paste Detector by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5031 * Fix key casting in form_dropdown helper. by @sfadschm in https://github.com/codeigniter4/CodeIgniter4/pull/5035 -* [Rector] Apply Rector: FixClassCaseSensitivityNameRector by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/5044 -* Bump to php-cs-fixer v3.1 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5045 * Switch to official coding standard by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5038 -* 4.1.4 Ready code by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5058 **New Contributors** From b89cf02a558c54de202f215ffda1f8fa848f990a Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 14:19:12 +0900 Subject: [PATCH 0861/2325] docs: remove PRs on coding style, github/workflow --- CHANGELOG.md | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a62c588d97c..9d2a65357cab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -86,41 +86,17 @@ This release focuses on code style. All changes (except those noted below) are c * Don't override `$path` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4787 * Don't override `$value` parameter by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4788 * Add brackets to clarify intent and avoid unwanted side-effects by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4791 -* Use constants instead of functions by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4793 -* Replace alias functions with origins by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4794 -* Use null coalescing operator by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4796 * Remove removed `safe_mode` ini Option by @jeromegamez in https://github.com/codeigniter4/CodeIgniter4/pull/4795 -* Ensure single space between cast and variable by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4797 * It will fix undefined index cid error when sending emails with embedded images by @mmfarhan in https://github.com/codeigniter4/CodeIgniter4/pull/4798 -* Class, trait and interface elements must be separated with one line by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4810 * Revert Model coalesce by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/4819 -* Modernize and standardize typecasting by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4824 -* Enforce ordering and trimming of phpdoc elements by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4822 -* Native functions and type hints should be written in correct case by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4845 * Master language constructs shall be used instead of aliases. by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4847 * [Commands] Remove unused $minPHPVersion property at Serve command by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4852 -* Test classes should be marked as final and internal by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4870 -* Normalize tests to use dedicated PHPUnit assertions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4868 * Update to latest laminas-escaper ^2.8 by @samsonasik in https://github.com/codeigniter4/CodeIgniter4/pull/4878 -* Strive for stricter assertions by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4874 -* Convert to explicit those implicit string variables by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4882 -* General phpdocs by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4917 -* Add `?` to nullable typehints by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4928 * Remove 'memory_usage' from 'displayPerformanceMetrics()' comment by @Mauricevb in https://github.com/codeigniter4/CodeIgniter4/pull/4939 -* Normalize var and return annotations by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4942 -* Fix tag casing and tag types by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4943 -* Change some phpdocs to simple comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4945 * Remove useless code separator comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4946 -* Normalize and add file-level headers to `system/`, `tests/`, `utils/` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4949 -* Update to phpdocumentor v3.0 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4773 -* Add workflow for linting framework by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4958 -* Update pre-commit to lint code by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4960 -* Remove superfluous phpdoc tags by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4941 * Optimize Filters by @mostafakhudair in https://github.com/codeigniter4/CodeIgniter4/pull/4965 * Fix properly the phpstan error in 0.12.93 by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4970 -* Fix API repo preparation step by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4969 * Manual cleanup of docblocks and comments by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4964 -* Delete `docs` directly, not `api/docs` by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/4976 * Make Cookie compatible with ArrayAccess by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5004 * Replace deprecated FILTER_SANITIZE_STRING by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5005 * Make CookieStore compatible with IteratorAggregate::getIterator by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5010 @@ -129,7 +105,6 @@ This release focuses on code style. All changes (except those noted below) are c * Make Time compatible with DateTime by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5022 * Add `ReturnTypeWillChange` attribute to Entity by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5028 * Replace unused Entity private method by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5029 -* Fix broken apt installation by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5037 * Make File compatible with SplFileInfo by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5040 * Update documentation code samples by @paulbalandan in https://github.com/codeigniter4/CodeIgniter4/pull/5039 * PHP Copy-Paste Detector by @MGatner in https://github.com/codeigniter4/CodeIgniter4/pull/5031 From 854fefbacfe930734d6c6ebe02fff927121f9546 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 09:21:06 +0900 Subject: [PATCH 0862/2325] docs: fix 404 link --- user_guide_src/source/installation/upgrade_emails.rst | 2 +- user_guide_src/source/libraries/email.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index 41778027dc30..d64a6bb2afea 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -22,7 +22,7 @@ Upgrade Guide 1. Within your class change the ``$this->load->library('email');`` to ``$email = service('email');``. 2. From that on you have to replace every line starting with ``$this->email`` to ``$email``. 3. The methods in the Email class are named slightly different. All methods, except for ``send()``, ``attach()``, ``printDebugger()`` and ``clear()`` have a ``set`` as prefix followed by the previous method name. ``bcc()`` is now ``setBcc()`` and so on. -4. The config attributes in ``app/Config/Email.php`` have changed. You should have a look at the `Email Class Documentation `__ to have a list of the new attributes. +4. The config attributes in **app/Config/Email.php** have changed. You should have a look at the :ref:`setting-email-preferences` to have a list of the new attributes. Code Example ============ diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index f57f3cf93d8d..a10b3d9bf6ca 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -44,6 +44,8 @@ Here is a basic example demonstrating how you might send email:: $email->send(); +.. _setting-email-preferences: + Setting Email Preferences ========================= From 66c588335a594346fb822e167b5e7b1f3ef1a20c Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 09:44:44 +0900 Subject: [PATCH 0863/2325] docs: decorate keywords in source code with '``' --- user_guide_src/source/incoming/restful.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst index bb2f9d8ad1bb..2ed7ed4607fe 100644 --- a/user_guide_src/source/incoming/restful.rst +++ b/user_guide_src/source/incoming/restful.rst @@ -47,7 +47,7 @@ name:: .. important:: The routes are matched in the order they are specified, so if you have a resource photos above a get 'photos/poll' the show action's route for the resource line will be matched before the get line. To fix this, move the get line above the resource line so that it is matched first. The second parameter accepts an array of options that can be used to modify the routes that are generated. While these -routes are geared toward API-usage, where more methods are allowed, you can pass in the 'websafe' option to have it +routes are geared toward API-usage, where more methods are allowed, you can pass in the ``websafe`` option to have it generate update and delete methods that work with HTML forms:: $routes->resource('photos', ['websafe' => 1]); @@ -90,15 +90,15 @@ Otherwise you can remove unused routes with the ``except`` option. This option r $routes->resource('photos', ['except' => 'new,edit']); -Valid methods are: index, show, create, update, new, edit and delete. +Valid methods are: ``index``, ``show``, ``create``, ``update``, ``new``, ``edit`` and ``delete``. ResourceController ============================================================ -The `ResourceController` provides a convenient starting point for your RESTful API, +The ``ResourceController`` provides a convenient starting point for your RESTful API, with methods that correspond to the resource routes above. -Extend it, over-riding the `modelName` and `format` properties, and then +Extend it, over-riding the ``modelName`` and ``format`` properties, and then implement those methods that you want handled.:: presenter('photos', ['except' => 'new,edit']); -Valid methods are: index, show, new, create, edit, update, remove and delete. +Valid methods are: ``index``, ``show``, ``new``, ``create``, ``edit``, ``update``, ``remove`` and ``delete``. ResourcePresenter ============================================================ -The `ResourcePresenter` provides a convenient starting point for presenting views +The ``ResourcePresenter`` provides a convenient starting point for presenting views of your resource, and processing data from forms in those views, with methods that align to the resource routes above. -Extend it, over-riding the `modelName` property, and then +Extend it, over-riding the ``modelName`` property, and then implement those methods that you want handled.:: Date: Tue, 30 Nov 2021 09:45:42 +0900 Subject: [PATCH 0864/2325] docs: replace segment with (:segment) Make it more precise. --- user_guide_src/source/incoming/restful.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst index 2ed7ed4607fe..9ac3ed1292c4 100644 --- a/user_guide_src/source/incoming/restful.rst +++ b/user_guide_src/source/incoming/restful.rst @@ -70,7 +70,7 @@ the controller that should be used:: Change the Placeholder Used --------------------------- -By default, the ``segment`` placeholder is used when a resource ID is needed. You can change this by passing +By default, the ``(:segment)`` placeholder is used when a resource ID is needed. You can change this by passing in the ``placeholder`` option with the new string to use:: $routes->resource('photos', ['placeholder' => '(:num)']); @@ -175,7 +175,7 @@ the controller that should be used:: Change the Placeholder Used --------------------------- -By default, the ``segment`` placeholder is used when a resource ID is needed. You can change this by passing +By default, the ``(:segment)`` placeholder is used when a resource ID is needed. You can change this by passing in the ``placeholder`` option with the new string to use:: $routes->presenter('photos', ['placeholder' => '(:num)']); From 36ae946804044bf4b46f4a55a9fac9c3890af452 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 09:47:50 +0900 Subject: [PATCH 0865/2325] docs: improve explanation for except option --- user_guide_src/source/incoming/restful.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst index 9ac3ed1292c4..8992221590a0 100644 --- a/user_guide_src/source/incoming/restful.rst +++ b/user_guide_src/source/incoming/restful.rst @@ -81,12 +81,12 @@ in the ``placeholder`` option with the new string to use:: Limit the Routes Made --------------------- -You can restrict the routes generated with the ``only`` option. This should be an array or comma separated list of method names that should +You can restrict the routes generated with the ``only`` option. This should be **an array** or **comma separated list** of method names that should be created. Only routes that match one of these methods will be created. The rest will be ignored:: $routes->resource('photos', ['only' => ['index', 'show']]); -Otherwise you can remove unused routes with the ``except`` option. This option run after ``only``:: +Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or **comma separated list** of method names. This option run after ``only``:: $routes->resource('photos', ['except' => 'new,edit']); @@ -186,12 +186,12 @@ in the ``placeholder`` option with the new string to use:: Limit the Routes Made --------------------- -You can restrict the routes generated with the ``only`` option. This should be an array or comma separated list of method names that should +You can restrict the routes generated with the ``only`` option. This should be **an array** or **comma separated list** of method names that should be created. Only routes that match one of these methods will be created. The rest will be ignored:: $routes->presenter('photos', ['only' => ['index', 'show']]); -Otherwise you can remove unused routes with the ``except`` option. This option run after ``only``:: +Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or **comma separated list** of method names. This option run after ``only``:: $routes->presenter('photos', ['except' => 'new,edit']); From c15b930b9d167a6ea1166b1cfe9081b047f680c7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:23:49 +0900 Subject: [PATCH 0866/2325] docs: fix sample code It seems 3.x and 4.x sample code are not the same. --- user_guide_src/source/installation/upgrade_routing.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index bd840b06a82c..8743cc7816f1 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -64,12 +64,12 @@ Path: ``app/Config/Routes.php``:: ... - $routes->add('posts', 'Posts::index'); + $routes->add('posts/index', 'Posts::index'); $routes->add('teams/create', 'Teams::create'); - $routes->add('teams/edit/(:any)', 'Teams::edit/$1'); + $routes->add('teams/update', 'Teams::update'); $routes->add('posts/create', 'Posts::create'); - $routes->add('posts/edit/(:any)', 'Posts::edit/$1'); + $routes->add('posts/update', 'Posts::update'); $routes->add('drivers/create', 'Drivers::create'); - $routes->add('drivers/edit/(:any)', 'Drivers::edit/$1'); + $routes->add('drivers/update', 'Drivers::update'); $routes->add('posts/(:any)', 'Posts::view/$1'); From 59660589ee1ede69770c4ab6eec31f00cd4f3b49 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:24:54 +0900 Subject: [PATCH 0867/2325] docs: decorate file paths with ** --- user_guide_src/source/installation/upgrade_routing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 8743cc7816f1..b99dd676bf5a 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -19,7 +19,7 @@ What has been changed Upgrade Guide ============= -1. You have to change the syntax of each routing line and append it in ``app/Config/Routes.php``. For example: +1. 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', 'App\Blogs');`` this would map to the ``index()`` method in the "Blogs" class. - ``$route['product/(:any)'] = 'catalog/product_lookup';`` to ``$routes->add('product/(:any)', 'Catalog::productLookup');`` @@ -30,7 +30,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/config/routes.php``:: +Path: **application/config/routes.php**:: Date: Tue, 30 Nov 2021 10:25:34 +0900 Subject: [PATCH 0868/2325] docs: fix indentation of the list and the explanation --- user_guide_src/source/installation/upgrade_routing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index b99dd676bf5a..5ea14f16e74d 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -21,9 +21,9 @@ Upgrade Guide ============= 1. 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', 'App\Blogs');`` this would map to the ``index()`` method in the "Blogs" class. -- ``$route['product/(:any)'] = 'catalog/product_lookup';`` to ``$routes->add('product/(:any)', 'Catalog::productLookup');`` -- ``$route['login/(.+)'] = 'auth/login/$1';`` to ``$routes->add('login/(.+)', 'Auth::login/$1');`` + - ``$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');`` + - ``$route['login/(.+)'] = 'auth/login/$1';`` to ``$routes->add('login/(.+)', 'Auth::login/$1');`` Code Example ============ From c9c8748770a062f59d6b54ff68b960400b0d4ced Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:46:19 +0900 Subject: [PATCH 0869/2325] docs: fix coding style of sample code --- user_guide_src/source/libraries/uploaded_files.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 094eacc1eafa..c0284f221d79 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -110,7 +110,7 @@ In controller:: foreach($imagefile['images'] as $img) { if ($img->isValid() && ! $img->hasMoved()) { $newName = $img->getRandomName(); - $img->move(WRITEPATH.'uploads', $newName); + $img->move(WRITEPATH . 'uploads', $newName); } } } @@ -153,7 +153,7 @@ Verify A File You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method:: if (! $file->isValid()) { - throw new \RuntimeException($file->getErrorString().'('.$file->getError().')'); + throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); } As seen in this example, if a file had an upload error, you can retrieve the error code (an integer) and the error @@ -216,12 +216,12 @@ Moving Files Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move the file to as the first parameter:: - $file->move(WRITEPATH.'uploads'); + $file->move(WRITEPATH . 'uploads'); By default, the original filename was used. You can specify a new filename by passing it as the second parameter:: $newName = $file->getRandomName(); - $file->move(WRITEPATH.'uploads', $newName); + $file->move(WRITEPATH . 'uploads', $newName); Once the file has been removed the temporary file is deleted. You can check if a file has been moved already with the ``hasMoved()`` method, which returns a boolean:: From 7422d99f97507a01af43a010baa0cbf2863d2de5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:46:49 +0900 Subject: [PATCH 0870/2325] docs: fix typo --- user_guide_src/source/libraries/uploaded_files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index c0284f221d79..b15185506e81 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -117,7 +117,7 @@ In controller:: where the **images** is a loop from the form field name -If there are multiple files with the same name you can use ``getFile()`` ro retrieve every file individually:: +If there are multiple files with the same name you can use ``getFile()`` to retrieve every file individually:: In controller:: $file1 = $this->request->getFile('images.0'); From 34340569a9866f3d52cb1338eff0b6afd01f4f1b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:47:24 +0900 Subject: [PATCH 0871/2325] docs: decorate words in code with '``' --- user_guide_src/source/libraries/uploaded_files.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index b15185506e81..c0e4b27baf9a 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -160,7 +160,7 @@ As seen in this example, if a file had an upload error, you can retrieve the err message with the ``getError()`` and ``getErrorString()`` methods. The following errors can be discovered through this method: -* The file exceeds your upload_max_filesize ini directive. +* The file exceeds your ``upload_max_filesize`` ini directive. * The file exceeds the upload limit defined in your form. * The file was only partially uploaded. * No file was uploaded. @@ -255,7 +255,7 @@ passing it as the second parameter:: $path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg'); -Moving an uploaded file can fail, with an HTTPException, under several circumstances: +Moving an uploaded file can fail, with an ``HTTPException``, under several circumstances: - the file has already been moved - the file did not upload successfully From a177ea33d1d8c70869053168d85afdc88ad2ac6e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:48:41 +0900 Subject: [PATCH 0872/2325] docs: make it a single sentence --- user_guide_src/source/libraries/uploaded_files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index c0e4b27baf9a..d48bc02a9dcb 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -138,7 +138,7 @@ In controller:: $file1 = $this->request->getFile('my-form.details.avatars.0'); $file2 = $this->request->getFile('my-form.details.avatars.1'); -.. note:: using ``getFiles()`` is more appropriate +.. note:: Using ``getFiles()`` is more appropriate. ===================== Working With the File From 80689ddc4cb3b72179f9cee57ef12ec619b3e13d Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:49:22 +0900 Subject: [PATCH 0873/2325] docs: decroate file paths with ** --- user_guide_src/source/libraries/uploaded_files.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index d48bc02a9dcb..e1734165c6e5 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -245,7 +245,7 @@ With the simplest usage, a single file might be submitted like:: -By default, upload files are saved in writable/uploads directory. The YYYYMMDD folder +By default, upload files are saved in **writable/uploads** directory. The **YYYYMMDD** folder and random file name will be created. Returns a file path:: $path = $this->request->getFile('userfile')->store(); From 49a07f0ccb46e313e08b8cb6c53de00e0df537e3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 10:49:48 +0900 Subject: [PATCH 0874/2325] docs: make warning for security matter --- user_guide_src/source/libraries/uploaded_files.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index e1734165c6e5..d4ecc9d34867 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -196,11 +196,12 @@ Other File Info **getClientExtension()** -Returns the original file extension, based on the file name that was uploaded. This is NOT a trusted source. For a -trusted version, use ``guessExtension()`` instead:: +Returns the original file extension, based on the file name that was uploaded:: $ext = $file->getClientExtension(); +.. warning:: This is NOT a trusted source. For a trusted version, use ``guessExtension()`` instead. + **getClientMimeType()** Returns the mime type (mime type) of the file as provided by the client. This is NOT a trusted value. For a trusted From 352a67166ad6e592c70c17c64626e41e075ccad0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 12:13:47 +0900 Subject: [PATCH 0875/2325] docs: add file upload sample code like CI3 --- .../source/libraries/uploaded_files.rst | 176 ++++++++++++++++-- 1 file changed, 163 insertions(+), 13 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index d4ecc9d34867..1f60167f9189 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -1,6 +1,6 @@ -*************************** +########################### Working with Uploaded Files -*************************** +########################### CodeIgniter makes working with files uploaded through a form much simpler and more secure than using PHP's ``$_FILES`` array directly. This extends the :doc:`File class ` and thus gains all of the features of that class. @@ -12,12 +12,162 @@ array directly. This extends the :doc:`File class ` and thus g :local: :depth: 2 -=============== +*********** +The Process +*********** + +Uploading a file involves the following general process: + +- An upload form is displayed, allowing a user to select a file and + upload it. +- When the form is submitted, the file is uploaded to the destination + you specify. +- Along the way, the file is validated to make sure it is allowed to be + uploaded based on the preferences you set. +- Once uploaded, the user will be shown a success message. + +To demonstrate this process here is brief tutorial. Afterward you'll +find reference information. + +Creating the Upload Form +======================== + +Using a text editor, create a form called upload_form.php. In it, place +this code and save it to your **app/Views/** directory:: + + + + + Upload Form + + + + +
  • + + + + + + +

    + + + + + + + + +You'll notice we are using a form helper to create the opening form tag. +File uploads require a multipart form, so the helper creates the proper +syntax for you. You'll also notice we have an ``$errors`` variable. This is +so we can show error messages in the event the user does something +wrong. + +The Success Page +================ + +Using a text editor, create a form called upload_success.php. In it, +place this code and save it to your **app/Views/** directory:: + + + + + Upload Form + + + +

    Your file was successfully uploaded!

    + +
      +
    • name: getBasename() ?>
    • +
    • size: getSizeByUnit('kb') ?> KB
    • +
    • extension: guessExtension() ?>
    • +
    + +

    + + + + +The Controller +============== + +Using a text editor, create a controller called Upload.php. In it, place +this code and save it to your **app/Controllers/** directory:: + + []]); + } + + public function upload() + { + $validationRule = [ + 'userfile' => [ + 'label' => 'Image File', + 'rules' => 'uploaded[userfile]' + . '|is_image[userfile]' + . '|mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]' + . '|max_size[userfile,100]' + . '|max_dims[userfile,1024,768]', + ], + ]; + if (! $this->validate($validationRule)) { + $data = ['errors' => $this->validator->getErrors()]; + + return view('upload_form', $data); + } + + $img = $this->request->getFile('userfile'); + + if (! $img->hasMoved()) { + $filepath = WRITEPATH . 'uploads/' . $img->store(); + + $data = ['uploaded_flleinfo' => new File($filepath)]; + + return view('upload_success', $data); + } else { + $data = ['errors' => 'The file has already been moved.']; + + return view('upload_form', $data); + } + } + } + +The Upload Directory +==================== + +The uploaded files are stored in the **writable/uploads/** directory. + +Try it! +======= + +To try your form, visit your site using a URL similar to this one:: + + example.com/index.php/upload/ + +You should see an upload form. Try uploading an image file (either a +**jpg**, **gif**, **png**, or **webp**). If the path in your controller is correct it should +work. + +*************** Accessing Files -=============== +*************** All Files ----------- +========= When you upload files they can be accessed natively in PHP through the ``$_FILES`` superglobal. This array has some major shortcomings when working with multiple files uploaded at once, and has potential security flaws many developers @@ -72,7 +222,7 @@ In this case, the returned array of files would be more like:: ] Single File ------------ +=========== If you just need to access a single file, you can use ``getFile()`` to retrieve the file instance directly. This will return an instance of ``CodeIgniter\HTTP\Files\UploadedFile``: @@ -140,15 +290,15 @@ In controller:: .. note:: Using ``getFiles()`` is more appropriate. -===================== +********************* Working With the File -===================== +********************* Once you've retrieved the UploadedFile instance, you can retrieve information about the file in safe ways, as well as move the file to a new location. Verify A File -------------- +============= You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method:: @@ -169,7 +319,7 @@ this method: * File upload was stopped by a PHP extension. File Names ----------- +========== **getName()** @@ -192,7 +342,7 @@ To get the full path of the temp file that was created during the upload, you ca $tempfile = $file->getTempName(); Other File Info ---------------- +=============== **getClientExtension()** @@ -212,7 +362,7 @@ version, use ``getMimeType()`` instead:: echo $type; // image/png Moving Files ------------- +============ Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move the file to as the first parameter:: @@ -238,7 +388,7 @@ Moving an uploaded file can fail, with an HTTPException, under several circumsta - the file move operation fails (e.g., improper permissions) Store Files ------------- +=========== Each file can be moved to its new location with the aptly named ``store()`` method. From f646b9c3ee2c3ce6d34ed99a7b9a703c1c9ebbd5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 13:03:40 +0900 Subject: [PATCH 0876/2325] docs: update sample code coding style --- user_guide_src/source/libraries/files.rst | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index 76b2e8a6acd8..cf46d8ceb9b5 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -96,17 +96,17 @@ Moving Files Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move the file to as the first parameter:: - $file->move(WRITEPATH.'uploads'); + $file->move(WRITEPATH . 'uploads'); By default, the original filename was used. You can specify a new filename by passing it as the second parameter:: $newName = $file->getRandomName(); - $file->move(WRITEPATH.'uploads', $newName); + $file->move(WRITEPATH . 'uploads', $newName); The move() method returns a new File instance that for the relocated file, so you must capture the result if the resulting location is needed:: - $file = $file->move(WRITEPATH.'uploads'); + $file = $file->move(WRITEPATH . 'uploads'); **************** File Collections @@ -136,8 +136,7 @@ When your collection is complete, you can use ``get()`` to retrieve the final li echo 'My files: ' . implode(PHP_EOL, $files->get()); echo 'I have ' . count($files) . ' files!'; - foreach ($files as $file) - { + foreach ($files as $file) { echo 'Moving ' . $file->getBasename() . ', ' . $file->getSizeByUnit('mb'); $file->move(WRITABLE . $file->getRandomName()); } From afdc97646f6d3e6073d288aca73cdee2ea3ab730 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 13:06:09 +0900 Subject: [PATCH 0877/2325] docs: decorate method/variable with '``' --- 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 cf46d8ceb9b5..04bd317356e2 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -149,7 +149,7 @@ Starting a Collection **__construct(string[] $files = [])** The constructor accepts an optional array of file paths to use as the initial collection. These are passed to -**add()** so any files supplied by child classes in the **$files** will remain. +``add()`` so any files supplied by child classes in the ``$files`` will remain. **define()** From 78cf411974a2b074faf5d91cec2a29fa16868ca1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 13:06:54 +0900 Subject: [PATCH 0878/2325] docs: add / to separate methods --- user_guide_src/source/libraries/files.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index 04bd317356e2..6734e98d5fda 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -180,17 +180,17 @@ Inputting Files Adds all files indicated by the path or array of paths. If the path resolves to a directory then ``$recursive`` will include sub-directories. -**addFile(string $file)** +**addFile(string $file)** / **addFiles(array $files)** Adds the file or files to the current list of input files. Files are absolute paths to actual files. -**removeFile(string $file)** +**removeFile(string $file)** / **removeFiles(array $files)** Removes the file or files from the current list of input files. -**addDirectory(string $directory, bool $recursive = false)** +**addDirectory(string $directory, bool $recursive = false)** / **addDirectories(array $directories, bool $recursive = false)** Adds all files from the directory or directories, optionally recursing into sub-directories. Directories are @@ -199,7 +199,7 @@ absolute paths to actual directories. Filtering Files =============== -**removePattern(string $pattern, string $scope = null)** +**removePattern(string $pattern, string $scope = null)** / **retainPattern(string $pattern, string $scope = null)** Filters the current file list through the pattern (and optional scope), removing or retaining matched From fbabefa946ae4899e90e9c0b0a92eca49861fb9f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 13:51:27 +0900 Subject: [PATCH 0879/2325] docs: add esc() to views --- user_guide_src/source/libraries/uploaded_files.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 1f60167f9189..961823036e60 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -43,7 +43,7 @@ this code and save it to your **app/Views/** directory:: -
  • +
  • @@ -81,9 +81,9 @@ place this code and save it to your **app/Views/** directory::

    Your file was successfully uploaded!

      -
    • name: getBasename() ?>
    • -
    • size: getSizeByUnit('kb') ?> KB
    • -
    • extension: guessExtension() ?>
    • +
    • name: getBasename()) ?>
    • +
    • size: getSizeByUnit('kb')) ?> KB
    • +
    • extension: guessExtension()) ?>

    From 4d8266dfb9d7ccb3611b09d305dc8054aeab07b7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 14:57:25 +0900 Subject: [PATCH 0880/2325] docs: add esc() to views It is not good practice to show variables without escaping --- user_guide_src/source/outgoing/views.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 533e3c9bead5..8b8f21efccaf 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -163,10 +163,10 @@ Now open your view file and change the text to variables that correspond to the - <?= $title ?> + <?= esc($title) ?> -

    +

    @@ -220,17 +220,17 @@ Now open your view file and create a loop:: - <?= $title ?> + <?= esc($title) ?> -

    +

    My Todo List

      -
    • +
    From 2fb74d0ab70215811a8bbac3deb4eacaf8545066 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 14:58:27 +0900 Subject: [PATCH 0881/2325] docs: fix coding style --- user_guide_src/source/outgoing/views.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 8b8f21efccaf..5cc77d05a3a4 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -228,11 +228,11 @@ Now open your view file and create a loop::

    My Todo List

      - +
    • - +
    From 69a6563d52229ddfa8fd2e2a0f833bd2d945d734 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 15:03:24 +0900 Subject: [PATCH 0882/2325] docs: fix coding style remove unneeded ; remove space before : --- user_guide_src/source/installation/upgrade_views.rst | 2 +- user_guide_src/source/libraries/pagination.rst | 4 ++-- user_guide_src/source/libraries/validation.rst | 2 +- user_guide_src/source/outgoing/alternative_php.rst | 8 ++++---- user_guide_src/source/tutorial/news_section.rst | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index 554a0a83ffc3..829b84a47e5f 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -70,7 +70,7 @@ Path: ``app/Views``::
    • - +
    diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 8b47ac046d1f..b665300749e2 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -250,7 +250,7 @@ usefulness. It is easiest to demonstrate creating a new view by showing you the - links() as $link) : ?> + links() as $link): ?>
  • > @@ -328,7 +328,7 @@ See following an example with these changes::
  • - links() as $link) : ?> + links() as $link): ?>
  • > diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 27691f084a55..468f05e5a41f 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -607,7 +607,7 @@ a new view at **/app/Views/_errors_list.php**::

    View article

    - + From 6ca2cfe78cfdf6beb83119ec68d41fa96a9745e6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 15:05:21 +0900 Subject: [PATCH 0883/2325] docs: fix coding style Align = position --- user_guide_src/source/installation/upgrade_migrations.rst | 8 ++++---- user_guide_src/source/installation/upgrade_models.rst | 6 +++--- user_guide_src/source/installation/upgrade_pagination.rst | 8 ++++---- .../source/installation/upgrade_view_parser.rst | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 10a75bf23f2d..fc65ea2aa8d3 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -63,13 +63,13 @@ Path: ``application/migrations``:: { $this->dbforge->add_field(array( 'blog_id' => array( - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => true, 'auto_increment' => true, ), 'blog_title' => array( - 'type' => 'VARCHAR', + 'type' => 'VARCHAR', 'constraint' => '100', ), 'blog_description' => array( diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst index 7100f6ca9202..ba508424cdf2 100644 --- a/user_guide_src/source/installation/upgrade_models.rst +++ b/user_guide_src/source/installation/upgrade_models.rst @@ -50,9 +50,9 @@ Path: ``application/models``:: public function insert($name, $address, $email) { $this->db->insert('user_contacts', array( - "name" => $name, - "address" => $address, - "email" => $email, + 'name' => $name, + 'address' => $address, + 'email' => $email, )); } } diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index 4743bb985cf2..23c8564d1390 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -39,11 +39,11 @@ CodeIgniter Version 3.11 :: $this->load->library('pagination'); - $config['base_url'] = base_url().'users/index/'; - $config['total_rows'] = $this->db->count_all('users'); - $config['per_page'] = 10; + $config['base_url'] = base_url().'users/index/'; + $config['total_rows'] = $this->db->count_all('users'); + $config['per_page'] = 10; $config['uri_segment'] = 3; - $config['attributes'] = array('class' => 'pagination-link'); + $config['attributes'] = array('class' => 'pagination-link'); $this->pagination->initialize($config); $data['users'] = $this->user_model->get_users(FALSE, $config['per_page'], $offset); diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index 94bd5ac67f19..96f821b81922 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -33,7 +33,7 @@ CodeIgniter Version 3.11 $this->load->library('parser'); $data = array( - 'blog_title' => 'My Blog Title', + 'blog_title' => 'My Blog Title', 'blog_heading' => 'My Blog Heading' ); From 3839795e6cd65c5440a5bc197fc20f69198f3099 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 19:03:12 +0900 Subject: [PATCH 0884/2325] docs: decorate variable with '``' --- user_guide_src/source/libraries/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 27691f084a55..3550bec9ff9d 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -896,7 +896,7 @@ Rules for File Uploads ====================== These validation rules enable you to do the basic checks you might need to verify that uploaded files meet your business needs. -Since the value of a file upload HTML field doesn't exist, and is stored in the $_FILES global, the name of the input field will +Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global, the name of the input field will need to be used twice. Once to specify the field name as you would for any other rule, but again as the first parameter of all file upload related rules:: From 0daf8c90166f35230216bb878343f8931444ad7a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 19:03:50 +0900 Subject: [PATCH 0885/2325] docs: add note about Validation rules --- user_guide_src/source/libraries/uploaded_files.rst | 4 ++++ user_guide_src/source/libraries/validation.rst | 2 ++ 2 files changed, 6 insertions(+) diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 961823036e60..615716ea0273 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -146,6 +146,10 @@ this code and save it to your **app/Controllers/** directory:: } } +.. note:: Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global, + only :ref:`rules-for-file-uploads` can be used to validate upload file with :doc:`validation`. + The rule ``required`` also can't be used, so use ``uploaded`` instead. + The Upload Directory ==================== diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 3550bec9ff9d..aed337d1b062 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -892,6 +892,8 @@ valid_cc_number Yes Verifies that the credit card number matches HSBC Canada Card (hsbc) ======================= ========== ============================================= =================================================== +.. _rules-for-file-uploads: + Rules for File Uploads ====================== From 47a4af22e8cef349171c510de319178037cc4368 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Dec 2021 16:29:58 +0900 Subject: [PATCH 0886/2325] docs: add TOC to general pages --- user_guide_src/source/general/ajax.rst | 4 ++++ user_guide_src/source/general/caching.rst | 4 ++++ user_guide_src/source/general/environments.rst | 4 ++++ user_guide_src/source/general/managing_apps.rst | 4 ++++ user_guide_src/source/general/urls.rst | 4 ++++ 5 files changed, 20 insertions(+) diff --git a/user_guide_src/source/general/ajax.rst b/user_guide_src/source/general/ajax.rst index 710406b41272..d3fd5945f1ff 100644 --- a/user_guide_src/source/general/ajax.rst +++ b/user_guide_src/source/general/ajax.rst @@ -8,6 +8,10 @@ To get around this problem, the most efficient solution (so far) is to manually Here's how to force the ``X-Requested-With`` header to be sent in the Fetch API and other JavaScript libraries. +.. contents:: + :local: + :depth: 2 + Fetch API ========= diff --git a/user_guide_src/source/general/caching.rst b/user_guide_src/source/general/caching.rst index f241cb02c15d..b3d5e152b879 100644 --- a/user_guide_src/source/general/caching.rst +++ b/user_guide_src/source/general/caching.rst @@ -12,6 +12,10 @@ page load speeds. By caching your pages, since they are saved in their fully rendered state, you can achieve performance much closer to that of static web pages. +.. contents:: + :local: + :depth: 2 + How Does Caching Work? ====================== diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst index ac860d4634cf..057dd8e57dea 100644 --- a/user_guide_src/source/general/environments.rst +++ b/user_guide_src/source/general/environments.rst @@ -9,6 +9,10 @@ while developing an application, but it may also pose a security issue when "live". In development environments, you might want additional tools loaded that you don't in production environments, etc. +.. contents:: + :local: + :depth: 2 + The ENVIRONMENT Constant ======================== diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index 21fcebdf9407..5e4711958c24 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -8,6 +8,10 @@ directory. It is possible, however, to have multiple sets of applications that share a single CodeIgniter installation, or even to rename or relocate your application directory. +.. contents:: + :local: + :depth: 2 + Renaming or Relocating the Application Directory ================================================ diff --git a/user_guide_src/source/general/urls.rst b/user_guide_src/source/general/urls.rst index 5eab9ee7a1e1..da056cc96cbc 100644 --- a/user_guide_src/source/general/urls.rst +++ b/user_guide_src/source/general/urls.rst @@ -2,6 +2,10 @@ CodeIgniter URLs ################ +.. contents:: + :local: + :depth: 2 + By default, URLs in CodeIgniter are designed to be search-engine and human-friendly. Rather than using the standard "query-string" approach to URLs that is synonymous with dynamic systems, CodeIgniter uses a **segment-based** approach:: From d3d514b4892c7c140cb210bf22d2d33f2c9b1e16 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 10:32:39 +0900 Subject: [PATCH 0887/2325] docs: fix application folder name --- user_guide_src/source/general/managing_apps.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index 21fcebdf9407..92c152c5dd63 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -3,7 +3,7 @@ Managing your Applications ########################## By default, it is assumed that you only intend to use CodeIgniter to -manage one application, which you will build in your **application** +manage one application, which you will build in your **app** directory. It is possible, however, to have multiple sets of applications that share a single CodeIgniter installation, or even to rename or relocate your application directory. @@ -16,7 +16,7 @@ it to a different location on your server, other than your project root, open your main **app/Config/Paths.php** and set a *full server path* in the ``$appDirectory`` variable (at about line 44):: - public $appDirectory = '/path/to/your/application'; + public $appDirectory = '/path/to/your/app'; You will need to modify two additional files in your project root, so that they can find the ``Paths`` configuration file: From c96224688927a3c64303fa1a817e490cfdf0a5f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 10:33:42 +0900 Subject: [PATCH 0888/2325] docs: decorate file paths with ** --- .../source/general/managing_apps.rst | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index 92c152c5dd63..6e156cd783d5 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -19,15 +19,15 @@ your main **app/Config/Paths.php** and set a *full server path* in the public $appDirectory = '/path/to/your/app'; You will need to modify two additional files in your project root, so that -they can find the ``Paths`` configuration file: +they can find the **Paths** configuration file: -- ``/spark`` runs command line apps; the path is specified on or about line 35:: +- **/spark** runs command line apps; the path is specified on or about line 35:: $pathsConfig = 'app/Config/Paths.php'; // ^^^ Change this line if you move your application folder -- ``/public/index.php`` is the front controller for your webapp; the config +- **/public/index.php** is the front controller for your webapp; the config path is specified on or about line 20:: $pathsConfig = FCPATH . '../app/Config/Paths.php'; @@ -41,8 +41,8 @@ If you would like to share a common CodeIgniter framework installation, to manag several different applications, simply put all of the directories located inside your application directory into their own (sub)-directory. -For example, let's say you want to create two applications, named "foo" -and "bar". You could structure your application project directories like this: +For example, let's say you want to create two applications, named **foo** +and **bar**. You could structure your application project directories like this: .. code-block:: text @@ -60,12 +60,12 @@ and "bar". You could structure your application project directories like this: /system /docs -This would have two apps, "foo" and "bar", both having standard application directories -and a ``public`` folder, and sharing a common codeigniter framework. +This would have two apps, **foo** and **bar**, both having standard application directories +and a **public** folder, and sharing a common **codeigniter** framework. -The ``index.php`` inside each application would refer to its own configuration, +The **index.php** inside each application would refer to its own configuration, ``../app/Config/Paths.php``, and the ``$systemDirectory`` variable inside each -of those would be set to refer to the shared common "system" folder. +of those would be set to refer to the shared common **system** folder. If either of the applications had a command-line component, then you would also -modify ``spark`` inside each application's project folder, as directed above. +modify **spark** inside each application's project folder, as directed above. From 95581fd3bb9f91a2e2fbd5e785f0738050bf3d31 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 10:53:25 +0900 Subject: [PATCH 0889/2325] docs: there is no `docs` folder now --- user_guide_src/source/general/managing_apps.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index 6e156cd783d5..d9a3e8e05d77 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -58,7 +58,6 @@ and **bar**. You could structure your application project directories like this: /writable /codeigniter /system - /docs This would have two apps, **foo** and **bar**, both having standard application directories and a **public** folder, and sharing a common **codeigniter** framework. From a2aed177b40949eeac58f4dde61a108916823be5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 10:56:49 +0900 Subject: [PATCH 0890/2325] docs: add `spark` file --- user_guide_src/source/general/managing_apps.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index d9a3e8e05d77..6e2279ede97c 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -51,11 +51,13 @@ and **bar**. You could structure your application project directories like this: /public /tests /writable + spark /bar /app /public /tests /writable + spark /codeigniter /system From a838edcb61ccb49998979411f12ecd6e2c877760 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 11:04:00 +0900 Subject: [PATCH 0891/2325] chore: temporary fix for PhpCoveralls error https://github.com/php-coveralls/php-coveralls/issues/327 --- .github/workflows/test-phpunit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 4583244ed358..61133437d3e8 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -137,7 +137,7 @@ jobs: - name: Run Coveralls if: github.repository_owner == 'codeigniter4' && matrix.php-versions == '8.0' run: | - composer global require --ansi php-coveralls/php-coveralls:^2.4 + composer global require --ansi php-coveralls/php-coveralls:^2.4 symfony/console:^5 php-coveralls --coverage_clover=build/logs/clover.xml -v env: COVERALLS_REPO_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 8cd4cd33bf357247b0b6fc40b099d6d54ceda113 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 15:49:25 +0900 Subject: [PATCH 0892/2325] refactor: Time::getDst() --- system/I18n/Time.php | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/system/I18n/Time.php b/system/I18n/Time.php index ca8ffc3dc72e..c182bee32e7e 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -479,21 +479,7 @@ public function getQuarter(): string */ public function getDst(): bool { - // grab the transactions that would affect today - $start = strtotime('-1 year', $this->getTimestamp()); - $end = strtotime('+2 year', $start); - $transitions = $this->timezone->getTransitions($start, $end); - - $daylightSaving = false; - - foreach ($transitions as $transition) { - if ($transition['time'] > $this->format('U')) { - $daylightSaving = (bool) ($transition['isdst'] ?? $daylightSaving); - break; - } - } - - return $daylightSaving; + return (bool) $this->format('I'); } /** From 027381d6fbbf18a284d4e75061f8e36919774c93 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Dec 2021 20:34:00 +0900 Subject: [PATCH 0893/2325] chore: fix example test code for starter and module --- .../tests/database/ExampleDatabaseTest.php | 12 ++++++------ .../module/tests/session/ExampleSessionTest.php | 17 +++++++---------- .../tests/database/ExampleDatabaseTest.php | 3 +++ .../tests/session/ExampleSessionTest.php | 7 +++++-- 4 files changed, 21 insertions(+), 18 deletions(-) diff --git a/admin/module/tests/database/ExampleDatabaseTest.php b/admin/module/tests/database/ExampleDatabaseTest.php index 203b1261c7e0..f9edc4d235d8 100644 --- a/admin/module/tests/database/ExampleDatabaseTest.php +++ b/admin/module/tests/database/ExampleDatabaseTest.php @@ -1,18 +1,18 @@ session->set('logged_in', 123); - - $value = $this->session->get('logged_in'); + $session = Services::session(); - $this->assertSame(123, $value); + $session->set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); } } diff --git a/admin/starter/tests/database/ExampleDatabaseTest.php b/admin/starter/tests/database/ExampleDatabaseTest.php index 5d13836f9dc6..f9edc4d235d8 100644 --- a/admin/starter/tests/database/ExampleDatabaseTest.php +++ b/admin/starter/tests/database/ExampleDatabaseTest.php @@ -2,6 +2,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; +use Tests\Support\Database\Seeds\ExampleSeeder; use Tests\Support\Models\ExampleModel; /** @@ -11,6 +12,8 @@ final class ExampleDatabaseTest extends CIUnitTestCase { use DatabaseTestTrait; + protected $seed = ExampleSeeder::class; + public function testModelFindAll() { $model = new ExampleModel(); diff --git a/admin/starter/tests/session/ExampleSessionTest.php b/admin/starter/tests/session/ExampleSessionTest.php index 151036412146..98fe7afa0d77 100644 --- a/admin/starter/tests/session/ExampleSessionTest.php +++ b/admin/starter/tests/session/ExampleSessionTest.php @@ -1,6 +1,7 @@ session->set('logged_in', 123); - $this->assertSame(123, $this->session->get('logged_in')); + $session = Services::session(); + + $session->set('logged_in', 123); + $this->assertSame(123, $session->get('logged_in')); } } From dfeb02f744f95ac879a2fc3550eea8b72c459916 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 08:31:56 +0900 Subject: [PATCH 0894/2325] docs: fix sample code that uses non-existent methods --- user_guide_src/source/libraries/time.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 12f3a9f38e7e..cd8dc0a9ddcf 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -334,9 +334,9 @@ thrown. :: $time = $time->setYear(2017); - $time = $time->setMonthNumber(4); // April - $time = $time->setMonthLongName('April'); - $time = $time->setMonthShortName('Feb'); // February + $time = $time->setMonth(4); // April + $time = $time->setMonth('April'); + $time = $time->setMonth('Feb'); // February $time = $time->setDay(25); $time = $time->setHour(14); // 2:00 pm $time = $time->setMinute(30); From 4ea0156e387b0684477e6d313332213eec76045d Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 08:35:28 +0900 Subject: [PATCH 0895/2325] docs: decorate class,method,variable with '``' --- user_guide_src/source/libraries/time.rst | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index cd8dc0a9ddcf..11093a3b5a60 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -4,7 +4,7 @@ Times and Dates CodeIgniter provides a fully-localized, immutable, date/time class that is built on PHP's DateTime object, but uses the Intl extension's features to convert times across timezones and display the output correctly for different locales. This class -is the **Time** class and lives in the **CodeIgniter\\I18n** namespace. +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. @@ -38,7 +38,7 @@ provided, the application defaults will be used. now() ----- -The Time class has several helper methods to instantiate the class. The first of these is the **now()** method +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 in the second and parameters, respectively. If no locale or timezone is provided, the application defaults will be used. @@ -92,7 +92,7 @@ fourth and fifth parameters:: createFromTime() ---------------- -Like **createFromDate** except it is only concerned with the **hours**, **minutes**, and **seconds**. Uses the +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 fourth and fifth parameters:: @@ -113,7 +113,7 @@ 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:: +and returns a ``Time`` instance, instead of DateTime:: $time = Time::createFromFormat('j-M-Y', '15-Feb-2009', 'America/Chicago'); @@ -154,7 +154,7 @@ 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, +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. A full listing of values can be found `here `__. :: @@ -224,8 +224,8 @@ The Time object provides a number of methods to allow to get and set individual of an existing instance. All of the values retrieved through the following methods will be fully localized and respect the locale that the Time instance was created with. -All of the following `getX` and `setX` methods can also be used as if they were a class property. So, any calls to methods -like `getYear` can also be accessed through `$time->year`, and so on. +All of the following ``getX()`` and ``setX()`` methods can also be used as if they were a class property. So, any calls to methods +like ``getYear()`` can also be accessed through ``$time->year``, and so on. Getters ------- @@ -416,7 +416,7 @@ a timezone string in as the second parameter. If no timezone is given, the syste sameAs() -------- -This is identical to the **equals** method, except that it only returns true when the date, time, AND timezone are +This is identical to the ``equals()`` method, except that it only returns true when the date, time, AND timezone are all identical:: $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); @@ -446,7 +446,7 @@ a timezone string in as the second parameter. If no timezone is given, the syste isAfter() --------- -Works exactly the same as **isBefore()** except checks if the time is after the time passed in:: +Works exactly the same as ``isBefore()`` except checks if the time is after the time passed in:: $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); $time2 = Time::parse('January 11, 2017 03:50:00', 'America/Chicago'); @@ -457,7 +457,7 @@ Works exactly the same as **isBefore()** except checks if the time is after the Viewing Differences =================== -To compare two Times directly, you would use the **difference()** method, which returns a **CodeIgniter\\I18n\\TimeDifference** +To compare two Times directly, you would use the ``difference()`` method, which returns a ``CodeIgniter\\I18n\\TimeDifference`` instance. The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If a string is passed in the first parameter, the second parameter can be a timezone string:: @@ -484,7 +484,7 @@ the original time:: echo $diff->getMinutes(); // -3682080 echo $diff->getSeconds(); // -220924800 -You can use either **getX()** methods, or access the calculate values as if they were properties:: +You can use either ``getX()`` methods, or access the calculate values as if they were properties:: echo $diff->years; // -7 echo $diff->months; // -84 @@ -497,7 +497,7 @@ You can use either **getX()** methods, or access the calculate values as if they humanize() ---------- -Much like Time's humanize() method, this returns a string that displays the difference between the times in a +Much like Time's ``humanize()`` method, this returns a string that displays the difference between the times in a human readable format that is geared towards being easily understood. It can create strings like '3 hours ago', 'in 1 month', etc. The biggest differences are in how very recent dates are handled:: From c30e02622109571d1a49710978034584c8599408 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 08:37:47 +0900 Subject: [PATCH 0896/2325] docs: decrate filename with ** --- user_guide_src/source/libraries/time.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 11093a3b5a60..6b2c2c32efd0 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -214,7 +214,7 @@ $time > now && < 1 hour in 35 minutes / 35 minutes ago $time == now Now =============================== ================================= -The exact language used is controlled through the language file, Time.php. +The exact language used is controlled through the language file, **Time.php**. ============================== Working with Individual Values @@ -522,4 +522,4 @@ $time > 1 minute && < 1 hour in 35 minutes / 35 minutes ago $time < 1 minute Now =============================== ================================= -The exact language used is controlled through the language file, Time.php. +The exact language used is controlled through the language file, **Time.php**. From 4cbbd7ecd6b520ef46b3fb537e14e823bcfa7b7d Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 08:38:29 +0900 Subject: [PATCH 0897/2325] docs: align comments --- user_guide_src/source/libraries/time.rst | 82 ++++++++++++------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 6b2c2c32efd0..494a934b4fea 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -85,7 +85,7 @@ Given separate inputs for **year**, **month**, and **day**, will return a new in are not provided, it will use the current value to fill it in. Accepts strings for the timezone and locale in the fourth and fifth parameters:: - $today = Time::createFromDate(); // Uses current year, month, and day + $today = Time::createFromDate(); // Uses current year, month, and day $anniversary = Time::createFromDate(2018); // Uses current month and day $date = Time::createFromDate(2018, 3, 15, 'America/Chicago', 'en_US'); @@ -96,7 +96,7 @@ Like ``createFromDate()`` except it is only concerned with the **hours**, **minu current day for the date portion of the Time instance. Accepts strings for the timezone and locale in the fourth and fifth parameters:: - $lunch = Time::createFromTime(11, 30); // 11:30 am today + $lunch = Time::createFromTime(11, 30); // 11:30 am today $dinner = Time::createFromTime(18, 00, 00); // 6:00 pm today $time = Time::createFromTime($hour, $minutes, $seconds, $timezone, $locale); @@ -234,17 +234,17 @@ The following basic getters exist:: $time = Time::parse('August 12, 2016 4:15:23pm'); - echo $time->getYear(); // 2016 - echo $time->getMonth(); // 8 - echo $time->getDay(); // 12 - echo $time->getHour(); // 16 + echo $time->getYear(); // 2016 + echo $time->getMonth(); // 8 + echo $time->getDay(); // 12 + echo $time->getHour(); // 16 echo $time->getMinute(); // 15 echo $time->getSecond(); // 23 - echo $time->year; // 2016 - echo $time->month; // 8 - echo $time->day; // 12 - echo $time->hour; // 16 + echo $time->year; // 2016 + echo $time->month; // 8 + echo $time->day; // 12 + echo $time->hour; // 16 echo $time->minute; // 15 echo $time->second; // 23 @@ -252,19 +252,19 @@ In addition to these, a number of methods exist to provide additional informatio $time = Time::parse('August 12, 2016 4:15:23pm'); - echo $time->getDayOfWeek(); // 6 - but may vary based on locale's starting day of the week - echo $time->getDayOfYear(); // 225 + echo $time->getDayOfWeek(); // 6 - but may vary based on locale's starting day of the week + echo $time->getDayOfYear(); // 225 echo $time->getWeekOfMonth(); // 2 - echo $time->getWeekOfYear(); // 33 - echo $time->getTimestamp(); // 1471018523 - UNIX timestamp - echo $time->getQuarter(); // 3 + echo $time->getWeekOfYear(); // 33 + echo $time->getTimestamp(); // 1471018523 - UNIX timestamp + echo $time->getQuarter(); // 3 - echo $time->dayOfWeek; // 6 - echo $time->dayOfYear; // 225 + echo $time->dayOfWeek; // 6 + echo $time->dayOfYear; // 225 echo $time->weekOfMonth; // 2 - echo $time->weekOfYear; // 33 - echo $time->timestamp; // 1471018523 - echo $time->quarter; // 3 + echo $time->weekOfYear; // 33 + echo $time->timestamp; // 1471018523 + echo $time->quarter; // 3 getAge() -------- @@ -275,7 +275,7 @@ the age of someone based on their birthday:: $time = Time::parse('5 years ago'); echo $time->getAge(); // 5 - echo $time->age; // 5 + echo $time->age; // 5 getDST() -------- @@ -283,14 +283,14 @@ getDST() Returns boolean true/false based on whether the Time instance is currently observing Daylight Savings Time:: echo Time::createFromDate(2012, 1, 1)->getDst(); // false - echo Time::createFromDate(2012, 9, 1)->dst; // true + echo Time::createFromDate(2012, 9, 1)->dst; // true getLocal() ---------- Returns boolean true if the Time instance is in the same timezone as the application is currently running in:: - echo Time::now()->getLocal(); // true + echo Time::now()->getLocal(); // true echo Time::now('Europe/London'); // false getUtc() @@ -299,7 +299,7 @@ getUtc() Returns boolean true if the Time instance is in UTC time:: echo Time::now('America/Chicago')->getUtc(); // false - echo Time::now('UTC')->utc; // true + echo Time::now('UTC')->utc; // true getTimezone() ------------- @@ -319,7 +319,7 @@ getTimezoneName() Returns the full `timezone string `__ of the Time instance:: echo Time::now('America/Chicago')->getTimezoneName(); // America/Chicago - echo Time::now('Europe/London')->timezoneName; // Europe/London + echo Time::now('Europe/London')->timezoneName; // Europe/London Setters ======= @@ -334,11 +334,11 @@ thrown. :: $time = $time->setYear(2017); - $time = $time->setMonth(4); // April + $time = $time->setMonth(4); // April $time = $time->setMonth('April'); - $time = $time->setMonth('Feb'); // February + $time = $time->setMonth('Feb'); // February $time = $time->setDay(25); - $time = $time->setHour(14); // 2:00 pm + $time = $time->setHour(14); // 2:00 pm $time = $time->setMinute(30); $time = $time->setSecond(54); @@ -350,10 +350,10 @@ Converts the time from it's current timezone into the new one:: $time = Time::parse('13 May 2020 10:00', 'America/Chicago'); $time2 = $time->setTimezone('Europe/London'); // Returns new instance converted to new timezone - echo $time->getTimezoneName(); // American/Chicago + echo $time->getTimezoneName(); // American/Chicago echo $time2->getTimezoneName(); // Europe/London - echo $time->toDateTimeString(); // 2020-05-13 10:00:00 + echo $time->toDateTimeString(); // 2020-05-13 10:00:00 echo $time2->toDateTimeString(); // 2020-05-13 18:00:00 setTimestamp() @@ -364,7 +364,7 @@ Returns a new instance with the date set to the new timestamp:: $time = Time::parse('May 10, 2017', 'America/Chicago'); $time2 = $time->setTimestamp(strtotime('April 1, 2017')); - echo $time->toDateTimeString(); // 2017-05-10 00:00:00 + echo $time->toDateTimeString(); // 2017-05-10 00:00:00 echo $time2->toDateTimeString(); // 2017-04-01 00:00:00 Modifying the Value @@ -422,7 +422,7 @@ all identical:: $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); $time2 = Time::parse('January 11, 2017 03:50:00', 'Europe/London'); - $time1->sameAs($time2); // false + $time1->sameAs($time2); // false $time2->sameAs('January 10, 2017 21:50:00', 'America/Chicago'); // true isBefore() @@ -476,21 +476,21 @@ the original time:: $diff = $current->difference($test); - echo $diff->getYears(); // -7 - echo $diff->getMonths(); // -84 - echo $diff->getWeeks(); // -365 - echo $diff->getDays(); // -2557 - echo $diff->getHours(); // -61368 + echo $diff->getYears(); // -7 + echo $diff->getMonths(); // -84 + echo $diff->getWeeks(); // -365 + echo $diff->getDays(); // -2557 + echo $diff->getHours(); // -61368 echo $diff->getMinutes(); // -3682080 echo $diff->getSeconds(); // -220924800 You can use either ``getX()`` methods, or access the calculate values as if they were properties:: echo $diff->years; // -7 - echo $diff->months; // -84 - echo $diff->weeks; // -365 - echo $diff->days; // -2557 - echo $diff->hours; // -61368 + echo $diff->months; // -84 + echo $diff->weeks; // -365 + echo $diff->days; // -2557 + echo $diff->hours; // -61368 echo $diff->minutes; // -3682080 echo $diff->seconds; // -220924800 From f55ddd28016fc258400fb905d2a19b5a3f495ecb Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 08:42:37 +0900 Subject: [PATCH 0898/2325] docs: remove duplicated '\' --- 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 494a934b4fea..57ee4d4572d6 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -457,7 +457,7 @@ Works exactly the same as ``isBefore()`` except checks if the time is after the Viewing Differences =================== -To compare two Times directly, you would use the ``difference()`` method, which returns a ``CodeIgniter\\I18n\\TimeDifference`` +To compare two Times directly, you would use the ``difference()`` method, which returns a ``CodeIgniter\I18n\TimeDifference`` instance. The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If a string is passed in the first parameter, the second parameter can be a timezone string:: From 11007b454370097d5e763472c62a01b737c33256 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 08:51:07 +0900 Subject: [PATCH 0899/2325] docs: add command prompt '>' before `php spark` --- user_guide_src/source/cli/cli_generators.rst | 2 +- user_guide_src/source/dbmgmt/forge.rst | 4 ++-- user_guide_src/source/installation/running.rst | 8 ++++---- user_guide_src/source/installation/troubleshooting.rst | 2 +- user_guide_src/source/tutorial/index.rst | 2 +- user_guide_src/source/tutorial/static_pages.rst | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/cli/cli_generators.rst b/user_guide_src/source/cli/cli_generators.rst index 210226b51edc..5cf4ed4279da 100644 --- a/user_guide_src/source/cli/cli_generators.rst +++ b/user_guide_src/source/cli/cli_generators.rst @@ -260,7 +260,7 @@ generator command are recognized by the scaffold command. Running this in your terminal:: - php spark make:scaffold user + > php spark make:scaffold user will create the following classes: diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index e1ed99e02c5c..720f77655d54 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -67,7 +67,7 @@ will complain that the database creation has failed. To start, just type the command and the name of the database (e.g., ``foo``):: - php spark db:create foo + > php spark db:create foo If everything went fine, you should expect the ``Database "foo" successfully created.`` message displayed. @@ -76,7 +76,7 @@ for the file where the database will be created using the ``--ext`` option. Vali ``sqlite`` and defaults to ``db``. Remember that these should not be preceded by a period. :: - php spark db:create foo --ext sqlite + > php spark db:create foo --ext sqlite // will create the db file in WRITEPATH/foo.sqlite .. note:: When using the special SQLite3 database name ``:memory:``, expect that the command will still diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index bb4b99aa468f..f16bb7636672 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -43,7 +43,7 @@ CodeIgniter 4 comes with a local development server, leveraging PHP's built-in w with CodeIgniter routing. You can use the ``serve`` script to launch it, with the following command line in the main directory:: - php spark serve + > php spark serve This will launch the server and you can now view your application in your browser at http://localhost:8080. @@ -58,17 +58,17 @@ The local development server can be customized with three command line options: - You can use the ``--host`` CLI option to specify a different host to run the application at:: - php spark serve --host example.dev + > php spark serve --host example.dev - By default, the server runs on port 8080 but you might have more than one site running, or already have another application using that port. You can use the ``--port`` CLI option to specify a different one:: - php spark serve --port 8081 + > php spark serve --port 8081 - You can also specify a specific version of PHP to use, with the ``--php`` CLI option, with its value set to the path of the PHP executable you want to use:: - php spark serve --php /usr/bin/php7.6.5.4 + > php spark serve --php /usr/bin/php7.6.5.4 Hosting with Apache =================== diff --git a/user_guide_src/source/installation/troubleshooting.rst b/user_guide_src/source/installation/troubleshooting.rst index ff30759efcad..0da650bdf07c 100644 --- a/user_guide_src/source/installation/troubleshooting.rst +++ b/user_guide_src/source/installation/troubleshooting.rst @@ -9,7 +9,7 @@ How do I know if my install is working? From the command line, at your project root:: - php spark serve + > php spark serve ``http://localhost:8080`` in your browser should then show the default welcome page: diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst index 6be36535579b..71182a6f5bf4 100644 --- a/user_guide_src/source/tutorial/index.rst +++ b/user_guide_src/source/tutorial/index.rst @@ -82,7 +82,7 @@ comes with a simple command that takes advantage of PHP's built-in server to get you up and running fast on your development machines. Type the following on the command line from the root of your project:: - php spark serve + > php spark serve The Welcome Page diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index 1763d1fae624..ecf6e87e03c5 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -178,7 +178,7 @@ From the command line, at the root of your project: :: - php spark serve + > php spark serve will start a web server, accessible on port 8080. If you set the location field in your browser to ``localhost:8080``, you should see the CodeIgniter welcome page. From 458aa5b24fbbd7f3848eb226777289972be9485b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 09:45:09 +0900 Subject: [PATCH 0900/2325] docs: add command prompt `>` before `composer` --- .../source/installation/installing_composer.rst | 14 +++++++------- user_guide_src/source/libraries/caching.rst | 2 +- user_guide_src/source/tutorial/index.rst | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/installation/installing_composer.rst b/user_guide_src/source/installation/installing_composer.rst index b63e34602425..41b288c02037 100644 --- a/user_guide_src/source/installation/installing_composer.rst +++ b/user_guide_src/source/installation/installing_composer.rst @@ -32,7 +32,7 @@ Installation & Set Up In the folder above your project root:: - composer create-project codeigniter4/appstarter project-root + > composer create-project codeigniter4/appstarter project-root The command above will create a "project-root" folder. @@ -46,7 +46,7 @@ trusted dependencies that we bundle, being composer-installed. A sample such installation command, using the default project-root "appstarter":: - composer create-project codeigniter4/appstarter --no-dev + > composer create-project codeigniter4/appstarter --no-dev After installation you should follow the steps in the "Upgrading" section. @@ -55,11 +55,11 @@ Upgrading Whenever there is a new release, then from the command line in your project root:: - composer update + > composer update If you want to compare the latest framework source structure for non-system directory (app, public, etc), you can update with ``--prefer-source``:: - composer update codeigniter4/framework --prefer-source + > composer update codeigniter4/framework --prefer-source If ``--prefer-source`` doesn't automatically update to pull latest framework source structure, you can remove first:: @@ -125,7 +125,7 @@ will be your document root. In your project root:: - composer require codeigniter4/framework --prefer-source + > composer require codeigniter4/framework --prefer-source As with the earlier two composer install methods, you can omit installing phpunit and its dependencies by adding the ``--no-dev`` argument to the ``composer require`` command. @@ -147,7 +147,7 @@ Upgrading Whenever there is a new release, then from the command line in your project root:: - composer update --prefer-source + > composer update --prefer-source Read the upgrade instructions, and check designated ``app/Config`` folders for affected changes. @@ -179,6 +179,6 @@ they can be added to your project in a similar fashion. From the command line inside your project root:: - composer require codeigniter4/translations + > composer require codeigniter4/translations These will be updated along with the framework whenever you do a ``composer update``. diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst index d9c79289c747..cc9049ee9a5d 100644 --- a/user_guide_src/source/libraries/caching.rst +++ b/user_guide_src/source/libraries/caching.rst @@ -315,7 +315,7 @@ Predis Caching Predis is a flexible and feature-complete PHP client library for the Redis key-value store. To use it, from the command line inside your project root:: - composer require predis/predis + > composer require predis/predis For more information on Redis, please see `https://github.com/nrk/predis `_. diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst index 6be36535579b..f396e44283c8 100644 --- a/user_guide_src/source/tutorial/index.rst +++ b/user_guide_src/source/tutorial/index.rst @@ -59,7 +59,7 @@ From your command line type the following: :: - composer create-project codeigniter4/appstarter ci-news + > composer create-project codeigniter4/appstarter ci-news This creates a new folder, **ci-news**, which contains your application code, with CodeIgniter installed in the vendor folder. From 5ecf75138a2d5debe505d285f35031daffcf620c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 09:55:41 +0900 Subject: [PATCH 0901/2325] docs: fix decoration for file path and code --- .../source/installation/upgrade_controllers.rst | 12 ++++++------ .../source/installation/upgrade_database.rst | 2 +- .../source/installation/upgrade_encryption.rst | 2 +- .../source/installation/upgrade_file_upload.rst | 2 +- .../source/installation/upgrade_localization.rst | 4 ++-- .../source/installation/upgrade_migrations.rst | 6 +++--- .../source/installation/upgrade_models.rst | 12 ++++++------ .../source/installation/upgrade_security.rst | 2 +- .../source/installation/upgrade_validations.rst | 8 ++++---- user_guide_src/source/installation/upgrade_views.rst | 6 +++--- 10 files changed, 28 insertions(+), 28 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index 2625bd29cbb0..003cad92a295 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -23,16 +23,16 @@ What has been changed Upgrade Guide ============= -1. First, move all controller files to the folder ``app/Controllers``. +1. First, move all controller files to the folder **app/Controllers**. 2. Add this line just after the opening php tag: ``namespace App\Controllers;`` 3. Replace ``extends CI_Controller`` with ``extends BaseController``. | If you use sub-directories in your controller structure, you have to change the namespace according to that. -| For example, you have a version 3 controller located in ``application/controllers/users/auth/Register.php``, +| For example, you have a version 3 controller located in **application/controllers/users/auth/Register.php**, the namespace has to be ``namespace App\Controllers\Users\Auth;`` and the controller path in the version 4 - should look like this: ``app/Controllers/Users/Auth/Register.php``. Make sure to have the first letters of + should look like this: **app/Controllers/Users/Auth/Register.php**. Make sure to have the first letters of the sub-directories as capitalized. -| After that you have to insert a "use" statement below the namespace definition in order to extend the "BaseController": +| After that you have to insert a ``use`` statement below the namespace definition in order to extend the ``BaseController``: ``use App\Controllers\BaseController;`` Code Example @@ -41,7 +41,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/controllers``:: +Path: **application/controllers**:: load->database();`` with ``$db = db_connect();``. 3. If you use multiple databases use the following code to load additional databases ``$db = db_connect('group_name');``. 4. Now you have to change all database queries. The most important change here is to replace ``$this->db`` with just ``$db`` and adjust the method name and ``$db``. Here are some examples: diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index dca7fbcbc27b..003abc7ae218 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -19,7 +19,7 @@ What has been changed Upgrade Guide ============= -1. Within your configs the ``$config['encryption_key'] = 'abc123';`` moved from ``application/config/config.php`` to ``public $key = 'abc123';`` in ``app/Config/Encryption.php``. +1. Within your configs the ``$config['encryption_key'] = 'abc123';`` moved from **application/config/config.php** to ``public $key = 'abc123';`` in **app/Config/Encryption.php**. 2. Wherever you have used the encryption library you have to replace ``$this->load->library('encryption');`` with ``$encrypter = service('encrypter');`` and change the methods for encryption and decrypting like in the following code example. Code Example diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index 3369442e6392..6161e999f45e 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -18,7 +18,7 @@ What has been changed Upgrade Guide ============= In CI4 you access uploaded files with ``$file = $this->request->getFile('userfile')``. From there you can validate if the file got uploaded successfully with ``$file->isValid()``. -To store the file you could use ``$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg');`` This will store the file in ``writable/uploads/head_img/user_name.jpg``. +To store the file you could use ``$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg');``. This will store the file in **writable/uploads/head_img/user_name.jpg**. You have to change your file uploading code to match the new methods. diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index b974570f5939..ca919c7cdb1b 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -19,11 +19,11 @@ What has been changed Upgrade Guide ============= -1. Specify the default language in *Config/App.php*::: +1. Specify the default language in **Config/App.php**:: public $defaultLocale = 'en'; -2. Now move your language files to ``app/Language//``. +2. Now move your language files to **app/Language/**. 3. After that you have to change the syntax within the language files. Below in the Code Example you will see how the language array within the file should look like. 4. Remove from every file the language loader ``$this->lang->load($file, $lang);``. 5. Replace the method to load the language line ``$this->lang->line('error_email_missing')`` with ``echo lang('Errors.errorEmailMissing');``. diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 10a75bf23f2d..9141cc82ae21 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -25,7 +25,7 @@ Upgrade Guide ============= 1. If your v3 project uses sequential migration names you have to change those to timestamp names. -2. You have to move all migration files to the new folder ``app/Database/Migrations``. +2. You have to move all migration files to the new folder **app/Database/Migrations**. 3. Remove the following line ``defined('BASEPATH') OR exit('No direct script access allowed');``. 4. Add this line just after the opening php tag: ``namespace App\Database\Migrations;``. 5. Below the ``namespace App\Database\Migrations;`` line add this line: ``use CodeIgniter\Database\Migration;`` @@ -51,7 +51,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/migrations``:: +Path: **application/migrations**:: load->model(x);``, you would now use ``$this->x = new X();``, following namespaced conventions for your component. Alternatively, you can use the ``model`` function: ``$this->x = model('X');``. +5. Instead of CI3’s ``$this->load->model(x);``, you would now use ``$this->x = new X();``, following namespaced conventions for your component. Alternatively, you can use the ``model()`` function: ``$this->x = model('X');``. If you use sub-directories in your model structure you have to change the namespace according to that. -Example: You have a version 3 model located in ``application/models/users/user_contact.php`` the namespace has to be ``namespace App\Models\Users;`` and the model path in the version 4 should look like this: ``app/Models/Users/UserContact.php`` +Example: You have a version 3 model located in **application/models/users/user_contact.php** the namespace has to be ``namespace App\Models\Users;`` and the model path in the version 4 should look like this: **app/Models/Users/UserContact.php** The new Model in CI4 has a lot of built-in methods. For example, the ``find($id)`` method. With this you can find data where the primary key is equal to ``$id``. Inserting data is also easier than before. In CI4 there is an ``insert($data)`` method. You can optionally make use of all those built-in methods and migrate your code to the new methods. @@ -41,7 +41,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/models``:: +Path: **application/models**:: insert()`` method because this method is built-in since CI 4. +To insert data you can just directly call the ``$model->insert()`` method because this method is built-in since CI4. diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 4aeb34e513c9..12990ba63347 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -21,7 +21,7 @@ What has been changed Upgrade Guide ============= -1. To enable CSRF protection in CI4 you have to enable it in ``app/Config/Filters.php``:: +1. To enable CSRF protection in CI4 you have to enable it in **app/Config/Filters.php**:: public $globals = [ 'before' => [ diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 5e2b1a2bf942..083479d210db 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -46,7 +46,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/views``:: +Path: **application/views**:: @@ -77,7 +77,7 @@ Path: ``application/views``:: -Path: ``application/controllers/``:: +Path: **application/controllers**:: @@ -135,7 +135,7 @@ Path: ``app/Views``:: -Path: ``app/Controllers/``:: +Path: **app/Controllers**:: load->view('directory_name/file_name')`` to ``echo view('directory_name/file_name');`` 3. (optional) You can change the echo syntax in views from ```` to ```` @@ -33,7 +33,7 @@ Code Example CodeIgniter Version 3.11 ------------------------ -Path: ``application/views``:: +Path: **application/views**:: @@ -56,7 +56,7 @@ Path: ``application/views``:: CodeIgniter Version 4.x ----------------------- -Path: ``app/Views``:: +Path: **app/Views**:: From f3eea52e21dee98ae74fbe6e372ebe892bd7e0dc Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 5 Dec 2021 11:53:00 +0900 Subject: [PATCH 0902/2325] docs: add "License Agreement" and "Change Logs" in the TOC --- user_guide_src/source/installation/index.rst | 1 + user_guide_src/source/intro/index.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/user_guide_src/source/installation/index.rst b/user_guide_src/source/installation/index.rst index 37a4e61751a0..c29bcd33857e 100644 --- a/user_guide_src/source/installation/index.rst +++ b/user_guide_src/source/installation/index.rst @@ -19,6 +19,7 @@ Which is right for you? installing_manual running upgrading + ../changelogs/index troubleshooting repositories diff --git a/user_guide_src/source/intro/index.rst b/user_guide_src/source/intro/index.rst index 2a815c7d6d2b..4daafc228876 100644 --- a/user_guide_src/source/intro/index.rst +++ b/user_guide_src/source/intro/index.rst @@ -44,3 +44,4 @@ CodeIgniter is right for you if: requirements credits psr + License Agreement <../license> From 92820fa54301e4875107460619ce67932b4702e9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 10:44:58 +0900 Subject: [PATCH 0903/2325] test: add tests for current validation behaviors --- tests/system/Validation/FormatRulesTest.php | 67 +++++++++++++++ tests/system/Validation/ValidationTest.php | 95 +++++++++++++++++++++ 2 files changed, 162 insertions(+) diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index 9a2e9bd46efc..1d7a0b33dc85 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -797,6 +797,73 @@ public function numericProvider(): Generator ]; } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5374 + * + * @dataProvider integerInvalidTypeDataProvider + * + * @param mixed $value + */ + public function testIntegerWithInvalidTypeData($value, bool $expected): void + { + $this->validation->setRules([ + 'foo' => 'integer', + ]); + + $data = [ + 'foo' => $value, + ]; + $this->assertsame($expected, $this->validation->run($data)); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5374 + * + * @dataProvider integerInvalidTypeDataProvider + * + * @param mixed $value + */ + public function testNumericWithInvalidTypeData($value, bool $expected): void + { + $this->validation->setRules([ + 'foo' => 'numeric', + ]); + + $data = [ + 'foo' => $value, + ]; + $this->assertsame($expected, $this->validation->run($data)); + } + + public function integerInvalidTypeDataProvider(): Generator + { + yield 'array with int' => [ + [555], + true, // incorrect + ]; + + // TypeError : CodeIgniter\Validation\FormatRules::integer(): Argument #1 ($str) must be of type ?string, array given + // yield 'empty array' => [ + // [], + // false, + // ]; + + yield 'bool true' => [ + true, + true, // incorrect + ]; + + yield 'bool false' => [ + false, + false, + ]; + + yield 'null' => [ + null, + false, + ]; + } + /** * @dataProvider integerProvider */ diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index cffde6abf3bd..f218117a70f8 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -100,6 +100,101 @@ public function testRunDoesTheBasics(): void $this->assertFalse($this->validation->run($data)); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5368 + * + * @dataProvider arrayDataProvider + * + * @param mixed $value + */ + public function testCanValidatetArrayData($value, bool $expected): void + { + $this->validation->setRules(['arr' => 'is_array']); + + $data['arr'] = $value; + $this->assertSame($expected, $this->validation->run($data)); + } + + public function arrayDataProvider(): Generator + { + yield 'list array' => [ + [1, 2, 3, 4, 5], + false, // incorrect + ]; + + yield 'associative array' => [ + [ + 'username' => 'admin001', + 'role' => 'administrator', + 'usepass' => 0, + ], + false, // incorrect + ]; + + yield 'int' => [ + 0, + false, + ]; + + yield 'string int' => [ + '0', + false, + ]; + + yield 'bool' => [ + false, + false, + ]; + + yield 'null' => [ + null, + false, + ]; + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5374 + * + * @dataProvider isIntInvalidTypeDataProvider + * + * @param mixed $value + */ + public function testIsIntWithInvalidTypeData($value, bool $expected): void + { + $this->validation->setRules(['foo' => 'is_int']); + + $data = ['foo' => $value]; + $this->assertSame($expected, $this->validation->run($data)); + } + + public function isIntInvalidTypeDataProvider(): Generator + { + yield 'array with int' => [ + [555], + true, // incorrect + ]; + + yield 'empty array' => [ + [], + false, + ]; + + yield 'bool true' => [ + true, + false, + ]; + + yield 'bool false' => [ + false, + false, + ]; + + yield 'null' => [ + null, + false, + ]; + } + public function testRunReturnsLocalizedErrors(): void { $data = ['foo' => 'notanumber']; From 61e476a36249048106c603a1412abeefc02fd7b4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 10:53:47 +0900 Subject: [PATCH 0904/2325] refactor: pass valid type value to method/function --- system/Validation/Validation.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 876ab3caffa0..e28a704a31b9 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -295,7 +295,8 @@ protected function processRules(string $field, ?string $label, $value, $rules = $value = json_encode($value); } - $this->errors[$field] = $error ?? $this->getErrorMessage($rule, $field, $label, $param, $value); + $param = ($param === false) ? '' : $param; + $this->errors[$field] = $error ?? $this->getErrorMessage($rule, $field, $label, $param, (string) $value); return false; } @@ -646,6 +647,9 @@ public function setError(string $field, string $error): ValidationInterface */ protected function getErrorMessage(string $rule, string $field, ?string $label = null, ?string $param = null, ?string $value = null): string { + $param = $param ?? ''; + + // Check if custom message has been defined by user if (isset($this->customErrors[$field][$rule])) { $message = lang($this->customErrors[$field][$rule]); } else { From cfd27fbdb0ecaa6a9501c88a94c4215f39274e18 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 10:59:36 +0900 Subject: [PATCH 0905/2325] docs: fix typo in comment --- system/Validation/Validation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index e28a704a31b9..20f388fb59ff 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -261,7 +261,7 @@ protected function processRules(string $field, ?string $label, $value, $rules = // Placeholder for custom errors from the rules. $error = null; - // If it's a callable, call and and get out of here. + // If it's a callable, call and get out of here. if ($isCallable) { $passed = $param === false ? $rule($value) : $rule($value, $param, $data); } else { From 6b3121d0ffe199c4b71ffe6ba37bb87c3180e083 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 11:00:36 +0900 Subject: [PATCH 0906/2325] fix: cast $value to string, because it may be int/bool/null... --- system/Validation/Validation.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 20f388fb59ff..f2c467c95e13 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -215,7 +215,7 @@ protected function processRules(string $field, ?string $label, $value, $rules = } if (in_array('permit_empty', $rules, true)) { - if (! in_array('required', $rules, true) && (is_array($value) ? $value === [] : trim($value ?? '') === '')) { + if (! in_array('required', $rules, true) && (is_array($value) ? $value === [] : trim((string) $value) === '')) { $passed = true; foreach ($rules as $rule) { From 16b027f8514edf71a39cd47291af8f3c53b6a9c7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 11:09:43 +0900 Subject: [PATCH 0907/2325] fix: separate process of multiple field and single field --- system/Validation/Validation.php | 12 ++++++++---- tests/system/Validation/FormatRulesTest.php | 9 +++++---- tests/system/Validation/ValidationTest.php | 6 +++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index f2c467c95e13..c2a31790e2cc 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -139,16 +139,20 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup } $values = dot_array_search($field, $data); - $values = is_array($values) ? $values : [$values]; if ($values === []) { // We'll process the values right away if an empty array $this->processRules($field, $setup['label'] ?? $field, $values, $rules, $data); } - foreach ($values as $value) { - // Otherwise, we'll let the loop do the job - $this->processRules($field, $setup['label'] ?? $field, $value, $rules, $data); + if (strpos($field, '*') !== false && is_array($values)) { + // Process multiple fields + foreach ($values as $value) { + $this->processRules($field, $setup['label'] ?? $field, $value, $rules, $data); + } + } else { + // Process single field + $this->processRules($field, $setup['label'] ?? $field, $values, $rules, $data); } } diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index 1d7a0b33dc85..411c173fcf8d 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -837,10 +837,11 @@ public function testNumericWithInvalidTypeData($value, bool $expected): void public function integerInvalidTypeDataProvider(): Generator { - yield 'array with int' => [ - [555], - true, // incorrect - ]; + // TypeError : CodeIgniter\Validation\FormatRules::integer(): Argument #1 ($str) must be of type ?string, array given + // yield 'array with int' => [ + // [555], + // false, + // ]; // TypeError : CodeIgniter\Validation\FormatRules::integer(): Argument #1 ($str) must be of type ?string, array given // yield 'empty array' => [ diff --git a/tests/system/Validation/ValidationTest.php b/tests/system/Validation/ValidationTest.php index f218117a70f8..d075b7b59151 100644 --- a/tests/system/Validation/ValidationTest.php +++ b/tests/system/Validation/ValidationTest.php @@ -119,7 +119,7 @@ public function arrayDataProvider(): Generator { yield 'list array' => [ [1, 2, 3, 4, 5], - false, // incorrect + true, ]; yield 'associative array' => [ @@ -128,7 +128,7 @@ public function arrayDataProvider(): Generator 'role' => 'administrator', 'usepass' => 0, ], - false, // incorrect + true, ]; yield 'int' => [ @@ -171,7 +171,7 @@ public function isIntInvalidTypeDataProvider(): Generator { yield 'array with int' => [ [555], - true, // incorrect + false, ]; yield 'empty array' => [ From aac0a51bce155190ba9239921fa5f49705feabcf Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 11:14:47 +0900 Subject: [PATCH 0908/2325] style: break long lines --- system/Validation/Validation.php | 36 ++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index c2a31790e2cc..e915e8c46528 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -198,11 +198,15 @@ protected function processRules(string $field, ?string $label, $value, $rules = // that can be used later $ifExistField = str_replace('\.\*', '\.(?:[^\.]+)', preg_quote($field, '/')); - $dataIsExisting = array_reduce(array_keys($flattenedData), static function ($carry, $item) use ($ifExistField) { - $pattern = sprintf('/%s/u', $ifExistField); - - return $carry || preg_match($pattern, $item) === 1; - }, false); + $dataIsExisting = array_reduce( + array_keys($flattenedData), + static function ($carry, $item) use ($ifExistField) { + $pattern = sprintf('/%s/u', $ifExistField); + + return $carry || preg_match($pattern, $item) === 1; + }, + false + ); } else { $dataIsExisting = array_key_exists($ifExistField, $flattenedData); } @@ -219,7 +223,10 @@ protected function processRules(string $field, ?string $label, $value, $rules = } if (in_array('permit_empty', $rules, true)) { - if (! in_array('required', $rules, true) && (is_array($value) ? $value === [] : trim((string) $value) === '')) { + if ( + ! in_array('required', $rules, true) + && (is_array($value) ? $value === [] : trim((string) $value) === '') + ) { $passed = true; foreach ($rules as $rule) { @@ -278,7 +285,8 @@ protected function processRules(string $field, ?string $label, $value, $rules = } $found = true; - $passed = $param === false ? $set->{$rule}($value, $error) : $set->{$rule}($value, $param, $data, $error); + $passed = $param === false ? $set->{$rule}($value, $error) + : $set->{$rule}($value, $param, $data, $error); break; } @@ -300,7 +308,13 @@ protected function processRules(string $field, ?string $label, $value, $rules = } $param = ($param === false) ? '' : $param; - $this->errors[$field] = $error ?? $this->getErrorMessage($rule, $field, $label, $param, (string) $value); + $this->errors[$field] = $error ?? $this->getErrorMessage( + $rule, + $field, + $label, + $param, + (string) $value + ); return false; } @@ -664,7 +678,11 @@ protected function getErrorMessage(string $rule, string $field, ?string $label = } $message = str_replace('{field}', empty($label) ? $field : lang($label), $message); - $message = str_replace('{param}', empty($this->rules[$param]['label']) ? $param : lang($this->rules[$param]['label']), $message); + $message = str_replace( + '{param}', + empty($this->rules[$param]['label']) ? $param : lang($this->rules[$param]['label']), + $message + ); return str_replace('{value}', $value ?? '', $message); } From a42a641bd946537bf280e9c8c53b4b46ab1665d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 29 Nov 2021 11:42:25 +0900 Subject: [PATCH 0909/2325] docs: add about Validation result changes in Upgrading --- .../source/installation/upgrade_416.rst | 55 +++++++++++++++++++ .../source/installation/upgrading.rst | 1 + 2 files changed, 56 insertions(+) create mode 100644 user_guide_src/source/installation/upgrade_416.rst diff --git a/user_guide_src/source/installation/upgrade_416.rst b/user_guide_src/source/installation/upgrade_416.rst new file mode 100644 index 000000000000..2735e4b07aa4 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_416.rst @@ -0,0 +1,55 @@ +############################# +Upgrading from 4.1.5 to 4.1.6 +############################# + +.. contents:: + :local: + :depth: 2 + +Breaking Changes +**************** + +Validation result changes +========================= + +The previous version of the Validation can't handle an array item. +Because of the bug fix, the validation results may be different, +or raise an TypeError. +But the previous version's results are probably incorrect. + +And the Validation separated the validation process of multiple field +like ``contacts.*.name`` and single field. +When a single field has an array data, the previous version validates each element of the array. +The validation rule gets an element of the array as the parameter. +On the other hand, the current version passes the array to the validation rule as a whole. + +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 +=============== + +The following files received significant changes (including deprecations or visual adjustments) +and it is recommended that you merge the updated versions with your application: + +* + +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: + +* diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 0264b6eaa3bb..771392d8f81a 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -8,6 +8,7 @@ upgrading from. .. toctree:: :titlesonly: + Upgrading from 4.1.5 to 4.1.6 Upgrading from 4.1.4 to 4.1.5 Upgrading from 4.1.3 to 4.1.4 Upgrading from 4.1.2 to 4.1.3 From 0485bb79bace65e1f831e198efa75faeaa4994d1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 5 Dec 2021 11:23:55 +0900 Subject: [PATCH 0910/2325] docs: the longer explanation in the changelog, the upgrading section has actual tasks that need to be done when upgrading --- user_guide_src/source/changelogs/v4.1.6.rst | 16 +++++++++++++++- .../source/installation/upgrade_416.rst | 11 +---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 2bb0f77f9536..2e2c50b11869 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -7,12 +7,26 @@ Release Date: Not released .. contents:: :local: - :depth: 1 + :depth: 2 BREAKING ======== - Multiple table names will no longer be stored in ``BaseBuilder::$tableName`` - an empty string will be used instead. +.. _changelog-v416-validation-changes: + +Validation changes +------------------ +- The previous version of the Validation can't handle an array item. + Because of the bug fix, the validation results may be different, + or raise an TypeError. + But the previous version's results are probably incorrect. +- The Validation separated the validation process of multiple field + like ``contacts.*.name`` and single field. + When a single field has an array data, the previous version validates each element of the array. + The validation rule gets an element of the array as the parameter. + On the other hand, the current version passes the array to the validation rule as a whole. + Enhancements ============ - Database pane on debug toolbar now displays location where Query was called from. Also displays full backtrace. diff --git a/user_guide_src/source/installation/upgrade_416.rst b/user_guide_src/source/installation/upgrade_416.rst index 2735e4b07aa4..a0c1cbd02a1b 100644 --- a/user_guide_src/source/installation/upgrade_416.rst +++ b/user_guide_src/source/installation/upgrade_416.rst @@ -12,16 +12,7 @@ Breaking Changes Validation result changes ========================= -The previous version of the Validation can't handle an array item. -Because of the bug fix, the validation results may be different, -or raise an TypeError. -But the previous version's results are probably incorrect. - -And the Validation separated the validation process of multiple field -like ``contacts.*.name`` and single field. -When a single field has an array data, the previous version validates each element of the array. -The validation rule gets an element of the array as the parameter. -On the other hand, the current version passes the array to the validation rule as a whole. +Due to a bug fix, the Validation now might change the validation results when you validate an array item (see :ref:`Changelog `). So check the validation results for all the code that validates the array. Validating multiple fields like ``contacts.*.name`` is not affected. Breaking Enhancements ********************* From 622fc0486cf675f82533532cffbc9b6267a686ed Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Dec 2021 11:39:30 +0900 Subject: [PATCH 0911/2325] docs: add space after `,` in sample code --- user_guide_src/source/dbmgmt/forge.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index 720f77655d54..29f35e7a83f0 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -230,18 +230,18 @@ Adding Foreign Keys Foreign Keys help to enforce relationships and actions across your tables. For tables that support Foreign Keys, you may add them directly in forge:: - $forge->addForeignKey('users_id','users','id'); + $forge->addForeignKey('users_id', 'users', 'id'); // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) - $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name']); + $forge->addForeignKey(['users_id', 'users_name'], 'users', ['id', 'name']); // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) You can specify the desired action for the "on delete" and "on update" properties of the constraint:: - $forge->addForeignKey('users_id','users','id','CASCADE','CASCADE'); + $forge->addForeignKey('users_id', 'users', 'id', 'CASCADE', 'CASCADE'); // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`) REFERENCES `users`(`id`) ON DELETE CASCADE ON UPDATE CASCADE - $forge->addForeignKey(['users_id', 'users_name'],'users',['id', 'name'],'CASCADE','CASCADE'); + $forge->addForeignKey(['users_id', 'users_name'], 'users', ['id', 'name'], 'CASCADE', 'CASCADE'); // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) ON DELETE CASCADE ON UPDATE CASCADE Creating a table @@ -302,7 +302,7 @@ Execute a DROP FOREIGN KEY. :: // Produces: ALTER TABLE `tablename` DROP FOREIGN KEY `users_foreign` - $forge->dropForeignKey('tablename','users_foreign'); + $forge->dropForeignKey('tablename', 'users_foreign'); Dropping a Key @@ -313,7 +313,7 @@ Execute a DROP KEY. :: // Produces: DROP INDEX `users_index` ON `tablename` - $forge->dropKey('tablename','users_index'); + $forge->dropKey('tablename', 'users_index'); Renaming a table ================ From a0a55ed84447904cb64e176294daa1d46f04c340 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Dec 2021 17:09:05 +0900 Subject: [PATCH 0912/2325] fix: when useAutoIncrement is disabled, countAllResults() is called --- system/Model.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Model.php b/system/Model.php index c73e5c716778..bcc1d46a48c6 100644 --- a/system/Model.php +++ b/system/Model.php @@ -584,12 +584,12 @@ public function set($key, $value = '', ?bool $escape = null) */ protected function shouldUpdate($data): bool { - // When useAutoIncrement feature is disabled check + // When useAutoIncrement feature is disabled, check // in the database if given record already exists return parent::shouldUpdate($data) - && $this->useAutoIncrement + && ($this->useAutoIncrement ? true - : $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1; + : $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1); } /** From 35b612b075c6e7cc7930f05ff817f6f5f05fad03 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Dec 2021 21:01:49 +0900 Subject: [PATCH 0913/2325] refactor: early return Complex conditions cause bugs. --- system/Model.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/system/Model.php b/system/Model.php index bcc1d46a48c6..767f7de08048 100644 --- a/system/Model.php +++ b/system/Model.php @@ -584,12 +584,15 @@ public function set($key, $value = '', ?bool $escape = null) */ protected function shouldUpdate($data): bool { + if (parent::shouldUpdate($data) === false) { + return false; + } + // When useAutoIncrement feature is disabled, check // in the database if given record already exists - return parent::shouldUpdate($data) - && ($this->useAutoIncrement + return $this->useAutoIncrement ? true - : $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1); + : $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1; } /** From 41f56cfb68fa18f6eed793e2eeef93b642884ced Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Dec 2021 21:29:15 +0900 Subject: [PATCH 0914/2325] style: add line break Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/Validation/Validation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index e915e8c46528..288fe8e02653 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -285,7 +285,8 @@ static function ($carry, $item) use ($ifExistField) { } $found = true; - $passed = $param === false ? $set->{$rule}($value, $error) + $passed = $param === false + ? $set->{$rule}($value, $error) : $set->{$rule}($value, $param, $data, $error); break; From dfdba23f490d5f07d2d1d28c1f810d18802b044e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Dec 2021 21:30:01 +0900 Subject: [PATCH 0915/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/changelogs/v4.1.6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 2e2c50b11869..4cddcc21f953 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -19,7 +19,7 @@ Validation changes ------------------ - The previous version of the Validation can't handle an array item. Because of the bug fix, the validation results may be different, - or raise an TypeError. + or raise a ``TypeError``. But the previous version's results are probably incorrect. - The Validation separated the validation process of multiple field like ``contacts.*.name`` and single field. From 82573aad8ae410aa433544b805052677201d34b2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Dec 2021 21:30:53 +0900 Subject: [PATCH 0916/2325] style: add new line --- system/Validation/Validation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 288fe8e02653..67cf1a16853d 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -308,7 +308,8 @@ static function ($carry, $item) use ($ifExistField) { $value = json_encode($value); } - $param = ($param === false) ? '' : $param; + $param = ($param === false) ? '' : $param; + $this->errors[$field] = $error ?? $this->getErrorMessage( $rule, $field, From d16b5ea53f3ddd2218325e9b220c4343fb40e0a3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 6 Dec 2021 22:03:11 +0900 Subject: [PATCH 0917/2325] fix: $this->processRules() may run twice --- system/Validation/Validation.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 67cf1a16853d..39af6703f8df 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -143,6 +143,8 @@ public function run(?array $data = null, ?string $group = null, ?string $dbGroup if ($values === []) { // We'll process the values right away if an empty array $this->processRules($field, $setup['label'] ?? $field, $values, $rules, $data); + + continue; } if (strpos($field, '*') !== false && is_array($values)) { From 1533fa038a71216f8fbd0b8cc0977cdcffc3d766 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 10:15:55 +0900 Subject: [PATCH 0918/2325] docs: add or improve links to other sections --- user_guide_src/source/changelogs/v4.1.5.rst | 4 ++-- user_guide_src/source/dbmgmt/forge.rst | 1 + user_guide_src/source/incoming/routing.rst | 4 +++- user_guide_src/source/installation/upgrade_415.rst | 4 +++- user_guide_src/source/libraries/security.rst | 2 ++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst index 9cd543f181e2..67589933074f 100644 --- a/user_guide_src/source/changelogs/v4.1.5.rst +++ b/user_guide_src/source/changelogs/v4.1.5.rst @@ -21,12 +21,12 @@ Enhancements ============ - Added Cache config for reserved characters -- The ``addForeignKey`` function of the ``Forge`` class can now define composite foreign keys in an array +- The :ref:`addForeignKey()` function of the ``Forge`` class can now define composite foreign keys in an array - The ``dropKey`` function of the ``Forge`` class can remove key - Now ``_`` can be used as separators in environment variable - Added Multiple filters for a route and Classname filter - Reduced memory usage of ``insertBatch()`` and ``updateBatch()`` -- Added Session based CSRF Protection +- Added :ref:`Session based CSRF Protection ` - Added ``valid_url_strict`` rule for ``Validation`` - Debug Toolbar - Added formatted query string to timeline diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index 29f35e7a83f0..bbaa01490b0e 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -223,6 +223,7 @@ and unique keys with specific methods:: $forge->addUniqueKey(['blog_id', 'uri']); // gives UNIQUE KEY `blog_id_uri` (`blog_id`, `uri`) +.. _adding-foreign-keys: Adding Foreign Keys =================== diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 0e9f3bb4e6be..97c2b1aa1fdd 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -354,6 +354,8 @@ can modify the generated routes, or further restrict them. The ``$options`` arra $routes->map($array, $options); $routes->group('name', $options, function ()); +.. _applying-filters: + Applying Filters ---------------- @@ -390,7 +392,7 @@ You specify a filter classname for the filter value:: **Multiple filters** -.. important:: *Multiple filters* is disabled by default. Because it breaks backward compatibility. If you want to use it, you need to configure. See *Multiple filters for a route* in :doc:`/installation/upgrade_415` for the details. +.. important:: *Multiple filters* is disabled by default. Because it breaks backward compatibility. If you want to use it, you need to configure. See :ref:`upgrade-415-multiple-filters-for-a-route` for the details. You specify an array for the filter value:: diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst index c7b885efa40a..a029724b3bfb 100644 --- a/user_guide_src/source/installation/upgrade_415.rst +++ b/user_guide_src/source/installation/upgrade_415.rst @@ -72,6 +72,8 @@ For optimization and a bug fix, the following behaviors, mostly used in testing, Breaking Enhancements ===================== +.. _upgrade-415-multiple-filters-for-a-route: + Multiple filters for a route ---------------------------- @@ -99,7 +101,7 @@ The following methods and a property have been deprecated: - ``CodeIgniter\Router\RouteCollection::getFilterForRoute()`` - ``CodeIgniter\Router\RouteCollection``'s property ``$filterInfo`` -See *Applying Filters* in :doc:`Routing ` for the functionality. +See :ref:`applying-filters` for the functionality. Project Files ============= diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 9b317a75ea91..b0a11af06b6d 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -29,6 +29,8 @@ Cross-site request forgery (CSRF) Config for CSRF =============== +.. _csrf-protection-methods: + CSRF Protection Methods ----------------------- From 4ed62286f861347fd045c748ddcd7b5be8cd0609 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 11:17:36 +0900 Subject: [PATCH 0919/2325] docs: remove out-of-dated
    It seems not used now. --- contributing/documentation.rst | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/contributing/documentation.rst b/contributing/documentation.rst index 03164f183e6e..d8756cc1623c 100644 --- a/contributing/documentation.rst +++ b/contributing/documentation.rst @@ -16,21 +16,9 @@ It is created automatically by inserting the following: .. contents:: :local: - .. raw:: html - -
    - .. contents:: :local: -.. raw:: html - -
    - -The
    that is inserted as raw HTML is a event for the documentation's -JavaScript to dynamically add links to any function and method definitions -contained in the current page. - ************** Tools Required ************** From a5d5d7eba3c15e5c1570e671dde24129cf388f17 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 11:18:18 +0900 Subject: [PATCH 0920/2325] docs: add depth to sample code --- contributing/documentation.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/contributing/documentation.rst b/contributing/documentation.rst index d8756cc1623c..3e6c3f43204f 100644 --- a/contributing/documentation.rst +++ b/contributing/documentation.rst @@ -15,6 +15,7 @@ It is created automatically by inserting the following: .. contents:: :local: + :depth: 2 .. contents:: :local: From 6c1a326e8cb68c8211b7ff1fb55ef69f9a4cd150 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 11:18:46 +0900 Subject: [PATCH 0921/2325] docs: add how to make references --- contributing/documentation.rst | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/contributing/documentation.rst b/contributing/documentation.rst index 3e6c3f43204f..eba3eb99437e 100644 --- a/contributing/documentation.rst +++ b/contributing/documentation.rst @@ -81,3 +81,32 @@ create these with the following tab triggers:: SubSubSubSubSection (!) """"""""""""""""""""""" + +********** +References +********** + +References to a Section +======================= + +If you need to link to a specific section, the first you add the label before a header:: + + .. _curlrequest-request-options-headers: + + headers + ======= + +And then you can reference it like this:: + + See :ref:`CURLRequest Class ` for how to add. + + See :ref:`curlrequest-request-options-headers` for how to add. + +References to a Page +==================== + +You can reference a page like the following:: + + :doc:`Session <../libraries/sessions>` library + + :doc:`../libraries/sessions` library From 1911a805a8c906e10dca1320d26e3100e9d88f39 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 11:26:48 +0900 Subject: [PATCH 0922/2325] docs: update the user guide URL --- user_guide_src/ghpages.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/ghpages.rst b/user_guide_src/ghpages.rst index 15619a060e0d..682c1eee49ce 100644 --- a/user_guide_src/ghpages.rst +++ b/user_guide_src/ghpages.rst @@ -8,7 +8,7 @@ in the meantime. The user guide takes advantage of GitHub pages, where the "gh-pages" branch of a repo, containing HTML only, is accessible through `github.io -`_. +`_. Setup for Repo Maintainers ========================== From c873c354ca0e4d6ab5d491e807d14678a3f39f23 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 12:51:56 +0900 Subject: [PATCH 0923/2325] refactor: add \ for regex string Both the string before and after the change are the same string in PHP, but I got a pattern error when I entered the string before the change in https://regex101.com/. --- system/Helpers/array_helper.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php index 423f9c266dd5..258a1874a766 100644 --- a/system/Helpers/array_helper.php +++ b/system/Helpers/array_helper.php @@ -20,7 +20,8 @@ */ function dot_array_search(string $index, array $array) { - $segments = preg_split('/(? Date: Tue, 7 Dec 2021 12:54:27 +0900 Subject: [PATCH 0924/2325] style: break long line --- system/Helpers/array_helper.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/system/Helpers/array_helper.php b/system/Helpers/array_helper.php index 258a1874a766..2f8a5f9c8366 100644 --- a/system/Helpers/array_helper.php +++ b/system/Helpers/array_helper.php @@ -21,7 +21,12 @@ function dot_array_search(string $index, array $array) { // See https://regex101.com/r/44Ipql/1 - $segments = preg_split('/(? Date: Tue, 7 Dec 2021 17:16:54 +0900 Subject: [PATCH 0925/2325] refactor: early return --- system/Model.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/system/Model.php b/system/Model.php index 767f7de08048..418b3057eeb9 100644 --- a/system/Model.php +++ b/system/Model.php @@ -588,11 +588,13 @@ protected function shouldUpdate($data): bool return false; } + if ($this->useAutoIncrement === true) { + return true; + } + // When useAutoIncrement feature is disabled, check // in the database if given record already exists - return $this->useAutoIncrement - ? true - : $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1; + return $this->where($this->primaryKey, $this->getIdValue($data))->countAllResults() === 1; } /** From bb82f4e76035075d36fcf455d6ce4fd0c295fea2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 7 Dec 2021 18:32:51 +0900 Subject: [PATCH 0926/2325] refactor: compare it to the return value to make it easier to understand what it is doing Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/I18n/Time.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/I18n/Time.php b/system/I18n/Time.php index c182bee32e7e..01698444587d 100644 --- a/system/I18n/Time.php +++ b/system/I18n/Time.php @@ -479,7 +479,7 @@ public function getQuarter(): string */ public function getDst(): bool { - return (bool) $this->format('I'); + return $this->format('I') === '1'; // 1 if Daylight Saving Time, 0 otherwise. } /** From 9ddc23980d8ad21e69ff5e04fb766690ccf33e53 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 10:02:37 +0900 Subject: [PATCH 0927/2325] fix: string literals to be enclosed in single quotes Fixes #5423 --- system/Database/MySQLi/Connection.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 62881620c46b..9736bf0b03c6 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -100,19 +100,19 @@ public function connect(bool $persistent = false) if ($this->strictOn) { $this->mysqli->options( MYSQLI_INIT_COMMAND, - 'SET SESSION sql_mode = CONCAT(@@sql_mode, ",", "STRICT_ALL_TABLES")' + "SET SESSION sql_mode = CONCAT(@@sql_mode, ',', 'STRICT_ALL_TABLES')" ); } else { $this->mysqli->options( MYSQLI_INIT_COMMAND, - 'SET SESSION sql_mode = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( + "SET SESSION sql_mode = REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(REPLACE( @@sql_mode, - "STRICT_ALL_TABLES,", ""), - ",STRICT_ALL_TABLES", ""), - "STRICT_ALL_TABLES", ""), - "STRICT_TRANS_TABLES,", ""), - ",STRICT_TRANS_TABLES", ""), - "STRICT_TRANS_TABLES", "")' + 'STRICT_ALL_TABLES,', ''), + ',STRICT_ALL_TABLES', ''), + 'STRICT_ALL_TABLES', ''), + 'STRICT_TRANS_TABLES,', ''), + ',STRICT_TRANS_TABLES', ''), + 'STRICT_TRANS_TABLES', '')" ); } } From e943b691e1f5b71cbf390c899f566bb41de88a25 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 1 Dec 2021 15:26:38 +0900 Subject: [PATCH 0928/2325] feat: add SecureHeaders filter --- app/Config/Filters.php | 11 ++-- system/Filters/SecureHeaders.php | 71 ++++++++++++++++++++++ tests/system/Filters/SecureHeadersTest.php | 40 ++++++++++++ user_guide_src/source/incoming/filters.rst | 2 +- 4 files changed, 119 insertions(+), 5 deletions(-) create mode 100644 system/Filters/SecureHeaders.php create mode 100644 tests/system/Filters/SecureHeadersTest.php diff --git a/app/Config/Filters.php b/app/Config/Filters.php index 02aaec533c17..14685207f71b 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -7,6 +7,7 @@ use CodeIgniter\Filters\DebugToolbar; use CodeIgniter\Filters\Honeypot; use CodeIgniter\Filters\InvalidChars; +use CodeIgniter\Filters\SecureHeaders; class Filters extends BaseConfig { @@ -17,10 +18,11 @@ class Filters extends BaseConfig * @var array */ public $aliases = [ - 'csrf' => CSRF::class, - 'toolbar' => DebugToolbar::class, - 'honeypot' => Honeypot::class, - 'invalidchars' => InvalidChars::class, + 'csrf' => CSRF::class, + 'toolbar' => DebugToolbar::class, + 'honeypot' => Honeypot::class, + 'invalidchars' => InvalidChars::class, + 'secureheaders' => SecureHeaders::class, ]; /** @@ -38,6 +40,7 @@ class Filters extends BaseConfig 'after' => [ 'toolbar', // 'honeypot', + // 'secureheaders', ], ]; diff --git a/system/Filters/SecureHeaders.php b/system/Filters/SecureHeaders.php new file mode 100644 index 000000000000..fd656af6a80f --- /dev/null +++ b/system/Filters/SecureHeaders.php @@ -0,0 +1,71 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Filters; + +use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\ResponseInterface; + +/** + * Add Common Security Headers + */ +class SecureHeaders implements FilterInterface +{ + /** + * @var array + */ + protected $headers = [ + // https://owasp.org/www-project-secure-headers/#x-frame-options + 'X-Frame-Options' => 'SAMEORIGIN', + + // https://owasp.org/www-project-secure-headers/#x-content-type-options + 'X-Content-Type-Options' => 'nosniff', + + // https://docs.microsoft.com/en-us/previous-versions/windows/internet-explorer/ie-developer/compatibility/jj542450(v=vs.85)#the-noopen-directive + 'X-Download-Options' => 'noopen', + + // https://owasp.org/www-project-secure-headers/#x-permitted-cross-domain-policies + 'X-Permitted-Cross-Domain-Policies' => 'none', + + // https://owasp.org/www-project-secure-headers/#referrer-policy + 'Referrer-Policy' => 'same-origin', + + // https://owasp.org/www-project-secure-headers/#x-xss-protection + // If you do not need to support legacy browsers, it is recommended that you use + // Content-Security-Policy without allowing unsafe-inline scripts instead. + // 'X-XSS-Protection' => '1; mode=block', + ]; + + /** + * We don't have anything to do here. + * + * @param array|null $arguments + * + * @return void + */ + public function before(RequestInterface $request, $arguments = null) + { + } + + /** + * Add security headers. + * + * @param array|null $arguments + * + * @return void + */ + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + foreach ($this->headers as $header => $value) { + $response->setHeader($header, $value); + } + } +} diff --git a/tests/system/Filters/SecureHeadersTest.php b/tests/system/Filters/SecureHeadersTest.php new file mode 100644 index 000000000000..038ef81003ab --- /dev/null +++ b/tests/system/Filters/SecureHeadersTest.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Filters; + +use CodeIgniter\Config\Services; +use CodeIgniter\Test\CIUnitTestCase; + +/** + * @internal + */ +final class SecureHeadersTest extends CIUnitTestCase +{ + protected $request; + protected $response; + + public function testAfter() + { + $filter = new SecureHeaders(); + $request = Services::request(null, false); + $response = Services::response(null, false); + + $filter->after($request, $response); + + $responseHeaders = $response->headers(); + $headers = $this->getPrivateProperty($filter, 'headers'); + + foreach ($headers as $header => $value) { + $this->assertSame($value, $responseHeaders[$header]->getValue()); + } + } +} diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 60e2ea90cc76..f0d6d7fbf6cb 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -193,6 +193,6 @@ In this example, the array ``['dual', 'noreturn']`` will be passed in ``$argumen Provided Filters **************** -The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``DebugToolbar``, and ``InvalidChars``. +The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``InvalidChars``, ``SecureHeaders``, and ``DebugToolbar``. .. note:: The filters are executed in the order defined in the config file. However, if enabled, ``DebugToolbar`` is always executed last because it should be able to capture everything that happens in the other filters. From 32ca70c732274d28f5d945f84eda1888ad29f891 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Dec 2021 10:01:18 +0900 Subject: [PATCH 0929/2325] docs: add how to customize SecureHeaders --- user_guide_src/source/incoming/filters.rst | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index f0d6d7fbf6cb..bbed197e7702 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -196,3 +196,17 @@ Provided Filters The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``InvalidChars``, ``SecureHeaders``, and ``DebugToolbar``. .. note:: The filters are executed in the order defined in the config file. However, if enabled, ``DebugToolbar`` is always executed last because it should be able to capture everything that happens in the other filters. + +SecureHeaders +============= + +This filter adds HTTP response headers that your application can use to increase the security of your application. + +If you want to customize the headers, extend ``CodeIgniter\Filters\SecureHeaders`` and override the ``$headers`` property. And change the ``$aliases`` property in **app/Config/Filters.php**:: + + public $aliases = [ + ... + 'secureheaders' => \App\Filters\SecureHeaders::class, + ]; + +If you want to know about secure headers, see `OWASP Secure Headers Project `_. From 27d9984476d17a1e997ac98961f88e555b4768af Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 16:03:58 +0900 Subject: [PATCH 0930/2325] fix: move secure cookie check from Security to CookieStore --- system/Cookie/CookieStore.php | 8 ++++++ system/Security/Security.php | 3 --- tests/system/HTTP/ResponseSendTest.php | 36 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 3 deletions(-) diff --git a/system/Cookie/CookieStore.php b/system/Cookie/CookieStore.php index 87dc472d1fe5..3edcd506d644 100644 --- a/system/Cookie/CookieStore.php +++ b/system/Cookie/CookieStore.php @@ -13,6 +13,8 @@ use ArrayIterator; use CodeIgniter\Cookie\Exceptions\CookieException; +use CodeIgniter\Security\Exceptions\SecurityException; +use Config\Services; use Countable; use IteratorAggregate; use Traversable; @@ -161,7 +163,13 @@ public function remove(string $name, string $prefix = '') */ public function dispatch(): void { + $request = Services::request(); + foreach ($this->cookies as $cookie) { + if ($cookie->isSecure() && ! $request->isSecure()) { + throw SecurityException::forDisallowedAction(); + } + $name = $cookie->getPrefixedName(); $value = $cookie->getValue(); $options = $cookie->getOptions(); diff --git a/system/Security/Security.php b/system/Security/Security.php index 35e889a85d69..dd03d4ac68d9 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -538,9 +538,6 @@ private function saveHashInCookie(): void */ protected function sendCookie(RequestInterface $request) { - if ($this->cookie->isSecure() && ! $request->isSecure()) { - return false; - } $this->doSendCookie(); log_message('info', 'CSRF cookie sent.'); diff --git a/tests/system/HTTP/ResponseSendTest.php b/tests/system/HTTP/ResponseSendTest.php index 5fedc69da7b1..6610321040a2 100644 --- a/tests/system/HTTP/ResponseSendTest.php +++ b/tests/system/HTTP/ResponseSendTest.php @@ -11,8 +11,10 @@ namespace CodeIgniter\HTTP; +use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Test\CIUnitTestCase; use Config\App; +use Config\Services; /** * This test suite has been created separately from @@ -135,4 +137,38 @@ public function testRedirectResponseCookies() $this->assertHeaderEmitted('Set-Cookie: foo=bar;'); $this->assertHeaderEmitted('Set-Cookie: login_time'); } + + /** + * Make sure secure cookies are not sent with HTTP request + * + * @ runInSeparateProcess + * @ preserveGlobalState disabled + */ + public function testDoNotSendUnSecureCookie(): void + { + $this->expectException(SecurityException::class); + $this->expectExceptionMessage('The action you requested is not allowed'); + + $request = $this->createMock(IncomingRequest::class); + $request->method('isSecure')->willReturn(false); + Services::injectMock('request', $request); + + $response = new Response(new App()); + $response->pretend(false); + $body = 'Hello'; + $response->setBody($body); + + $response->setCookie( + 'foo', + 'bar', + '', + '', + '/', + '', + true + ); + + // send it + $response->send(); + } } From a3c65d75fef7c95fb322214544aaa89383bb80c6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 16:06:36 +0900 Subject: [PATCH 0931/2325] docs: fix doc comments --- system/HTTP/ResponseTrait.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 7ec5f1e69e6b..39657af8464f 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -22,7 +22,7 @@ use InvalidArgumentException; /** - * Request Trait + * Response Trait * * Additional methods to make a PSR-7 Response class * compliant with the framework's own ResponseInterface. @@ -446,7 +446,7 @@ public function send() } /** - * Sends the headers of this HTTP request to the browser. + * Sends the headers of this HTTP response to the browser. * * @return Response */ From fd72e192cb9050abf6233bdd4f2daa10a73d4739 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 16:06:58 +0900 Subject: [PATCH 0932/2325] test: fix setUp() --- tests/system/CommonFunctionsTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index ba4c1e7a4e07..c6f1d6b9b2e1 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -41,10 +41,10 @@ final class CommonFunctionsTest extends CIUnitTestCase { protected function setUp(): void { - parent::setUp(); - $renderer = Services::renderer(); - $renderer->resetData(); unset($_ENV['foo'], $_SERVER['foo']); + Services::reset(); + + parent::setUp(); } public function testStringifyAttributes() From 3aadd002fa4753cfe5ae97aed93fb9a278ff423a Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 16:09:28 +0900 Subject: [PATCH 0933/2325] fix: Security class does not send cookies Add Response::setCookieStore() --- system/HTTP/ResponseTrait.php | 8 ++++ system/Security/Security.php | 28 ++----------- tests/system/Security/SecurityTest.php | 58 +++----------------------- 3 files changed, 17 insertions(+), 77 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 39657af8464f..46835cc515c6 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -596,6 +596,14 @@ public function getCookieStore() return $this->cookieStore; } + /** + * Sets the CookieStore. + */ + public function setCookieStore(CookieStore $cookieStore) + { + $this->cookieStore = $cookieStore; + } + /** * Checks to see if the Response has a specified cookie or not. */ diff --git a/system/Security/Security.php b/system/Security/Security.php index dd03d4ac68d9..a484310d40c5 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -528,32 +528,12 @@ private function saveHashInCookie(): void 'expires' => $this->expires === 0 ? 0 : time() + $this->expires, ] ); - $this->sendCookie($this->request); - } - - /** - * CSRF Send Cookie - * - * @return false|Security - */ - protected function sendCookie(RequestInterface $request) - { - - $this->doSendCookie(); - log_message('info', 'CSRF cookie sent.'); - return $this; - } + $response = Services::response(); + $cookieStore = $response->getCookieStore(); + $cookieStore = $cookieStore->put($this->cookie); - /** - * Actual dispatching of cookies. - * Extracted for this to be unit tested. - * - * @codeCoverageIgnore - */ - protected function doSendCookie(): void - { - cookies([$this->cookie], false)->dispatch(); + $response->setCookieStore($cookieStore); } private function saveHashInSession(): void diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index cc9fcf753853..6bb8d3a809b5 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -20,8 +20,8 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockAppConfig; use CodeIgniter\Test\Mock\MockSecurity; -use Config\Cookie as CookieConfig; use Config\Security as SecurityConfig; +use Config\Services; /** * @backupGlobals enabled @@ -41,11 +41,7 @@ protected function setUp(): void public function testBasicConfigIsSaved() { - $config = new MockAppConfig(); - $security = $this->getMockBuilder(Security::class) - ->setConstructorArgs([$config]) - ->onlyMethods(['doSendCookie']) - ->getMock(); + $security = new MockSecurity(new MockAppConfig()); $hash = $security->getHash(); @@ -57,11 +53,7 @@ public function testHashIsReadFromCookie() { $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $config = new MockAppConfig(); - $security = $this->getMockBuilder(Security::class) - ->setConstructorArgs([$config]) - ->onlyMethods(['doSendCookie']) - ->getMock(); + $security = new MockSecurity(new MockAppConfig()); $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); } @@ -74,7 +66,8 @@ public function testGetHashSetsCookieWhenGETWithoutCSRFCookie() $security->verify(new Request(new MockAppConfig())); - $this->assertSame($_COOKIE['csrf_cookie_name'], $security->getHash()); + $cookie = Services::response()->getCookie('csrf_cookie_name'); + $this->assertSame($security->getHash(), $cookie->getValue()); } public function testGetHashReturnsCSRFCookieWhenGETWithCSRFCookie() @@ -238,45 +231,4 @@ public function testGetters(): void $this->assertIsString($security->getCookieName()); $this->assertIsBool($security->shouldRedirect()); } - - public function testSendingCookiesFalse(): void - { - $request = $this->createMock(IncomingRequest::class); - $request->method('isSecure')->willReturn(false); - - $config = new CookieConfig(); - - $config->secure = true; - Factories::injectMock('config', CookieConfig::class, $config); - - $security = $this->getMockBuilder(Security::class) - ->setConstructorArgs([new MockAppConfig()]) - ->onlyMethods(['doSendCookie']) - ->getMock(); - - $sendCookie = $this->getPrivateMethodInvoker($security, 'sendCookie'); - - $security->expects($this->never())->method('doSendCookie'); - $this->assertFalse($sendCookie($request)); - } - - public function testSendingGoodCookies(): void - { - $request = $this->createMock(IncomingRequest::class); - $request->method('isSecure')->willReturn(true); - - $config = new MockAppConfig(); - - $config->cookieSecure = true; - - $security = $this->getMockBuilder(Security::class) - ->setConstructorArgs([$config]) - ->onlyMethods(['doSendCookie']) - ->getMock(); - - $sendCookie = $this->getPrivateMethodInvoker($security, 'sendCookie'); - - $security->expects($this->once())->method('doSendCookie'); - $this->assertInstanceOf(Security::class, $sendCookie($request)); - } } From 7ea464cd4d44b713d4d86a558bcf23865cc69b53 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 16:10:36 +0900 Subject: [PATCH 0934/2325] test: break long lines --- tests/system/Security/SecurityTest.php | 69 ++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 11 deletions(-) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 6bb8d3a809b5..160e35b17cb6 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -55,7 +55,10 @@ public function testHashIsReadFromCookie() $security = new MockSecurity(new MockAppConfig()); - $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); + $this->assertSame( + '8b9218a55906f9dcc1dc263dce7f005a', + $security->getHash() + ); } public function testGetHashSetsCookieWhenGETWithoutCSRFCookie() @@ -89,7 +92,12 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch() $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); $this->expectException(SecurityException::class); $security->verify($request); @@ -103,7 +111,12 @@ public function testCSRFVerifyPostReturnsSelfOnMatch() $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -117,7 +130,12 @@ public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch() $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); @@ -132,7 +150,12 @@ public function testCSRFVerifyHeaderReturnsSelfOnMatch() $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); @@ -148,9 +171,16 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch() $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); - $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a"}'); + $request->setBody( + '{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a"}' + ); $this->expectException(SecurityException::class); $security->verify($request); @@ -162,9 +192,16 @@ public function testCSRFVerifyJsonReturnsSelfOnMatch() $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); - $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}'); + $request->setBody( + '{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}' + ); $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -192,7 +229,12 @@ public function testRegenerateWithFalseSecurityRegenerateProperty() Factories::injectMock('config', 'Security', $config); $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); $oldHash = $security->getHash(); $security->verify($request); @@ -212,7 +254,12 @@ public function testRegenerateWithTrueSecurityRegenerateProperty() Factories::injectMock('config', 'Security', $config); $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request = new IncomingRequest( + new MockAppConfig(), + new URI('http://badurl.com'), + null, + new UserAgent() + ); $oldHash = $security->getHash(); $security->verify($request); From 628db685b1fa1667535f08aa50828739cebcd707 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 2 Dec 2021 17:29:18 +0900 Subject: [PATCH 0935/2325] test: fix setUp() --- tests/system/HTTP/ResponseTest.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/system/HTTP/ResponseTest.php b/tests/system/HTTP/ResponseTest.php index b4eba4c547c9..a94cd8e8b2b5 100644 --- a/tests/system/HTTP/ResponseTest.php +++ b/tests/system/HTTP/ResponseTest.php @@ -30,14 +30,18 @@ final class ResponseTest extends CIUnitTestCase protected function setUp(): void { - parent::setUp(); $this->server = $_SERVER; + + Services::reset(); + + parent::setUp(); } protected function tearDown(): void { - $_SERVER = $this->server; Factories::reset('config'); + + $_SERVER = $this->server; } public function testCanSetStatusCode() From d94cca96462ff14108160ed447b4814d964f4a4f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 09:24:55 +0900 Subject: [PATCH 0936/2325] chore: add rule Cookie depends on Security --- depfile.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/depfile.yaml b/depfile.yaml index 2c87969f4fc4..61b85383b329 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -157,6 +157,8 @@ ruleset: Controller: - HTTP - Validation + Cookie: + - Security Database: - Entity - Events From d472ec1faafaee79e386aa68176b88f98c3eae7b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 19:52:07 +0900 Subject: [PATCH 0937/2325] refactor: move cookie dispatching to Response class --- system/Cookie/CookieStore.php | 14 +++++------ system/HTTP/ResponseTrait.php | 47 ++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 9 deletions(-) diff --git a/system/Cookie/CookieStore.php b/system/Cookie/CookieStore.php index 3edcd506d644..af7dd2f0e437 100644 --- a/system/Cookie/CookieStore.php +++ b/system/Cookie/CookieStore.php @@ -13,8 +13,6 @@ use ArrayIterator; use CodeIgniter\Cookie\Exceptions\CookieException; -use CodeIgniter\Security\Exceptions\SecurityException; -use Config\Services; use Countable; use IteratorAggregate; use Traversable; @@ -160,16 +158,12 @@ public function remove(string $name, string $prefix = '') /** * Dispatches all cookies in store. + * + * @deprecated Response should dispatch cookies. */ public function dispatch(): void { - $request = Services::request(); - foreach ($this->cookies as $cookie) { - if ($cookie->isSecure() && ! $request->isSecure()) { - throw SecurityException::forDisallowedAction(); - } - $name = $cookie->getPrefixedName(); $value = $cookie->getValue(); $options = $cookie->getOptions(); @@ -240,6 +234,8 @@ protected function validateCookies(array $cookies): void * Extracted call to `setrawcookie()` in order to run unit tests on it. * * @codeCoverageIgnore + * + * @deprecated */ protected function setRawCookie(string $name, string $value, array $options): void { @@ -250,6 +246,8 @@ protected function setRawCookie(string $name, string $value, array $options): vo * Extracted call to `setcookie()` in order to run unit tests on it. * * @codeCoverageIgnore + * + * @deprecated */ protected function setCookie(string $name, string $value, array $options): void { diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 46835cc515c6..3b2a42c9b82d 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -16,6 +16,7 @@ use CodeIgniter\Cookie\Exceptions\CookieException; use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\Pager\PagerInterface; +use CodeIgniter\Security\Exceptions\SecurityException; use Config\Services; use DateTime; use DateTimeZone; @@ -697,7 +698,51 @@ protected function sendCookies() return; } - $this->cookieStore->dispatch(); + $this->dispatchCookies(); + } + + private function dispatchCookies(): void + { + /** @var IncomingRequest $request */ + $request = Services::request(); + + foreach ($this->cookieStore->display() as $cookie) { + if ($cookie->isSecure() && ! $request->isSecure()) { + throw SecurityException::forDisallowedAction(); + } + + $name = $cookie->getPrefixedName(); + $value = $cookie->getValue(); + $options = $cookie->getOptions(); + + if ($cookie->isRaw()) { + $this->doSetRawCookie($name, $value, $options); + } else { + $this->doSetCookie($name, $value, $options); + } + } + + $this->cookieStore->clear(); + } + + /** + * Extracted call to `setrawcookie()` in order to run unit tests on it. + * + * @codeCoverageIgnore + */ + private function doSetRawCookie(string $name, string $value, array $options): void + { + setrawcookie($name, $value, $options); + } + + /** + * Extracted call to `setcookie()` in order to run unit tests on it. + * + * @codeCoverageIgnore + */ + private function doSetCookie(string $name, string $value, array $options): void + { + setcookie($name, $value, $options); } /** From 246f3358ba33118f842cfc32a76f500feb506f5e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 19:53:56 +0900 Subject: [PATCH 0938/2325] refactor: add @var To explicitly indicate dependency --- system/Security/Security.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/Security/Security.php b/system/Security/Security.php index a484310d40c5..bacbc9ee74d9 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -13,6 +13,7 @@ use CodeIgniter\Cookie\Cookie; use CodeIgniter\HTTP\RequestInterface; +use CodeIgniter\HTTP\Response; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Session; use Config\App; @@ -529,6 +530,7 @@ private function saveHashInCookie(): void ] ); + /** @var Response $response */ $response = Services::response(); $cookieStore = $response->getCookieStore(); $cookieStore = $cookieStore->put($this->cookie); From 11e22972ca7190026b42bad84195ed11a9d934da Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 19:55:38 +0900 Subject: [PATCH 0939/2325] chore: update deptrac rule --- depfile.yaml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/depfile.yaml b/depfile.yaml index 61b85383b329..301f17076f82 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -157,8 +157,6 @@ ruleset: Controller: - HTTP - Validation - Cookie: - - Security Database: - Entity - Events @@ -174,6 +172,7 @@ ruleset: HTTP: - Cookie - Files + - Security - URI Images: - Files From 3376a7cbe4e188bb32906a8040b9cc26791e7d0e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 20:10:10 +0900 Subject: [PATCH 0940/2325] fix: restore removed methods as deprecated --- system/Security/Security.php | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/system/Security/Security.php b/system/Security/Security.php index bacbc9ee74d9..344ef5cfe00c 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -538,6 +538,38 @@ private function saveHashInCookie(): void $response->setCookieStore($cookieStore); } + /** + * CSRF Send Cookie + * + * @return false|Security + * + * @deprecated Set cookies to Response object instead. + */ + protected function sendCookie(RequestInterface $request) + { + if ($this->cookie->isSecure() && ! $request->isSecure()) { + return false; + } + + $this->doSendCookie(); + log_message('info', 'CSRF cookie sent.'); + + return $this; + } + + /** + * Actual dispatching of cookies. + * Extracted for this to be unit tested. + * + * @codeCoverageIgnore + * + * @deprecated Set cookies to Response object instead. + */ + protected function doSendCookie(): void + { + cookies([$this->cookie], false)->dispatch(); + } + private function saveHashInSession(): void { $this->session->set($this->tokenName, $this->hash); From 23ba12cfe1b3ee5354559258cde5947120a16c54 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Dec 2021 10:35:43 +0900 Subject: [PATCH 0941/2325] feat: Response::setCookie() can get Cookie object as the first parameter --- system/HTTP/ResponseTrait.php | 24 +++++++++++++++--------- tests/system/HTTP/ResponseCookieTest.php | 11 +++++++++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 3b2a42c9b82d..7caa5ebbbcca 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -536,15 +536,15 @@ public function redirect(string $uri, string $method = 'auto', ?int $code = null * Accepts an arbitrary number of binds (up to 7) or an associative * array in the first parameter containing all the values. * - * @param array|string $name Cookie name or array containing binds - * @param string $value Cookie value - * @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 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 + * @param array|Cookie|string $name Cookie name / array containing binds / Cookie object + * @param string $value Cookie value + * @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 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 * * @return $this */ @@ -559,6 +559,12 @@ public function setCookie( $httponly = false, $samesite = null ) { + if ($name instanceof Cookie) { + $this->cookieStore = $this->cookieStore->put($name); + + return $this; + } + if (is_array($name)) { // always leave 'name' in last place, as the loop will break otherwise, due to $$item foreach (['samesite', 'value', 'expire', 'domain', 'path', 'prefix', 'secure', 'httponly', 'name'] as $item) { diff --git a/tests/system/HTTP/ResponseCookieTest.php b/tests/system/HTTP/ResponseCookieTest.php index 721a2fbd47b7..678928463cc4 100644 --- a/tests/system/HTTP/ResponseCookieTest.php +++ b/tests/system/HTTP/ResponseCookieTest.php @@ -65,6 +65,17 @@ public function testCookiesAll() $this->assertTrue($response->hasCookie('bee')); } + public function testSetCookieObject() + { + $cookie = new Cookie('foo', 'bar'); + $response = new Response(new App()); + + $response->setCookie($cookie); + + $this->assertCount(1, $response->getCookies()); + $this->assertTrue($response->hasCookie('foo')); + } + public function testCookieGet() { $response = new Response(new App()); From 943b4e04051774fa5be8ca89ea8667dc7dca832b Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 4 Dec 2021 10:37:53 +0900 Subject: [PATCH 0942/2325] refactor: use Response::setCookie() --- system/HTTP/ResponseTrait.php | 8 -------- system/Security/Security.php | 7 ++----- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index 7caa5ebbbcca..278143fd3c3a 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -603,14 +603,6 @@ public function getCookieStore() return $this->cookieStore; } - /** - * Sets the CookieStore. - */ - public function setCookieStore(CookieStore $cookieStore) - { - $this->cookieStore = $cookieStore; - } - /** * Checks to see if the Response has a specified cookie or not. */ diff --git a/system/Security/Security.php b/system/Security/Security.php index 344ef5cfe00c..008e94aeb612 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -531,11 +531,8 @@ private function saveHashInCookie(): void ); /** @var Response $response */ - $response = Services::response(); - $cookieStore = $response->getCookieStore(); - $cookieStore = $cookieStore->put($this->cookie); - - $response->setCookieStore($cookieStore); + $response = Services::response(); + $response->setCookie($this->cookie); } /** From 6817dc6f5f99cf9636e36479daf0259c512f136d Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Dec 2021 10:21:19 +0900 Subject: [PATCH 0943/2325] docs: fix header level --- user_guide_src/source/changelogs/v4.1.6.rst | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 4cddcc21f953..e747e9181fa8 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -10,13 +10,15 @@ Release Date: Not released :depth: 2 BREAKING -======== +******** + - Multiple table names will no longer be stored in ``BaseBuilder::$tableName`` - an empty string will be used instead. .. _changelog-v416-validation-changes: Validation changes ------------------- +================== + - The previous version of the Validation can't handle an array item. Because of the bug fix, the validation results may be different, or raise a ``TypeError``. @@ -28,14 +30,15 @@ Validation changes On the other hand, the current version passes the array to the validation rule as a whole. Enhancements -============ +************ + - Database pane on debug toolbar now displays location where Query was called from. Also displays full backtrace. Changes -======= +******* Deprecations -============ +************ Bugs Fixed -========== +********** From 49cd87991b218e67641557285ef5f3b4ba3c51fb Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 8 Dec 2021 10:46:06 +0900 Subject: [PATCH 0944/2325] docs: add changelog and update Response::setCookie() --- user_guide_src/source/changelogs/v4.1.6.rst | 14 ++++++++++++++ user_guide_src/source/outgoing/response.rst | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index e747e9181fa8..82b03127cda2 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -37,8 +37,22 @@ Enhancements Changes ******* +- The process of sending cookies has been moved to the ``Response`` class. Now the ``Security`` and ``CookieStore`` class don't send cookies, set them to the Response. + Deprecations ************ +Sending Cookies +=============== + +The process of sending cookies has been moved to the ``Response`` class. +And the following methods are deprecated: + +- ``CookieStore::dispatch()`` +- ``CookieStore::setRawCookie()`` +- ``CookieStore::setCookie()`` +- ``Security::sendCookie()`` +- ``Security::doSendCookie()`` + Bugs Fixed ********** diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index 060e2cd28291..2cd619dbd390 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -396,7 +396,7 @@ The methods provided by the parent class that are available are: .. php:method:: setCookie($name = ''[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = false[, $httponly = false[, $samesite = null]]]]]]]]) - :param mixed $name: Cookie name or an array of parameters + :param array|Cookie|string $name: Cookie name or an array of parameters or an instance of ``CodeIgniter\Cookie\Cookie`` :param string $value: Cookie value :param int $expire: Cookie expiration time in seconds :param string $domain: Cookie domain From 004f42ab6c8169ed518aec8dad3662312a74babe Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 30 Nov 2021 16:46:20 +0900 Subject: [PATCH 0945/2325] fix: SQL in MySQLi\Connection::_foreignKeyData() Fixes #4996 --- system/Database/MySQLi/Connection.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 9736bf0b03c6..5badaf1c4881 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -485,8 +485,10 @@ protected function _foreignKeyData(string $table): array FROM information_schema.TABLE_CONSTRAINTS AS tc INNER JOIN information_schema.REFERENTIAL_CONSTRAINTS AS rc ON tc.CONSTRAINT_NAME = rc.CONSTRAINT_NAME + AND tc.CONSTRAINT_SCHEMA = rc.CONSTRAINT_SCHEMA INNER JOIN information_schema.KEY_COLUMN_USAGE AS kcu ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME + AND tc.CONSTRAINT_SCHEMA = kcu.CONSTRAINT_SCHEMA WHERE tc.CONSTRAINT_TYPE = ' . $this->escape('FOREIGN KEY') . ' AND tc.TABLE_SCHEMA = ' . $this->escape($this->database) . ' AND From 29f8bf85c7dbd19d88c1728f917ab60e8dd3c715 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 26 Nov 2021 09:15:05 +0900 Subject: [PATCH 0946/2325] fix: is_cli() returns true when $_SERVER['HTTP_USER_AGENT'] is missing Fixes #5336 --- system/Common.php | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/system/Common.php b/system/Common.php index 32943189b56b..bf91834ac0b1 100644 --- a/system/Common.php +++ b/system/Common.php @@ -643,16 +643,7 @@ function helper($filenames) */ function is_cli(): bool { - if (defined('STDIN')) { - return true; - } - - if (! isset($_SERVER['REMOTE_ADDR'], $_SERVER['HTTP_USER_AGENT']) && isset($_SERVER['argv']) && count($_SERVER['argv']) > 0) { - return true; - } - - // if source of request is from CLI, the `$_SERVER` array will not populate this key - return ! isset($_SERVER['REQUEST_METHOD']); + return in_array(PHP_SAPI, ['cli', 'phpdbg'], true); } } From 00fc5852a8fc199e70e967b84faa7cbaa71b0315 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 3 Dec 2021 14:52:45 +0900 Subject: [PATCH 0947/2325] fix: handle edge case of 'cgi-fcgi' and 'fpm-fcgi' --- system/Common.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/system/Common.php b/system/Common.php index bf91834ac0b1..85a2506dfb9f 100644 --- a/system/Common.php +++ b/system/Common.php @@ -643,7 +643,13 @@ function helper($filenames) */ function is_cli(): bool { - return in_array(PHP_SAPI, ['cli', 'phpdbg'], true); + if (in_array(PHP_SAPI, ['cli', 'phpdbg'], true)) { + return true; + } + + // PHP_SAPI could be 'cgi-fcgi', 'fpm-fcgi'. + // See https://github.com/codeigniter4/CodeIgniter4/pull/5393 + return ! isset($_SERVER['REMOTE_ADDR']) && ! isset($_SERVER['REQUEST_METHOD']); } } From 19057bff9ed577966b47605f9193d3a9b3c32df0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Dec 2021 10:01:47 +0900 Subject: [PATCH 0948/2325] docs: improve text decoration --- user_guide_src/source/general/helpers.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/general/helpers.rst b/user_guide_src/source/general/helpers.rst index 51deea953590..c454bee36180 100644 --- a/user_guide_src/source/general/helpers.rst +++ b/user_guide_src/source/general/helpers.rst @@ -24,10 +24,10 @@ in your :doc:`controller ` and :doc:`views `. Helpers are typically stored in your **system/Helpers**, or -**app/Helpers directory**. CodeIgniter will look first in your -**app/Helpers directory**. If the directory does not exist or the +**app/Helpers** directory. CodeIgniter will look first in your +**app/Helpers** directory. If the directory does not exist or the specified helper is not located there CI will instead look in your -global *system/Helpers/* directory. +global **system/Helpers** directory. Loading a Helper ================ @@ -36,8 +36,8 @@ Loading a helper file is quite simple using the following method:: helper('name'); -Where **name** is the file name of the helper, without the .php file -extension or the "_helper" part. +Where ``name`` is the file name of the helper, without the "**.php**" file +extension or the "**_helper**" part. For example, to load the **Cookie Helper** file, which is named **cookie_helper.php**, you would do this:: @@ -69,7 +69,7 @@ Helpers can be loaded from directories outside of **app/Helpers** and has been set up within the PSR-4 section of the :doc:`Autoloader config file <../concepts/autoloader>`. You would prefix the name of the Helper with the namespace that it can be located in. Within that namespaced directory, the loader expects it to live within a -sub-directory named ``Helpers``. An example will help understand this. +sub-directory named **Helpers**. An example will help understand this. For this example, assume that we have grouped together all of our Blog-related code into its own namespace, ``Example\Blog``. The files exist on our server at @@ -94,7 +94,7 @@ your view files you would do this:: -Where "Click Here" is the name of the link, and "blog/comments" is the +Where ``Click Here`` is the name of the link, and ``blog/comments`` is the URI to the controller/method you wish to link to. "Extending" Helpers @@ -139,7 +139,7 @@ functions:: return array_pop($array); } -The **helper()** method will scan through all PSR-4 namespaces defined in **app/Config/Autoload.php** +The ``helper()`` method will scan through all PSR-4 namespaces defined in **app/Config/Autoload.php** and load in ALL matching helpers of the same name. This allows any module's helpers to be loaded, as well as any helpers you've created specifically for this application. The load order is as follows: From 18138fa4c781b05ff4f091135644963a1024cad9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 11 Nov 2021 17:10:10 +0900 Subject: [PATCH 0949/2325] fix: remove unserialize() in old() I can't think of any use cases. --- system/Common.php | 5 ----- tests/system/CommonFunctionsTest.php | 2 +- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/system/Common.php b/system/Common.php index 32943189b56b..61e2716fb56b 100644 --- a/system/Common.php +++ b/system/Common.php @@ -813,11 +813,6 @@ function old(string $key, $default = null, $escape = 'html') return $default; } - // If the result was serialized array or string, then unserialize it for use... - if (is_string($value) && (strpos($value, 'a:') === 0 || strpos($value, 's:') === 0)) { - $value = unserialize($value); - } - return $escape === false ? $value : esc($value, $escape); } } diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index c6f1d6b9b2e1..0febdb038c1f 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -300,7 +300,7 @@ public function testOldInput() $_GET = ['foo' => 'bar']; $_POST = [ 'bar' => 'baz', - 'zibble' => serialize('fritz'), + 'zibble' => 'fritz', ]; $response = new RedirectResponse(new App()); From c2ab3d24504b70893be116e09fb7c8b7fa0475c6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 12 Nov 2021 12:42:22 +0900 Subject: [PATCH 0950/2325] docs: add security advisories URL in SECURITY.md --- SECURITY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SECURITY.md b/SECURITY.md index 7879188492b5..87b894ee713c 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -20,6 +20,7 @@ This person will coordinate the fix and release process, involving the following - Confirm the problem and determine the affected versions. - Audit code to find any potential similar problems. - Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible. +- Publish security advisories at https://github.com/codeigniter4/CodeIgniter4/security/advisories ## Comments on this Policy From 7c69140b65a1d4705a63c0bbd55e61171bfd132e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 12 Nov 2021 14:08:04 +0900 Subject: [PATCH 0951/2325] docs: remove out-of-dated comment --- tests/system/CommonFunctionsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 0febdb038c1f..1b9bcbbbf3ad 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -308,7 +308,7 @@ public function testOldInput() $this->assertSame('bar', old('foo')); // regular parameter $this->assertSame('doo', old('yabba dabba', 'doo')); // non-existing parameter - $this->assertSame('fritz', old('zibble')); // serialized parameter + $this->assertSame('fritz', old('zibble')); } /** From 78e4b27a16300c430248c0797a2d980093ef68e2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 12 Nov 2021 14:09:37 +0900 Subject: [PATCH 0952/2325] test: add test for serialize data --- tests/system/CommonFunctionsTest.php | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 1b9bcbbbf3ad..35175209da64 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -311,6 +311,39 @@ public function testOldInput() $this->assertSame('fritz', old('zibble')); } + /** + * @runInSeparateProcess + * @preserveGlobalState disabled + */ + public function testOldInputSerializeData() + { + $this->injectSessionMock(); + // setup from RedirectResponseTest... + $_SERVER['REQUEST_METHOD'] = 'GET'; + + $this->config = new App(); + $this->config->baseURL = 'http://example.com/'; + + $this->routes = new RouteCollection(Services::locator(), new Modules()); + Services::injectMock('routes', $this->routes); + + $this->request = new MockIncomingRequest($this->config, new URI('http://example.com'), null, new UserAgent()); + Services::injectMock('request', $this->request); + + // setup & ask for a redirect... + $_SESSION = []; + $_GET = []; + $_POST = [ + 'zibble' => serialize('fritz'), + ]; + + $response = new RedirectResponse(new App()); + $response->withInput(); + + // serialized parameters are only HTML-escaped. + $this->assertSame('s:5:"fritz";', old('zibble')); + } + /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492 * @runInSeparateProcess From b2d27c354c89b740a4c63443066a06b1bdf2469e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 12 Nov 2021 14:24:49 +0900 Subject: [PATCH 0953/2325] docs: add about Deserialization of Untrusted Data in old() to changelogs/v4.1.6.rst --- user_guide_src/source/changelogs/v4.1.6.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 82b03127cda2..f3c513b48b99 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -9,6 +9,11 @@ Release Date: Not released :local: :depth: 2 +SECURITY +======== + +- *Deserialization of Untrusted Data* found in the ``old()`` function was fixed. See the `Security advisory `_ for more information. + BREAKING ******** From 19d27497ca0c5bbcfb978d23581285cef03d058f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 13 Nov 2021 08:06:30 +0900 Subject: [PATCH 0954/2325] docs: move // comments into PHPDoc --- tests/system/HTTP/IncomingRequestTest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 4229d5d264ec..2ea9dd38914f 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -107,7 +107,9 @@ public function testMissingOldInput() $this->assertNull($this->request->getOldInput('pineapple.name')); } - // Reference: https://github.com/codeigniter4/CodeIgniter4/issues/1492 + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492 + */ public function testCanGetOldInputArray() { $_SESSION['_ci_old_input'] = [ @@ -119,9 +121,9 @@ public function testCanGetOldInputArray() $this->assertSame(['name' => 'foo'], $this->request->getOldInput('banana')); } - // Reference: https://github.com/codeigniter4/CodeIgniter4/issues/1492 - /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492 + * * @runInSeparateProcess * @preserveGlobalState disabled */ From 24ae7250a91208a9dfd1ba0d14ccad6aad028d01 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 13 Nov 2021 08:12:18 +0900 Subject: [PATCH 0955/2325] test: refactor: fix test method names --- tests/system/HTTP/IncomingRequestTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/HTTP/IncomingRequestTest.php b/tests/system/HTTP/IncomingRequestTest.php index 2ea9dd38914f..e8c91268a8e2 100644 --- a/tests/system/HTTP/IncomingRequestTest.php +++ b/tests/system/HTTP/IncomingRequestTest.php @@ -110,7 +110,7 @@ public function testMissingOldInput() /** * @see https://github.com/codeigniter4/CodeIgniter4/issues/1492 */ - public function testCanGetOldInputArray() + public function testCanGetOldInputArrayWithSESSION() { $_SESSION['_ci_old_input'] = [ 'get' => ['apple' => ['name' => 'two']], @@ -127,7 +127,7 @@ public function testCanGetOldInputArray() * @runInSeparateProcess * @preserveGlobalState disabled */ - public function testCanSerializeOldArray() + public function testCanGetOldInputArrayWithSessionService() { $locations = [ 'AB' => 'Alberta', From 025a63bb2a0a0c9a1a34334b35e87f8ac19d6c96 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Dec 2021 10:14:03 +0900 Subject: [PATCH 0956/2325] docs: update header level --- user_guide_src/source/changelogs/v4.1.6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index f3c513b48b99..60b2dca40e30 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -10,7 +10,7 @@ Release Date: Not released :depth: 2 SECURITY -======== +******** - *Deserialization of Untrusted Data* found in the ``old()`` function was fixed. See the `Security advisory `_ for more information. From 6c7742cfadf4c3c3df8be9e4c2a61ea3e15cd460 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Dec 2021 10:39:29 +0900 Subject: [PATCH 0957/2325] docs: fix wrong sample code --- user_guide_src/source/libraries/sessions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index d38ec66e8994..cb6e78c25330 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -91,7 +91,7 @@ longer need it. So, what you need is to close the session for the current request after you no longer need it. :: - $session->destroy(); + session_write_close(); What is Session Data? ===================== From 2778b37527edd1411b3bf14285570fb481170822 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Dec 2021 21:20:08 +0900 Subject: [PATCH 0958/2325] docs: update command option --- user_guide_src/source/dbmgmt/migration.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 9f748da69521..4d76e04d903b 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -199,13 +199,13 @@ You can use (migrate) with the following options: - ``-g`` - to chose database group, otherwise default database group will be used. - ``-n`` - to choose namespace, otherwise (App) namespace will be used. -- ``-all`` - to migrate all namespaces to the latest migration +- ``--all`` - to migrate all namespaces to the latest migration This example will migrate Blog namespace with any new migrations on the test database group:: > php spark migrate -g test -n Blog -When using the ``-all`` option, it will scan through all namespaces attempting to find any migrations that have +When using the ``--all`` option, it will scan through all namespaces attempting to find any migrations that have not been run. These will all be collected and then sorted as a group by date created. This should help to minimize any potential conflicts between the main application and any modules. @@ -231,7 +231,7 @@ You can use (refresh) with the following options: - ``-g`` - to choose database group, otherwise default database group will be used. - ``-n`` - to choose namespace, otherwise (App) namespace will be used. -- ``-all`` - to refresh all namespaces +- ``--all`` - to refresh all namespaces - ``-f`` - to force a bypass confirmation question, it is only asked in a production environment **status** From 641873bed9c8bdc0f297aad607f8b4949b033270 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 9 Dec 2021 21:24:35 +0900 Subject: [PATCH 0959/2325] docs: improve command sample '\' is a meta character in the shell. --- user_guide_src/source/dbmgmt/migration.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index 4d76e04d903b..e7bd41f34bc0 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -201,9 +201,9 @@ You can use (migrate) with the following options: - ``-n`` - to choose namespace, otherwise (App) namespace will be used. - ``--all`` - to migrate all namespaces to the latest migration -This example will migrate Blog namespace with any new migrations on the test database group:: +This example will migrate ``Acme\Blog`` namespace with any new migrations on the test database group:: - > php spark migrate -g test -n Blog + > php spark migrate -g test -n 'Acme\Blog' When using the ``--all`` option, it will scan through all namespaces attempting to find any migrations that have not been run. These will all be collected and then sorted as a group by date created. This should help From 05ac0503b4f2dab6607ff796c93e548e19bc1720 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Dec 2021 14:24:47 +0900 Subject: [PATCH 0960/2325] docs: add note and warning Waring about the possibility of bypassing the filter. --- user_guide_src/source/incoming/filters.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index bbed197e7702..267ef4c921f4 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -91,6 +91,13 @@ Configuring Filters Once you've created your filters, you need to configure when they get run. This is done in **app/Config/Filters.php**. This file contains four properties that allow you to configure exactly when the filters run. +.. Note:: The safest way to apply filters is to :ref:`disable auto-routing `, and :ref:`set filters to routes `. + +.. Warning:: It is recommended that you should always add ``*`` at the end of a URI in the filter settings. + Because a controller method might be accessible by different URLs than you think. + For example, when auto-routing is enabled, if you have ``Blog::index``, + it can be accessible with ``blog``, ``blog/index``, and ``blog/index/1``, etc. + $aliases ======== From bfd0812346b4b028f3d2970cea7806573a9a0be8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 10 Dec 2021 14:27:40 +0900 Subject: [PATCH 0961/2325] docs: replace uri with URI --- user_guide_src/source/incoming/filters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 267ef4c921f4..096d1020f77f 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -140,7 +140,7 @@ run on every request. Filters can be specified by adding their alias to either t There are times where you want to apply a filter to almost every request, but have a few that should be left alone. One common example is if you need to exclude a few URI's from the CSRF protection filter to allow requests from third-party websites to hit one or two specific URI's, while keeping the rest of them protected. To do this, add -an array with the 'except' key and a uri to match as the value alongside the alias:: +an array with the 'except' key and a URI to match as the value alongside the alias:: public $globals = [ 'before' => [ From 7d3f02ca53327e492ab15f3409b5f4e7ce95e68d Mon Sep 17 00:00:00 2001 From: Toto Date: Fri, 10 Dec 2021 21:49:51 +0700 Subject: [PATCH 0962/2325] update docs about `esc()` `null` is not `$context` --- user_guide_src/source/general/common_functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index dd4c69a9915e..c1cdb038984a 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -81,7 +81,7 @@ Service Accessors If $data is a string, then it simply escapes and returns it. If $data is an array, then it loops over it, escaping each 'value' of the key/value pairs. - Valid context values: html, js, css, url, attr, raw, null + Valid context values: html, js, css, url, attr, raw .. php:function:: helper($filename) From 85de0fa9c2e753089ec3b95e9d6bc11eb4c5213b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 11 Dec 2021 01:46:37 +0000 Subject: [PATCH 0963/2325] chore(deps-dev): update rector/rector requirement from 0.12.5 to 0.12.7 (#5451) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 064f7b392e05..ab1c999190bf 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.5" + "rector/rector": "0.12.7" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From 19d9f111dcc87746efe4ca255062370d7a8bf31b Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 10:59:30 +0900 Subject: [PATCH 0964/2325] fix: VENDORPATH definition When using multiple apps, vendor/ is not ROOTPATH/vendor/. --- system/bootstrap.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/bootstrap.php b/system/bootstrap.php index 17226d099974..4549fbc2c939 100644 --- a/system/bootstrap.php +++ b/system/bootstrap.php @@ -117,7 +117,7 @@ class_alias('Config\Services', 'CodeIgniter\Services'); * We do not want to enforce this, so set the constant if Composer was used. */ if (! defined('VENDORPATH')) { - define('VENDORPATH', realpath(ROOTPATH . 'vendor') . DIRECTORY_SEPARATOR); + define('VENDORPATH', dirname(COMPOSER_PATH) . DIRECTORY_SEPARATOR); } require_once COMPOSER_PATH; From 290b4d0dbf6db5dd8f57f9ba6d35c2aa8a8477b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 11:02:18 +0900 Subject: [PATCH 0965/2325] refactor: COMPOSER_PATH and VENDORPATH are defined above --- system/Test/bootstrap.php | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index f6ddb2ad68d1..48a266d14600 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -84,20 +84,6 @@ class_alias('Config\Services', 'CodeIgniter\Services'); // Initialize and register the loader with the SPL autoloader stack. Services::autoloader()->initialize(new Autoload(), new Modules())->register(); -// Now load Composer's if it's available -if (is_file(COMPOSER_PATH)) { - /* - * The path to the vendor directory. - * - * We do not want to enforce this, so set the constant if Composer was used. - */ - if (! defined('VENDORPATH')) { - define('VENDORPATH', realpath(ROOTPATH . 'vendor') . DIRECTORY_SEPARATOR); - } - - require_once COMPOSER_PATH; -} - // Load environment settings from .env files into $_SERVER and $_ENV require_once SYSTEMPATH . 'Config/DotEnv.php'; From e2ec0fea517bde7319f3208c628484233b3aebb9 Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Sat, 11 Dec 2021 10:07:18 +0700 Subject: [PATCH 0966/2325] remove null as `$context` Co-authored-by: kenjis --- system/Common.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Common.php b/system/Common.php index 85a2506dfb9f..f531a82f7284 100644 --- a/system/Common.php +++ b/system/Common.php @@ -380,7 +380,7 @@ function env(string $key, $default = null) * If $data is an array, then it loops over it, escaping each * 'value' of the key/value pairs. * - * Valid context values: html, js, css, url, attr, raw, null + * Valid context values: html, js, css, url, attr, raw * * @param array|string $data * @param string $encoding From 9792a6b25f53640bca4d59715c58389df6bcc578 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 13:03:35 +0900 Subject: [PATCH 0967/2325] fix: $fraction type NumberFormatter::setAttribute(): Passing null to parameter #2 ($value) of type int|float is deprecated --- system/Helpers/number_helper.php | 2 +- tests/system/Helpers/NumberHelperTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index b3d7c80c6006..7e5428455aaf 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -116,7 +116,7 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) * @param string $locale * @param int $fraction */ - function number_to_currency(float $num, string $currency, ?string $locale = null, ?int $fraction = null): string + function number_to_currency(float $num, string $currency, ?string $locale = null, int $fraction = 0): string { return format_number($num, 1, $locale, [ 'type' => NumberFormatter::CURRENCY, diff --git a/tests/system/Helpers/NumberHelperTest.php b/tests/system/Helpers/NumberHelperTest.php index 286440d7423b..006d0a650118 100755 --- a/tests/system/Helpers/NumberHelperTest.php +++ b/tests/system/Helpers/NumberHelperTest.php @@ -126,6 +126,7 @@ public function testQuadrillions() */ public function testCurrencyCurrentLocale() { + $this->assertSame('$1,235', number_to_currency(1234.56, 'USD', 'en_US')); $this->assertSame('$1,234.56', number_to_currency(1234.56, 'USD', 'en_US', 2)); $this->assertSame('£1,234.56', number_to_currency(1234.56, 'GBP', 'en_GB', 2)); $this->assertSame("1.234,56\u{a0}RSD", number_to_currency(1234.56, 'RSD', 'sr_RS', 2)); From a6eb95dcc44e194d6799dc95da203023e5fcb8b3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 13:11:39 +0900 Subject: [PATCH 0968/2325] docs: remove unneeded doc comments --- system/Helpers/number_helper.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index 7e5428455aaf..04c8b9e4c0c2 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -112,10 +112,7 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) } if (! function_exists('number_to_currency')) { - /** - * @param string $locale - * @param int $fraction - */ + function number_to_currency(float $num, string $currency, ?string $locale = null, int $fraction = 0): string { return format_number($num, 1, $locale, [ From ad3a204f6c6f1829d7ca9d1e944397dec0dc4af8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 13:29:49 +0900 Subject: [PATCH 0969/2325] docs: fix number_helper.rst --- .../source/helpers/number_helper.rst | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/helpers/number_helper.rst b/user_guide_src/source/helpers/number_helper.rst index eeca3a00614f..be5be2a8018c 100644 --- a/user_guide_src/source/helpers/number_helper.rst +++ b/user_guide_src/source/helpers/number_helper.rst @@ -27,7 +27,7 @@ Available Functions The following functions are available: -.. php:function:: number_to_size($num[, $precision = 1[, $locale = null]) +.. php:function:: number_to_size($num[, $precision = 1[, $locale = null]]) :param mixed $num: Number of bytes :param int $precision: Floating point precision @@ -86,21 +86,23 @@ The following functions are available: echo number_to_amount('123,456,789,012', 2, 'de_DE'); // Returns 123,46 billion -.. php:function:: number_to_currency($num, $currency[, $locale = null]) +.. php:function:: number_to_currency($num, $currency[, $locale = null[, $fraction = 0]]) - :param mixed $num: Number to format + :param float $num: Number to format :param string $currency: The currency type, i.e., USD, EUR, etc - :param string $locale: The locale to use for formatting + :param string|null $locale: The locale to use for formatting :param integer $fraction: Number of fraction digits after decimal point :returns: The number as the appropriate currency for the locale :rtype: string Converts a number in common currency formats, like USD, EUR, GBP, etc:: - echo number_to_currency(1234.56, 'USD'); // Returns $1,234.56 - echo number_to_currency(1234.56, 'EUR'); // Returns €1,234.56 - echo number_to_currency(1234.56, 'GBP'); // Returns £1,234.56 - echo number_to_currency(1234.56, 'YEN'); // Returns YEN1,234.56 + echo number_to_currency(1234.56, 'USD', 'en_US', 2); // Returns $1,234.56 + echo number_to_currency(1234.56, 'EUR', 'de_DE', 2); // Returns 1.234,56 € + echo number_to_currency(1234.56, 'GBP', 'en_GB', 2); // Returns £1,234.56 + echo number_to_currency(1234.56, 'YEN', 'ja_JP', 2); // Returns YEN 1,234.56 + + If you don't specify a locale, the Request locale is used. .. php:function:: number_to_roman($num) From ce3d3cc9d5a4633e6c5f464c2295420d54b807ba Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 13:56:09 +0900 Subject: [PATCH 0970/2325] style: remove empty line --- system/Helpers/number_helper.php | 1 - 1 file changed, 1 deletion(-) diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index 04c8b9e4c0c2..35e748978fbb 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -112,7 +112,6 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) } if (! function_exists('number_to_currency')) { - function number_to_currency(float $num, string $currency, ?string $locale = null, int $fraction = 0): string { return format_number($num, 1, $locale, [ From 9e9b9cd7324d43c72a493c1fb9518aa446f1a349 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Dec 2021 14:17:22 +0900 Subject: [PATCH 0971/2325] docs: add about COMPOSER_PATH change --- user_guide_src/source/general/managing_apps.rst | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index c967c4a296bc..8b82a697698c 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -69,8 +69,13 @@ This would have two apps, **foo** and **bar**, both having standard application and a **public** folder, and sharing a common **codeigniter** framework. The **index.php** inside each application would refer to its own configuration, -``../app/Config/Paths.php``, and the ``$systemDirectory`` variable inside each +``../app/Config/Paths.php``, and the ``$systemDirectory`` variable in **app/Config/Paths.php** inside each of those would be set to refer to the shared common **system** folder. If either of the applications had a command-line component, then you would also modify **spark** inside each application's project folder, as directed above. + +When you use Composer autoloader, fix the ``COMPOSER_PATH`` constant in **app/Config/Constants.php** inside each +of those:: + + defined('COMPOSER_PATH') || define('COMPOSER_PATH', ROOTPATH . '../vendor/autoload.php'); From 544e0c15c87bf1bb3ac5744aa7ed08c9894ad6bf Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 11 Dec 2021 16:36:48 +0800 Subject: [PATCH 0972/2325] The View class. Optimizing duplicate code. --- system/View/View.php | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/system/View/View.php b/system/View/View.php index 6005b5f40582..e65416e5cf48 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -199,11 +199,7 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n } // Make our view data available to the view. - $this->tempData = $this->tempData ?? $this->data; - - if ($saveData) { - $this->data = $this->tempData; - } + $this->prepareTemplateData($saveData); // Save current vars $renderVars = $this->renderVars; @@ -275,13 +271,9 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n */ public function renderString(string $view, ?array $options = null, ?bool $saveData = null): string { - $start = microtime(true); - $saveData = $saveData ?? $this->saveData; - $this->tempData = $this->tempData ?? $this->data; - - if ($saveData) { - $this->data = $this->tempData; - } + $start = microtime(true); + $saveData = $saveData ?? $this->saveData; + $this->prepareTemplateData($saveData); $output = (function (string $view): string { extract($this->tempData); @@ -454,4 +446,13 @@ protected function logPerformance(float $start, float $end, string $view) ]; } } + + protected function prepareTemplateData(bool $saveData): void + { + $this->tempData = $this->tempData ?? $this->data; + + if ($saveData) { + $this->data = $this->tempData; + } + } } From 623b1024963bbfc119c8ddfb1e7b5ecf367ba8d0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Dec 2021 09:53:51 +0900 Subject: [PATCH 0973/2325] test: fix: restore `require_once` that was accidentally deleted --- system/Test/bootstrap.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index 48a266d14600..00a4341c6e2a 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -84,6 +84,11 @@ class_alias('Config\Services', 'CodeIgniter\Services'); // Initialize and register the loader with the SPL autoloader stack. Services::autoloader()->initialize(new Autoload(), new Modules())->register(); +// Now load Composer's if it's available +if (is_file(COMPOSER_PATH)) { + require_once COMPOSER_PATH; +} + // Load environment settings from .env files into $_SERVER and $_ENV require_once SYSTEMPATH . 'Config/DotEnv.php'; From b22183c7a280debd5f084d0ffb43d723a041932e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Dec 2021 19:57:41 +0900 Subject: [PATCH 0974/2325] docs: add space after // --- user_guide_src/source/models/entities.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 10828c0dc56b..9df5239cb820 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -433,7 +433,7 @@ Let's say the class will be located in the 'app/Entity/Cast' directory:: use CodeIgniter\Entity\Cast\BaseCast; - //The class must inherit the CodeIgniter\Entity\Cast\BaseCast class + // The class must inherit the CodeIgniter\Entity\Cast\BaseCast class class CastBase64 extends BaseCast { public static function get($value, array $params = []) @@ -462,13 +462,13 @@ Now you need to register it:: 'key' => 'base64', ]; - //Bind the type to the handler + // Bind the type to the handler protected $castHandlers = [ 'base64' => \App\Entity\Cast\CastBase64::class, ]; } - //... + // ... $entity->key = 'test'; // dGVzdA== echo $entity->key; // test From 46d592a0f6be3eabc14ed0c42e94a7086b7cb6b9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Dec 2021 19:58:16 +0900 Subject: [PATCH 0975/2325] docs: align `=>` positions --- user_guide_src/source/models/entities.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 9df5239cb820..7a170aa2790c 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -239,10 +239,10 @@ As an example, imagine you have the simplified User Entity that is used througho class User extends Entity { protected $attributes = [ - 'id' => null, - 'name' => null, // Represents a username - 'email' => null, - 'password' => null, + 'id' => null, + 'name' => null, // Represents a username + 'email' => null, + 'password' => null, 'created_at' => null, 'updated_at' => null, ]; @@ -266,10 +266,10 @@ simply map the ``full_name`` column in the database to the ``$name`` property, a class User extends Entity { protected $attributes = [ - 'id' => null, - 'name' => null, // Represents a username - 'email' => null, - 'password' => null, + 'id' => null, + 'name' => null, // Represents a username + 'email' => null, + 'password' => null, 'created_at' => null, 'updated_at' => null, ]; From b7e0f8b20921a69f8c04a95d1a37a2cd5b78da89 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Dec 2021 20:00:30 +0900 Subject: [PATCH 0976/2325] docs: fix the variable name --- user_guide_src/source/models/entities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 7a170aa2790c..1ac2f2c3ebf6 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -299,7 +299,7 @@ By default, the Entity class will convert fields named `created_at`, `updated_at :doc:`Time ` instances whenever they are set or retrieved. The Time class provides a large number of helpful methods in an immutable, localized way. -You can define which properties are automatically converted by adding the name to the **options['dates']** array:: +You can define which properties are automatically converted by adding the name to the ``$dates`` property:: Date: Sun, 12 Dec 2021 20:01:21 +0900 Subject: [PATCH 0977/2325] docs: fix the classname --- user_guide_src/source/models/entities.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 1ac2f2c3ebf6..54c0c0ed8b00 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -107,8 +107,8 @@ Now that all of the pieces are in place, you would work with the Entity class as $userModel->save($user); You may have noticed that the User class has not set any properties for the columns, but you can still -access them as if they were public properties. The base class, **CodeIgniter\\Entity**, takes care of this for you, as well as providing the ability to check the properties with **isset()**, or **unset()** the property, and keep track +access them as if they were public properties. The base class, ``CodeIgniter\Entity\Entity``, takes care of this for you, as of what columns have changed since the object was created or pulled from the database. When the User is passed to the model's **save()** method, it automatically takes care of reading the properties From 155d16b222e4bcd7117182d06e489a216a9cece7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Dec 2021 20:02:09 +0900 Subject: [PATCH 0978/2325] docs: improve text decoration Code is decrated with ``. File paths are decrated with **. --- user_guide_src/source/models/entities.rst | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 54c0c0ed8b00..489685a8c5ff 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -106,13 +106,13 @@ Now that all of the pieces are in place, you would work with the Entity class as $user->email = 'foo@example.com'; $userModel->save($user); -You may have noticed that the User class has not set any properties for the columns, but you can still -well as providing the ability to check the properties with **isset()**, or **unset()** the property, and keep track +You may have noticed that the ``User`` class has not set any properties for the columns, but you can still access them as if they were public properties. The base class, ``CodeIgniter\Entity\Entity``, takes care of this for you, as +well as providing the ability to check the properties with ``isset()``, or ``unset()`` the property, and keep track of what columns have changed since the object was created or pulled from the database. -When the User is passed to the model's **save()** method, it automatically takes care of reading the properties -and saving any changes to columns listed in the model's **$allowedFields** property. It also knows whether to create +When the User is passed to the model's ``save()`` method, it automatically takes care of reading the properties +and saving any changes to columns listed in the model's ``$allowedFields`` property. It also knows whether to create a new row, or update an existing one. .. note:: When we are making a call to the ``insert()`` all the values from Entity are passed to the method, but when we @@ -123,7 +123,7 @@ Filling Properties Quickly The Entity class also provides a method, ``fill()`` that allows you to shove an array of key/value pairs into the class and populate the class properties. Any property in the array will be set on the Entity. However, when saving through -the model, only the fields in $allowedFields will actually be saved to the database, so you can store additional data +the model, only the fields in ``$allowedFields`` will actually be saved to the database, so you can store additional data on your entities without worrying much about stray fields getting saved incorrectly. :: @@ -198,7 +198,7 @@ Here's an updated User entity to provide some examples of how this could be used The first thing to notice is the name of the methods we've added. For each one, the class expects the snake_case column name to be converted into PascalCase, and prefixed with either ``set`` or ``get``. These methods will then -be automatically called whenever you set or retrieve the class property using the direct syntax (i.e., $user->email). +be automatically called whenever you set or retrieve the class property using the direct syntax (i.e., ``$user->email``). The methods do not need to be public unless you want them accessed from other classes. For example, the ``created_at`` class property will be accessed through the ``setCreatedAt()`` and ``getCreatedAt()`` methods. @@ -327,14 +327,14 @@ current timezone, as set in **app/Config/App.php**:: Property Casting ---------------- -You can specify that properties in your Entity should be converted to common data types with the **casts** property. +You can specify that properties in your Entity should be converted to common data types with the ``$casts`` property. This option should be an array where the key is the name of the class property, and the value is the data type it should be cast to. Casting only affects when values are read. No conversions happen that affect the permanent value in either the entity or the database. Properties can be cast to any of the following data types: **integer**, **float**, **double**, **string**, **boolean**, **object**, **array**, **datetime**, **timestamp**, and **uri**. Add a question mark at the beginning of type to mark property as nullable, i.e., **?string**, **?integer**. -For example, if you had a User entity with an **is_banned** property, you can cast it as a boolean:: +For example, if you had a User entity with an ``is_banned`` property, you can cast it as a boolean:: Date: Mon, 13 Dec 2021 09:14:59 +0900 Subject: [PATCH 0979/2325] docs: remove out of dated raw html --- user_guide_src/source/helpers/html_helper.rst | 4 ---- 1 file changed, 4 deletions(-) diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst index 3e88f19360fc..978f0ea67f04 100755 --- a/user_guide_src/source/helpers/html_helper.rst +++ b/user_guide_src/source/helpers/html_helper.rst @@ -8,10 +8,6 @@ HTML. .. contents:: :local: -.. raw:: html - -
    - Loading this Helper =================== From f941858bcf244e7925d6f0513a11efbeaf1c3312 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 13 Dec 2021 15:05:13 +0800 Subject: [PATCH 0980/2325] Use PHPStan's baseline instead of global ignore of errors --- phpstan-baseline.neon.dist | 1022 +++++++++++++++++ phpstan.neon.dist | 27 +- system/Autoloader/Autoloader.php | 4 +- system/Cache/Handlers/FileHandler.php | 1 - system/Cache/Handlers/MemcachedHandler.php | 6 +- system/CodeIgniter.php | 7 +- system/Common.php | 1 - system/Database/BaseConnection.php | 1 - system/Database/BaseResult.php | 2 - system/Database/Postgre/Connection.php | 1 - system/Database/SQLite3/Result.php | 16 +- system/Debug/Exceptions.php | 2 +- system/Debug/Toolbar/Collectors/Events.php | 2 +- system/Debug/Toolbar/Collectors/Views.php | 6 +- system/HTTP/CURLRequest.php | 2 +- system/HTTP/RequestTrait.php | 1 - system/HTTP/URI.php | 2 +- system/Helpers/number_helper.php | 2 +- system/Helpers/text_helper.php | 1 - system/Helpers/url_helper.php | 2 +- system/Images/Handlers/ImageMagickHandler.php | 6 +- system/Model.php | 2 +- system/Router/Router.php | 1 - system/Session/Handlers/DatabaseHandler.php | 1 - system/Session/Handlers/RedisHandler.php | 1 - system/Test/CIUnitTestCase.php | 2 +- system/Test/Fabricator.php | 6 +- system/Test/FeatureTestCase.php | 2 +- system/Test/FeatureTestTrait.php | 2 +- system/Test/Mock/MockConnection.php | 2 +- 30 files changed, 1060 insertions(+), 73 deletions(-) create mode 100644 phpstan-baseline.neon.dist diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist new file mode 100644 index 000000000000..0a91bd7fc64f --- /dev/null +++ b/phpstan-baseline.neon.dist @@ -0,0 +1,1022 @@ +parameters: + ignoreErrors: + - + message: "#^Parameter \\#1 \\$callback of function spl_autoload_register expects \\(callable\\(string\\)\\: void\\)\\|null, array\\{\\$this\\(CodeIgniter\\\\Autoloader\\\\Autoloader\\), 'loadClass'\\} given\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Parameter \\#1 \\$callback of function spl_autoload_register expects \\(callable\\(string\\)\\: void\\)\\|null, array\\{\\$this\\(CodeIgniter\\\\Autoloader\\\\Autoloader\\), 'loadClassmap'\\} given\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Property Config\\\\Autoload\\:\\:\\$classmap \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Property Config\\\\Autoload\\:\\:\\$files \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Property Config\\\\Autoload\\:\\:\\$psr4 \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Autoloader/Autoloader.php + + - + message: "#^Method CodeIgniter\\\\Validation\\\\ValidationInterface\\:\\:run\\(\\) invoked with 3 parameters, 0\\-2 required\\.$#" + count: 1 + path: system/BaseModel.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$backupHandler \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/CacheFactory.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$handler \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/CacheFactory.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$validHandlers \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/CacheFactory.php + + - + message: "#^Comparison operation \"\\>\" between int\\<1, max\\> and \\(array\\|float\\|int\\) results in an error\\.$#" + count: 1 + path: system/Cache/Handlers/FileHandler.php + + - + message: "#^If condition is always true\\.$#" + count: 1 + path: system/Cache/Handlers/FileHandler.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$storePath \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Cache/Handlers/FileHandler.php + + - + message: "#^Method MemcachePool\\:\\:decrement\\(\\) invoked with 4 parameters, 1\\-2 required\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Method MemcachePool\\:\\:increment\\(\\) invoked with 4 parameters, 1\\-2 required\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Variable \\$config in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Variable \\$data might not be defined\\.$#" + count: 1 + path: system/Cache/Handlers/MemcachedHandler.php + + - + message: "#^Property Config\\\\Cache\\:\\:\\$redis \\(array\\\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/Handlers/PredisHandler.php + + - + message: "#^Property CodeIgniter\\\\Cache\\\\Handlers\\\\RedisHandler\\:\\:\\$redis \\(Redis\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Cache/Handlers/RedisHandler.php + + - + message: "#^Variable \\$config in empty\\(\\) always exists and is not falsy\\.$#" + count: 1 + path: system/Cache/Handlers/RedisHandler.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:getPost\\(\\)\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:getSegments\\(\\)\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\HTTP\\\\Request\\:\\:setLocale\\(\\)\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Dead catch \\- CodeIgniter\\\\Exceptions\\\\PageNotFoundException is never thrown in the try block\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Property Config\\\\App\\:\\:\\$appTimezone \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Property Config\\\\App\\:\\:\\$defaultLocale \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: system/CodeIgniter.php + + - + message: "#^Binary operation \"\\+\" between array\\\\|false and non\\-empty\\-array\\ results in an error\\.$#" + count: 1 + path: system/Common.php + + - + message: "#^Variable \\$params on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/Common.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:\\$db \\(CodeIgniter\\\\Database\\\\BaseConnection\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/Database/BaseBuilder.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:_disableForeignKeyChecks\\(\\)\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\BaseConnection\\:\\:_enableForeignKeyChecks\\(\\)\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\QueryInterface\\:\\:getOriginalQuery\\(\\)\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Negated boolean expression is always true\\.$#" + count: 1 + path: system/Database/BaseConnection.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 3 + path: system/Database/BaseResult.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 2 + path: system/Database/BaseResult.php + + - + message: "#^While loop condition is always true\\.$#" + count: 2 + path: system/Database/BaseResult.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\ConnectionInterface\\:\\:\\$DBDriver\\.$#" + count: 2 + path: system/Database/Database.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\ConnectionInterface\\:\\:\\$connID\\.$#" + count: 2 + path: system/Database/Database.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\Migration\\:\\:\\$DBGroup \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/Migration.php + + - + message: "#^Property Config\\\\Migrations\\:\\:\\$enabled \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/MigrationRunner.php + + - + message: "#^Property Config\\\\Migrations\\:\\:\\$table \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/MigrationRunner.php + + - + message: "#^Cannot access property \\$affected_rows on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot access property \\$errno on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot access property \\$error on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot access property \\$insert_id on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method autocommit\\(\\) on bool\\|object\\|resource\\.$#" + count: 3 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method begin_transaction\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method close\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method commit\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method more_results\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method next_result\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method query\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method real_escape_string\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method rollback\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method select_db\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Cannot call method store_result\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$strictOn \\(bool\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\MySQLi\\\\Connection\\:\\:\\$mysqli \\(mysqli\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/Database/MySQLi/Connection.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$mysqli\\.$#" + count: 3 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot call method bind_param\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot call method execute\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot call method get_result\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/MySQLi/PreparedQuery.php + + - + message: "#^Cannot access property \\$field_count on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot access property \\$num_rows on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method data_seek\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_assoc\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_field\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_fields\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method fetch_object\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Cannot call method field_seek\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/MySQLi/Result.php + + - + message: "#^Strict comparison using \\=\\=\\= between array and false will always evaluate to false\\.$#" + count: 1 + path: system/Database/Postgre/Connection.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/Postgre/PreparedQuery.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$schema\\.$#" + count: 2 + path: system/Database/SQLSRV/Builder.php + + - + message: "#^Access to an undefined property CodeIgniter\\\\Database\\\\BaseConnection\\:\\:\\$schema\\.$#" + count: 14 + path: system/Database/SQLSRV/Forge.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/SQLSRV/PreparedQuery.php + + - + message: "#^Cannot call method changes\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method close\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method escapeString\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method exec\\(\\) on bool\\|object\\|resource\\.$#" + count: 4 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method lastErrorCode\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method lastErrorMsg\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method lastInsertRowID\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method query\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/Connection.php + + - + message: "#^Cannot call method bindValue\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method execute\\(\\) on object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method lastErrorCode\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method lastErrorMsg\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method prepare\\(\\) on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Property CodeIgniter\\\\Database\\\\BasePreparedQuery\\:\\:\\$statement \\(object\\|resource\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Database/SQLite3/PreparedQuery.php + + - + message: "#^Cannot call method columnName\\(\\) on object\\|resource\\|false\\.$#" + count: 2 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method columnType\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method fetchArray\\(\\) on object\\|resource\\|false\\.$#" + count: 2 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method numColumns\\(\\) on object\\|resource\\|false\\.$#" + count: 1 + path: system/Database/SQLite3/Result.php + + - + message: "#^Cannot call method reset\\(\\) on object\\|resource\\|false\\.$#" + count: 2 + path: system/Database/SQLite3/Result.php + + - + message: "#^Property Config\\\\Database\\:\\:\\$filesPath \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Database/Seeder.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Parameter \\#4 \\$replacement of function array_splice expects array\\|string, true given\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Property CodeIgniter\\\\Debug\\\\Exceptions\\:\\:\\$formatter \\(CodeIgniter\\\\Format\\\\FormatterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Property Config\\\\Exceptions\\:\\:\\$sensitiveDataInTrace \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Debug/Exceptions.php + + - + message: "#^Property Config\\\\Toolbar\\:\\:\\$collectVarData \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar.php + + - + message: "#^Variable \\$request on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar.php + + - + message: "#^Variable \\$response on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getPerformanceData\\(\\)\\.$#" + count: 1 + path: system/Debug/Toolbar/Collectors/Events.php + + - + message: "#^Property CodeIgniter\\\\Log\\\\Logger\\:\\:\\$logCache \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Debug/Toolbar/Collectors/Logs.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getData\\(\\)\\.$#" + count: 1 + path: system/Debug/Toolbar/Collectors/Views.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getPerformanceData\\(\\)\\.$#" + count: 2 + path: system/Debug/Toolbar/Collectors/Views.php + + - + message: "#^Static property CodeIgniter\\\\Email\\\\Email\\:\\:\\$func_overload \\(bool\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Email/Email.php + + - + message: "#^Property Config\\\\Encryption\\:\\:\\$digest \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 2 + path: system/Encryption/Encryption.php + + - + message: "#^Property CodeIgniter\\\\Files\\\\File\\:\\:\\$size \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Files/File.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Property Config\\\\Filters\\:\\:\\$filters \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Property Config\\\\Filters\\:\\:\\$globals \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Property Config\\\\Filters\\:\\:\\$methods \\(array\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Filters/Filters.php + + - + message: "#^Parameter \\#1 \\$seconds of function sleep expects int, float given\\.$#" + count: 1 + path: system/HTTP/CURLRequest.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/Files/UploadedFile.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Files\\\\UploadedFile\\:\\:\\$error \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 2 + path: system/HTTP/Files/UploadedFile.php + + - + message: "#^Return type \\(bool\\) of method CodeIgniter\\\\HTTP\\\\Files\\\\UploadedFile\\:\\:move\\(\\) should be compatible with return type \\(CodeIgniter\\\\Files\\\\File\\) of method CodeIgniter\\\\Files\\\\File\\:\\:move\\(\\)$#" + count: 1 + path: system/HTTP/Files/UploadedFile.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\IncomingRequest\\:\\:\\$locale \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/IncomingRequest.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Message\\:\\:\\$protocolVersion \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/Message.php + + - + message: "#^Variable \\$_GET on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/HTTP/RedirectResponse.php + + - + message: "#^Variable \\$_POST on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: system/HTTP/RedirectResponse.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$proxyIPs \\(array\\|string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/Request.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$uri \\(CodeIgniter\\\\HTTP\\\\URI\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/HTTP/Request.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieSameSite \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 3 + path: system/HTTP/Response.php + + - + message: "#^Cannot unset offset 'path' on array\\{host\\: mixed\\}\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$fragment \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$host \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Property CodeIgniter\\\\HTTP\\\\URI\\:\\:\\$path \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/HTTP/URI.php + + - + message: "#^Right side of && is always true\\.$#" + count: 1 + path: system/Helpers/filesystem_helper.php + + - + message: "#^Offset 'checked' on array\\{type\\: 'checkbox', name\\: mixed, value\\: string\\} in isset\\(\\) does not exist\\.$#" + count: 1 + path: system/Helpers/form_helper.php + + - + message: "#^Binary operation \"\\+\" between 0 and string results in an error\\.$#" + count: 1 + path: system/Helpers/number_helper.php + + - + message: "#^Variable \\$mockService in empty\\(\\) always exists and is always falsy\\.$#" + count: 1 + path: system/Helpers/test_helper.php + + - + message: "#^Parameter \\#2 \\$times of function str_repeat expects int, float given\\.$#" + count: 1 + path: system/Helpers/text_helper.php + + - + message: "#^Variable \\$pool might not be defined\\.$#" + count: 2 + path: system/Helpers/text_helper.php + + - + message: "#^Variable \\$count might not be defined\\.$#" + count: 1 + path: system/Helpers/url_helper.php + + - + message: "#^Property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$image \\(CodeIgniter\\\\Images\\\\Image\\) in empty\\(\\) is not falsy\\.$#" + count: 1 + path: system/Images/Handlers/BaseHandler.php + + - + message: "#^Comparison operation \"\\>\\=\" between \\(array\\|float\\|int\\) and 0 results in an error\\.$#" + count: 2 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^PHPDoc type string\\|null of property CodeIgniter\\\\Images\\\\Handlers\\\\ImageMagickHandler\\:\\:\\$resource is not covariant with PHPDoc type resource\\|null of overridden property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$resource\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$height \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 4 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Property CodeIgniter\\\\Images\\\\Handlers\\\\BaseHandler\\:\\:\\$width \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 4 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Variable \\$gravity might not be defined\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Variable \\$xAxis might not be defined\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Variable \\$yAxis might not be defined\\.$#" + count: 1 + path: system/Images/Handlers/ImageMagickHandler.php + + - + message: "#^Property Config\\\\Logger\\:\\:\\$dateFormat \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Log/Logger.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:asArray\\(\\)\\.$#" + count: 1 + path: system/Model.php + + - + message: "#^Property CodeIgniter\\\\RESTful\\\\ResourceController\\:\\:\\$formatter \\(CodeIgniter\\\\Format\\\\FormatterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/RESTful/ResourceController.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getDefaultNamespace\\(\\)\\.$#" + count: 2 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getFilterForRoute\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getFiltersForRoute\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getRoutesOptions\\(\\)\\.$#" + count: 2 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:isFiltered\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Call to an undefined method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:setHTTPVerb\\(\\)\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Router/Router.php + + - + message: "#^Method CodeIgniter\\\\Router\\\\RouteCollectionInterface\\:\\:getRoutes\\(\\) invoked with 1 parameter, 0 required\\.$#" + count: 2 + path: system/Router/Router.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFCookieName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFExpire \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFHeaderName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFRegenerate \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\App\\:\\:\\$CSRFTokenName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$cookieName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$csrfProtection \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$expires \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$headerName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$regenerate \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$tokenName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Property Config\\\\Security\\:\\:\\$tokenRandomize \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Security/Security.php + + - + message: "#^Access to an undefined property Config\\\\App\\:\\:\\$sessionDBGroup\\.$#" + count: 1 + path: system/Session/Handlers/DatabaseHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/DatabaseHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/FileHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/MemcachedHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Handlers/RedisHandler.php + + - + message: "#^Strict comparison using \\=\\=\\= between string and true will always evaluate to false\\.$#" + count: 1 + path: system/Session/Handlers/RedisHandler.php + + - + message: "#^Property CodeIgniter\\\\Session\\\\Session\\:\\:\\$sessionExpiration \\(int\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieDomain \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookiePath \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieSameSite \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 2 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$cookieSecure \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionCookieName \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionExpiration \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionMatchIP \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionRegenerateDestroy \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\App\\:\\:\\$sessionTimeToUpdate \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$domain \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$path \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$raw \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$samesite \\(string\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Property Config\\\\Cookie\\:\\:\\$secure \\(bool\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Session/Session.php + + - + message: "#^Negated boolean expression is always false\\.$#" + count: 1 + path: system/Test/CIUnitTestCase.php + + - + message: "#^Access to an undefined property object\\:\\:\\$createdField\\.$#" + count: 1 + path: system/Test/Fabricator.php + + - + message: "#^Access to an undefined property object\\:\\:\\$deletedField\\.$#" + count: 1 + path: system/Test/Fabricator.php + + - + message: "#^Access to an undefined property object\\:\\:\\$updatedField\\.$#" + count: 1 + path: system/Test/Fabricator.php + + - + message: "#^Access to protected property CodeIgniter\\\\HTTP\\\\Request\\:\\:\\$uri\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\CIUnitTestCase\\:\\:\\$bodyFormat \\(string\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\CIUnitTestCase\\:\\:\\$clean \\(bool\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\CIUnitTestCase\\:\\:\\$session \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Test/FeatureTestCase.php + + - + message: "#^Cannot access property \\$insert_id on bool\\|object\\|resource\\.$#" + count: 1 + path: system/Test/Mock/MockConnection.php + + - + message: "#^Property CodeIgniter\\\\Test\\\\Mock\\\\MockResourcePresenter\\:\\:\\$formatter \\(CodeIgniter\\\\Format\\\\FormatterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: system/Test/Mock/MockResourcePresenter.php + + - + message: "#^Property CodeIgniter\\\\Throttle\\\\Throttler\\:\\:\\$testTime \\(int\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Throttle/Throttler.php + + - + message: "#^Property CodeIgniter\\\\Validation\\\\Validation\\:\\:\\$errors \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/Validation/Validation.php + + - + message: "#^Variable \\$error on left side of \\?\\? always exists and is always null\\.$#" + count: 1 + path: system/Validation/Validation.php + + - + message: "#^Property CodeIgniter\\\\View\\\\Cell\\:\\:\\$cache \\(CodeIgniter\\\\Cache\\\\CacheInterface\\) in empty\\(\\) is not falsy\\.$#" + count: 2 + path: system/View/Cell.php + + - + message: "#^Property Config\\\\View\\:\\:\\$plugins \\(array\\) on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: system/View/Parser.php + diff --git a/phpstan.neon.dist b/phpstan.neon.dist index bf23eb5303ed..741b147136b3 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,6 +8,9 @@ services: tags: - phpstan.rules.rule +includes: + - phpstan-baseline.neon.dist + parameters: tmpDir: build/phpstan level: 5 @@ -28,30 +31,6 @@ parameters: - system/Test/Filters/CITestStreamFilter.php - system/ThirdParty/* - system/Validation/Views/single.php - ignoreErrors: - - '#Access to an undefined property CodeIgniter\\Database\\BaseConnection::\$mysqli|\$schema#' - - '#Access to an undefined property CodeIgniter\\Database\\ConnectionInterface::(\$DBDriver|\$connID|\$likeEscapeStr|\$likeEscapeChar|\$escapeChar|\$protectIdentifiers|\$schema)#' - - '#Call to an undefined method CodeIgniter\\Database\\BaseConnection::_(disable|enable)ForeignKeyChecks\(\)#' - - '#Call to an undefined method CodeIgniter\\Router\\RouteCollectionInterface::(getDefaultNamespace|isFiltered|getFilterForRoute|getFiltersForRoute|getRoutesOptions)\(\)#' - - '#Cannot access property [\$a-z_]+ on ((bool\|)?object\|resource)#' - - '#Cannot call method [a-zA-Z_]+\(\) on ((bool\|)?object\|resource)#' - - '#Method CodeIgniter\\Router\\RouteCollectionInterface::getRoutes\(\) invoked with 1 parameter, 0 required#' - - '#Method CodeIgniter\\Validation\\ValidationInterface::run\(\) invoked with 3 parameters, 0-2 required#' - - '#Negated boolean expression is always (true|false)#' - - '#Return type \(bool\) of method CodeIgniter\\HTTP\\Files\\UploadedFile::move\(\) should be compatible with return type \(CodeIgniter\\Files\\File\) of method CodeIgniter\\Files\\File::move\(\)#' - - '#.*\son left side of \?\? is not nullable#' - - '#While loop condition is always true#' - - '#Right side of && is always true#' - - '#.*in isset\(\) is not nullable#' - - '#.*in empty\(\) is not falsy#' - - '#.*on left side of \?\? always exists and is not nullable#' - - '#Variable \$error on left side of \?\? always exists and is always null#' - - '#Variable \$config in empty\(\) always exists and is not falsy#' - - '#If condition is always true#' - - '#Dead catch - CodeIgniter\\Exceptions\\PageNotFoundException is never thrown in the try block#' - - '#.* in isset\(\) does not exist#' - - '#Variable \$mockService in empty\(\) always exists and is always falsy#' - - '#PHPDoc type string\|null of property CodeIgniter\\Images\\Handlers\\ImageMagickHandler::\$resource is not covariant with PHPDoc type resource\|null of overridden property CodeIgniter\\Images\\Handlers\\BaseHandler::\$resource#' parallel: processTimeout: 300.0 scanDirectories: diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 3472756ad4dd..492fb09930f0 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -114,10 +114,10 @@ public function initialize(Autoload $config, Modules $modules) public function register() { // Prepend the PSR4 autoloader for maximum performance. - spl_autoload_register([$this, 'loadClass'], true, true); // @phpstan-ignore-line + spl_autoload_register([$this, 'loadClass'], true, true); // Now prepend another loader for the files in our class map. - spl_autoload_register([$this, 'loadClassmap'], true, true); // @phpstan-ignore-line + spl_autoload_register([$this, 'loadClassmap'], true, true); // Load our non-class files foreach ($this->files as $file) { diff --git a/system/Cache/Handlers/FileHandler.php b/system/Cache/Handlers/FileHandler.php index a7df6971b4bc..2517c6a5df11 100644 --- a/system/Cache/Handlers/FileHandler.php +++ b/system/Cache/Handlers/FileHandler.php @@ -241,7 +241,6 @@ protected function getItem(string $filename) return false; } - // @phpstan-ignore-next-line if ($data['ttl'] > 0 && time() > $data['time'] + $data['ttl']) { // If the file is still there then try to remove it if (is_file($this->path . $filename)) { diff --git a/system/Cache/Handlers/MemcachedHandler.php b/system/Cache/Handlers/MemcachedHandler.php index 93c8cc59e0b5..f240a5d08de2 100644 --- a/system/Cache/Handlers/MemcachedHandler.php +++ b/system/Cache/Handlers/MemcachedHandler.php @@ -146,7 +146,7 @@ public function get(string $key) } } - return is_array($data) ? $data[0] : $data; // @phpstan-ignore-line + return is_array($data) ? $data[0] : $data; } /** @@ -172,7 +172,6 @@ public function save(string $key, $value, int $ttl = 60) return $this->memcached->set($key, $value, 0, $ttl); } - // @phpstan-ignore-next-line return false; } @@ -205,7 +204,6 @@ public function increment(string $key, int $offset = 1) $key = static::validateKey($key, $this->prefix); - // @phpstan-ignore-next-line return $this->memcached->increment($key, $offset, $offset, 60); } @@ -221,7 +219,7 @@ public function decrement(string $key, int $offset = 1) $key = static::validateKey($key, $this->prefix); // FIXME: third parameter isn't other handler actions. - // @phpstan-ignore-next-line + return $this->memcached->decrement($key, $offset, $offset, 60); } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index a8ebeef1b5cf..41e775dbf58d 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -537,7 +537,6 @@ protected function getRequestObject() return; } - // @phpstan-ignore-next-line if (is_cli() && ENVIRONMENT !== 'testing') { // @codeCoverageIgnoreStart $this->request = Services::clirequest($this->config); @@ -721,7 +720,7 @@ protected function tryToRouteIt(?RouteCollectionInterface $routes = null) // If a {locale} segment was matched in the final route, // then we need to set the correct locale on our Request. if ($this->router->hasLocale()) { - $this->request->setLocale($this->router->getLocale()); // @phpstan-ignore-line + $this->request->setLocale($this->router->getLocale()); } $this->benchmark->stop('routing'); @@ -816,7 +815,7 @@ protected function createController() protected function runController($class) { // If this is a console request then use the input segments as parameters - $params = defined('SPARKED') ? $this->request->getSegments() : $this->router->params(); // @phpstan-ignore-line + $params = defined('SPARKED') ? $this->request->getSegments() : $this->router->params(); if (method_exists($class, '_remap')) { $output = $class->_remap($this->method, ...$params); @@ -969,7 +968,7 @@ public function spoofRequestMethod() return; } - $method = $this->request->getPost('_method'); // @phpstan-ignore-line + $method = $this->request->getPost('_method'); if (empty($method)) { return; diff --git a/system/Common.php b/system/Common.php index f531a82f7284..567135babe1f 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1153,7 +1153,6 @@ function class_uses_recursive($class) $results = []; - // @phpstan-ignore-next-line foreach (array_reverse(class_parents($class)) + [$class => $class] as $class) { $results += trait_uses_recursive($class); } diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index f2ceb5a0f907..5f678e5114d7 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -883,7 +883,6 @@ public function prepare(Closure $func, array $options = []) $this->pretend(false); if ($sql instanceof QueryInterface) { - // @phpstan-ignore-next-line $sql = $sql->getOriginalQuery(); } diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index 49a970f5bf11..5d223c7fc08b 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -154,7 +154,6 @@ public function getCustomResultObject(string $className) $this->customResultObject[$className][] = $row; } - // @phpstan-ignore-next-line return $this->customResultObject[$className]; } @@ -233,7 +232,6 @@ public function getResultObject(): array $this->resultObject[] = $row; } - // @phpstan-ignore-next-line return $this->resultObject; } diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index d39587821036..57b4c78fd749 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -117,7 +117,6 @@ public function getVersion(): string return $this->dataCache['version']; } - // @phpstan-ignore-next-line if (! $this->connID || ($pgVersion = pg_version($this->connID)) === false) { $this->initialize(); } diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 6ad8e5dc939f..6afc04c51578 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -27,7 +27,7 @@ class Result extends BaseResult */ public function getFieldCount(): int { - return $this->resultID->numColumns(); // @phpstan-ignore-line + return $this->resultID->numColumns(); } /** @@ -38,7 +38,7 @@ public function getFieldNames(): array $fieldNames = []; for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { - $fieldNames[] = $this->resultID->columnName($i); // @phpstan-ignore-line + $fieldNames[] = $this->resultID->columnName($i); } return $fieldNames; @@ -58,18 +58,18 @@ public function getFieldData(): array ]; $retVal = []; - $this->resultID->fetchArray(SQLITE3_NUM); // @phpstan-ignore-line + $this->resultID->fetchArray(SQLITE3_NUM); for ($i = 0, $c = $this->getFieldCount(); $i < $c; $i++) { $retVal[$i] = new stdClass(); - $retVal[$i]->name = $this->resultID->columnName($i); // @phpstan-ignore-line - $type = $this->resultID->columnType($i); // @phpstan-ignore-line + $retVal[$i]->name = $this->resultID->columnName($i); + $type = $this->resultID->columnType($i); $retVal[$i]->type = $type; $retVal[$i]->type_name = $dataTypes[$type] ?? null; $retVal[$i]->max_length = null; $retVal[$i]->length = null; } - $this->resultID->reset(); // @phpstan-ignore-line + $this->resultID->reset(); return $retVal; } @@ -100,7 +100,7 @@ public function dataSeek(int $n = 0) throw new DatabaseException('SQLite3 doesn\'t support seeking to other offset.'); } - return $this->resultID->reset(); // @phpstan-ignore-line + return $this->resultID->reset(); } /** @@ -112,7 +112,7 @@ public function dataSeek(int $n = 0) */ protected function fetchAssoc() { - return $this->resultID->fetchArray(SQLITE3_ASSOC); // @phpstan-ignore-line + return $this->resultID->fetchArray(SQLITE3_ASSOC); } /** diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index c594bc4eac9f..d319c2f9746e 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -394,7 +394,7 @@ public static function highlightFile(string $file, int $lineNumber, int $lines = $start = max($lineNumber - (int) round($lines / 2), 0); // Get just the lines we need to display, while keeping line numbers... - $source = array_splice($source, $start, $lines, true); // @phpstan-ignore-line + $source = array_splice($source, $start, $lines, true); // Used to format the line number in the source $format = '% ' . strlen((string) ($start + $lines)) . 'd'; diff --git a/system/Debug/Toolbar/Collectors/Events.php b/system/Debug/Toolbar/Collectors/Events.php index b8c59f4566bb..a8a7e7aa4c35 100644 --- a/system/Debug/Toolbar/Collectors/Events.php +++ b/system/Debug/Toolbar/Collectors/Events.php @@ -74,7 +74,7 @@ protected function formatTimelineData(): array { $data = []; - $rows = $this->viewer->getPerformanceData(); // @phpstan-ignore-line + $rows = $this->viewer->getPerformanceData(); foreach ($rows as $info) { $data[] = [ diff --git a/system/Debug/Toolbar/Collectors/Views.php b/system/Debug/Toolbar/Collectors/Views.php index 75fea1d6cc6d..fae3385fffbc 100644 --- a/system/Debug/Toolbar/Collectors/Views.php +++ b/system/Debug/Toolbar/Collectors/Views.php @@ -89,7 +89,7 @@ protected function formatTimelineData(): array { $data = []; - $rows = $this->viewer->getPerformanceData(); // @phpstan-ignore-line + $rows = $this->viewer->getPerformanceData(); foreach ($rows as $info) { $data[] = [ @@ -122,7 +122,7 @@ protected function formatTimelineData(): array public function getVarData(): array { return [ - // @phpstan-ignore-next-line + 'View Data' => $this->viewer->getData(), ]; } @@ -132,7 +132,7 @@ public function getVarData(): array */ public function getBadgeValue(): int { - return count($this->viewer->getPerformanceData()); // @phpstan-ignore-line + return count($this->viewer->getPerformanceData()); } /** diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 9a66e632783b..e00ac44f97e0 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -358,7 +358,7 @@ public function send(string $method, string $url) // Do we need to delay this request? if ($this->delay > 0) { - sleep($this->delay); // @phpstan-ignore-line + sleep($this->delay); } $output = $this->sendRequest($curlOptions); diff --git a/system/HTTP/RequestTrait.php b/system/HTTP/RequestTrait.php index c0bb005099ab..327cddcb0e7f 100644 --- a/system/HTTP/RequestTrait.php +++ b/system/HTTP/RequestTrait.php @@ -273,7 +273,6 @@ public function fetchGlobal(string $method, $index = null, ?int $filter = null, $value = $this->globals[$method][$index] ?? null; } - // @phpstan-ignore-next-line if (is_array($value) && ( $filter !== FILTER_DEFAULT diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index c7bdbb135354..f9e9d34c277d 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -625,7 +625,7 @@ public function setAuthority(string $str) if (empty($parts['host']) && $parts['path'] !== '') { $parts['host'] = $parts['path']; - unset($parts['path']); // @phpstan-ignore-line + unset($parts['path']); } $this->applyParts($parts); diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php index 35e748978fbb..a9a2a938c36f 100644 --- a/system/Helpers/number_helper.php +++ b/system/Helpers/number_helper.php @@ -77,7 +77,7 @@ function number_to_amount($num, int $precision = 0, ?string $locale = null) { // Strip any formatting & ensure numeric input try { - $num = 0 + str_replace(',', '', $num); // @phpstan-ignore-line + $num = 0 + str_replace(',', '', $num); } catch (ErrorException $ee) { return false; } diff --git a/system/Helpers/text_helper.php b/system/Helpers/text_helper.php index 5f0738421908..4e7e5d855302 100755 --- a/system/Helpers/text_helper.php +++ b/system/Helpers/text_helper.php @@ -564,7 +564,6 @@ function random_string(string $type = 'alnum', int $len = 8): string break; } - // @phpstan-ignore-next-line return substr(str_shuffle(str_repeat($pool, ceil($len / strlen($pool)))), 0, $len); case 'md5': diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php index 8d089083eddd..42bcdc473619 100644 --- a/system/Helpers/url_helper.php +++ b/system/Helpers/url_helper.php @@ -352,7 +352,7 @@ function safe_mailto(string $email, string $title = '', $attributes = ''): strin $temp[] = $ordinal; - if (count($temp) === $count) { // @phpstan-ignore-line + if (count($temp) === $count) { $number = ($count === 3) ? (($temp[0] % 16) * 4096) + (($temp[1] % 64) * 64) + ($temp[2] % 64) : (($temp[0] % 32) * 64) + ($temp[1] % 64); $x[] = '|' . $number; $count = 1; diff --git a/system/Images/Handlers/ImageMagickHandler.php b/system/Images/Handlers/ImageMagickHandler.php index 5ec6a23cc4f7..37bd168ead02 100644 --- a/system/Images/Handlers/ImageMagickHandler.php +++ b/system/Images/Handlers/ImageMagickHandler.php @@ -384,10 +384,10 @@ protected function _text(string $text, array $options = []) break; } - $xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis; // @phpstan-ignore-line - $yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis; // @phpstan-ignore-line + $xAxis = $xAxis >= 0 ? '+' . $xAxis : $xAxis; + $yAxis = $yAxis >= 0 ? '+' . $yAxis : $yAxis; - $cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}"; // @phpstan-ignore-line + $cmd .= " -gravity {$gravity} -geometry {$xAxis}{$yAxis}"; } // Color diff --git a/system/Model.php b/system/Model.php index 418b3057eeb9..32fa82fcff64 100644 --- a/system/Model.php +++ b/system/Model.php @@ -158,7 +158,7 @@ protected function doFind(bool $singleton, $id = null) */ protected function doFindColumn(string $columnName) { - return $this->select($columnName)->asArray()->find(); // @phpstan-ignore-line + return $this->select($columnName)->asArray()->find(); } /** diff --git a/system/Router/Router.php b/system/Router/Router.php index 621c54a5e9dd..5c4b3f0255d7 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -124,7 +124,6 @@ public function __construct(RouteCollectionInterface $routes, ?Request $request $this->controller = $this->collection->getDefaultController(); $this->method = $this->collection->getDefaultMethod(); - // @phpstan-ignore-next-line $this->collection->setHTTPVerb($request->getMethod() ?? strtolower($_SERVER['REQUEST_METHOD'])); } diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index f0164d2dfc3c..dfaa472029fd 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -69,7 +69,6 @@ public function __construct(AppConfig $config, string $ipAddress) throw SessionException::forMissingDatabaseTable(); } - // @phpstan-ignore-next-line $this->DBGroup = $config->sessionDBGroup ?? config(Database::class)->defaultGroup; $this->db = Database::connect($this->DBGroup); diff --git a/system/Session/Handlers/RedisHandler.php b/system/Session/Handlers/RedisHandler.php index ce6e7bde5180..93a601eade70 100644 --- a/system/Session/Handlers/RedisHandler.php +++ b/system/Session/Handlers/RedisHandler.php @@ -206,7 +206,6 @@ public function close(): bool try { $pingReply = $this->redis->ping(); - // @phpstan-ignore-next-line if (($pingReply === true) || ($pingReply === '+PONG')) { if (isset($this->lockKey)) { $this->redis->del($this->lockKey); diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 50a28e13d2da..e2c6eab609bb 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -231,7 +231,7 @@ protected function setUp(): void { parent::setUp(); - if (! $this->app) { // @phpstan-ignore-line + if (! $this->app) { $this->app = $this->createApplication(); } diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index 0fb013cb1820..d4369765f0ee 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -510,12 +510,12 @@ protected function createMock(?int $count = null) $fields = []; if (! empty($this->model->useTimestamps)) { - $fields[$this->model->createdField] = $datetime; // @phpstan-ignore-line - $fields[$this->model->updatedField] = $datetime; // @phpstan-ignore-line + $fields[$this->model->createdField] = $datetime; + $fields[$this->model->updatedField] = $datetime; } if (! empty($this->model->useSoftDeletes)) { - $fields[$this->model->deletedField] = null; // @phpstan-ignore-line + $fields[$this->model->deletedField] = null; } // Iterate over new entities and add the necessary fields diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index 87423271cd63..d1a75edb8f62 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -349,7 +349,7 @@ protected function populateGlobals(string $method, Request $request, ?array $par // otherwise set it from the URL. $get = ! empty($params) && $method === 'get' ? $params - : $this->getPrivateProperty($request->uri, 'query'); // @phpstan-ignore-line + : $this->getPrivateProperty($request->uri, 'query'); $request->setGlobal('get', $get); if ($method !== 'get') { diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index b44ff8c65491..afb93376b9a0 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -344,7 +344,7 @@ protected function populateGlobals(string $method, Request $request, ?array $par // otherwise set it from the URL. $get = ! empty($params) && $method === 'get' ? $params - : $this->getPrivateProperty($request->uri, 'query'); // @phpstan-ignore-line + : $this->getPrivateProperty($request->uri, 'query'); $request->setGlobal('get', $get); if ($method !== 'get') { diff --git a/system/Test/Mock/MockConnection.php b/system/Test/Mock/MockConnection.php index 78bd405babad..c9d03e7638d6 100644 --- a/system/Test/Mock/MockConnection.php +++ b/system/Test/Mock/MockConnection.php @@ -166,7 +166,7 @@ public function error(): array */ public function insertID(): int { - return $this->connID->insert_id; // @phpstan-ignore-line + return $this->connID->insert_id; } /** From a0b8140b4f5b5ebe1cb7cb1b7d4b751e97fb174e Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Mon, 13 Dec 2021 20:23:40 +0800 Subject: [PATCH 0981/2325] Test phpstan on PHP 8.0+ --- .github/workflows/test-phpstan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index 0e59e3bf4e3a..eceb97524605 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -29,7 +29,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: ['7.4', '8.0'] + php-versions: ['8.0', '8.1'] steps: - name: Checkout uses: actions/checkout@v2 From 01ca5857fb3b64982670b1f808dad6129476cf0c Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Dec 2021 10:29:38 +0900 Subject: [PATCH 0982/2325] docs: use BaseController instead of Controller --- user_guide_src/source/tutorial/news_section.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index 42bda88c5d06..396c74255962 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -142,9 +142,8 @@ a new ``News`` controller is defined. Create the new controller at namespace App\Controllers; use App\Models\NewsModel; - use CodeIgniter\Controller; - class News extends Controller + class News extends BaseController { public function index() { From 2f8d694d77717e5166a100b6cbda8a47660bb779 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Dec 2021 13:13:41 +0900 Subject: [PATCH 0983/2325] docs: improve text decoration --- user_guide_src/source/incoming/content_negotiation.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/content_negotiation.rst b/user_guide_src/source/incoming/content_negotiation.rst index 11940b82092a..8122a4a910b5 100644 --- a/user_guide_src/source/incoming/content_negotiation.rst +++ b/user_guide_src/source/incoming/content_negotiation.rst @@ -60,7 +60,7 @@ be able to return data as raw HTML, JSON, or XML. This list should be provided i $format = $negotiate->media($supported); In this case, both the client and the server can agree on formatting the data as JSON so 'json' is returned from -the negotiate method. By default, if no match is found, the first element in the $supported array would be returned. +the negotiate method. By default, if no match is found, the first element in the ``$supported`` array would be returned. In some cases, though, you might need to enforce the format to be a strict match. If you pass ``true`` as the final value, it will return an empty string if no match is found:: @@ -92,7 +92,7 @@ and German you would do something like:: $lang = $negotiate->language($supported); In this example, 'en' would be returned as the current language. If no match is found, it will return the first element -in the $supported array, so that should always be the preferred language. +in the ``$supported`` array, so that should always be the preferred language. Encoding ======== From 5956d9821fd44b4c5ee882141b1399e273f8c710 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Dec 2021 15:02:53 +0000 Subject: [PATCH 0984/2325] chore(deps-dev): update rector/rector requirement from 0.12.7 to 0.12.8 Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.12.7...0.12.8) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index ab1c999190bf..38ddfd6ef3c7 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.7" + "rector/rector": "0.12.8" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From eaab880886eff83b87734087b258754fe3d73ce5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Dec 2021 10:50:31 +0900 Subject: [PATCH 0985/2325] docs: fix view() $options explanation --- user_guide_src/source/general/common_functions.rst | 9 +++++---- user_guide_src/source/testing/debugging.rst | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index c1cdb038984a..f4b61548f4da 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -179,11 +179,12 @@ Service Accessors a convenience method that can be used in Controllers, libraries, and routed closures. - Currently, only one option is available for use within the `$options` array, `saveData` which specifies - that data will persistent between multiple calls to `view()` within the same request. By default, the - data for that view is forgotten after displaying that single view file. + Currently, only two options are available for use within the ``$options`` array: - The $option array is provided primarily to facilitate third-party integrations with + - ``saveData`` specifies that data will persistent between multiple calls to ``view()`` within the same request. If you do not want the data to be persisted, specify false. + - ``debug`` can be set to false to disable the addition of debug code for :ref:`Debug Toolbar `. + + The ``$option`` array is provided primarily to facilitate third-party integrations with libraries like Twig. Example:: diff --git a/user_guide_src/source/testing/debugging.rst b/user_guide_src/source/testing/debugging.rst index 3e456d118793..22c77141e116 100644 --- a/user_guide_src/source/testing/debugging.rst +++ b/user_guide_src/source/testing/debugging.rst @@ -45,6 +45,8 @@ This provides a backtrace to the current execution point, with Kint's own unique For more information, see `Kint's page `_. +.. _the-debug-toolbar: + ================= The Debug Toolbar ================= From 36d9c137e95300636da4232012746d40d1a06f05 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Dec 2021 11:03:56 +0900 Subject: [PATCH 0986/2325] docs: add sample code --- user_guide_src/source/incoming/routing.rst | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 97c2b1aa1fdd..954fc8ca24b1 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -259,7 +259,13 @@ This would handle the URL at ``admin/users/list``. Note that options passed to t At some point, you may want to group routes for the purpose of applying filters or other route config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the -given route config options. +given route config options:: + + $routes->group('', ['namespace' => 'Myth\Auth\Controllers'], function ($routes) { + $routes->get('login', 'AuthController::login', ['as' => 'login']); + $routes->post('login', 'AuthController::attemptLogin'); + $routes->get('logout', 'AuthController::logout'); + }); Environment Restrictions ======================== From c890ef7bc56b79e416a52b52a7d44455c44d2257 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Dec 2021 11:23:52 +0900 Subject: [PATCH 0987/2325] docs: fix sample code Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 954fc8ca24b1..9d4ab0d88998 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -261,7 +261,7 @@ config options like namespace, subdomain, etc. Without necessarily needing to ad an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the given route config options:: - $routes->group('', ['namespace' => 'Myth\Auth\Controllers'], function ($routes) { + $routes->group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { $routes->get('login', 'AuthController::login', ['as' => 'login']); $routes->post('login', 'AuthController::attemptLogin'); $routes->get('logout', 'AuthController::logout'); From f7c42268f6a99ab4cb3c503b2b30389ed371fe4a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Dec 2021 09:29:43 +0900 Subject: [PATCH 0988/2325] fix: use $this->time() instead of time() For testing, we need to use testTime in all places. --- system/Throttle/Throttler.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/system/Throttle/Throttler.php b/system/Throttle/Throttler.php index 0bdf8a95522d..5154f386439b 100644 --- a/system/Throttle/Throttler.php +++ b/system/Throttle/Throttler.php @@ -100,7 +100,7 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): // If it hasn't been created, then we'll set it to the maximum // capacity - 1, and save it to the cache. $this->cache->save($tokenName, $capacity - $cost, $seconds); - $this->cache->save($tokenName . 'Time', time(), $seconds); + $this->cache->save($tokenName . 'Time', $this->time(), $seconds); return true; } @@ -129,7 +129,7 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): // we need to decrement the number of available tokens. if ($tokens >= 1) { $this->cache->save($tokenName, $tokens - $cost, $seconds); - $this->cache->save($tokenName . 'Time', time(), $seconds); + $this->cache->save($tokenName . 'Time', $this->time(), $seconds); return true; } @@ -164,6 +164,8 @@ public function setTestTime(int $time) /** * Return the test time, defaulting to current. + * + * @TODO should be private */ public function time(): int { From f8c22452d3ebce55460d0add9b82481b827671c3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 14 Dec 2021 09:31:40 +0900 Subject: [PATCH 0989/2325] test: fix time dependent test Fixes #5444 --- tests/system/Throttle/ThrottleTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index a7905a2f59bf..498cbf0673d5 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -127,7 +127,10 @@ public function testOverload() public function testFlooding() { + $time = 1639441295; + $throttler = new Throttler($this->cache); + $throttler->setTestTime($time); $rate = 60; // allow 1 per second after the bucket is emptied $cost = 1; @@ -141,7 +144,7 @@ public function testFlooding() $this->assertFalse($throttler->check('127.0.0.1', $rate, MINUTE, $cost)); $this->assertSame(0, $this->cache->get('throttler_127.0.0.1')); - $throttler = $throttler->setTestTime(strtotime('+10 seconds')); + $throttler = $throttler->setTestTime($time + 10); $this->assertTrue($throttler->check('127.0.0.1', $rate, MINUTE, 0)); $this->assertSame(10.0, round($this->cache->get('throttler_127.0.0.1'))); From 0ca3ef9aa722799b8120abf3edc2b2b5ddc8bdc0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Dec 2021 10:39:11 +0900 Subject: [PATCH 0990/2325] docs: add InvalidChars filter explanation --- user_guide_src/source/incoming/filters.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 096d1020f77f..cb62defe02a3 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -204,6 +204,14 @@ The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``InvalidChar .. note:: The filters are executed in the order defined in the config file. However, if enabled, ``DebugToolbar`` is always executed last because it should be able to capture everything that happens in the other filters. +InvalidChars +============= + +This filter checks if user input data (``$_GET``, ``$_POST``, ``$_COOKIE``, ``php://input``) do not contain the following characters: + +- invalid UTF-8 characters +- control characters except line break and tab code + SecureHeaders ============= From 1ebc173f9519875518ac47b750e8f33ca6337c0d Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Dec 2021 10:39:45 +0900 Subject: [PATCH 0991/2325] docs: add links to other pages --- user_guide_src/source/incoming/filters.rst | 2 +- user_guide_src/source/libraries/security.rst | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index cb62defe02a3..b8b16bb1c9ce 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -200,7 +200,7 @@ In this example, the array ``['dual', 'noreturn']`` will be passed in ``$argumen Provided Filters **************** -The filters bundled with CodeIgniter4 are: ``Honeypot``, ``CSRF``, ``InvalidChars``, ``SecureHeaders``, and ``DebugToolbar``. +The filters bundled with CodeIgniter4 are: :doc:`Honeypot <../libraries/honeypot>`, :ref:`CSRF `, ``InvalidChars``, ``SecureHeaders``, and :ref:`DebugToolbar `. .. note:: The filters are executed in the order defined in the config file. However, if enabled, ``DebugToolbar`` is always executed last because it should be able to capture everything that happens in the other filters. diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index b0a11af06b6d..00c6173ee4f3 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -19,6 +19,8 @@ If you find a case where you do need direct access though, you may load it throu $security = \Config\Services::security(); +.. _cross-site-request-forgery: + ********************************* Cross-site request forgery (CSRF) ********************************* From 0924a0c965dc760c89cc367ad7da0a9d1498bc1f Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Dec 2021 11:26:09 +0900 Subject: [PATCH 0992/2325] docs: change TOC depth 2 or more --- user_guide_src/source/changelogs/v4.1.5.rst | 2 +- user_guide_src/source/dbmgmt/migration.rst | 3 ++- user_guide_src/source/helpers/array_helper.rst | 1 + user_guide_src/source/helpers/cookie_helper.rst | 3 ++- user_guide_src/source/helpers/date_helper.rst | 3 ++- user_guide_src/source/helpers/filesystem_helper.rst | 3 ++- user_guide_src/source/helpers/form_helper.rst | 3 ++- user_guide_src/source/helpers/html_helper.rst | 1 + user_guide_src/source/helpers/inflector_helper.rst | 3 ++- user_guide_src/source/helpers/number_helper.rst | 3 ++- user_guide_src/source/helpers/security_helper.rst | 3 ++- user_guide_src/source/helpers/test_helper.rst | 3 ++- user_guide_src/source/helpers/text_helper.rst | 3 ++- user_guide_src/source/helpers/url_helper.rst | 3 ++- user_guide_src/source/helpers/xml_helper.rst | 3 ++- user_guide_src/source/installation/installing_composer.rst | 2 +- user_guide_src/source/installation/installing_manual.rst | 4 ++++ user_guide_src/source/installation/running.rst | 2 +- user_guide_src/source/installation/upgrade_415.rst | 2 +- user_guide_src/source/installation/upgrade_configuration.rst | 2 +- user_guide_src/source/installation/upgrade_controllers.rst | 2 +- user_guide_src/source/installation/upgrade_database.rst | 2 +- user_guide_src/source/installation/upgrade_emails.rst | 2 +- user_guide_src/source/installation/upgrade_encryption.rst | 2 +- user_guide_src/source/installation/upgrade_file_upload.rst | 2 +- user_guide_src/source/installation/upgrade_html_tables.rst | 2 +- user_guide_src/source/installation/upgrade_localization.rst | 2 +- user_guide_src/source/installation/upgrade_migrations.rst | 2 +- user_guide_src/source/installation/upgrade_models.rst | 2 +- user_guide_src/source/installation/upgrade_pagination.rst | 2 +- user_guide_src/source/installation/upgrade_responses.rst | 2 +- user_guide_src/source/installation/upgrade_routing.rst | 2 +- user_guide_src/source/installation/upgrade_security.rst | 2 +- user_guide_src/source/installation/upgrade_sessions.rst | 2 +- user_guide_src/source/installation/upgrade_validations.rst | 2 +- user_guide_src/source/installation/upgrade_view_parser.rst | 2 +- user_guide_src/source/installation/upgrade_views.rst | 2 +- user_guide_src/source/libraries/encryption.rst | 3 ++- user_guide_src/source/libraries/time.rst | 2 +- user_guide_src/source/outgoing/table.rst | 3 ++- user_guide_src/source/testing/mocking.rst | 2 +- 41 files changed, 58 insertions(+), 38 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst index 67589933074f..1ef2ec8775a0 100644 --- a/user_guide_src/source/changelogs/v4.1.5.rst +++ b/user_guide_src/source/changelogs/v4.1.5.rst @@ -7,7 +7,7 @@ Release Date: November 8, 2021 .. contents:: :local: - :depth: 1 + :depth: 2 BREAKING ======== diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index e7bd41f34bc0..d88d3e226118 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -15,7 +15,8 @@ state. You can also use ``$migration->setNamespace(null)->latest()`` to include migrations from all namespaces. .. contents:: - :local: + :local: + :depth: 2 ******************** Migration file names diff --git a/user_guide_src/source/helpers/array_helper.rst b/user_guide_src/source/helpers/array_helper.rst index 2457790e4ad6..21e798a1ee2e 100644 --- a/user_guide_src/source/helpers/array_helper.rst +++ b/user_guide_src/source/helpers/array_helper.rst @@ -7,6 +7,7 @@ any of the existing functionality that PHP provides - unless it is to vastly sim .. contents:: :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index c7df02f6461f..597adaa66c9a 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -6,7 +6,8 @@ The Cookie Helper file contains functions that assist in working with cookies. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/date_helper.rst b/user_guide_src/source/helpers/date_helper.rst index 876a09bfbae6..cc97b46a9dbf 100644 --- a/user_guide_src/source/helpers/date_helper.rst +++ b/user_guide_src/source/helpers/date_helper.rst @@ -6,7 +6,8 @@ The Date Helper file contains functions that assist in working with dates. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 2d884aeee08d..c7a7e8ad22a2 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -6,7 +6,8 @@ The Directory Helper file contains functions that assist in working with directories. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index e8788de0a499..490a4cd3ccc1 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -6,7 +6,8 @@ The Form Helper file contains functions that assist in working with forms. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst index 978f0ea67f04..b73b3222f711 100755 --- a/user_guide_src/source/helpers/html_helper.rst +++ b/user_guide_src/source/helpers/html_helper.rst @@ -7,6 +7,7 @@ HTML. .. contents:: :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/inflector_helper.rst b/user_guide_src/source/helpers/inflector_helper.rst index 31e603b2941d..924ee5b75559 100755 --- a/user_guide_src/source/helpers/inflector_helper.rst +++ b/user_guide_src/source/helpers/inflector_helper.rst @@ -6,7 +6,8 @@ The Inflector Helper file contains functions that permit you to change **English** words to plural, singular, camel case, etc. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/number_helper.rst b/user_guide_src/source/helpers/number_helper.rst index be5be2a8018c..c085a59f8d12 100644 --- a/user_guide_src/source/helpers/number_helper.rst +++ b/user_guide_src/source/helpers/number_helper.rst @@ -6,7 +6,8 @@ The Number Helper file contains functions that help you work with numeric data in a locale-aware manner. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst index 2c3812a49def..b5ada61fe254 100644 --- a/user_guide_src/source/helpers/security_helper.rst +++ b/user_guide_src/source/helpers/security_helper.rst @@ -5,7 +5,8 @@ Security Helper The Security Helper file contains security related functions. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/test_helper.rst b/user_guide_src/source/helpers/test_helper.rst index 4d98f005fb0a..f6a59d6e6c11 100644 --- a/user_guide_src/source/helpers/test_helper.rst +++ b/user_guide_src/source/helpers/test_helper.rst @@ -5,7 +5,8 @@ Test Helper The Test Helper file contains functions that assist in testing your project. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/text_helper.rst b/user_guide_src/source/helpers/text_helper.rst index d83fb54835ae..0c842677a001 100755 --- a/user_guide_src/source/helpers/text_helper.rst +++ b/user_guide_src/source/helpers/text_helper.rst @@ -5,7 +5,8 @@ Text Helper The Text Helper file contains functions that assist in working with Text. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst index 780becac13d8..b3f5daf5e439 100644 --- a/user_guide_src/source/helpers/url_helper.rst +++ b/user_guide_src/source/helpers/url_helper.rst @@ -5,7 +5,8 @@ URL Helper The URL Helper file contains functions that assist in working with URLs. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/helpers/xml_helper.rst b/user_guide_src/source/helpers/xml_helper.rst index ebccaca79f91..ac72f26891f9 100644 --- a/user_guide_src/source/helpers/xml_helper.rst +++ b/user_guide_src/source/helpers/xml_helper.rst @@ -6,7 +6,8 @@ The XML Helper file contains functions that assist in working with XML data. .. contents:: - :local: + :local: + :depth: 2 Loading this Helper =================== diff --git a/user_guide_src/source/installation/installing_composer.rst b/user_guide_src/source/installation/installing_composer.rst index 41b288c02037..ac1be8c5e12c 100644 --- a/user_guide_src/source/installation/installing_composer.rst +++ b/user_guide_src/source/installation/installing_composer.rst @@ -3,7 +3,7 @@ Composer Installation .. contents:: :local: - :depth: 1 + :depth: 2 Composer can be used in several ways to install CodeIgniter4 on your system. diff --git a/user_guide_src/source/installation/installing_manual.rst b/user_guide_src/source/installation/installing_manual.rst index c64f7dc5b212..daf7ea26c55f 100644 --- a/user_guide_src/source/installation/installing_manual.rst +++ b/user_guide_src/source/installation/installing_manual.rst @@ -1,6 +1,10 @@ Manual Installation ################### +.. contents:: + :local: + :depth: 2 + The `CodeIgniter 4 framework `_ repository holds the released versions of the framework. It is intended for developers who do not wish to use Composer. diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst index f16bb7636672..8b2d0668a867 100644 --- a/user_guide_src/source/installation/running.rst +++ b/user_guide_src/source/installation/running.rst @@ -3,7 +3,7 @@ Running Your App .. contents:: :local: - :depth: 1 + :depth: 2 A CodeIgniter 4 app can be run in a number of different ways: hosted on a web server, using virtualization, or using CodeIgniter’s command line tool for testing. diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst index a029724b3bfb..d995a58d8ffd 100644 --- a/user_guide_src/source/installation/upgrade_415.rst +++ b/user_guide_src/source/installation/upgrade_415.rst @@ -4,7 +4,7 @@ Upgrading from 4.1.4 to 4.1.5 .. contents:: :local: - :depth: 1 + :depth: 2 Breaking Changes ================ diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index cad74dc1e713..4592f2d1e001 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -3,7 +3,7 @@ Upgrade Configuration .. contents:: :local: - :depth: 1 + :depth: 2 Documentations ============== diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index 003cad92a295..44999b0dc6ec 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -3,7 +3,7 @@ Upgrade Controllers .. contents:: :local: - :depth: 1 + :depth: 2 Documentations ============== diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index f2f4ee65440f..666a51e97716 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -3,7 +3,7 @@ Upgrade Database .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index d64a6bb2afea..0ce8b0792bc1 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -3,7 +3,7 @@ Upgrade Emails .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index 003abc7ae218..04c857ba8f4e 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -3,7 +3,7 @@ Upgrade Encryption .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index 6161e999f45e..6ad3c533a03a 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -3,7 +3,7 @@ Upgrade Working with Uploaded Files .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst index 9fc98e1fd838..715d80660876 100644 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -3,7 +3,7 @@ Upgrade HTML Tables .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index ca919c7cdb1b..cde7f81c0e31 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -3,7 +3,7 @@ Upgrade Localization .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index ce1e92664d6d..90e1999e29f6 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -3,7 +3,7 @@ Upgrade Migrations .. contents:: :local: - :depth: 1 + :depth: 2 Documentations ============== diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst index 12e0680e7320..b76bc10d67d5 100644 --- a/user_guide_src/source/installation/upgrade_models.rst +++ b/user_guide_src/source/installation/upgrade_models.rst @@ -3,7 +3,7 @@ Upgrade Models .. contents:: :local: - :depth: 1 + :depth: 2 Documentations ============== diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index 23c8564d1390..f952da0c5074 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -3,7 +3,7 @@ Upgrade Pagination .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index aafcf9731faa..2f87f9ec50ef 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -3,7 +3,7 @@ Upgrade HTTP Responses .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 5ea14f16e74d..1d2540b2ded1 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -3,7 +3,7 @@ Upgrade Routing .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 12990ba63347..18b61209ec1b 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -3,7 +3,7 @@ Upgrade Security .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index 23688000ff96..e935b08cfd16 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -3,7 +3,7 @@ Upgrade Sessions .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 083479d210db..825b8be9ccdf 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -3,7 +3,7 @@ Upgrade Validations .. contents:: :local: - :depth: 1 + :depth: 2 Documentations of Library diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index 96f821b81922..a970a5ab5e88 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -3,7 +3,7 @@ Upgrade View Parser .. contents:: :local: - :depth: 1 + :depth: 2 Documentations diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index 38da7443ea53..903ac6838be1 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -3,7 +3,7 @@ Upgrade Views .. contents:: :local: - :depth: 1 + :depth: 2 Documentations ============== diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 2c45e7ad79d9..1a8bf834d94c 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -31,7 +31,8 @@ A more comprehensive package like `Halite ` been deprecated as of PHP 7.2. .. contents:: - :local: + :local: + :depth: 2 .. _usage: diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 57ee4d4572d6..6e55cf87aed3 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -11,7 +11,7 @@ is the ``Time`` class and lives in the ``CodeIgniter\I18n`` namespace. .. contents:: :local: - :depth: 1 + :depth: 2 ============= Instantiating diff --git a/user_guide_src/source/outgoing/table.rst b/user_guide_src/source/outgoing/table.rst index 0c8810fdb277..01b7dabe5cef 100644 --- a/user_guide_src/source/outgoing/table.rst +++ b/user_guide_src/source/outgoing/table.rst @@ -6,7 +6,8 @@ The Table Class provides methods that enable you to auto-generate HTML tables from arrays or database result sets. .. contents:: - :local: + :local: + :depth: 2 ********************* Using the Table Class diff --git a/user_guide_src/source/testing/mocking.rst b/user_guide_src/source/testing/mocking.rst index 03b464cf6570..758f6c2f3a50 100644 --- a/user_guide_src/source/testing/mocking.rst +++ b/user_guide_src/source/testing/mocking.rst @@ -9,7 +9,7 @@ emails were sent correctly, etc. .. contents:: :local: - :depth: 1 + :depth: 2 Cache ===== From e1085c81c44ce5c094d3d279b6472d6a49088070 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Dec 2021 13:34:53 +0900 Subject: [PATCH 0993/2325] docs: fix $request->getMethod() return values Now the method name is lower case by default. --- user_guide_src/source/concepts/http.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/http.rst b/user_guide_src/source/concepts/http.rst index 8ae030fc1811..bc9bb25fe2b9 100644 --- a/user_guide_src/source/concepts/http.rst +++ b/user_guide_src/source/concepts/http.rst @@ -95,7 +95,7 @@ is an object-oriented representation of the HTTP request. It provides everything $request->getHeader('host'); $request->getHeader('Content-Type'); - $request->getMethod(); // GET, POST, PUT, etc + $request->getMethod(); // get, post, put, etc The request class does a lot of work in the background for you, that you never need to worry about. The `isAJAX()` and `isSecure()` methods check several different methods to determine the correct answer. From 9a9ebccfe141e7cc289738d0bbe3932bbbdd1cfa Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Dec 2021 13:38:32 +0900 Subject: [PATCH 0994/2325] docs: decorate method names with '``' --- user_guide_src/source/concepts/http.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/http.rst b/user_guide_src/source/concepts/http.rst index bc9bb25fe2b9..d5c82f2a1492 100644 --- a/user_guide_src/source/concepts/http.rst +++ b/user_guide_src/source/concepts/http.rst @@ -98,7 +98,7 @@ is an object-oriented representation of the HTTP request. It provides everything $request->getMethod(); // get, post, put, etc The request class does a lot of work in the background for you, that you never need to worry about. -The `isAJAX()` and `isSecure()` methods check several different methods to determine the correct answer. +The ``isAJAX()`` and ``isSecure()`` methods check several different methods to determine the correct answer. .. note:: The ``isAJAX()`` method depends on the ``X-Requested-With`` header, which in some cases is not sent by default in XHR requests via JavaScript (i.e., fetch). See the :doc:`AJAX Requests ` section on how to avoid this problem. From 757a9d630ef7da7fc55d23454f762fe2bc4f1601 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Dec 2021 16:33:54 +0900 Subject: [PATCH 0995/2325] refactor: update deprecated method --- system/Entity/Cast/DatetimeCast.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Entity/Cast/DatetimeCast.php b/system/Entity/Cast/DatetimeCast.php index 4655b4e374e3..99f425a410be 100644 --- a/system/Entity/Cast/DatetimeCast.php +++ b/system/Entity/Cast/DatetimeCast.php @@ -32,7 +32,7 @@ public static function get($value, array $params = []) } if ($value instanceof DateTime) { - return Time::instance($value); + return Time::createFromInstance($value); } if (is_numeric($value)) { From 986d46f12d332d39861cf1a4c2fe67a37420ac50 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Thu, 16 Dec 2021 22:51:51 -0600 Subject: [PATCH 0996/2325] Add final deploy workflow --- .github/workflows/deploy-userguide.yml | 53 ++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 .github/workflows/deploy-userguide.yml diff --git a/.github/workflows/deploy-userguide.yml b/.github/workflows/deploy-userguide.yml new file mode 100644 index 000000000000..0fc7900197a8 --- /dev/null +++ b/.github/workflows/deploy-userguide.yml @@ -0,0 +1,53 @@ +# When changes are pushed to the master branch, +# build the current version of the User Guide +# with Sphinx and deploy it to the production server. +# +# @todo Consolidate checkouts +name: Deploy User Guide + +on: + push: + branches: + - 'master' + paths: + - 'user_guide_src/**' + +jobs: + build: + name: Deploy to production + if: (github.repository == 'codeigniter4/CodeIgniter4') + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + # Build the latest User Guide + - name: Build with Sphinx + uses: ammaraskar/sphinx-action@0.4 + with: + docs-folder: user_guide_src/ + + # Create an artifact of the html output + - name: Upload artifact + uses: actions/upload-artifact@v2 + with: + name: HTML Documentation + path: user_guide_src/build/html/ + + - name: Install SSH key + uses: shimataro/ssh-key-action@v2 + with: + key: ${{ secrets.DEPLOY_KEY }} + name: id_rsa + known_hosts: ${{ secrets.SSH_KNOWN_HOSTS }} + + - name: Deploy to Webserver + uses: yeshan333/rsync-deploy-action@main + id: rsync-deploy-action + with: + ssh_login_username: ${{ secrets.DEPLOY_USER }} + remote_server_ip: ${{ secrets.DEPLOY_SSH_BOX }} + ssh_port: ${{ secrets.DEPLOY_PORT }} + ssh_private_key: ${{ secrets.DEPLOY_KEY }} + source_path: "./user_guide_src/build/html/*" + destination_path: "/home/public_html/userguides/v4/" From 091b324102bc28b179514a7795128ad122f968a3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Dec 2021 15:13:28 +0900 Subject: [PATCH 0997/2325] docs: remove environment-specific configuration files There is no such a thing. --- user_guide_src/source/general/environments.rst | 8 -------- 1 file changed, 8 deletions(-) diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst index 057dd8e57dea..ca9c6efc1042 100644 --- a/user_guide_src/source/general/environments.rst +++ b/user_guide_src/source/general/environments.rst @@ -103,11 +103,3 @@ Conversely, setting the constant to 'production' will disable all error output. Disabling error reporting in production is a :doc:`good security practice `. -Configuration Files -------------------- - -Optionally, you can have CodeIgniter load environment-specific -configuration files. This may be useful for managing things like -differing API keys across multiple environments. This is described in -more detail in the Handling Different Environments section of the -:doc:`Working with Configuration Files ` documentation. From b3ea655665e101d068c0df6edcf7309176397387 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Dec 2021 15:22:14 +0900 Subject: [PATCH 0998/2325] docs: change text decoration --- user_guide_src/source/general/environments.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst index ca9c6efc1042..6abd709a00a9 100644 --- a/user_guide_src/source/general/environments.rst +++ b/user_guide_src/source/general/environments.rst @@ -97,7 +97,7 @@ is affected. Error Reporting --------------- -Setting the ENVIRONMENT constant to a value of 'development' will cause +Setting the ENVIRONMENT constant to a value of ``development`` will cause all PHP errors to be rendered to the browser when they occur. Conversely, setting the constant to 'production' will disable all error output. Disabling error reporting in production is a From a81c37d95aea6c4e15785e86d4067f36146ef1f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Dec 2021 15:26:49 +0900 Subject: [PATCH 0999/2325] docs: fix JSONFormatter namespace --- user_guide_src/source/outgoing/api_responses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index 99e89783f7d5..dd9f9593278f 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -113,7 +113,7 @@ support both JSON and XML:: ]; So, if your request asks for JSON formatted data in an **Accept** header, the data array you pass any of the -``respond*`` or ``fail*`` methods will be formatted by the **CodeIgniter\\API\\JSONFormatter** class. The resulting +``respond*`` or ``fail*`` methods will be formatted by the ``CodeIgniter\Format\JSONFormatter`` class. The resulting JSON data will be sent back to the client. Class Reference From d8b2cdc0307a67740851bdf78e5766bec5344b22 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Dec 2021 15:27:21 +0900 Subject: [PATCH 1000/2325] docs: change text decoration --- user_guide_src/source/outgoing/api_responses.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index dd9f9593278f..92eaa066f36f 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -104,7 +104,7 @@ type of response to return. If no matches are found between what the client requ format in this array is what will be returned. Next, you need to define the class that is used to format the array of data. This must be a fully qualified class -name, and the class must implement **CodeIgniter\\Format\\FormatterInterface**. Formatters come out of the box that +name, and the class must implement ``CodeIgniter\Format\FormatterInterface``. Formatters come out of the box that support both JSON and XML:: public $formatters = [ @@ -240,7 +240,7 @@ Class Reference :param string $message: A custom "reason" message to return. :returns: The value of the Response object's send() method. - Unlike ``failUnauthorized``, this method should be used when the requested API endpoint is never allowed. + Unlike ``failUnauthorized()``, this method should be used when the requested API endpoint is never allowed. Unauthorized implies the client is encouraged to try again with different credentials. Forbidden means the client should not try again because it won't help. Status code is 403. From 714235bf39517376c47126d37c77d140a7750391 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 08:56:10 +0900 Subject: [PATCH 1001/2325] docs: change from note to warning, because it is a security matter --- user_guide_src/source/outgoing/view_parser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 8bf3db46bb83..80c2f37d5c73 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -356,7 +356,7 @@ of the comparison operators you would normally, like ``==``, ``===``, ``!==``, `

    Welcome, User

    {endif} -.. note:: In the background, conditionals are parsed using an **eval()**, so you must ensure that you take +.. warning:: In the background, conditionals are parsed using an ``eval()``, so you must ensure that you take care with the user data that is used within conditionals, or you could open your application up to security risks. Escaping Data From fec61fb2db116ea766219fde563523c0b2a12c6a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 09:04:37 +0900 Subject: [PATCH 1002/2325] docs: change text decration Code is decorated with '``'. --- .../source/outgoing/view_parser.rst | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 80c2f37d5c73..7070b1f8deac 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -53,9 +53,9 @@ can instantiate it directly:: $parser = new \CodeIgniter\View\Parser(); Then you can use any of the three standard rendering methods that it provides: -**render(viewpath, options, save)**, **setVar(name, value, context)** and -**setData(data, context)**. You will also be able to specify delimiters directly, -through the **setDelimiters(left, right)** method. +``render(viewpath, options, save)``, ``setVar(name, value, context)`` and +``setData(data, context)``. You will also be able to specify delimiters directly, +through the ``setDelimiters(left, right)`` method. Using the ``Parser``, your view templates are processed only by the Parser itself, and not like a conventional view PHP script. PHP code in such a script @@ -221,12 +221,12 @@ method:: ->render('blog_template'); If the array you are trying to loop over contains objects instead of arrays, -the parser will first look for an ``asArray`` method on the object. If it exists, +the parser will first look for an ``asArray()`` method on the object. If it exists, that method will be called and the resulting array is then looped over just as -described above. If no ``asArray`` method exists, the object will be cast as +described above. If no ``asArray()`` method exists, the object will be cast as an array and its public properties will be made available to the Parser. -This is especially useful with the Entity classes, which has an asArray method +This is especially useful with the Entity classes, which has an ``asArray()`` method that returns all public and protected properties (minus the _options property) and makes them available to the Parser. @@ -262,8 +262,8 @@ A **blog_template.php** that might work for the above::
    {/blog_entry} -If you would like the other pseudo-variables accessible inside the "blog_entry" -scope, then make sure that the "cascadeData" option is set to true. +If you would like the other pseudo-variables accessible inside the ``blog_entry`` +scope, then make sure that the ``cascadeData`` option is set to true. Comments ======== @@ -362,9 +362,9 @@ of the comparison operators you would normally, like ``==``, ``===``, ``!==``, ` Escaping Data ============= -By default, all variable substitution is escaped to help prevent XSS attacks on your pages. CodeIgniter's ``esc`` method -supports several different contexts, like general **html**, when it's in an HTML **attr**, in **css**, etc. If nothing -else is specified, the data will be assumed to be in an HTML context. You can specify the context used by using the **esc** +By default, all variable substitution is escaped to help prevent XSS attacks on your pages. CodeIgniter's ``esc()`` method +supports several different contexts, like general ``html``, when it's in an HTML ``attr``, in ``css``, etc. If nothing +else is specified, the data will be assumed to be in an HTML context. You can specify the context used by using the ``esc()`` filter:: { user_styles | esc(css) } From c9af04cf985b62d4caafaddf151b9a375e860fbc Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 09:41:31 +0900 Subject: [PATCH 1003/2325] docs: shorten the width of tables --- .../source/outgoing/view_parser.rst | 144 +++++++++--------- 1 file changed, 72 insertions(+), 72 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 7070b1f8deac..e182ce789b35 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -402,66 +402,65 @@ Provided Filters The following filters are available when using the parser: -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ **Filter** + **Arguments** + **Description** + **Example** + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ abs + + Displays the absolute value of a number. + { v|abs } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ capitalize + + Displays the string in sentence case: all lowercase + { v|capitalize} + -+ + + with firstletter capitalized. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ date + format (Y-m-d) + A PHP **date**-compatible formatting string. + { v|date(Y-m-d) } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ date_modify + value to add + A **strtotime** compatible string to modify the date, + { v|date_modify(+1 day) } + -+ + / subtract + like ``+5 day`` or ``-1 week``. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ default + default value + Displays the default value if the variable is empty or + { v|default(just in case) } + -+ + + undefined. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ esc + html, attr, css, js + Specifies the context to escape the data. + { v|esc(attr) } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ excerpt + phrase, radius + Returns the text within a radius of words from a given + { v|excerpt(green giant, 20) } + -+ + + phrase. Same as **excerpt** helper function. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ highlight + phrase + Highlights a given phrase within the text using + { v|highlight(view parser) } + -+ + + '' tags. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ highlight_code+ + Highlights code samples with HTML/CSS. + { v|highlight_code } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ limit_chars + limit + Limits the number of characters to $limit. + { v|limit_chars(100) } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ limit_words + limit + Limits the number of words to $limit. + { v|limit_words(20) } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ local_currency+ currency, locale + Displays a localized version of a currency. "currency" + { v|local_currency(EUR,en_US) } + -+ + + valueis any 3-letter ISO 4217 currency code. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ local_number + type, precision, + Displays a localized version of a number. "type" can be + { v|local_number(decimal,2,en_US) } + -+ + locale + one of: decimal, currency, percent, scientific, spellout, + + -+ + + ordinal, duration. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ lower + + Converts a string to lowercase. + { v|lower } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ nl2br + + Replaces all newline characters (\n) to an HTML
    tag. + { v|nl2br } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ number_format + places + Wraps PHP **number_format** function for use within the + { v|number_format(3) } + -+ + + parser. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ prose + + Takes a body of text and uses the **auto_typography()** + { v|prose } + -+ + + method to turn it into prettier, easier-to-read, prose. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ round + places, type + Rounds a number to the specified places. Types of **ceil** + { v|round(3) } { v|round(ceil) } + -+ + + and **floor** can be passed to use those functions instead. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ strip_tags + allowed chars + Wraps PHP **strip_tags**. Can accept a string of allowed + { v|strip_tags(
    ) } + -+ + + tags. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ title + + Displays a "title case" version of the string, with all + { v|title } + -+ + + lowercase, and each word capitalized. + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ upper + + Displays the string in all uppercase. + { v|upper } + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ -+ + + + + -+---------------+---------------------+--------------------------------------------------------------+-------------------------------------+ +================ ================= =========================================================== ====================================== +Filter Arguments Description Example +================ ================= =========================================================== ====================================== +abs Displays the absolute value of a number. { v|abs } + +capitalize Displays the string in sentence case: all lowercase { v|capitalize} + with firstletter capitalized. + +date format (Y-m-d) A PHP **date**-compatible formatting string. { v|date(Y-m-d) } + +date_modify value to add A **strtotime** compatible string to modify the date, { v|date_modify(+1 day) } + / subtract like ``+5 day`` or ``-1 week``. + +default default value Displays the default value if the variable is empty or { v|default(just in case) } + undefined. + +esc html, attr, Specifies the context to escape the data. { v|esc(attr) } + css, js + +excerpt phrase, radius Returns the text within a radius of words from a given { v|excerpt(green giant, 20) } + phrase. Same as **excerpt** helper function. + +highlight phrase Highlights a given phrase within the text using { v|highlight(view parser) } + '' tags. + +highlight_code Highlights code samples with HTML/CSS. { v|highlight_code } + +limit_chars limit Limits the number of characters to $limit. { v|limit_chars(100) } + +limit_words limit Limits the number of words to $limit. { v|limit_words(20) } + +local_currency currency, locale Displays a localized version of a currency. "currency" { v|local_currency(EUR,en_US) } + valueis any 3-letter ISO 4217 currency code. + +local_number type, precision, Displays a localized version of a number. "type" can be { v|local_number(decimal,2,en_US) } + locale one of: decimal, currency, percent, scientific, spellout, + ordinal, duration. + +lower Converts a string to lowercase. { v|lower } + +nl2br Replaces all newline characters (\n) to an HTML
    tag. { v|nl2br } + +number_format places Wraps PHP **number_format** function for use within the { v|number_format(3) } + parser. + +prose Takes a body of text and uses the **auto_typography()** { v|prose } + method to turn it into prettier, easier-to-read, prose. + +round places, type Rounds a number to the specified places. Types of **ceil** { v|round(3) } { v|round(ceil) } + and **floor** can be passed to use those functions instead. + +strip_tags allowed chars Wraps PHP **strip_tags**. Can accept a string of allowed { v|strip_tags(
    ) } + tags. + +title Displays a "title case" version of the string, with all { v|title } + lowercase, and each word capitalized. + +upper Displays the string in all uppercase. { v|upper } +================ ================= =========================================================== ====================================== See `PHP's NumberFormatter `_ for details relevant to the "local_number" filter. @@ -519,18 +518,19 @@ Provided Plugins The following plugins are available when using the parser: -==================== ========================== ================================================================================== ================================================================ -Plugin Arguments Description Example -==================== ========================== ================================================================================== ================================================================ -current_url Alias for the current_url helper function. {+ current_url +} -previous_url Alias for the previous_url helper function. {+ previous_url +} -siteURL Alias for the site_url helper function. {+ siteURL "login" +} -mailto email, title, attributes Alias for the mailto helper function. {+ mailto email=foo@example.com title="Stranger Things" +} -safe_mailto email, title, attributes Alias for the safe_mailto helper function. {+ safe_mailto email=foo@example.com title="Stranger Things" +} -lang language string Alias for the lang helper function. {+ lang number.terabyteAbbr +} -validation_errors fieldname(optional) Returns either error string for the field (if specified) or all validation errors. {+ validation_errors +} , {+ validation_errors field="email" +} -route route name Alias for the route_to helper function. {+ route "login" +} -==================== ========================== ================================================================================== ================================================================ +================== ========================= ============================================ ================================================================ +Plugin Arguments Description Example +================== ========================= ============================================ ================================================================ +current_url Alias for the current_url helper function. {+ current_url +} +previous_url Alias for the previous_url helper function. {+ previous_url +} +siteURL Alias for the site_url helper function. {+ siteURL "login" +} +mailto email, title, attributes Alias for the mailto helper function. {+ mailto email=foo@example.com title="Stranger Things" +} +safe_mailto email, title, attributes Alias for the safe_mailto helper function. {+ safe_mailto email=foo@example.com title="Stranger Things" +} +lang language string Alias for the lang helper function. {+ lang number.terabyteAbbr +} +validation_errors fieldname(optional) Returns either error string for the field {+ validation_errors +} , {+ validation_errors field="email" +} + (if specified) or all validation errors. +route route name Alias for the route_to helper function. {+ route "login" +} +================== ========================= ============================================ ================================================================ Registering a Plugin -------------------- From 3b1078f93aeb4d34f075817b81525078400ddb01 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 10:35:36 +0900 Subject: [PATCH 1004/2325] docs: change text decoration --- user_guide_src/source/libraries/validation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index b29f6651d4eb..be46d861e747 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -527,7 +527,7 @@ or the value that was validated you can add the ``{field}``, ``{param}`` and ``{ 'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.' -On a field with the human name Username and a rule of min_length[6] with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must have +On a field with the human name Username and a rule of ``min_length[6]`` with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must have at least 6 characters.” .. note:: If you pass the last parameter the labeled style error messages will be ignored. @@ -643,11 +643,11 @@ short alias they can be referenced by. If we were to add our example file from a Specifying the Template ======================= -You can specify the template to use by passing it's alias as the first parameter in ``listErrors``:: +You can specify the template to use by passing it's alias as the first parameter in ``listErrors()``:: listErrors('my_list') ?> -When showing field-specific errors, you can pass the alias as the second parameter to the ``showError`` method, +When showing field-specific errors, you can pass the alias as the second parameter to the ``showError()`` method, right after the name of the field the error should belong to:: showError('username', 'my_single') ?> From d16fec7fdf4def1b18d1f9c1c995ed03d149fb48 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 10:39:52 +0900 Subject: [PATCH 1005/2325] docs: fix note explanation --- user_guide_src/source/libraries/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index be46d861e747..137da33afdee 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -530,7 +530,7 @@ or the value that was validated you can add the ``{field}``, ``{param}`` and ``{ On a field with the human name Username and a rule of ``min_length[6]`` with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must have at least 6 characters.” -.. note:: If you pass the last parameter the labeled style error messages will be ignored. +.. note:: When using label-style error messages, if you pass the second parameter to ``setRules()``, it will be overwritten with the value of the first parameter. Translation Of Messages And Validation Labels ============================================= From 6750eee38449c987b285c60ed85346bab3ee8a58 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 10:41:44 +0900 Subject: [PATCH 1006/2325] docs: add warning about XSS risk --- user_guide_src/source/libraries/validation.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 137da33afdee..ae2e48962f3b 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -530,6 +530,8 @@ or the value that was validated you can add the ``{field}``, ``{param}`` and ``{ On a field with the human name Username and a rule of ``min_length[6]`` with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must have at least 6 characters.” +.. warning:: If you get the error messages with ``getErrors()`` or ``getError()``, the messages are not HTML escaped. If you use user input data like ``({value})`` to make the error message, it might contain HTML tags. If you don't escape the messages before displying them, XSS attacks are possible. + .. note:: When using label-style error messages, if you pass the second parameter to ``setRules()``, it will be overwritten with the value of the first parameter. Translation Of Messages And Validation Labels From d2f12fb8da231ba027e52b00555ea19d19e762f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 10:42:02 +0900 Subject: [PATCH 1007/2325] docs: remove uneeded '*' --- user_guide_src/source/libraries/validation.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index ae2e48962f3b..960a1bce3dda 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -594,7 +594,7 @@ You can check to see if an error exists with the ``hasError()`` method. The only } Customizing Error Display -************************************************ +************************* When you call ``$validation->listErrors()`` or ``$validation->showError()``, it loads a view file in the background that determines how the errors are displayed. By default, they display with a class of ``errors`` on the wrapping div. From dc969c1f4272710b3dfa2386e91267dc1039e4cd Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 18 Dec 2021 10:54:29 +0900 Subject: [PATCH 1008/2325] docs: fix directory inconsistency --- user_guide_src/source/models/entities.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index 489685a8c5ff..34928d628dbe 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -425,11 +425,11 @@ Custom casting You can define your own conversion types for getting and setting data. At first you need to create a handler class for your type. -Let's say the class will be located in the **app/Entity/Cast** directory:: +Let's say the class will be located in the **app/Entities/Cast** directory:: \App\Entity\Cast\CastBase64::class, + 'base64' => \App\Entities\Cast\CastBase64::class, ]; } From 31fb03b98571c5453d18c773bfe99b96c569cfc7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Dec 2021 16:38:05 +0900 Subject: [PATCH 1009/2325] fix: does not show correct token time until 1 token is available Fixes #5458 --- system/Throttle/Throttler.php | 30 +++++++++++++-------- tests/system/Throttle/ThrottleTest.php | 36 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/system/Throttle/Throttler.php b/system/Throttle/Throttler.php index 5154f386439b..28d08739e123 100644 --- a/system/Throttle/Throttler.php +++ b/system/Throttle/Throttler.php @@ -95,13 +95,21 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): { $tokenName = $this->prefix . $key; + // Number of tokens to add back per second + $rate = $capacity / $seconds; + // Number of seconds to get one token + $refresh = 1 / $rate; + // Check to see if the bucket has even been created yet. if (($tokens = $this->cache->get($tokenName)) === null) { // If it hasn't been created, then we'll set it to the maximum // capacity - 1, and save it to the cache. - $this->cache->save($tokenName, $capacity - $cost, $seconds); + $tokens = $capacity - $cost; + $this->cache->save($tokenName, $tokens, $seconds); $this->cache->save($tokenName . 'Time', $this->time(), $seconds); + $this->tokenTime = max(1, (int) $refresh); + return true; } @@ -110,15 +118,6 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): $throttleTime = $this->cache->get($tokenName . 'Time'); $elapsed = $this->time() - $throttleTime; - // Number of tokens to add back per second - $rate = $capacity / $seconds; - - // How many seconds till a new token is available. - // We must have a minimum wait of 1 second for a new token. - // Primarily stored to allow devs to report back to users. - $newTokenAvailable = (1 / $rate) - $elapsed; - $this->tokenTime = max(1, $newTokenAvailable); - // Add tokens based up on number per second that // should be refilled, then checked against capacity // to be sure the bucket didn't overflow. @@ -128,12 +127,21 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): // If $tokens >= 1, then we are safe to perform the action, but // we need to decrement the number of available tokens. if ($tokens >= 1) { - $this->cache->save($tokenName, $tokens - $cost, $seconds); + $tokens = $tokens - $cost; + $this->cache->save($tokenName, $tokens, $seconds); $this->cache->save($tokenName . 'Time', $this->time(), $seconds); + $this->tokenTime = max(1, (int) ($refresh - $elapsed)); + return true; } + // How many seconds till a new token is available. + // We must have a minimum wait of 1 second for a new token. + // Primarily stored to allow devs to report back to users. + $newTokenAvailable = (int) ($refresh - $elapsed - $refresh * $tokens); + $this->tokenTime = max(1, $newTokenAvailable); + return false; } diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index 498cbf0673d5..930e34c5e184 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -45,6 +45,42 @@ public function testTokenTime() $this->assertGreaterThanOrEqual(1, $throttler->getTokenTime()); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5458 + */ + public function testTokenTimeCalculation() + { + $time = 1639441295; + + $throttler = new Throttler($this->cache); + $throttler->setTestTime($time); + + $capacity = 2; + $seconds = 200; + + // refresh = 200 / 2 = 100 seconds + // refresh rate = 2 / 200 = 0.01 token per second + + // token should be 2 + $this->assertTrue($throttler->check('test', $capacity, $seconds)); + // token should be 2 - 1 = 1 + $this->assertSame(100, $throttler->getTokenTime(), 'Wrong token time'); + + // do nothing for 3 seconds + $throttler = $throttler->setTestTime($time + 3); + + // token should be 1 + 3 * 0.01 = 1.03 + $this->assertTrue($throttler->check('test', $capacity, $seconds)); + // token should be 1.03 - 1 = 0.03 + $this->assertSame(97, $throttler->getTokenTime(), 'Wrong token time'); + + $this->assertFalse($throttler->check('test', $capacity, $seconds)); + // token should still be 0.03 because check failed + + // expect remaining time: (1 - 0.03) * 100 = 97 + $this->assertSame(97, $throttler->getTokenTime(), 'Wrong token time'); + } + public function testIPSavesBucket() { $throttler = new Throttler($this->cache); From 10f772a4b93f2d18cbee03cb6ccd6cccda9a8636 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Dec 2021 16:39:44 +0900 Subject: [PATCH 1010/2325] docs: update sample code in comment --- system/Throttle/Throttler.php | 5 ++--- tests/system/Throttle/ThrottleTest.php | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/system/Throttle/Throttler.php b/system/Throttle/Throttler.php index 28d08739e123..239abd0d6d20 100644 --- a/system/Throttle/Throttler.php +++ b/system/Throttle/Throttler.php @@ -79,10 +79,9 @@ public function getTokenTime(): int * * Example: * - * if (! $throttler->check($request->ipAddress(), 60, MINUTE)) - * { + * if (! $throttler->check($request->ipAddress(), 60, MINUTE)) { * die('You submitted over 60 requests within a minute.'); - * } + * } * * @param string $key The name to use as the "bucket" name. * @param int $capacity The number of requests the "bucket" can hold diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index 930e34c5e184..8da9e6fe4396 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -56,7 +56,7 @@ public function testTokenTimeCalculation() $throttler->setTestTime($time); $capacity = 2; - $seconds = 200; + $seconds = 200; // refresh = 200 / 2 = 100 seconds // refresh rate = 2 / 200 = 0.01 token per second From 47c4c9cdc7041725a6a911aabc77b1a1ed9f011a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Dec 2021 21:49:28 +0900 Subject: [PATCH 1011/2325] fix: tokenTime calcuration When check() returns false, tokenTime is 0. --- system/Throttle/Throttler.php | 4 ++-- tests/system/Throttle/ThrottleTest.php | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/system/Throttle/Throttler.php b/system/Throttle/Throttler.php index 239abd0d6d20..89c32981a841 100644 --- a/system/Throttle/Throttler.php +++ b/system/Throttle/Throttler.php @@ -107,7 +107,7 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): $this->cache->save($tokenName, $tokens, $seconds); $this->cache->save($tokenName . 'Time', $this->time(), $seconds); - $this->tokenTime = max(1, (int) $refresh); + $this->tokenTime = 0; return true; } @@ -130,7 +130,7 @@ public function check(string $key, int $capacity, int $seconds, int $cost = 1): $this->cache->save($tokenName, $tokens, $seconds); $this->cache->save($tokenName . 'Time', $this->time(), $seconds); - $this->tokenTime = max(1, (int) ($refresh - $elapsed)); + $this->tokenTime = 0; return true; } diff --git a/tests/system/Throttle/ThrottleTest.php b/tests/system/Throttle/ThrottleTest.php index 8da9e6fe4396..cc8ccb82856d 100644 --- a/tests/system/Throttle/ThrottleTest.php +++ b/tests/system/Throttle/ThrottleTest.php @@ -36,11 +36,11 @@ public function testTokenTime() // set $rate $rate = 1; // allow 1 request per minute - // first check just creates a bucket, so tokenTime should be 0 + // When the first check you have a token, so tokenTime should be 0 $throttler->check('127.0.0.1', $rate, MINUTE); $this->assertSame(0, $throttler->getTokenTime()); - // additional check affects tokenTime, so tokenTime should be 1 or greater + // When additional check you don't have one token, so tokenTime should be 1 or greater $throttler->check('127.0.0.1', $rate, MINUTE); $this->assertGreaterThanOrEqual(1, $throttler->getTokenTime()); } @@ -64,7 +64,7 @@ public function testTokenTimeCalculation() // token should be 2 $this->assertTrue($throttler->check('test', $capacity, $seconds)); // token should be 2 - 1 = 1 - $this->assertSame(100, $throttler->getTokenTime(), 'Wrong token time'); + $this->assertSame(0, $throttler->getTokenTime(), 'Wrong token time'); // do nothing for 3 seconds $throttler = $throttler->setTestTime($time + 3); @@ -72,7 +72,7 @@ public function testTokenTimeCalculation() // token should be 1 + 3 * 0.01 = 1.03 $this->assertTrue($throttler->check('test', $capacity, $seconds)); // token should be 1.03 - 1 = 0.03 - $this->assertSame(97, $throttler->getTokenTime(), 'Wrong token time'); + $this->assertSame(0, $throttler->getTokenTime(), 'Wrong token time'); $this->assertFalse($throttler->check('test', $capacity, $seconds)); // token should still be 0.03 because check failed From cc901dbd138f3e866760d2ca77b602f8a5535845 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Dec 2021 16:14:04 +0900 Subject: [PATCH 1012/2325] docs: add views()'s option `cache` --- user_guide_src/source/general/common_functions.rst | 3 ++- user_guide_src/source/outgoing/views.rst | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index f4b61548f4da..b9b21e29ba38 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -179,9 +179,10 @@ Service Accessors a convenience method that can be used in Controllers, libraries, and routed closures. - Currently, only two options are available for use within the ``$options`` array: + Currently, these options are available for use within the ``$options`` array: - ``saveData`` specifies that data will persistent between multiple calls to ``view()`` within the same request. If you do not want the data to be persisted, specify false. + - ``cache`` specifies the number of seconds to cache the view for. See :ref:`caching-views` for the details. - ``debug`` can be set to false to disable the addition of debug code for :ref:`Debug Toolbar `. The ``$option`` array is provided primarily to facilitate third-party integrations with diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 5cc77d05a3a4..96e350216ce7 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -113,6 +113,8 @@ example, you could load the **blog_view.php** file from **example/blog/Views** b echo view('Example\Blog\Views\blog_view'); +.. _caching-views: + Caching Views ============= From 95bad7cb0464c22179e522063903ea59ffb25c1c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Dec 2021 16:24:07 +0900 Subject: [PATCH 1013/2325] chore: update Kint to ^4.0 --- composer.json | 2 +- system/ThirdParty/Kint/CallFinder.php | 124 ++++++--- system/ThirdParty/Kint/Kint.php | 256 ++++++++---------- .../Kint/Parser/ArrayLimitPlugin.php | 142 ++++++++++ .../Kint/Parser/ArrayObjectPlugin.php | 6 +- .../ThirdParty/Kint/Parser/Base64Plugin.php | 11 +- .../ThirdParty/Kint/Parser/BinaryPlugin.php | 10 +- .../Kint/Parser/BlacklistPlugin.php | 74 +---- .../Kint/Parser/ClassMethodsPlugin.php | 26 +- .../Kint/Parser/ClassStaticsPlugin.php | 46 ++-- .../ThirdParty/Kint/Parser/ClosurePlugin.php | 26 +- system/ThirdParty/Kint/Parser/ColorPlugin.php | 8 +- .../Kint/Parser/DOMDocumentPlugin.php | 107 ++++---- .../ThirdParty/Kint/Parser/DateTimePlugin.php | 10 +- .../ThirdParty/Kint/Parser/FsPathPlugin.php | 10 +- .../ThirdParty/Kint/Parser/IteratorPlugin.php | 25 +- system/ThirdParty/Kint/Parser/JsonPlugin.php | 10 +- .../Kint/Parser/MicrotimePlugin.php | 10 +- .../ThirdParty/Kint/Parser/MysqliPlugin.php | 98 +++++-- system/ThirdParty/Kint/Parser/Parser.php | 223 ++++++++------- system/ThirdParty/Kint/Parser/Plugin.php | 6 +- system/ThirdParty/Kint/Parser/ProxyPlugin.php | 6 +- .../Kint/Parser/SerializePlugin.php | 18 +- .../Kint/Parser/SimpleXMLElementPlugin.php | 189 ++++++++----- .../Kint/Parser/SplFileInfoPlugin.php | 8 +- .../Kint/Parser/SplObjectStoragePlugin.php | 6 +- .../ThirdParty/Kint/Parser/StreamPlugin.php | 23 +- system/ThirdParty/Kint/Parser/TablePlugin.php | 8 +- .../Kint/Parser/ThrowablePlugin.php | 12 +- .../Kint/Parser/TimestampPlugin.php | 12 +- .../ThirdParty/Kint/Parser/ToStringPlugin.php | 12 +- system/ThirdParty/Kint/Parser/TracePlugin.php | 46 +++- system/ThirdParty/Kint/Parser/XmlPlugin.php | 31 ++- .../ThirdParty/Kint/Renderer/CliRenderer.php | 18 +- .../Kint/Renderer/PlainRenderer.php | 34 +-- system/ThirdParty/Kint/Renderer/Renderer.php | 52 ++-- .../Kint/Renderer/Rich/ArrayLimitPlugin.php | 36 +++ .../Kint/Renderer/Rich/BinaryPlugin.php | 15 +- .../Kint/Renderer/Rich/BlacklistPlugin.php | 6 +- .../Kint/Renderer/Rich/CallablePlugin.php | 40 +-- .../Kint/Renderer/Rich/ClosurePlugin.php | 10 +- .../Kint/Renderer/Rich/ColorPlugin.php | 12 +- .../Kint/Renderer/Rich/DepthLimitPlugin.php | 6 +- .../Kint/Renderer/Rich/DocstringPlugin.php | 10 +- .../Kint/Renderer/Rich/MicrotimePlugin.php | 6 +- .../ThirdParty/Kint/Renderer/Rich/Plugin.php | 7 +- .../Kint/Renderer/Rich/RecursionPlugin.php | 6 +- .../Renderer/Rich/SimpleXMLElementPlugin.php | 20 +- .../Kint/Renderer/Rich/SourcePlugin.php | 6 +- .../Kint/Renderer/Rich/TabPluginInterface.php | 7 +- .../Kint/Renderer/Rich/TablePlugin.php | 8 +- .../Kint/Renderer/Rich/TimestampPlugin.php | 2 +- .../Kint/Renderer/Rich/TraceFramePlugin.php | 10 +- ...Interface.php => ValuePluginInterface.php} | 9 +- .../ThirdParty/Kint/Renderer/RichRenderer.php | 98 ++++--- .../Kint/Renderer/Text/ArrayLimitPlugin.php | 44 +++ .../Kint/Renderer/Text/BlacklistPlugin.php | 4 +- .../Kint/Renderer/Text/DepthLimitPlugin.php | 4 +- .../Kint/Renderer/Text/MicrotimePlugin.php | 8 +- .../ThirdParty/Kint/Renderer/Text/Plugin.php | 7 +- .../Kint/Renderer/Text/RecursionPlugin.php | 4 +- .../Kint/Renderer/Text/TracePlugin.php | 8 +- .../ThirdParty/Kint/Renderer/TextRenderer.php | 36 +-- system/ThirdParty/Kint/Utils.php | 69 +++-- .../BlobObject.php => Zval/BlobValue.php} | 14 +- .../ClosureValue.php} | 10 +- .../DateTimeValue.php} | 6 +- .../InstanceValue.php} | 14 +- .../MethodObject.php => Zval/MethodValue.php} | 32 +-- .../ParameterValue.php} | 7 +- .../Representation/ColorRepresentation.php | 31 +-- .../DocstringRepresentation.php | 4 +- .../MicrotimeRepresentation.php | 4 +- .../Representation/Representation.php | 6 +- .../Representation/SourceRepresentation.php | 6 +- .../SplFileInfoRepresentation.php | 16 +- .../ResourceValue.php} | 6 +- .../Kint/Zval/SimpleXMLElementValue.php | 48 ++++ .../StreamObject.php => Zval/StreamValue.php} | 4 +- .../ThrowableValue.php} | 8 +- .../TraceFrameValue.php} | 31 ++- .../TraceObject.php => Zval/TraceValue.php} | 6 +- .../BasicObject.php => Zval/Value.php} | 28 +- system/ThirdParty/Kint/init.php | 14 +- system/ThirdParty/Kint/init_helpers.php | 16 +- .../Kint/resources/compiled/aante-light.css | 2 +- .../Kint/resources/compiled/microtime.js | 2 +- .../Kint/resources/compiled/original.css | 2 +- .../Kint/resources/compiled/rich.js | 2 +- .../Kint/resources/compiled/shared.js | 2 +- .../resources/compiled/solarized-dark.css | 2 +- .../Kint/resources/compiled/solarized.css | 2 +- 92 files changed, 1511 insertions(+), 1017 deletions(-) create mode 100644 system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php create mode 100644 system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php rename system/ThirdParty/Kint/Renderer/Rich/{ObjectPluginInterface.php => ValuePluginInterface.php} (88%) create mode 100644 system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php rename system/ThirdParty/Kint/{Object/BlobObject.php => Zval/BlobValue.php} (95%) rename system/ThirdParty/Kint/{Object/ClosureObject.php => Zval/ClosureValue.php} (91%) rename system/ThirdParty/Kint/{Object/DateTimeObject.php => Zval/DateTimeValue.php} (93%) rename system/ThirdParty/Kint/{Object/InstanceObject.php => Zval/InstanceValue.php} (88%) rename system/ThirdParty/Kint/{Object/MethodObject.php => Zval/MethodValue.php} (90%) rename system/ThirdParty/Kint/{Object/ParameterObject.php => Zval/ParameterValue.php} (95%) rename system/ThirdParty/Kint/{Object => Zval}/Representation/ColorRepresentation.php (96%) rename system/ThirdParty/Kint/{Object => Zval}/Representation/DocstringRepresentation.php (97%) rename system/ThirdParty/Kint/{Object => Zval}/Representation/MicrotimeRepresentation.php (96%) rename system/ThirdParty/Kint/{Object => Zval}/Representation/Representation.php (95%) rename system/ThirdParty/Kint/{Object => Zval}/Representation/SourceRepresentation.php (96%) rename system/ThirdParty/Kint/{Object => Zval}/Representation/SplFileInfoRepresentation.php (95%) rename system/ThirdParty/Kint/{Object/ResourceObject.php => Zval/ResourceValue.php} (93%) create mode 100644 system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php rename system/ThirdParty/Kint/{Object/StreamObject.php => Zval/StreamValue.php} (96%) rename system/ThirdParty/Kint/{Object/ThrowableObject.php => Zval/ThrowableValue.php} (88%) rename system/ThirdParty/Kint/{Object/TraceFrameObject.php => Zval/TraceFrameValue.php} (81%) rename system/ThirdParty/Kint/{Object/TraceObject.php => Zval/TraceValue.php} (93%) rename system/ThirdParty/Kint/{Object/BasicObject.php => Zval/Value.php} (91%) diff --git a/composer.json b/composer.json index 38ddfd6ef3c7..330209cb21a6 100644 --- a/composer.json +++ b/composer.json @@ -10,7 +10,7 @@ "ext-intl": "*", "ext-json": "*", "ext-mbstring": "*", - "kint-php/kint": "^3.3", + "kint-php/kint": "^4.0", "laminas/laminas-escaper": "^2.9", "psr/log": "^1.1" }, diff --git a/system/ThirdParty/Kint/CallFinder.php b/system/ThirdParty/Kint/CallFinder.php index e7192a815284..e77a6407f018 100644 --- a/system/ThirdParty/Kint/CallFinder.php +++ b/system/ThirdParty/Kint/CallFinder.php @@ -27,7 +27,7 @@ class CallFinder { - private static $ignore = array( + private static $ignore = [ T_CLOSE_TAG => true, T_COMMENT => true, T_DOC_COMMENT => true, @@ -35,7 +35,7 @@ class CallFinder T_OPEN_TAG => true, T_OPEN_TAG_WITH_ECHO => true, T_WHITESPACE => true, - ); + ]; /** * Things we need to do specially for operator tokens: @@ -43,17 +43,19 @@ class CallFinder * - Wrap the access path in parentheses if there * are any of these in the final short parameter. */ - private static $operator = array( + private static $operator = [ T_AND_EQUAL => true, T_BOOLEAN_AND => true, T_BOOLEAN_OR => true, T_ARRAY_CAST => true, T_BOOL_CAST => true, + T_CLASS => true, T_CLONE => true, T_CONCAT_EQUAL => true, T_DEC => true, T_DIV_EQUAL => true, T_DOUBLE_CAST => true, + T_FUNCTION => true, T_INC => true, T_INCLUDE => true, T_INCLUDE_ONCE => true, @@ -84,6 +86,9 @@ class CallFinder T_STRING_CAST => true, T_UNSET_CAST => true, T_XOR_EQUAL => true, + T_POW => true, + T_POW_EQUAL => true, + T_DOUBLE_ARROW => true, '!' => true, '%' => true, '&' => true, @@ -100,9 +105,9 @@ class CallFinder '^' => true, '|' => true, '~' => true, - ); + ]; - private static $strip = array( + private static $strip = [ '(' => true, ')' => true, '[' => true, @@ -112,39 +117,43 @@ class CallFinder T_OBJECT_OPERATOR => true, T_DOUBLE_COLON => true, T_NS_SEPARATOR => true, - ); + ]; + + private static $classcalls = [ + T_DOUBLE_COLON => true, + T_OBJECT_OPERATOR => true, + ]; + + private static $namespace = [ + T_STRING => true, + ]; public static function getFunctionCalls($source, $line, $function) { - static $up = array( + static $up = [ '(' => true, '[' => true, '{' => true, T_CURLY_OPEN => true, T_DOLLAR_OPEN_CURLY_BRACES => true, - ); - static $down = array( + ]; + static $down = [ ')' => true, ']' => true, '}' => true, - ); - static $modifiers = array( + ]; + static $modifiers = [ '!' => true, '@' => true, '~' => true, '+' => true, '-' => true, - ); - static $identifier = array( + ]; + static $identifier = [ T_DOUBLE_COLON => true, T_STRING => true, T_NS_SEPARATOR => true, - ); - - if (KINT_PHP56) { - self::$operator[T_POW] = true; - self::$operator[T_POW_EQUAL] = true; - } + ]; if (KINT_PHP70) { self::$operator[T_SPACESHIP] = true; @@ -154,11 +163,24 @@ public static function getFunctionCalls($source, $line, $function) self::$operator[T_COALESCE_EQUAL] = true; } + if (KINT_PHP80) { + $up[T_ATTRIBUTE] = true; + self::$operator[T_MATCH] = true; + self::$strip[T_NULLSAFE_OBJECT_OPERATOR] = true; + self::$classcalls[T_NULLSAFE_OBJECT_OPERATOR] = true; + self::$namespace[T_NAME_FULLY_QUALIFIED] = true; + self::$namespace[T_NAME_QUALIFIED] = true; + self::$namespace[T_NAME_RELATIVE] = true; + $identifier[T_NAME_FULLY_QUALIFIED] = true; + $identifier[T_NAME_QUALIFIED] = true; + $identifier[T_NAME_RELATIVE] = true; + } + $tokens = \token_get_all($source); $cursor = 1; - $function_calls = array(); - /** @var array Performance optimization preventing backwards loops */ - $prev_tokens = array(null, null, null); + $function_calls = []; + // Performance optimization preventing backwards loops + $prev_tokens = [null, null, null]; if (\is_array($function)) { $class = \explode('\\', $function[0]); @@ -188,10 +210,16 @@ public static function getFunctionCalls($source, $line, $function) continue; } - $prev_tokens = array($prev_tokens[1], $prev_tokens[2], $token); + $prev_tokens = [$prev_tokens[1], $prev_tokens[2], $token]; // Check if it's the right type to be the function we're looking for - if (T_STRING !== $token[0] || \strtolower($token[1]) !== $function) { + if (!isset(self::$namespace[$token[0]])) { + continue; + } + + $ns = \explode('\\', \strtolower($token[1])); + + if (\end($ns) !== $function) { continue; } @@ -203,7 +231,7 @@ public static function getFunctionCalls($source, $line, $function) // Check if it matches the signature if (null === $class) { - if ($prev_tokens[1] && \in_array($prev_tokens[1][0], array(T_DOUBLE_COLON, T_OBJECT_OPERATOR), true)) { + if ($prev_tokens[1] && isset(self::$classcalls[$prev_tokens[1][0]])) { continue; } } else { @@ -211,7 +239,15 @@ public static function getFunctionCalls($source, $line, $function) continue; } - if (!$prev_tokens[0] || T_STRING !== $prev_tokens[0][0] || \strtolower($prev_tokens[0][1]) !== $class) { + if (!$prev_tokens[0] || !isset(self::$namespace[$prev_tokens[0][0]])) { + continue; + } + + /** @var array{int, string, int} $prev_tokens[0] */ + // All self::$namespace tokens are T_ constants + $ns = \explode('\\', \strtolower($prev_tokens[0][1])); + + if (\end($ns) !== $class) { continue; } } @@ -222,8 +258,8 @@ public static function getFunctionCalls($source, $line, $function) $instring = false; // Whether we're in a string or not $realtokens = false; // Whether the current scope contains anything meaningful or not $paramrealtokens = false; // Whether the current parameter contains anything meaningful - $params = array(); // All our collected parameters - $shortparam = array(); // The short version of the parameter + $params = []; // All our collected parameters + $shortparam = []; // The short version of the parameter $param_start = $offset; // The distance to the start of the parameter // Loop through the following tokens until the function call ends @@ -276,11 +312,11 @@ public static function getFunctionCalls($source, $line, $function) $shortparam[] = '"'; } elseif (1 === $depth) { if (',' === $token[0]) { - $params[] = array( + $params[] = [ 'full' => \array_slice($tokens, $param_start, $offset - $param_start), 'short' => $shortparam, - ); - $shortparam = array(); + ]; + $shortparam = []; $paramrealtokens = false; $param_start = $offset + 1; } elseif (T_CONSTANT_ENCAPSED_STRING === $token[0] && \strlen($token[1]) > 2) { @@ -293,10 +329,10 @@ public static function getFunctionCalls($source, $line, $function) // Depth has dropped to 0 (So we've hit the closing paren) if ($depth <= 0) { if ($paramrealtokens) { - $params[] = array( + $params[] = [ 'full' => \array_slice($tokens, $param_start, $offset - $param_start), 'short' => $shortparam, - ); + ]; } break; @@ -322,11 +358,11 @@ public static function getFunctionCalls($source, $line, $function) } } - $param = array( + $param = [ 'name' => self::tokensToString($name), 'path' => self::tokensToString(self::tokensTrim($param['full'])), 'expression' => $expression, - ); + ]; } // Get the modifiers @@ -340,7 +376,7 @@ public static function getFunctionCalls($source, $line, $function) --$index; } - $mods = array(); + $mods = []; while (isset($tokens[$index])) { if (isset(self::$ignore[$tokens[$index][0]])) { @@ -357,10 +393,10 @@ public static function getFunctionCalls($source, $line, $function) break; } - $function_calls[] = array( + $function_calls[] = [ 'parameters' => $params, 'modifiers' => $mods, - ); + ]; } return $function_calls; @@ -436,10 +472,11 @@ private static function tokensTrim(array $tokens) private static function tokensFormatted(array $tokens) { $space = false; + $attribute = false; $tokens = self::tokensTrim($tokens); - $output = array(); + $output = []; $last = null; foreach ($tokens as $index => $token) { @@ -450,7 +487,10 @@ private static function tokensFormatted(array $tokens) $next = $tokens[self::realTokenIndex($tokens, $index)]; - if (isset(self::$strip[$last[0]]) && !self::tokenIsOperator($next)) { + /** @var array|string $last */ + if ($attribute && ']' === $last[0]) { + $attribute = false; + } elseif (isset(self::$strip[$last[0]]) && !self::tokenIsOperator($next)) { continue; } @@ -461,6 +501,10 @@ private static function tokensFormatted(array $tokens) $token = ' '; $space = true; } else { + if (KINT_PHP80 && $last && T_ATTRIBUTE == $last[0]) { + $attribute = true; + } + $space = false; $last = $token; } diff --git a/system/ThirdParty/Kint/Kint.php b/system/ThirdParty/Kint/Kint.php index e0ce96337753..f11ed498c45f 100644 --- a/system/ThirdParty/Kint/Kint.php +++ b/system/ThirdParty/Kint/Kint.php @@ -26,11 +26,11 @@ namespace Kint; use InvalidArgumentException; -use Kint\Object\BasicObject; use Kint\Parser\Parser; use Kint\Parser\Plugin; use Kint\Renderer\Renderer; use Kint\Renderer\TextRenderer; +use Kint\Zval\Value; class Kint { @@ -102,12 +102,12 @@ class Kint * * Defaults to [$_SERVER['DOCUMENT_ROOT'] => ''] */ - public static $app_root_dirs = array(); + public static $app_root_dirs = []; /** - * @var int max array/object levels to go deep, if zero no limits are applied + * @var int depth limit for array/object traversal. 0 for no limit */ - public static $max_depth = 6; + public static $depth_limit = 7; /** * @var bool expand all trees by default for rich view @@ -124,23 +124,24 @@ class Kint /** * @var array Kint aliases. Add debug functions in Kint wrappers here to fix modifiers and backtraces */ - public static $aliases = array( - array('Kint\\Kint', 'dump'), - array('Kint\\Kint', 'trace'), - array('Kint\\Kint', 'dumpArray'), - ); + public static $aliases = [ + ['Kint\\Kint', 'dump'], + ['Kint\\Kint', 'trace'], + ['Kint\\Kint', 'dumpArray'], + ]; /** * @var array Array of modes to renderer class names */ - public static $renderers = array( + public static $renderers = [ self::MODE_RICH => 'Kint\\Renderer\\RichRenderer', self::MODE_PLAIN => 'Kint\\Renderer\\PlainRenderer', self::MODE_TEXT => 'Kint\\Renderer\\TextRenderer', self::MODE_CLI => 'Kint\\Renderer\\CliRenderer', - ); + ]; - public static $plugins = array( + public static $plugins = [ + 'Kint\\Parser\\ArrayLimitPlugin', 'Kint\\Parser\\ArrayObjectPlugin', 'Kint\\Parser\\Base64Plugin', 'Kint\\Parser\\BlacklistPlugin', @@ -162,9 +163,9 @@ class Kint 'Kint\\Parser\\TimestampPlugin', 'Kint\\Parser\\TracePlugin', 'Kint\\Parser\\XmlPlugin', - ); + ]; - protected static $plugin_pool = array(); + protected static $plugin_pool = []; protected $parser; protected $renderer; @@ -199,24 +200,25 @@ public function setStatesFromStatics(array $statics) { $this->renderer->setStatics($statics); - $this->parser->setDepthLimit(isset($statics['max_depth']) ? $statics['max_depth'] : false); + $this->parser->setDepthLimit(isset($statics['depth_limit']) ? $statics['depth_limit'] : 0); $this->parser->clearPlugins(); if (!isset($statics['plugins'])) { return; } - $plugins = array(); + $plugins = []; foreach ($statics['plugins'] as $plugin) { if ($plugin instanceof Plugin) { $plugins[] = $plugin; - } elseif (\is_string($plugin) && \is_subclass_of($plugin, 'Kint\\Parser\\Plugin')) { - if (!isset(self::$plugin_pool[$plugin])) { + } elseif (\is_string($plugin) && \is_subclass_of($plugin, Plugin::class)) { + if (!isset(static::$plugin_pool[$plugin])) { + /** @psalm-suppress UnsafeInstantiation */ $p = new $plugin(); - self::$plugin_pool[$plugin] = $p; + static::$plugin_pool[$plugin] = $p; } - $plugins[] = self::$plugin_pool[$plugin]; + $plugins[] = static::$plugin_pool[$plugin]; } } @@ -232,7 +234,7 @@ public function setStatesFromCallInfo(array $info) $this->renderer->setCallInfo($info); if (isset($info['modifiers']) && \is_array($info['modifiers']) && \in_array('+', $info['modifiers'], true)) { - $this->parser->setDepthLimit(false); + $this->parser->setDepthLimit(0); } $this->parser->setCallerClass(isset($info['caller']['class']) ? $info['caller']['class'] : null); @@ -241,8 +243,8 @@ public function setStatesFromCallInfo(array $info) /** * Renders a list of vars including the pre and post renders. * - * @param array $vars Data to dump - * @param BasicObject[] $base Base objects + * @param array $vars Data to dump + * @param array $base Base Zval\Value objects * * @return string */ @@ -254,13 +256,13 @@ public function dumpAll(array $vars, array $base) $output = $this->renderer->preRender(); - if ($vars === array()) { + if ([] === $vars) { $output .= $this->renderer->renderNothing(); } foreach ($vars as $key => $arg) { - if (!$base[$key] instanceof BasicObject) { - throw new InvalidArgumentException('Kint::dumpAll requires all elements of the second argument to be BasicObject instances'); + if (!$base[$key] instanceof Value) { + throw new InvalidArgumentException('Kint::dumpAll requires all elements of the second argument to be Value instances'); } $output .= $this->dumpVar($arg, $base[$key]); } @@ -273,12 +275,12 @@ public function dumpAll(array $vars, array $base) /** * Dumps and renders a var. * - * @param mixed $var Data to dump - * @param BasicObject $base Base object + * @param mixed $var Data to dump + * @param Value $base Base object * * @return string */ - public function dumpVar(&$var, BasicObject $base) + public function dumpVar(&$var, Value $base) { return $this->renderer->render( $this->parser->parse($var, $base) @@ -292,21 +294,21 @@ public function dumpVar(&$var, BasicObject $base) */ public static function getStatics() { - return array( - 'aliases' => self::$aliases, - 'app_root_dirs' => self::$app_root_dirs, - 'cli_detection' => self::$cli_detection, - 'display_called_from' => self::$display_called_from, - 'enabled_mode' => self::$enabled_mode, - 'expanded' => self::$expanded, - 'file_link_format' => self::$file_link_format, - 'max_depth' => self::$max_depth, - 'mode_default' => self::$mode_default, - 'mode_default_cli' => self::$mode_default_cli, - 'plugins' => self::$plugins, - 'renderers' => self::$renderers, - 'return' => self::$return, - ); + return [ + 'aliases' => static::$aliases, + 'app_root_dirs' => static::$app_root_dirs, + 'cli_detection' => static::$cli_detection, + 'depth_limit' => static::$depth_limit, + 'display_called_from' => static::$display_called_from, + 'enabled_mode' => static::$enabled_mode, + 'expanded' => static::$expanded, + 'file_link_format' => static::$file_link_format, + 'mode_default' => static::$mode_default, + 'mode_default_cli' => static::$mode_default_cli, + 'plugins' => static::$plugins, + 'renderers' => static::$renderers, + 'return' => static::$return, + ]; } /** @@ -325,7 +327,7 @@ public static function createFromStatics(array $statics) if (isset($statics['enabled_mode'])) { $mode = $statics['enabled_mode']; - if (true === $statics['enabled_mode'] && isset($statics['mode_default'])) { + if (true === $mode && isset($statics['mode_default'])) { $mode = $statics['mode_default']; if (PHP_SAPI === 'cli' && !empty($statics['cli_detection']) && isset($statics['mode_default_cli'])) { @@ -334,7 +336,7 @@ public static function createFromStatics(array $statics) } } - if (!$mode) { + if (false === $mode) { return null; } @@ -345,7 +347,8 @@ public static function createFromStatics(array $statics) $renderer = new $statics['renderers'][$mode](); } - return new self(new Parser(), $renderer); + /** @psalm-suppress UnsafeInstantiation */ + return new static(new Parser(), $renderer); } /** @@ -354,11 +357,11 @@ public static function createFromStatics(array $statics) * @param array $params Parameters as returned from getCallInfo * @param int $argc Number of arguments the helper was called with * - * @return BasicObject[] Base objects for the arguments + * @return Value[] Base objects for the arguments */ public static function getBasesFromParamInfo(array $params, $argc) { - static $blacklist = array( + static $blacklist = [ 'null', 'true', 'false', @@ -372,10 +375,10 @@ public static function getBasesFromParamInfo(array $params, $argc) 'b"..."', "'...'", "b'...'", - ); + ]; $params = \array_values($params); - $bases = array(); + $bases = []; for ($i = 0; $i < $argc; ++$i) { if (isset($params[$i])) { @@ -402,7 +405,7 @@ public static function getBasesFromParamInfo(array $params, $argc) $access_path = '$'.$i; } - $bases[] = BasicObject::blank($name, $access_path); + $bases[] = Value::blank($name, $access_path); } return $bases; @@ -424,23 +427,21 @@ public static function getCallInfo(array $aliases, array $trace, $argc) $found = false; $callee = null; $caller = null; - $miniTrace = array(); + $miniTrace = []; foreach ($trace as $index => $frame) { if (Utils::traceFrameIsListed($frame, $aliases)) { $found = true; - $miniTrace = array(); + $miniTrace = []; } - if (!Utils::traceFrameIsListed($frame, array('spl_autoload_call'))) { + if (!Utils::traceFrameIsListed($frame, ['spl_autoload_call'])) { $miniTrace[] = $frame; } } if ($found) { $callee = \reset($miniTrace) ?: null; - - /** @var null|array Psalm bug workaround */ $caller = \next($miniTrace) ?: null; } @@ -455,15 +456,15 @@ public static function getCallInfo(array $aliases, array $trace, $argc) $miniTrace = \array_values($miniTrace); - $call = self::getSingleCall($callee ?: array(), $argc); + $call = static::getSingleCall($callee ?: [], $argc); - $ret = array( + $ret = [ 'params' => null, - 'modifiers' => array(), + 'modifiers' => [], 'callee' => $callee, 'caller' => $caller, 'trace' => $miniTrace, - ); + ]; if ($call) { $ret['params'] = $call['parameters']; @@ -482,23 +483,21 @@ public static function getCallInfo(array $aliases, array $trace, $argc) */ public static function trace() { - if (!self::$enabled_mode) { + if (false === static::$enabled_mode) { return 0; } - Utils::normalizeAliases(self::$aliases); - - $args = \func_get_args(); + Utils::normalizeAliases(static::$aliases); - $call_info = self::getCallInfo(self::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); + $call_info = static::getCallInfo(static::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \func_num_args()); - $statics = self::getStatics(); + $statics = static::getStatics(); if (\in_array('~', $call_info['modifiers'], true)) { - $statics['enabled_mode'] = self::MODE_TEXT; + $statics['enabled_mode'] = static::MODE_TEXT; } - $kintstance = self::createFromStatics($statics); + $kintstance = static::createFromStatics($statics); if (!$kintstance) { // Should never happen return 0; // @codeCoverageIgnore @@ -513,23 +512,25 @@ public static function trace() $kintstance->setStatesFromStatics($statics); $kintstance->setStatesFromCallInfo($call_info); - $trimmed_trace = array(); - $trace = \debug_backtrace(true); + $trimmed_trace = []; + $trace = \debug_backtrace(); foreach ($trace as $frame) { - if (Utils::traceFrameIsListed($frame, self::$aliases)) { - $trimmed_trace = array(); + if (Utils::traceFrameIsListed($frame, static::$aliases)) { + $trimmed_trace = []; } $trimmed_trace[] = $frame; } + \array_shift($trimmed_trace); + $output = $kintstance->dumpAll( - array($trimmed_trace), - array(BasicObject::blank('Kint\\Kint::trace()', 'debug_backtrace(true)')) + [$trimmed_trace], + [Value::blank('Kint\\Kint::trace()', 'debug_backtrace()')] ); - if (self::$return || \in_array('@', $call_info['modifiers'], true)) { + if (static::$return || \in_array('@', $call_info['modifiers'], true)) { return $output; } @@ -545,29 +546,29 @@ public static function trace() /** * Dumps some data. * - * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace(true)) + * Functionally equivalent to Kint::dump(1) or Kint::dump(debug_backtrace()) * * @return int|string */ public static function dump() { - if (!self::$enabled_mode) { + if (false === static::$enabled_mode) { return 0; } - Utils::normalizeAliases(self::$aliases); + Utils::normalizeAliases(static::$aliases); $args = \func_get_args(); - $call_info = self::getCallInfo(self::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); + $call_info = static::getCallInfo(static::$aliases, \debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS), \count($args)); - $statics = self::getStatics(); + $statics = static::getStatics(); if (\in_array('~', $call_info['modifiers'], true)) { - $statics['enabled_mode'] = self::MODE_TEXT; + $statics['enabled_mode'] = static::MODE_TEXT; } - $kintstance = self::createFromStatics($statics); + $kintstance = static::createFromStatics($statics); if (!$kintstance) { // Should never happen return 0; // @codeCoverageIgnore @@ -582,40 +583,13 @@ public static function dump() $kintstance->setStatesFromStatics($statics); $kintstance->setStatesFromCallInfo($call_info); - // If the call is Kint::dump(1) then dump a backtrace instead - if ($args === array(1) && (!isset($call_info['params'][0]['name']) || '1' === $call_info['params'][0]['name'])) { - $args = \debug_backtrace(true); - $trace = array(); - - foreach ($args as $index => $frame) { - if (Utils::traceFrameIsListed($frame, self::$aliases)) { - $trace = array(); - } - - $trace[] = $frame; - } - - if (isset($call_info['callee']['function'])) { - $tracename = $call_info['callee']['function'].'(1)'; - if (isset($call_info['callee']['class'], $call_info['callee']['type'])) { - $tracename = $call_info['callee']['class'].$call_info['callee']['type'].$tracename; - } - } else { - $tracename = 'Kint\\Kint::dump(1)'; - } - - $tracebase = BasicObject::blank($tracename, 'debug_backtrace(true)'); - - $output = $kintstance->dumpAll(array($trace), array($tracebase)); - } else { - $bases = self::getBasesFromParamInfo( - isset($call_info['params']) ? $call_info['params'] : array(), - \count($args) - ); - $output = $kintstance->dumpAll($args, $bases); - } + $bases = static::getBasesFromParamInfo( + isset($call_info['params']) ? $call_info['params'] : [], + \count($args) + ); + $output = $kintstance->dumpAll($args, $bases); - if (self::$return || \in_array('@', $call_info['modifiers'], true)) { + if (static::$return || \in_array('@', $call_info['modifiers'], true)) { return $output; } @@ -643,7 +617,7 @@ public static function shortenPath($file) $longest_match = 0; $match = '/'; - foreach (self::$app_root_dirs as $path => $alias) { + foreach (static::$app_root_dirs as $path => $alias) { if (empty($path)) { continue; } @@ -657,7 +631,7 @@ public static function shortenPath($file) } if ($longest_match) { - $file = \array_merge(array($match), \array_slice($file, $longest_match)); + $file = \array_merge([$match], \array_slice($file, $longest_match)); return \implode('/', $file); } @@ -676,7 +650,7 @@ public static function shortenPath($file) public static function getIdeLink($file, $line) { - return \str_replace(array('%f', '%l'), array($file, $line), self::$file_link_format); + return \str_replace(['%f', '%l'], [$file, $line], static::$file_link_format); } /** @@ -696,7 +670,7 @@ protected static function getSingleCall(array $frame, $argc) if (empty($frame['class'])) { $callfunc = $frame['function']; } else { - $callfunc = array($frame['class'], $frame['function']); + $callfunc = [$frame['class'], $frame['function']]; } $calls = CallFinder::getFunctionCalls( @@ -711,32 +685,30 @@ protected static function getSingleCall(array $frame, $argc) $is_unpack = false; // Handle argument unpacking as a last resort - if (KINT_PHP56) { - foreach ($call['parameters'] as $i => &$param) { - if (0 === \strpos($param['name'], '...')) { - if ($i < $argc && $i === \count($call['parameters']) - 1) { - for ($j = 1; $j + $i < $argc; ++$j) { - $call['parameters'][] = array( - 'name' => 'array_values('.\substr($param['name'], 3).')['.$j.']', - 'path' => 'array_values('.\substr($param['path'], 3).')['.$j.']', - 'expression' => false, - ); - } - - $param['name'] = 'reset('.\substr($param['name'], 3).')'; - $param['path'] = 'reset('.\substr($param['path'], 3).')'; - $param['expression'] = false; - } else { - $call['parameters'] = \array_slice($call['parameters'], 0, $i); + foreach ($call['parameters'] as $i => &$param) { + if (0 === \strpos($param['name'], '...')) { + if ($i < $argc && $i === \count($call['parameters']) - 1) { + for ($j = 1; $j + $i < $argc; ++$j) { + $call['parameters'][] = [ + 'name' => 'array_values('.\substr($param['name'], 3).')['.$j.']', + 'path' => 'array_values('.\substr($param['path'], 3).')['.$j.']', + 'expression' => false, + ]; } - $is_unpack = true; - break; + $param['name'] = 'reset('.\substr($param['name'], 3).')'; + $param['path'] = 'reset('.\substr($param['path'], 3).')'; + $param['expression'] = false; + } else { + $call['parameters'] = \array_slice($call['parameters'], 0, $i); } - if ($i >= $argc) { - continue 2; - } + $is_unpack = true; + break; + } + + if ($i >= $argc) { + continue 2; } } diff --git a/system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php b/system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php new file mode 100644 index 000000000000..4fa94c63c3b9 --- /dev/null +++ b/system/ThirdParty/Kint/Parser/ArrayLimitPlugin.php @@ -0,0 +1,142 @@ += self::$trigger) { + throw new InvalidArgumentException('ArrayLimitPlugin::$limit can not be lower than ArrayLimitPlugin::$trigger'); + } + + $depth = $this->parser->getDepthLimit(); + + if (!$depth) { + return; + } + + if ($o->depth >= $depth - 1) { + return; + } + + if (\count($var) < self::$trigger) { + return; + } + + if (self::$numeric_only && Utils::isAssoc($var)) { + return; + } + + $base = clone $o; + $base->depth = $depth - 1; + $obj = $this->parser->parse($var, $base); + + if (!$obj instanceof Value || 'array' != $obj->type) { + return; // @codeCoverageIgnore + } + + $obj->depth = $o->depth; + $i = 0; + + foreach ($obj->value->contents as $child) { + // We only bother setting the correct depth for the first child, + // any deeper children should be cancelled by the depth limit + $child->depth = $o->depth + 1; + $this->recalcDepthLimit($child); + } + + $var2 = \array_slice($var, 0, self::$limit, true); + $base = clone $o; + $slice = $this->parser->parse($var2, $base); + + \array_splice($obj->value->contents, 0, self::$limit, $slice->value->contents); + + $o = $obj; + + $this->parser->haltParse(); + } + + protected function recalcDepthLimit(Value $o) + { + $hintkey = \array_search('depth_limit', $o->hints, true); + if (false !== $hintkey) { + $o->hints[$hintkey] = 'array_limit'; + } + + $reps = $o->getRepresentations(); + if ($o->value) { + $reps[] = $o->value; + } + + foreach ($reps as $rep) { + if ($rep->contents instanceof Value) { + $this->recalcDepthLimit($rep->contents); + } elseif (\is_array($rep->contents)) { + foreach ($rep->contents as $child) { + if ($child instanceof Value) { + $this->recalcDepthLimit($child); + } + } + } + } + } +} diff --git a/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php b/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php index 286d255b16b9..f32b4fada23a 100644 --- a/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php +++ b/system/ThirdParty/Kint/Parser/ArrayObjectPlugin.php @@ -26,13 +26,13 @@ namespace Kint\Parser; use ArrayObject; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class ArrayObjectPlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_BEGIN; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof ArrayObject) { return; diff --git a/system/ThirdParty/Kint/Parser/Base64Plugin.php b/system/ThirdParty/Kint/Parser/Base64Plugin.php index 3d7d6bc29011..5208d7ddef4a 100644 --- a/system/ThirdParty/Kint/Parser/Base64Plugin.php +++ b/system/ThirdParty/Kint/Parser/Base64Plugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class Base64Plugin extends Plugin { @@ -46,7 +46,7 @@ class Base64Plugin extends Plugin public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -54,7 +54,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\strlen($var) < self::$min_length_hard || \strlen($var) % 4) { return; @@ -68,14 +68,13 @@ public function parse(&$var, BasicObject &$o, $trigger) return; } - /** @var false|string */ $data = \base64_decode($var, true); if (false === $data) { return; } - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = 'base64_decode('.$o->name.')'; diff --git a/system/ThirdParty/Kint/Parser/BinaryPlugin.php b/system/ThirdParty/Kint/Parser/BinaryPlugin.php index 327c297cd560..9a6b117ba50e 100644 --- a/system/ThirdParty/Kint/Parser/BinaryPlugin.php +++ b/system/ThirdParty/Kint/Parser/BinaryPlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; +use Kint\Zval\BlobValue; +use Kint\Zval\Value; class BinaryPlugin extends Plugin { public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -40,9 +40,9 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - if (!$o instanceof BlobObject || !\in_array($o->encoding, array('ASCII', 'UTF-8'), true)) { + if (!$o instanceof BlobValue || !\in_array($o->encoding, ['ASCII', 'UTF-8'], true)) { $o->value->hints[] = 'binary'; } } diff --git a/system/ThirdParty/Kint/Parser/BlacklistPlugin.php b/system/ThirdParty/Kint/Parser/BlacklistPlugin.php index b37e45ff6fbf..9c472d43e798 100644 --- a/system/ThirdParty/Kint/Parser/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Parser/BlacklistPlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; +use Kint\Zval\InstanceValue; +use Kint\Zval\Value; class BlacklistPlugin extends Plugin { @@ -35,32 +35,18 @@ class BlacklistPlugin extends Plugin * * @var array */ - public static $blacklist = array(); + public static $blacklist = []; /** * List of classes and interfaces to blacklist except when dumped directly. * * @var array */ - public static $shallow_blacklist = array(); - - /** - * Maximum size of arrays before blacklisting. - * - * @var int - */ - public static $array_limit = 10000; - - /** - * Maximum size of arrays before blacklisting except when dumped directly. - * - * @var int - */ - public static $shallow_array_limit = 1000; + public static $shallow_blacklist = ['Psr\\Container\\ContainerInterface']; public function getTypes() { - return array('object', 'array'); + return ['object']; } public function getTriggers() @@ -68,21 +54,11 @@ public function getTriggers() return Parser::TRIGGER_BEGIN; } - public function parse(&$var, BasicObject &$o, $trigger) - { - if (\is_object($var)) { - return $this->parseObject($var, $o); - } - if (\is_array($var)) { - return $this->parseArray($var, $o); - } - } - - protected function parseObject(&$var, BasicObject &$o) + public function parse(&$var, Value &$o, $trigger) { foreach (self::$blacklist as $class) { if ($var instanceof $class) { - return $this->blacklistObject($var, $o); + return $this->blacklistValue($var, $o); } } @@ -92,17 +68,17 @@ protected function parseObject(&$var, BasicObject &$o) foreach (self::$shallow_blacklist as $class) { if ($var instanceof $class) { - return $this->blacklistObject($var, $o); + return $this->blacklistValue($var, $o); } } } - protected function blacklistObject(&$var, BasicObject &$o) + protected function blacklistValue(&$var, Value &$o) { - $object = new InstanceObject(); + $object = new InstanceValue(); $object->transplant($o); $object->classname = \get_class($var); - $object->hash = \spl_object_hash($var); + $object->spl_object_hash = \spl_object_hash($var); $object->clearRepresentations(); $object->value = null; $object->size = null; @@ -112,32 +88,4 @@ protected function blacklistObject(&$var, BasicObject &$o) $this->parser->haltParse(); } - - protected function parseArray(array &$var, BasicObject &$o) - { - if (\count($var) > self::$array_limit) { - return $this->blacklistArray($var, $o); - } - - if ($o->depth <= 0) { - return; - } - - if (\count($var) > self::$shallow_array_limit) { - return $this->blacklistArray($var, $o); - } - } - - protected function blacklistArray(array &$var, BasicObject &$o) - { - $object = new BasicObject(); - $object->transplant($o); - $object->value = null; - $object->size = \count($var); - $object->hints[] = 'blacklist'; - - $o = $object; - - $this->parser->haltParse(); - } } diff --git a/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php b/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php index e4c23716186a..152e59d9c762 100644 --- a/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php +++ b/system/ThirdParty/Kint/Parser/ClassMethodsPlugin.php @@ -25,19 +25,19 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; -use Kint\Object\MethodObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\InstanceValue; +use Kint\Zval\MethodValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionClass; class ClassMethodsPlugin extends Plugin { - private static $cache = array(); + private static $cache = []; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -45,21 +45,21 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $class = \get_class($var); // assuming class definition will not change inside one request if (!isset(self::$cache[$class])) { - $methods = array(); + $methods = []; $reflection = new ReflectionClass($class); foreach ($reflection->getMethods() as $method) { - $methods[] = new MethodObject($method); + $methods[] = new MethodValue($method); } - \usort($methods, array('Kint\\Parser\\ClassMethodsPlugin', 'sort')); + \usort($methods, ['Kint\\Parser\\ClassMethodsPlugin', 'sort']); self::$cache[$class] = $methods; } @@ -91,19 +91,19 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - private static function sort(MethodObject $a, MethodObject $b) + private static function sort(MethodValue $a, MethodValue $b) { $sort = ((int) $a->static) - ((int) $b->static); if ($sort) { return $sort; } - $sort = BasicObject::sortByAccess($a, $b); + $sort = Value::sortByAccess($a, $b); if ($sort) { return $sort; } - $sort = InstanceObject::sortByHierarchy($a->owner_class, $b->owner_class); + $sort = InstanceValue::sortByHierarchy($a->owner_class, $b->owner_class); if ($sort) { return $sort; } diff --git a/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php b/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php index 0ba58ca24874..89601af2f9f7 100644 --- a/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php +++ b/system/ThirdParty/Kint/Parser/ClassStaticsPlugin.php @@ -25,19 +25,19 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionClass; use ReflectionProperty; class ClassStaticsPlugin extends Plugin { - private static $cache = array(); + private static $cache = []; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -45,7 +45,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $class = \get_class($var); $reflection = new ReflectionClass($class); @@ -53,14 +53,14 @@ public function parse(&$var, BasicObject &$o, $trigger) // Constants // TODO: PHP 7.1 allows private consts but reflection doesn't have a way to check them yet if (!isset(self::$cache[$class])) { - $consts = array(); + $consts = []; foreach ($reflection->getConstants() as $name => $val) { - $const = BasicObject::blank($name, '\\'.$class.'::'.$name); + $const = Value::blank($name, '\\'.$class.'::'.$name); $const->const = true; $const->depth = $o->depth + 1; $const->owner_class = $class; - $const->operator = BasicObject::OPERATOR_STATIC; + $const->operator = Value::OPERATOR_STATIC; $const = $this->parser->parse($val, $const); $consts[] = $const; @@ -73,18 +73,18 @@ public function parse(&$var, BasicObject &$o, $trigger) $statics->contents = self::$cache[$class]; foreach ($reflection->getProperties(ReflectionProperty::IS_STATIC) as $static) { - $prop = new BasicObject(); + $prop = new Value(); $prop->name = '$'.$static->getName(); $prop->depth = $o->depth + 1; $prop->static = true; - $prop->operator = BasicObject::OPERATOR_STATIC; + $prop->operator = Value::OPERATOR_STATIC; $prop->owner_class = $static->getDeclaringClass()->name; - $prop->access = BasicObject::ACCESS_PUBLIC; + $prop->access = Value::ACCESS_PUBLIC; if ($static->isProtected()) { - $prop->access = BasicObject::ACCESS_PROTECTED; + $prop->access = Value::ACCESS_PROTECTED; } elseif ($static->isPrivate()) { - $prop->access = BasicObject::ACCESS_PRIVATE; + $prop->access = Value::ACCESS_PRIVATE; } if ($this->parser->childHasPath($o, $prop)) { @@ -92,31 +92,37 @@ public function parse(&$var, BasicObject &$o, $trigger) } $static->setAccessible(true); - $static = $static->getValue(); - $statics->contents[] = $this->parser->parse($static, $prop); + + if (KINT_PHP74 && !$static->isInitialized()) { + $prop->type = 'uninitialized'; + $statics->contents[] = $prop; + } else { + $static = $static->getValue(); + $statics->contents[] = $this->parser->parse($static, $prop); + } } if (empty($statics->contents)) { return; } - \usort($statics->contents, array('Kint\\Parser\\ClassStaticsPlugin', 'sort')); + \usort($statics->contents, ['Kint\\Parser\\ClassStaticsPlugin', 'sort']); $o->addRepresentation($statics); } - private static function sort(BasicObject $a, BasicObject $b) + private static function sort(Value $a, Value $b) { $sort = ((int) $a->const) - ((int) $b->const); if ($sort) { return $sort; } - $sort = BasicObject::sortByAccess($a, $b); + $sort = Value::sortByAccess($a, $b); if ($sort) { return $sort; } - return InstanceObject::sortByHierarchy($a->owner_class, $b->owner_class); + return InstanceValue::sortByHierarchy($a->owner_class, $b->owner_class); } } diff --git a/system/ThirdParty/Kint/Parser/ClosurePlugin.php b/system/ThirdParty/Kint/Parser/ClosurePlugin.php index 73e367b22b03..f4a68f5db737 100644 --- a/system/ThirdParty/Kint/Parser/ClosurePlugin.php +++ b/system/ThirdParty/Kint/Parser/ClosurePlugin.php @@ -26,17 +26,17 @@ namespace Kint\Parser; use Closure; -use Kint\Object\BasicObject; -use Kint\Object\ClosureObject; -use Kint\Object\ParameterObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\ClosureValue; +use Kint\Zval\ParameterValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionFunction; class ClosurePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -44,13 +44,13 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Closure) { return; } - $object = new ClosureObject(); + $object = new ClosureValue(); $object->transplant($o); $o = $object; $object->removeRepresentation('properties'); @@ -61,24 +61,24 @@ public function parse(&$var, BasicObject &$o, $trigger) $o->startline = $closure->getStartLine(); foreach ($closure->getParameters() as $param) { - $o->parameters[] = new ParameterObject($param); + $o->parameters[] = new ParameterValue($param); } $p = new Representation('Parameters'); $p->contents = &$o->parameters; $o->addRepresentation($p, 0); - $statics = array(); + $statics = []; - if (\method_exists($closure, 'getClosureThis') && $v = $closure->getClosureThis()) { - $statics = array('this' => $v); + if ($v = $closure->getClosureThis()) { + $statics = ['this' => $v]; } if (\count($statics = $statics + $closure->getStaticVariables())) { - $statics_parsed = array(); + $statics_parsed = []; foreach ($statics as $name => &$static) { - $obj = BasicObject::blank('$'.$name); + $obj = Value::blank('$'.$name); $obj->depth = $o->depth + 1; $statics_parsed[$name] = $this->parser->parse($static, $obj); if (null === $statics_parsed[$name]->value) { diff --git a/system/ThirdParty/Kint/Parser/ColorPlugin.php b/system/ThirdParty/Kint/Parser/ColorPlugin.php index 0d748f2c35f2..a00b338c4708 100644 --- a/system/ThirdParty/Kint/Parser/ColorPlugin.php +++ b/system/ThirdParty/Kint/Parser/ColorPlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\ColorRepresentation; +use Kint\Zval\Representation\ColorRepresentation; +use Kint\Zval\Value; class ColorPlugin extends Plugin { public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\strlen($var) > 32) { return; diff --git a/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php b/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php index ec08d311ffef..53329820f787 100644 --- a/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php +++ b/system/ThirdParty/Kint/Parser/DOMDocumentPlugin.php @@ -28,9 +28,10 @@ use DOMNamedNodeMap; use DOMNode; use DOMNodeList; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\BlobValue; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; /** * The DOMDocument parser plugin is particularly useful as it is both the only @@ -63,14 +64,14 @@ class DOMDocumentPlugin extends Plugin * * @var array */ - public static $blacklist = array( + public static $blacklist = [ 'parentNode' => 'DOMNode', 'firstChild' => 'DOMNode', 'lastChild' => 'DOMNode', 'previousSibling' => 'DOMNode', 'nextSibling' => 'DOMNode', 'ownerDocument' => 'DOMDocument', - ); + ]; /** * Show all properties and methods. @@ -81,7 +82,7 @@ class DOMDocumentPlugin extends Plugin public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -89,9 +90,9 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - if (!$o instanceof InstanceObject) { + if (!$o instanceof InstanceValue) { return; } @@ -104,10 +105,10 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - protected function parseList(&$var, InstanceObject &$o, $trigger) + protected function parseList(&$var, InstanceValue &$o, $trigger) { // Recursion should never happen, should always be stopped at the parent - // DOMNode. Depth limit on the other hand we're going to skip since + // DOMNode. Depth limit on the other hand we're going to skip since // that would show an empty iterator and rather useless. Let the depth // limit hit the children (DOMNodeList only has DOMNode as children) if ($trigger & Parser::TRIGGER_RECURSION) { @@ -125,36 +126,42 @@ protected function parseList(&$var, InstanceObject &$o, $trigger) // Depth limit // Make empty iterator representation since we need it in DOMNode to point out depth limits if ($this->parser->getDepthLimit() && $o->depth + 1 >= $this->parser->getDepthLimit()) { - $b = new BasicObject(); + $b = new Value(); $b->name = $o->classname.' Iterator Contents'; $b->access_path = 'iterator_to_array('.$o->access_path.')'; $b->depth = $o->depth + 1; $b->hints[] = 'depth_limit'; $r = new Representation('Iterator'); - $r->contents = array($b); + $r->contents = [$b]; $o->replaceRepresentation($r, 0); return; } - $data = \iterator_to_array($var); - $r = new Representation('Iterator'); $o->replaceRepresentation($r, 0); - foreach ($data as $key => $item) { - $base_obj = new BasicObject(); + foreach ($var as $key => $item) { + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = $item->nodeName; if ($o->access_path) { if ($var instanceof DOMNamedNodeMap) { - $base_obj->access_path = $o->access_path.'->getNamedItem('.\var_export($key, true).')'; + // We can't use getNamedItem() for attributes without a + // namespace because it will pick the first matching + // attribute of *any* namespace. + // + // Contrary to the PHP docs, getNamedItemNS takes null + // as a namespace argument for an unnamespaced item. + $base_obj->access_path = $o->access_path.'->getNamedItemNS('; + $base_obj->access_path .= \var_export($item->namespaceURI, true); + $base_obj->access_path .= ', '; + $base_obj->access_path .= \var_export($item->name, true); + $base_obj->access_path .= ')'; } elseif ($var instanceof DOMNodeList) { $base_obj->access_path = $o->access_path.'->item('.\var_export($key, true).')'; - } else { - $base_obj->access_path = 'iterator_to_array('.$o->access_path.')'; } } @@ -162,19 +169,19 @@ protected function parseList(&$var, InstanceObject &$o, $trigger) } } - protected function parseNode(&$var, InstanceObject &$o) + protected function parseNode(&$var, InstanceValue &$o) { // Fill the properties // They can't be enumerated through reflection or casting, // so we have to trust the docs and try them one at a time - $known_properties = array( + $known_properties = [ 'nodeValue', 'childNodes', 'attributes', - ); + ]; if (self::$verbose) { - $known_properties = array( + $known_properties = [ 'nodeName', 'nodeValue', 'nodeType', @@ -191,11 +198,11 @@ protected function parseNode(&$var, InstanceObject &$o) 'localName', 'baseURI', 'textContent', - ); + ]; } - $childNodes = array(); - $attributes = array(); + $childNodes = null; + $attributes = null; $rep = $o->value; @@ -217,7 +224,9 @@ protected function parseNode(&$var, InstanceObject &$o) // Attributes and comments and text nodes don't // need children or attributes of their own - if (\in_array($o->classname, array('DOMAttr', 'DOMText', 'DOMComment'), true)) { + if (\in_array($o->classname, ['DOMAttr', 'DOMText', 'DOMComment'], true)) { + $o = self::textualNodeToString($o); + return; } @@ -225,7 +234,7 @@ protected function parseNode(&$var, InstanceObject &$o) if ($attributes) { $a = new Representation('Attributes'); foreach ($attributes->contents as $attribute) { - $a->contents[] = self::textualNodeToString($attribute); + $a->contents[] = $attribute; } $o->addRepresentation($a, 0); } @@ -235,21 +244,16 @@ protected function parseNode(&$var, InstanceObject &$o) $c = new Representation('Children'); if (1 === \count($childNodes->contents) && ($node = \reset($childNodes->contents)) && \in_array('depth_limit', $node->hints, true)) { - $n = new InstanceObject(); + $n = new InstanceValue(); $n->transplant($node); $n->name = 'childNodes'; $n->classname = 'DOMNodeList'; - $c->contents = array($n); + $c->contents = [$n]; } else { - foreach ($childNodes->contents as $index => $node) { - // Shortcircuit text nodes to plain strings - if ('DOMText' === $node->classname || 'DOMComment' === $node->classname) { - $node = self::textualNodeToString($node); - - // And remove them if they're empty - if (\ctype_space($node->value->contents) || '' === $node->value->contents) { - continue; - } + foreach ($childNodes->contents as $node) { + // Remove text nodes if theyre empty + if ($node instanceof BlobValue && '#text' === $node->name && (\ctype_space($node->value->contents) || '' === $node->value->contents)) { + continue; } $c->contents[] = $node; @@ -259,8 +263,8 @@ protected function parseNode(&$var, InstanceObject &$o) $o->addRepresentation($c, 0); } - if (isset($c) && \count($c->contents)) { - $o->size = \count($c->contents); + if ($childNodes) { + $o->size = \count($childNodes->contents); } if (!$o->size) { @@ -268,15 +272,15 @@ protected function parseNode(&$var, InstanceObject &$o) } } - protected function parseProperty(InstanceObject $o, $prop, &$var) + protected function parseProperty(InstanceValue $o, $prop, &$var) { // Duplicating (And slightly optimizing) the Parser::parseObject() code here - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->owner_class = $o->classname; $base_obj->name = $prop; - $base_obj->operator = BasicObject::OPERATOR_OBJECT; - $base_obj->access = BasicObject::ACCESS_PUBLIC; + $base_obj->operator = Value::OPERATOR_OBJECT; + $base_obj->access = Value::ACCESS_PUBLIC; if (null !== $o->access_path) { $base_obj->access_path = $o->access_path; @@ -291,14 +295,19 @@ protected function parseProperty(InstanceObject $o, $prop, &$var) if (!isset($var->{$prop})) { $base_obj->type = 'null'; } elseif (isset(self::$blacklist[$prop])) { - $b = new InstanceObject(); + $b = new InstanceValue(); $b->transplant($base_obj); $base_obj = $b; $base_obj->hints[] = 'blacklist'; $base_obj->classname = self::$blacklist[$prop]; } elseif ('attributes' === $prop) { - $base_obj = $this->parser->parseDeep($var->{$prop}, $base_obj); + // Attributes are strings. If we're too deep set the + // depth limit to enable parsing them, but no deeper. + if ($this->parser->getDepthLimit() && $this->parser->getDepthLimit() - 2 < $base_obj->depth) { + $base_obj->depth = $this->parser->getDepthLimit() - 2; + } + $base_obj = $this->parser->parse($var->{$prop}, $base_obj); } else { $base_obj = $this->parser->parse($var->{$prop}, $base_obj); } @@ -306,13 +315,13 @@ protected function parseProperty(InstanceObject $o, $prop, &$var) return $base_obj; } - protected static function textualNodeToString(InstanceObject $o) + protected static function textualNodeToString(InstanceValue $o) { if (empty($o->value) || empty($o->value->contents) || empty($o->classname)) { return; } - if (!\in_array($o->classname, array('DOMText', 'DOMAttr', 'DOMComment'), true)) { + if (!\in_array($o->classname, ['DOMText', 'DOMAttr', 'DOMComment'], true)) { return; } diff --git a/system/ThirdParty/Kint/Parser/DateTimePlugin.php b/system/ThirdParty/Kint/Parser/DateTimePlugin.php index f2cebb643cb9..1c546fd7d2a1 100644 --- a/system/ThirdParty/Kint/Parser/DateTimePlugin.php +++ b/system/ThirdParty/Kint/Parser/DateTimePlugin.php @@ -26,14 +26,14 @@ namespace Kint\Parser; use DateTime; -use Kint\Object\BasicObject; -use Kint\Object\DateTimeObject; +use Kint\Zval\DateTimeValue; +use Kint\Zval\Value; class DateTimePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -41,13 +41,13 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof DateTime) { return; } - $object = new DateTimeObject($var); + $object = new DateTimeValue($var); $object->transplant($o); $o = $object; diff --git a/system/ThirdParty/Kint/Parser/FsPathPlugin.php b/system/ThirdParty/Kint/Parser/FsPathPlugin.php index 3a8d1e0538c2..79ed3288ca9a 100644 --- a/system/ThirdParty/Kint/Parser/FsPathPlugin.php +++ b/system/ThirdParty/Kint/Parser/FsPathPlugin.php @@ -25,17 +25,17 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\SplFileInfoRepresentation; +use Kint\Zval\Representation\SplFileInfoRepresentation; +use Kint\Zval\Value; use SplFileInfo; class FsPathPlugin extends Plugin { - public static $blacklist = array('/', '.'); + public static $blacklist = ['/', '.']; public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -43,7 +43,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\strlen($var) > 2048) { return; diff --git a/system/ThirdParty/Kint/Parser/IteratorPlugin.php b/system/ThirdParty/Kint/Parser/IteratorPlugin.php index 0487a381f5b9..8aa1c342f5ce 100644 --- a/system/ThirdParty/Kint/Parser/IteratorPlugin.php +++ b/system/ThirdParty/Kint/Parser/IteratorPlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use Traversable; class IteratorPlugin extends Plugin @@ -40,17 +40,17 @@ class IteratorPlugin extends Plugin * * @var array */ - public static $blacklist = array( + public static $blacklist = [ 'DOMNamedNodeMap', 'DOMNodeList', 'mysqli_result', 'PDOStatement', 'SplFileObject', - ); + ]; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -58,7 +58,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Traversable) { return; @@ -66,14 +66,14 @@ public function parse(&$var, BasicObject &$o, $trigger) foreach (self::$blacklist as $class) { if ($var instanceof $class) { - $b = new BasicObject(); + $b = new Value(); $b->name = $class.' Iterator Contents'; $b->access_path = 'iterator_to_array('.$o->access_path.', true)'; $b->depth = $o->depth + 1; $b->hints[] = 'blacklist'; $r = new Representation('Iterator'); - $r->contents = array($b); + $r->contents = [$b]; $o->addRepresentation($r); @@ -81,14 +81,9 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - /** @var array|false */ $data = \iterator_to_array($var); - if (false === $data) { - return; - } - - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth; if ($o->access_path) { @@ -101,7 +96,7 @@ public function parse(&$var, BasicObject &$o, $trigger) $primary = $o->getRepresentations(); $primary = \reset($primary); - if ($primary && $primary === $o->value && $primary->contents === array()) { + if ($primary && $primary === $o->value && [] === $primary->contents) { $o->addRepresentation($r, 0); } else { $o->addRepresentation($r); diff --git a/system/ThirdParty/Kint/Parser/JsonPlugin.php b/system/ThirdParty/Kint/Parser/JsonPlugin.php index 84b251955383..a105b8fd6ff1 100644 --- a/system/ThirdParty/Kint/Parser/JsonPlugin.php +++ b/system/ThirdParty/Kint/Parser/JsonPlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class JsonPlugin extends Plugin { public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!isset($var[0]) || ('{' !== $var[0] && '[' !== $var[0])) { return; @@ -54,7 +54,7 @@ public function parse(&$var, BasicObject &$o, $trigger) $json = (array) $json; - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth; if ($o->access_path) { diff --git a/system/ThirdParty/Kint/Parser/MicrotimePlugin.php b/system/ThirdParty/Kint/Parser/MicrotimePlugin.php index 5062b59ad224..782c11f84f85 100644 --- a/system/ThirdParty/Kint/Parser/MicrotimePlugin.php +++ b/system/ThirdParty/Kint/Parser/MicrotimePlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\MicrotimeRepresentation; +use Kint\Zval\Representation\MicrotimeRepresentation; +use Kint\Zval\Value; class MicrotimePlugin extends Plugin { @@ -37,7 +37,7 @@ class MicrotimePlugin extends Plugin public function getTypes() { - return array('string', 'double'); + return ['string', 'double']; } public function getTriggers() @@ -45,7 +45,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (0 !== $o->depth) { return; @@ -79,7 +79,7 @@ public function parse(&$var, BasicObject &$o, $trigger) self::$start = $time; } - self::$last = array($sec, $usec); + self::$last = [$sec, $usec]; if (null !== $lap) { $total = $time - self::$start; diff --git a/system/ThirdParty/Kint/Parser/MysqliPlugin.php b/system/ThirdParty/Kint/Parser/MysqliPlugin.php index 265299bec6ee..4c95d790a772 100644 --- a/system/ThirdParty/Kint/Parser/MysqliPlugin.php +++ b/system/ThirdParty/Kint/Parser/MysqliPlugin.php @@ -25,8 +25,10 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; use Mysqli; +use ReflectionClass; +use Throwable; /** * Adds support for Mysqli object parsing. @@ -37,21 +39,21 @@ class MysqliPlugin extends Plugin { // These 'properties' are actually globals - protected $always_readable = array( + protected $always_readable = [ 'client_version' => true, 'connect_errno' => true, 'connect_error' => true, - ); + ]; // These are readable on empty mysqli objects, but not on failed connections - protected $empty_readable = array( + protected $empty_readable = [ 'client_info' => true, 'errno' => true, 'error' => true, - ); + ]; // These are only readable on connected mysqli objects - protected $connected_readable = array( + protected $connected_readable = [ 'affected_rows' => true, 'error_list' => true, 'field_count' => true, @@ -60,16 +62,15 @@ class MysqliPlugin extends Plugin 'insert_id' => true, 'server_info' => true, 'server_version' => true, - 'stat' => true, 'sqlstate' => true, 'protocol_version' => true, 'thread_id' => true, 'warning_count' => true, - ); + ]; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -77,19 +78,24 @@ public function getTriggers() return Parser::TRIGGER_COMPLETE; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Mysqli) { return; } - $connected = false; - $empty = false; + try { + $connected = \is_string(@$var->sqlstate); + } catch (Throwable $t) { + $connected = false; + } - if (\is_string(@$var->sqlstate)) { - $connected = true; - } elseif (\is_string(@$var->client_info)) { - $empty = true; + try { + $empty = !$connected && \is_string(@$var->client_info); + } catch (Throwable $t) { // @codeCoverageIgnore + // Only possible in PHP 8.0. Before 8.0 there's no exception, + // after 8.1 there are no failed connection objects + $empty = false; // @codeCoverageIgnore } foreach ($o->value->contents as $key => $obj) { @@ -98,8 +104,9 @@ public function parse(&$var, BasicObject &$o, $trigger) continue; } } elseif (isset($this->empty_readable[$obj->name])) { - if (!$connected && !$empty) { - continue; + // No failed connections after PHP 8.1 + if (!$connected && !$empty) { // @codeCoverageIgnore + continue; // @codeCoverageIgnore } } elseif (!isset($this->always_readable[$obj->name])) { continue; @@ -109,13 +116,17 @@ public function parse(&$var, BasicObject &$o, $trigger) continue; } + // @codeCoverageIgnoreStart + // All of this is irellevant after 8.1, + // we have separate logic for that below + $param = $var->{$obj->name}; if (null === $param) { continue; } - $base = BasicObject::blank($obj->name, $obj->access_path); + $base = Value::blank($obj->name, $obj->access_path); $base->depth = $obj->depth; $base->owner_class = $obj->owner_class; @@ -124,6 +135,55 @@ public function parse(&$var, BasicObject &$o, $trigger) $base->reference = $obj->reference; $o->value->contents[$key] = $this->parser->parse($param, $base); + + // @codeCoverageIgnoreEnd + } + + // PHP81 returns an empty array when casting a Mysqli instance + if (KINT_PHP81) { + $r = new ReflectionClass(Mysqli::class); + + $basepropvalues = []; + + foreach ($r->getProperties() as $prop) { + if ($prop->isStatic()) { + continue; // @codeCoverageIgnore + } + + $pname = $prop->getName(); + $param = null; + + if (isset($this->connected_readable[$pname])) { + if ($connected) { + $param = $var->{$pname}; + } + } else { + $param = $var->{$pname}; + } + + $child = new Value(); + $child->depth = $o->depth + 1; + $child->owner_class = Mysqli::class; + $child->operator = Value::OPERATOR_OBJECT; + $child->name = $pname; + + if ($prop->isPublic()) { + $child->access = Value::ACCESS_PUBLIC; + } elseif ($prop->isProtected()) { // @codeCoverageIgnore + $child->access = Value::ACCESS_PROTECTED; // @codeCoverageIgnore + } elseif ($prop->isPrivate()) { // @codeCoverageIgnore + $child->access = Value::ACCESS_PRIVATE; // @codeCoverageIgnore + } + + // We only do base Mysqli properties so we don't need to worry about complex names + if ($this->parser->childHasPath($o, $child)) { + $child->access_path .= $o->access_path.'->'.$child->name; + } + + $basepropvalues[] = $this->parser->parse($param, $child); + } + + $o->value->contents = \array_merge($basepropvalues, $o->value->contents); } } } diff --git a/system/ThirdParty/Kint/Parser/Parser.php b/system/ThirdParty/Kint/Parser/Parser.php index b7f81c62186f..d658b092479d 100644 --- a/system/ThirdParty/Kint/Parser/Parser.php +++ b/system/ThirdParty/Kint/Parser/Parser.php @@ -27,11 +27,11 @@ use DomainException; use Exception; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; -use Kint\Object\ResourceObject; +use Kint\Zval\BlobValue; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\ResourceValue; +use Kint\Zval\Value; use ReflectionObject; use stdClass; @@ -58,25 +58,22 @@ class Parser const TRIGGER_COMPLETE = 14; protected $caller_class; - protected $depth_limit = false; + protected $depth_limit = 0; protected $marker; - protected $object_hashes = array(); + protected $object_hashes = []; protected $parse_break = false; - protected $plugins = array(); + protected $plugins = []; /** - * @param false|int $depth_limit Maximum depth to parse data + * @param int $depth_limit Maximum depth to parse data * @param null|string $caller Caller class name */ - public function __construct($depth_limit = false, $caller = null) + public function __construct($depth_limit = 0, $caller = null) { $this->marker = \uniqid("kint\0", true); + $this->depth_limit = $depth_limit; $this->caller_class = $caller; - - if ($depth_limit) { - $this->depth_limit = $depth_limit; - } } /** @@ -99,9 +96,9 @@ public function getCallerClass() /** * Set the depth limit. * - * @param false|int $depth_limit Maximum depth to parse data + * @param int $depth_limit Maximum depth to parse data */ - public function setDepthLimit($depth_limit = false) + public function setDepthLimit($depth_limit = 0) { $this->noRecurseCall(); @@ -113,37 +110,15 @@ public function getDepthLimit() return $this->depth_limit; } - /** - * Disables the depth limit and parses a variable. - * - * This should not be used unless you know what you're doing! - * - * @param mixed $var The input variable - * @param BasicObject $o The base object - * - * @return BasicObject - */ - public function parseDeep(&$var, BasicObject $o) - { - $depth_limit = $this->depth_limit; - $this->depth_limit = false; - - $out = $this->parse($var, $o); - - $this->depth_limit = $depth_limit; - - return $out; - } - /** * Parses a variable into a Kint object structure. * - * @param mixed $var The input variable - * @param BasicObject $o The base object + * @param mixed $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - public function parse(&$var, BasicObject $o) + public function parse(&$var, Value $o) { $o->type = \strtolower(\gettype($var)); @@ -165,8 +140,10 @@ public function parse(&$var, BasicObject $o) return $this->parseResource($var, $o); case 'string': return $this->parseString($var, $o); + case 'unknown type': + case 'resource (closed)': default: - return $this->parseUnknown($var, $o); + return $this->parseResourceClosed($var, $o); } } @@ -184,12 +161,12 @@ public function addPlugin(Plugin $p) foreach ($types as $type) { if (!isset($this->plugins[$type])) { - $this->plugins[$type] = array( - self::TRIGGER_BEGIN => array(), - self::TRIGGER_SUCCESS => array(), - self::TRIGGER_RECURSION => array(), - self::TRIGGER_DEPTH_LIMIT => array(), - ); + $this->plugins[$type] = [ + self::TRIGGER_BEGIN => [], + self::TRIGGER_SUCCESS => [], + self::TRIGGER_RECURSION => [], + self::TRIGGER_DEPTH_LIMIT => [], + ]; } foreach ($this->plugins[$type] as $trigger => &$pool) { @@ -204,7 +181,7 @@ public function addPlugin(Plugin $p) public function clearPlugins() { - $this->plugins = array(); + $this->plugins = []; } public function haltParse() @@ -212,18 +189,18 @@ public function haltParse() $this->parse_break = true; } - public function childHasPath(InstanceObject $parent, BasicObject $child) + public function childHasPath(InstanceValue $parent, Value $child) { if ('object' === $parent->type && (null !== $parent->access_path || $child->static || $child->const)) { - if (BasicObject::ACCESS_PUBLIC === $child->access) { + if (Value::ACCESS_PUBLIC === $child->access) { return true; } - if (BasicObject::ACCESS_PRIVATE === $child->access && $this->caller_class) { + if (Value::ACCESS_PRIVATE === $child->access && $this->caller_class) { if ($this->caller_class === $child->owner_class) { return true; } - } elseif (BasicObject::ACCESS_PROTECTED === $child->access && $this->caller_class) { + } elseif (Value::ACCESS_PROTECTED === $child->access && $this->caller_class) { if ($this->caller_class === $child->owner_class) { return true; } @@ -262,9 +239,9 @@ protected function noRecurseCall() { $bt = \debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT | DEBUG_BACKTRACE_IGNORE_ARGS); - $caller_frame = array( + $caller_frame = [ 'function' => __FUNCTION__, - ); + ]; while (isset($bt[0]['object']) && $bt[0]['object'] === $this) { $caller_frame = \array_shift($bt); @@ -277,7 +254,7 @@ protected function noRecurseCall() } } - private function parseGeneric(&$var, BasicObject $o) + private function parseGeneric(&$var, Value $o) { $rep = new Representation('Contents'); $rep->contents = $var; @@ -291,19 +268,19 @@ private function parseGeneric(&$var, BasicObject $o) } /** - * Parses a string into a Kint BlobObject structure. + * Parses a string into a Kint BlobValue structure. * - * @param string $var The input variable - * @param BasicObject $o The base object + * @param string $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseString(&$var, BasicObject $o) + private function parseString(&$var, Value $o) { - $string = new BlobObject(); + $string = new BlobValue(); $string->transplant($o); - $string->encoding = BlobObject::detectEncoding($var); - $string->size = BlobObject::strlen($var, $string->encoding); + $string->encoding = BlobValue::detectEncoding($var); + $string->size = \strlen($var); $rep = new Representation('Contents'); $rep->contents = $var; @@ -320,14 +297,14 @@ private function parseString(&$var, BasicObject $o) /** * Parses an array into a Kint object structure. * - * @param array $var The input variable - * @param BasicObject $o The base object + * @param array $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseArray(array &$var, BasicObject $o) + private function parseArray(array &$var, Value $o) { - $array = new BasicObject(); + $array = new Value(); $array->transplant($o); $array->size = \count($var); @@ -379,11 +356,11 @@ private function parseArray(array &$var, BasicObject $o) continue; } - $child = new BasicObject(); + $child = new Value(); $child->name = $key; $child->depth = $array->depth + 1; - $child->access = BasicObject::ACCESS_NONE; - $child->operator = BasicObject::OPERATOR_ARRAY; + $child->access = Value::ACCESS_NONE; + $child->operator = Value::OPERATOR_ARRAY; if (null !== $array->access_path) { if (\is_string($key) && (string) (int) $key === $key) { @@ -411,22 +388,22 @@ private function parseArray(array &$var, BasicObject $o) } /** - * Parses an object into a Kint InstanceObject structure. + * Parses an object into a Kint InstanceValue structure. * - * @param object $var The input variable - * @param BasicObject $o The base object + * @param object $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseObject(&$var, BasicObject $o) + private function parseObject(&$var, Value $o) { $hash = \spl_object_hash($var); $values = (array) $var; - $object = new InstanceObject(); + $object = new InstanceValue(); $object->transplant($o); $object->classname = \get_class($var); - $object->hash = $hash; + $object->spl_object_hash = $hash; $object->size = \count($values); if (isset($this->object_hashes[$hash])) { @@ -457,6 +434,48 @@ private function parseObject(&$var, BasicObject $o) $rep = new Representation('Properties'); + if (KINT_PHP74) { + $rprops = $reflector->getProperties(); + + foreach ($rprops as $rprop) { + if ($rprop->isStatic()) { + continue; + } + + $rprop->setAccessible(true); + if ($rprop->isInitialized($var)) { + continue; + } + + $undefined = null; + + $child = new Value(); + $child->type = 'undefined'; + $child->depth = $object->depth + 1; + $child->owner_class = $rprop->getDeclaringClass()->getName(); + $child->operator = Value::OPERATOR_OBJECT; + $child->name = $rprop->getName(); + + if ($rprop->isPublic()) { + $child->access = Value::ACCESS_PUBLIC; + } elseif ($rprop->isProtected()) { + $child->access = Value::ACCESS_PROTECTED; + } elseif ($rprop->isPrivate()) { + $child->access = Value::ACCESS_PRIVATE; + } + + // Can't dynamically add undefined properties, so no need to use var_export + if ($this->childHasPath($object, $child)) { + $child->access_path .= $object->access_path.'->'.$child->name; + } + + if ($this->applyPlugins($undefined, $child, self::TRIGGER_BEGIN)) { + $this->applyPlugins($undefined, $child, self::TRIGGER_SUCCESS); + } + $rep->contents[] = $child; + } + } + $copy = \array_values($values); $refmarker = new stdClass(); $i = 0; @@ -470,20 +489,20 @@ private function parseObject(&$var, BasicObject $o) // public properties show in the form "$property_name"; // http://www.php.net/manual/en/language.types.array.php#language.types.array.casting - $child = new BasicObject(); + $child = new Value(); $child->depth = $object->depth + 1; $child->owner_class = $object->classname; - $child->operator = BasicObject::OPERATOR_OBJECT; - $child->access = BasicObject::ACCESS_PUBLIC; + $child->operator = Value::OPERATOR_OBJECT; + $child->access = Value::ACCESS_PUBLIC; $split_key = \explode("\0", $key, 3); if (3 === \count($split_key) && '' === $split_key[0]) { $child->name = $split_key[2]; if ('*' === $split_key[1]) { - $child->access = BasicObject::ACCESS_PROTECTED; + $child->access = Value::ACCESS_PROTECTED; } else { - $child->access = BasicObject::ACCESS_PRIVATE; + $child->access = Value::ACCESS_PRIVATE; $child->owner_class = $split_key[1]; } } elseif (KINT_PHP72) { @@ -524,16 +543,16 @@ private function parseObject(&$var, BasicObject $o) } /** - * Parses a resource into a Kint ResourceObject structure. + * Parses a resource into a Kint ResourceValue structure. * - * @param resource $var The input variable - * @param BasicObject $o The base object + * @param resource $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseResource(&$var, BasicObject $o) + private function parseResource(&$var, Value $o) { - $resource = new ResourceObject(); + $resource = new ResourceValue(); $resource->transplant($o); $resource->resource_type = \get_resource_type($var); @@ -543,16 +562,16 @@ private function parseResource(&$var, BasicObject $o) } /** - * Parses an unknown into a Kint object structure. + * Parses a closed resource into a Kint object structure. * - * @param mixed $var The input variable - * @param BasicObject $o The base object + * @param mixed $var The input variable + * @param Value $o The base object * - * @return BasicObject + * @return Value */ - private function parseUnknown(&$var, BasicObject $o) + private function parseResourceClosed(&$var, Value $o) { - $o->type = 'unknown'; + $o->type = 'resource (closed)'; $this->applyPlugins($var, $o, self::TRIGGER_SUCCESS); return $o; @@ -561,20 +580,20 @@ private function parseUnknown(&$var, BasicObject $o) /** * Applies plugins for an object type. * - * @param mixed $var variable - * @param BasicObject $o Kint object parsed so far - * @param int $trigger The trigger to check for the plugins + * @param mixed $var variable + * @param Value $o Kint object parsed so far + * @param int $trigger The trigger to check for the plugins * * @return bool Continue parsing */ - private function applyPlugins(&$var, BasicObject &$o, $trigger) + private function applyPlugins(&$var, Value &$o, $trigger) { $break_stash = $this->parse_break; /** @var bool Psalm bug workaround */ $this->parse_break = false; - $plugins = array(); + $plugins = []; if (isset($this->plugins[$o->type][$trigger])) { $plugins = $this->plugins[$o->type][$trigger]; diff --git a/system/ThirdParty/Kint/Parser/Plugin.php b/system/ThirdParty/Kint/Parser/Plugin.php index 51d5f0b1440b..981d2aa56e1b 100644 --- a/system/ThirdParty/Kint/Parser/Plugin.php +++ b/system/ThirdParty/Kint/Parser/Plugin.php @@ -25,7 +25,7 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; abstract class Plugin { @@ -43,7 +43,7 @@ public function setParser(Parser $p) */ public function getTypes() { - return array(); + return []; } public function getTriggers() @@ -51,5 +51,5 @@ public function getTriggers() return Parser::TRIGGER_NONE; } - abstract public function parse(&$variable, BasicObject &$o, $trigger); + abstract public function parse(&$var, Value &$o, $trigger); } diff --git a/system/ThirdParty/Kint/Parser/ProxyPlugin.php b/system/ThirdParty/Kint/Parser/ProxyPlugin.php index 3376d3aa9016..116f3883dbdb 100644 --- a/system/ThirdParty/Kint/Parser/ProxyPlugin.php +++ b/system/ThirdParty/Kint/Parser/ProxyPlugin.php @@ -26,7 +26,7 @@ namespace Kint\Parser; use InvalidArgumentException; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class ProxyPlugin extends Plugin { @@ -59,8 +59,8 @@ public function getTriggers() return $this->triggers; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - return \call_user_func_array($this->callback, array(&$var, &$o, $trigger, $this->parser)); + return \call_user_func_array($this->callback, [&$var, &$o, $trigger, $this->parser]); } } diff --git a/system/ThirdParty/Kint/Parser/SerializePlugin.php b/system/ThirdParty/Kint/Parser/SerializePlugin.php index c5dadb88d9de..5924483fc50e 100644 --- a/system/ThirdParty/Kint/Parser/SerializePlugin.php +++ b/system/ThirdParty/Kint/Parser/SerializePlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class SerializePlugin extends Plugin { @@ -45,11 +45,11 @@ class SerializePlugin extends Plugin * @var bool */ public static $safe_mode = true; - public static $options = array(true); + public static $options = [true]; public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -57,7 +57,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $trimmed = \rtrim($var); @@ -65,7 +65,7 @@ public function parse(&$var, BasicObject &$o, $trigger) return; } - if (!self::$safe_mode || !\in_array($trimmed[0], array('C', 'O', 'a'), true)) { + if (!self::$safe_mode || !\in_array($trimmed[0], ['C', 'O', 'a'], true)) { // Second parameter only supported on PHP 7 if (KINT_PHP70) { // Suppress warnings on unserializeable variable @@ -79,15 +79,15 @@ public function parse(&$var, BasicObject &$o, $trigger) } } - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = 'unserialize('.$o->name.')'; if ($o->access_path) { $base_obj->access_path = 'unserialize('.$o->access_path; - if (!KINT_PHP70 || self::$options === array(true)) { + if (!KINT_PHP70 || self::$options === [true]) { $base_obj->access_path .= ')'; - } elseif (self::$options === array(false)) { + } elseif (self::$options === [false]) { $base_obj->access_path .= ', false)'; } else { $base_obj->access_path .= ', Serialize::$options)'; diff --git a/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php b/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php index b90c863f8873..9e44e5388ec8 100644 --- a/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php +++ b/system/ThirdParty/Kint/Parser/SimpleXMLElementPlugin.php @@ -25,9 +25,10 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\BlobValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\SimpleXMLElementValue; +use Kint\Zval\Value; use SimpleXMLElement; class SimpleXMLElementPlugin extends Plugin @@ -41,7 +42,7 @@ class SimpleXMLElementPlugin extends Plugin public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -49,106 +50,168 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof SimpleXMLElement) { return; } - $o->hints[] = 'simplexml_element'; - if (!self::$verbose) { $o->removeRepresentation('properties'); $o->removeRepresentation('iterator'); $o->removeRepresentation('methods'); } + // An invalid SimpleXMLElement can gum up the works with + // warnings if we call stuff children/attributes on it. + if (!$var) { + $o->size = null; + + return; + } + + $x = new SimpleXMLElementValue(); + $x->transplant($o); + + $namespaces = \array_merge([null], $var->getDocNamespaces()); + // Attributes $a = new Representation('Attributes'); - $base_obj = new BasicObject(); - $base_obj->depth = $o->depth; + $base_obj = new Value(); + $base_obj->depth = $x->depth; - if ($o->access_path) { - $base_obj->access_path = '(string) '.$o->access_path; + if ($x->access_path) { + $base_obj->access_path = '(string) '.$x->access_path; } - if ($attribs = $var->attributes()) { - $attribs = \iterator_to_array($attribs); - $attribs = \array_map('strval', $attribs); - } else { - $attribs = array(); + // Attributes are strings. If we're too deep set the + // depth limit to enable parsing them, but no deeper. + if ($this->parser->getDepthLimit() && $this->parser->getDepthLimit() - 2 < $base_obj->depth) { + $base_obj->depth = $this->parser->getDepthLimit() - 2; } - // XML attributes are by definition strings and don't have children, - // so up the depth limit in case we're just below the limit since - // there won't be any recursive stuff anyway. - $a->contents = $this->parser->parseDeep($attribs, $base_obj)->value->contents; + $attribs = []; - $o->addRepresentation($a, 0); + foreach ($namespaces as $nsAlias => $nsUrl) { + if ($nsAttribs = $var->attributes($nsUrl)) { + $cleanAttribs = []; + foreach ($nsAttribs as $name => $attrib) { + $cleanAttribs[(string) $name] = $attrib; + } - // Children - // We need to check children() separately from the values we already parsed because - // text contents won't show up in children() but they will show up in properties. - // - // Why do we still need to check for attributes if we already have an attributes() - // method? Hell if I know! - $children = $var->children(); - - if ($o->value) { - $c = new Representation('Children'); - - foreach ($o->value->contents as $value) { - if ('@attributes' === $value->name) { - continue; + if (null === $nsUrl) { + $obj = clone $base_obj; + if ($obj->access_path) { + $obj->access_path .= '->attributes()'; + } + + $a->contents = $this->parser->parse($cleanAttribs, $obj)->value->contents; + } else { + $obj = clone $base_obj; + if ($obj->access_path) { + $obj->access_path .= '->attributes('.\var_export($nsAlias, true).', true)'; + } + + $cleanAttribs = $this->parser->parse($cleanAttribs, $obj)->value->contents; + + foreach ($cleanAttribs as $attribute) { + $attribute->name = $nsAlias.':'.$attribute->name; + $a->contents[] = $attribute; + } } + } + } + + $x->addRepresentation($a, 0); - if (isset($children->{$value->name})) { - $i = 0; + // Children + $c = new Representation('Children'); + + foreach ($namespaces as $nsAlias => $nsUrl) { + // This is doubling items because of the root namespace + // and the implicit namespace on its children. + $thisNs = $var->getNamespaces(); + if (isset($thisNs['']) && $thisNs[''] === $nsUrl) { + continue; + } - while (isset($children->{$value->name}[$i])) { - $base_obj = new BasicObject(); - $base_obj->depth = $o->depth + 1; - $base_obj->name = $value->name; - if ($value->access_path) { - $base_obj->access_path = $value->access_path.'['.$i.']'; + if ($nsChildren = $var->children($nsUrl)) { + $nsap = []; + foreach ($nsChildren as $name => $child) { + $obj = new Value(); + $obj->depth = $x->depth + 1; + $obj->name = (string) $name; + if ($x->access_path) { + if (null === $nsUrl) { + $obj->access_path = $x->access_path.'->children()->'; + } else { + $obj->access_path = $x->access_path.'->children('.\var_export($nsAlias, true).', true)->'; } - $value = $this->parser->parse($children->{$value->name}[$i], $base_obj); + if (\preg_match('/^[a-zA-Z_\\x7f-\\xff][a-zA-Z0-9_\\x7f-\\xff]+$/', (string) $name)) { + $obj->access_path .= (string) $name; + } else { + $obj->access_path .= '{'.\var_export((string) $name, true).'}'; + } - if ($value->access_path && 'string' === $value->type) { - $value->access_path = '(string) '.$value->access_path; + if (isset($nsap[$obj->access_path])) { + ++$nsap[$obj->access_path]; + $obj->access_path .= '['.$nsap[$obj->access_path].']'; + } else { + $nsap[$obj->access_path] = 0; } + } - $c->contents[] = $value; + $value = $this->parser->parse($child, $obj); - ++$i; + if ($value->access_path && 'string' === $value->type) { + $value->access_path = '(string) '.$value->access_path; } + + $c->contents[] = $value; } } + } - $o->size = \count($c->contents); + $x->size = \count($c->contents); - if (!$o->size) { - $o->size = null; + if ($x->size) { + $x->addRepresentation($c, 0); + } else { + $x->size = null; + + if (\strlen((string) $var)) { + $base_obj = new BlobValue(); + $base_obj->depth = $x->depth + 1; + $base_obj->name = $x->name; + if ($x->access_path) { + $base_obj->access_path = '(string) '.$x->access_path; + } + + $value = (string) $var; + + $s = $this->parser->parse($value, $base_obj); + $srep = $s->getRepresentation('contents'); + $svalrep = $s->value && 'contents' == $s->value->getName() ? $s : null; - if (\strlen((string) $var)) { - $base_obj = new BlobObject(); - $base_obj->depth = $o->depth + 1; - $base_obj->name = $o->name; - if ($o->access_path) { - $base_obj->access_path = '(string) '.$o->access_path; + if ($srep || $svalrep) { + $x->setIsStringValue(true); + $x->value = $srep ?: $svalrep; + + if ($srep) { + $x->replaceRepresentation($x->value, 0); } + } - $value = (string) $var; + $reps = \array_reverse($s->getRepresentations()); - $c = new Representation('Contents'); - $c->implicit_label = true; - $c->contents = array($this->parser->parseDeep($value, $base_obj)); + foreach ($reps as $rep) { + $x->addRepresentation($rep, 0); } } - - $o->addRepresentation($c, 0); } + + $o = $x; } } diff --git a/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php b/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php index 8b72193bc369..ada3e1fb8e85 100644 --- a/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php +++ b/system/ThirdParty/Kint/Parser/SplFileInfoPlugin.php @@ -25,8 +25,8 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\SplFileInfoRepresentation; +use Kint\Zval\Representation\SplFileInfoRepresentation; +use Kint\Zval\Value; use SplFileInfo; use SplFileObject; @@ -34,7 +34,7 @@ class SplFileInfoPlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -42,7 +42,7 @@ public function getTriggers() return Parser::TRIGGER_COMPLETE; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof SplFileInfo || $var instanceof SplFileObject) { return; diff --git a/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php b/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php index 03ff301d3477..359774d3bfff 100644 --- a/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php +++ b/system/ThirdParty/Kint/Parser/SplObjectStoragePlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; use SplObjectStorage; class SplObjectStoragePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_COMPLETE; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof SplObjectStorage || !($r = $o->getRepresentation('iterator'))) { return; diff --git a/system/ThirdParty/Kint/Parser/StreamPlugin.php b/system/ThirdParty/Kint/Parser/StreamPlugin.php index 464a3fff12c5..76608d94a6a6 100644 --- a/system/ThirdParty/Kint/Parser/StreamPlugin.php +++ b/system/ThirdParty/Kint/Parser/StreamPlugin.php @@ -25,16 +25,16 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; -use Kint\Object\ResourceObject; -use Kint\Object\StreamObject; +use Kint\Zval\Representation\Representation; +use Kint\Zval\ResourceValue; +use Kint\Zval\StreamValue; +use Kint\Zval\Value; class StreamPlugin extends Plugin { public function getTypes() { - return array('resource'); + return ['resource']; } public function getTriggers() @@ -42,20 +42,23 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { - if (!$o instanceof ResourceObject || 'stream' !== $o->resource_type) { + if (!$o instanceof ResourceValue || 'stream' !== $o->resource_type) { return; } - if (!$meta = \stream_get_meta_data($var)) { + // Doublecheck that the resource is open before we get the metadata + if (!\is_resource($var)) { return; } + $meta = \stream_get_meta_data($var); + $rep = new Representation('Stream'); $rep->implicit_label = true; - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth; if ($o->access_path) { @@ -71,7 +74,7 @@ public function parse(&$var, BasicObject &$o, $trigger) $o->addRepresentation($rep, 0); $o->value = $rep; - $stream = new StreamObject($meta); + $stream = new StreamValue($meta); $stream->transplant($o); $o = $stream; } diff --git a/system/ThirdParty/Kint/Parser/TablePlugin.php b/system/ThirdParty/Kint/Parser/TablePlugin.php index 510c4ff0ef86..c6ca6e248d68 100644 --- a/system/ThirdParty/Kint/Parser/TablePlugin.php +++ b/system/ThirdParty/Kint/Parser/TablePlugin.php @@ -25,14 +25,14 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class TablePlugin extends Plugin { public function getTypes() { - return array('array'); + return ['array']; } public function getTriggers() @@ -40,7 +40,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (empty($o->value->contents)) { return; diff --git a/system/ThirdParty/Kint/Parser/ThrowablePlugin.php b/system/ThirdParty/Kint/Parser/ThrowablePlugin.php index 8490d1d41a1a..ea343e96ee78 100644 --- a/system/ThirdParty/Kint/Parser/ThrowablePlugin.php +++ b/system/ThirdParty/Kint/Parser/ThrowablePlugin.php @@ -26,16 +26,16 @@ namespace Kint\Parser; use Exception; -use Kint\Object\BasicObject; -use Kint\Object\Representation\SourceRepresentation; -use Kint\Object\ThrowableObject; +use Kint\Zval\Representation\SourceRepresentation; +use Kint\Zval\ThrowableValue; +use Kint\Zval\Value; use Throwable; class ThrowablePlugin extends Plugin { public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -43,13 +43,13 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$var instanceof Exception && (!KINT_PHP70 || !$var instanceof Throwable)) { return; } - $throw = new ThrowableObject($var); + $throw = new ThrowableValue($var); $throw->transplant($o); $r = new SourceRepresentation($var->getFile(), $var->getLine()); $r->showfilename = true; diff --git a/system/ThirdParty/Kint/Parser/TimestampPlugin.php b/system/ThirdParty/Kint/Parser/TimestampPlugin.php index 72958d6465c0..fa8d743dea89 100644 --- a/system/ThirdParty/Kint/Parser/TimestampPlugin.php +++ b/system/ThirdParty/Kint/Parser/TimestampPlugin.php @@ -25,20 +25,20 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class TimestampPlugin extends Plugin { - public static $blacklist = array( + public static $blacklist = [ 2147483648, 2147483647, 1073741824, 1073741823, - ); + ]; public function getTypes() { - return array('string', 'integer'); + return ['string', 'integer']; } public function getTriggers() @@ -46,7 +46,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (\is_string($var) && !\ctype_digit($var)) { return; @@ -56,7 +56,7 @@ public function parse(&$var, BasicObject &$o, $trigger) return; } - $len = \strlen($var); + $len = \strlen((string) $var); // Guess for anything between March 1973 and November 2286 if (9 === $len || 10 === $len) { diff --git a/system/ThirdParty/Kint/Parser/ToStringPlugin.php b/system/ThirdParty/Kint/Parser/ToStringPlugin.php index 8b7a65fe60f5..d13cb29cc93b 100644 --- a/system/ThirdParty/Kint/Parser/ToStringPlugin.php +++ b/system/ThirdParty/Kint/Parser/ToStringPlugin.php @@ -25,20 +25,20 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; use ReflectionClass; class ToStringPlugin extends Plugin { - public static $blacklist = array( + public static $blacklist = [ 'SimpleXMLElement', 'SplFileObject', - ); + ]; public function getTypes() { - return array('object'); + return ['object']; } public function getTriggers() @@ -46,7 +46,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { $reflection = new ReflectionClass($var); if (!$reflection->hasMethod('__toString')) { diff --git a/system/ThirdParty/Kint/Parser/TracePlugin.php b/system/ThirdParty/Kint/Parser/TracePlugin.php index 3554993dd2e1..ccdcadec59a8 100644 --- a/system/ThirdParty/Kint/Parser/TracePlugin.php +++ b/system/ThirdParty/Kint/Parser/TracePlugin.php @@ -25,18 +25,19 @@ namespace Kint\Parser; -use Kint\Object\BasicObject; -use Kint\Object\TraceFrameObject; -use Kint\Object\TraceObject; use Kint\Utils; +use Kint\Zval\TraceFrameValue; +use Kint\Zval\TraceValue; +use Kint\Zval\Value; class TracePlugin extends Plugin { - public static $blacklist = array('spl_autoload_call'); + public static $blacklist = ['spl_autoload_call']; + public static $path_blacklist = []; public function getTypes() { - return array('array'); + return ['array']; } public function getTriggers() @@ -44,27 +45,29 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if (!$o->value) { return; } + /** @var array[] $trace Psalm workaround */ $trace = $this->parser->getCleanArray($var); if (\count($trace) !== \count($o->value->contents) || !Utils::isTrace($trace)) { return; } - $traceobj = new TraceObject(); + $traceobj = new TraceValue(); $traceobj->transplant($o); $rep = $traceobj->value; $old_trace = $rep->contents; Utils::normalizeAliases(self::$blacklist); + $path_blacklist = self::normalizePaths(self::$path_blacklist); - $rep->contents = array(); + $rep->contents = []; foreach ($old_trace as $frame) { $index = $frame->name; @@ -78,7 +81,16 @@ public function parse(&$var, BasicObject &$o, $trigger) continue; } - $rep->contents[$index] = new TraceFrameObject($frame, $trace[$index]); + if (isset($trace[$index]['file'])) { + $realfile = \realpath($trace[$index]['file']); + foreach ($path_blacklist as $path) { + if (0 === \strpos($realfile, $path)) { + continue 2; + } + } + } + + $rep->contents[$index] = new TraceFrameValue($frame, $trace[$index]); } \ksort($rep->contents); @@ -89,4 +101,20 @@ public function parse(&$var, BasicObject &$o, $trigger) $traceobj->size = \count($rep->contents); $o = $traceobj; } + + protected static function normalizePaths(array $paths) + { + $normalized = []; + + foreach ($paths as $path) { + $realpath = \realpath($path); + if (\is_dir($realpath)) { + $realpath .= DIRECTORY_SEPARATOR; + } + + $normalized[] = $realpath; + } + + return $normalized; + } } diff --git a/system/ThirdParty/Kint/Parser/XmlPlugin.php b/system/ThirdParty/Kint/Parser/XmlPlugin.php index 0947e9a6cb14..a4fa2b0c21c8 100644 --- a/system/ThirdParty/Kint/Parser/XmlPlugin.php +++ b/system/ThirdParty/Kint/Parser/XmlPlugin.php @@ -27,8 +27,8 @@ use DOMDocument; use Exception; -use Kint\Object\BasicObject; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class XmlPlugin extends Plugin { @@ -45,7 +45,7 @@ class XmlPlugin extends Plugin public function getTypes() { - return array('string'); + return ['string']; } public function getTriggers() @@ -53,7 +53,7 @@ public function getTriggers() return Parser::TRIGGER_SUCCESS; } - public function parse(&$var, BasicObject &$o, $trigger) + public function parse(&$var, Value &$o, $trigger) { if ('access_path); + $xml = \call_user_func([\get_class($this), 'xmlTo'.self::$parse_method], $var, $o->access_path); if (empty($xml)) { return; @@ -71,7 +71,7 @@ public function parse(&$var, BasicObject &$o, $trigger) list($xml, $access_path, $name) = $xml; - $base_obj = new BasicObject(); + $base_obj = new Value(); $base_obj->depth = $o->depth + 1; $base_obj->name = $name; $base_obj->access_path = $access_path; @@ -96,7 +96,7 @@ protected static function xmlToSimpleXML($var, $parent_path) return; } - if (!$xml) { + if (false === $xml) { return; } @@ -108,7 +108,7 @@ protected static function xmlToSimpleXML($var, $parent_path) $name = $xml->getName(); - return array($xml, $access_path, $name); + return [$xml, $access_path, $name]; } /** @@ -135,16 +135,23 @@ protected static function xmlToDOMDocument($var, $parent_path) $xml = new DOMDocument(); $xml->loadXML($var); - $xml = $xml->firstChild; + + if ($xml->childNodes->count() > 1) { + $xml = $xml->childNodes; + $access_path = 'childNodes'; + } else { + $xml = $xml->firstChild; + $access_path = 'firstChild'; + } if (null === $parent_path) { $access_path = null; } else { - $access_path = '@\\DOMDocument::loadXML('.$parent_path.')->firstChild'; + $access_path = '(function($s){$x = new \\DomDocument(); $x->loadXML($s); return $x;})('.$parent_path.')->'.$access_path; } - $name = $xml->nodeName; + $name = isset($xml->nodeName) ? $xml->nodeName : null; - return array($xml, $access_path, $name); + return [$xml, $access_path, $name]; } } diff --git a/system/ThirdParty/Kint/Renderer/CliRenderer.php b/system/ThirdParty/Kint/Renderer/CliRenderer.php index 0d0846a411c3..f86671ff1cf3 100644 --- a/system/ThirdParty/Kint/Renderer/CliRenderer.php +++ b/system/ThirdParty/Kint/Renderer/CliRenderer.php @@ -25,7 +25,9 @@ namespace Kint\Renderer; -use Kint\Object\BasicObject; +use Exception; +use Kint\Zval\Value; +use Throwable; class CliRenderer extends TextRenderer { @@ -73,7 +75,13 @@ public function __construct() if (!self::$terminal_width) { if (!KINT_WIN && self::$detect_width) { - self::$terminal_width = \exec('tput cols'); + try { + self::$terminal_width = \exec('tput cols'); + } catch (Exception $e) { + self::$terminal_width = self::$default_width; + } catch (Throwable $t) { + self::$terminal_width = self::$default_width; + } } if (self::$terminal_width < self::$min_terminal_width) { @@ -113,7 +121,7 @@ public function colorTitle($string) return "\x1b[36m".\str_replace("\n", "\x1b[0m\n\x1b[36m", $string)."\x1b[0m"; } - public function renderTitle(BasicObject $o) + public function renderTitle(Value $o) { if ($this->windows_output) { return $this->utf8ToWindows(parent::renderTitle($o)); @@ -144,8 +152,8 @@ public function escape($string, $encoding = false) protected function utf8ToWindows($string) { return \str_replace( - array('┌', '═', '┐', '│', '└', '─', '┘'), - array("\xda", "\xdc", "\xbf", "\xb3", "\xc0", "\xc4", "\xd9"), + ['┌', '═', '┐', '│', '└', '─', '┘'], + ["\xda", "\xdc", "\xbf", "\xb3", "\xc0", "\xc4", "\xd9"], $string ); } diff --git a/system/ThirdParty/Kint/Renderer/PlainRenderer.php b/system/ThirdParty/Kint/Renderer/PlainRenderer.php index 493a7743bed4..4b8102a4750f 100644 --- a/system/ThirdParty/Kint/Renderer/PlainRenderer.php +++ b/system/ThirdParty/Kint/Renderer/PlainRenderer.php @@ -26,21 +26,21 @@ namespace Kint\Renderer; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; +use Kint\Zval\BlobValue; +use Kint\Zval\Value; class PlainRenderer extends TextRenderer { - public static $pre_render_sources = array( - 'script' => array( - array('Kint\\Renderer\\PlainRenderer', 'renderJs'), - array('Kint\\Renderer\\Text\\MicrotimePlugin', 'renderJs'), - ), - 'style' => array( - array('Kint\\Renderer\\PlainRenderer', 'renderCss'), - ), - 'raw' => array(), - ); + public static $pre_render_sources = [ + 'script' => [ + ['Kint\\Renderer\\PlainRenderer', 'renderJs'], + ['Kint\\Renderer\\Text\\MicrotimePlugin', 'renderJs'], + ], + 'style' => [ + ['Kint\\Renderer\\PlainRenderer', 'renderCss'], + ], + 'raw' => [], + ]; /** * Path to the CSS file to load by default. @@ -118,7 +118,7 @@ public function colorTitle($string) return ''.$string.''; } - public function renderTitle(BasicObject $o) + public function renderTitle(Value $o) { if (self::$disable_utf8) { return $this->utf8ToHtmlentity(parent::renderTitle($o)); @@ -193,7 +193,7 @@ public function ideLink($file, $line) public function escape($string, $encoding = false) { if (false === $encoding) { - $encoding = BlobObject::detectEncoding($string); + $encoding = BlobValue::detectEncoding($string); } $original_encoding = $encoding; @@ -206,7 +206,7 @@ public function escape($string, $encoding = false) // this call converts all non-ASCII characters into numeirc htmlentities if (\function_exists('mb_encode_numericentity') && 'ASCII' !== $original_encoding) { - $string = \mb_encode_numericentity($string, array(0x80, 0xffff, 0, 0xffff), $encoding); + $string = \mb_encode_numericentity($string, [0x80, 0xFFFF, 0, 0xFFFF], $encoding); } return $string; @@ -215,8 +215,8 @@ public function escape($string, $encoding = false) protected function utf8ToHtmlentity($string) { return \str_replace( - array('┌', '═', '┐', '│', '└', '─', '┘'), - array('┌', '═', '┐', '│', '└', '─', '┘'), + ['┌', '═', '┐', '│', '└', '─', '┘'], + ['┌', '═', '┐', '│', '└', '─', '┘'], $string ); } diff --git a/system/ThirdParty/Kint/Renderer/Renderer.php b/system/ThirdParty/Kint/Renderer/Renderer.php index cf8b0a781179..0ed7ce0895b5 100644 --- a/system/ThirdParty/Kint/Renderer/Renderer.php +++ b/system/ThirdParty/Kint/Renderer/Renderer.php @@ -25,8 +25,8 @@ namespace Kint\Renderer; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; +use Kint\Zval\InstanceValue; +use Kint\Zval\Value; abstract class Renderer { @@ -34,11 +34,11 @@ abstract class Renderer const SORT_VISIBILITY = 1; const SORT_FULL = 2; - protected $call_info = array(); - protected $statics = array(); + protected $call_info = []; + protected $statics = []; protected $show_trace = true; - abstract public function render(BasicObject $o); + abstract public function render(Value $o); abstract public function renderNothing(); @@ -49,7 +49,7 @@ public function setCallInfo(array $info) } if (!isset($info['modifiers']) || !\is_array($info['modifiers'])) { - $info['modifiers'] = array(); + $info['modifiers'] = []; } if (!isset($info['callee'])) { @@ -61,16 +61,16 @@ public function setCallInfo(array $info) } if (!isset($info['trace']) || !\is_array($info['trace'])) { - $info['trace'] = array(); + $info['trace'] = []; } - $this->call_info = array( + $this->call_info = [ 'params' => $info['params'], 'modifiers' => $info['modifiers'], 'callee' => $info['callee'], 'caller' => $info['caller'], 'trace' => $info['trace'], - ); + ]; } public function getCallInfo() @@ -109,7 +109,7 @@ public function getShowTrace() */ public function matchPlugins(array $plugins, array $hints) { - $out = array(); + $out = []; foreach ($hints as $key) { if (isset($plugins[$key])) { @@ -135,40 +135,40 @@ public function postRender() return ''; } - public static function sortPropertiesFull(BasicObject $a, BasicObject $b) + public static function sortPropertiesFull(Value $a, Value $b) { - $sort = BasicObject::sortByAccess($a, $b); + $sort = Value::sortByAccess($a, $b); if ($sort) { return $sort; } - $sort = BasicObject::sortByName($a, $b); + $sort = Value::sortByName($a, $b); if ($sort) { return $sort; } - return InstanceObject::sortByHierarchy($a->owner_class, $b->owner_class); + return InstanceValue::sortByHierarchy($a->owner_class, $b->owner_class); } /** - * Sorts an array of BasicObject. + * Sorts an array of Value. * - * @param BasicObject[] $contents Object properties to sort - * @param int $sort + * @param Value[] $contents Object properties to sort + * @param int $sort * - * @return BasicObject[] + * @return Value[] */ public static function sortProperties(array $contents, $sort) { switch ($sort) { case self::SORT_VISIBILITY: - /** @var array Containers to quickly stable sort by type */ - $containers = array( - BasicObject::ACCESS_PUBLIC => array(), - BasicObject::ACCESS_PROTECTED => array(), - BasicObject::ACCESS_PRIVATE => array(), - BasicObject::ACCESS_NONE => array(), - ); + // Containers to quickly stable sort by type + $containers = [ + Value::ACCESS_PUBLIC => [], + Value::ACCESS_PROTECTED => [], + Value::ACCESS_PRIVATE => [], + Value::ACCESS_NONE => [], + ]; foreach ($contents as $item) { $containers[$item->access][] = $item; @@ -176,7 +176,7 @@ public static function sortProperties(array $contents, $sort) return \call_user_func_array('array_merge', $containers); case self::SORT_FULL: - \usort($contents, array('Kint\\Renderer\\Renderer', 'sortPropertiesFull')); + \usort($contents, ['Kint\\Renderer\\Renderer', 'sortPropertiesFull']); // no break default: return $contents; diff --git a/system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php new file mode 100644 index 000000000000..e6ebe569b85e --- /dev/null +++ b/system/ThirdParty/Kint/Renderer/Rich/ArrayLimitPlugin.php @@ -0,0 +1,36 @@ +'.$this->renderLockedHeader($o, 'Array Limit').''; + } +} diff --git a/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php index 5b4d613fdce6..b12690a49969 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/BinaryPlugin.php @@ -25,7 +25,7 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; class BinaryPlugin extends Plugin implements TabPluginInterface { @@ -36,12 +36,17 @@ public function renderTab(Representation $r) { $out = '
    ';
     
    -        $chunks = \str_split($r->contents, self::$line_length);
    +        /** @var string[] Psalm bug workaround */
    +        $lines = \str_split($r->contents, self::$line_length);
     
    -        foreach ($chunks as $index => $chunk) {
    +        foreach ($lines as $index => $line) {
                 $out .= \sprintf('%08X', $index * self::$line_length).":\t";
    -            $out .= \implode(' ', \str_split(\str_pad(\bin2hex($chunk), 2 * self::$line_length, ' '), self::$chunk_length));
    -            $out .= "\t".\preg_replace('/[^\\x20-\\x7E]/', '.', $chunk)."\n";
    +
    +            /** @var string[] Psalm bug workaround */
    +            $chunks = \str_split(\str_pad(\bin2hex($line), 2 * self::$line_length, ' '), self::$chunk_length);
    +
    +            $out .= \implode(' ', $chunks);
    +            $out .= "\t".\preg_replace('/[^\\x20-\\x7E]/', '.', $line)."\n";
             }
     
             $out .= '
    '; diff --git a/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php index fcfedc1a00be..ed7f4ec96495 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/BlacklistPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -class BlacklistPlugin extends Plugin implements ObjectPluginInterface +class BlacklistPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { return '
    '.$this->renderLockedHeader($o, 'Blacklisted').'
    '; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php index 5834017ba550..b28b56a07ad1 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/CallablePlugin.php @@ -25,30 +25,30 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\ClosureObject; -use Kint\Object\MethodObject; use Kint\Renderer\RichRenderer; +use Kint\Utils; +use Kint\Zval\ClosureValue; +use Kint\Zval\MethodValue; +use Kint\Zval\Value; -class CallablePlugin extends Plugin implements ObjectPluginInterface +class CallablePlugin extends Plugin implements ValuePluginInterface { - protected static $method_cache = array(); + protected static $method_cache = []; - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { - if ($o instanceof MethodObject) { + if ($o instanceof MethodValue) { return $this->renderMethod($o); } - if ($o instanceof ClosureObject) { + if ($o instanceof ClosureValue) { return $this->renderClosure($o); } return $this->renderCallable($o); } - protected function renderClosure(ClosureObject $o) + protected function renderClosure(ClosureValue $o) { $children = $this->renderer->renderChildren($o); @@ -63,8 +63,8 @@ protected function renderClosure(ClosureObject $o) } if (null !== ($s = $o->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } $header .= ' '.$this->renderer->escape($s); } @@ -72,7 +72,7 @@ protected function renderClosure(ClosureObject $o) return '
    '.$this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header).$children.'
    '; } - protected function renderCallable(BasicObject $o) + protected function renderCallable(Value $o) { $children = $this->renderer->renderChildren($o); @@ -87,8 +87,8 @@ protected function renderCallable(BasicObject $o) } if (null !== ($s = $o->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } $header .= ' '.$this->renderer->escape($s); } @@ -96,7 +96,7 @@ protected function renderCallable(BasicObject $o) return '
    '.$this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header).$children.'
    '; } - protected function renderMethod(MethodObject $o) + protected function renderMethod(MethodValue $o) { if (!empty(self::$method_cache[$o->owner_class][$o->name])) { $children = self::$method_cache[$o->owner_class][$o->name]['children']; @@ -154,17 +154,17 @@ protected function renderMethod(MethodObject $o) } if (null !== ($s = $o->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } $header .= ' '.$this->renderer->escape($s); } if (\strlen($o->owner_class) && \strlen($o->name)) { - self::$method_cache[$o->owner_class][$o->name] = array( + self::$method_cache[$o->owner_class][$o->name] = [ 'header' => $header, 'children' => $children, - ); + ]; } $header = $this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header); diff --git a/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php index 79a9926cab7f..44813e3ef89f 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/ClosurePlugin.php @@ -26,16 +26,16 @@ namespace Kint\Renderer\Rich; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\ClosureObject; +use Kint\Zval\ClosureValue; +use Kint\Zval\Value; -class ClosurePlugin extends Plugin implements ObjectPluginInterface +class ClosurePlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { $children = $this->renderer->renderChildren($o); - if (!($o instanceof ClosureObject)) { + if (!($o instanceof ClosureValue)) { $header = $this->renderer->renderHeader($o); } else { $header = ''; diff --git a/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php index 241a8154f430..ebd02cb59e24 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/ColorPlugin.php @@ -25,13 +25,13 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\Representation\ColorRepresentation; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\ColorRepresentation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; -class ColorPlugin extends Plugin implements TabPluginInterface, ObjectPluginInterface +class ColorPlugin extends Plugin implements TabPluginInterface, ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { $r = $o->getRepresentation('color'); @@ -92,7 +92,7 @@ public function renderTab(Representation $r) } if (!\strlen($out)) { - return false; + return; } return '
    '.$out.'
    '; diff --git a/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php index cd92b417985c..69808c7c3e1d 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/DepthLimitPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -class DepthLimitPlugin extends Plugin implements ObjectPluginInterface +class DepthLimitPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { return '
    '.$this->renderLockedHeader($o, 'Depth Limit').'
    '; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php index 19c530951c4d..cb53a74fb182 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/DocstringPlugin.php @@ -26,25 +26,25 @@ namespace Kint\Renderer\Rich; use Kint\Kint; -use Kint\Object\Representation\DocstringRepresentation; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\DocstringRepresentation; +use Kint\Zval\Representation\Representation; class DocstringPlugin extends Plugin implements TabPluginInterface { public function renderTab(Representation $r) { if (!($r instanceof DocstringRepresentation)) { - return false; + return; } - $docstring = array(); + $docstring = []; foreach (\explode("\n", $r->contents) as $line) { $docstring[] = \trim($line); } $docstring = \implode("\n", $docstring); - $location = array(); + $location = []; if ($r->class) { $location[] = 'Inherited from '.$this->renderer->escape($r->class); diff --git a/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php index a56bb23ef53a..3d06b529252b 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/MicrotimePlugin.php @@ -25,16 +25,16 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\MicrotimeRepresentation; -use Kint\Object\Representation\Representation; use Kint\Utils; +use Kint\Zval\Representation\MicrotimeRepresentation; +use Kint\Zval\Representation\Representation; class MicrotimePlugin extends Plugin implements TabPluginInterface { public function renderTab(Representation $r) { if (!($r instanceof MicrotimeRepresentation)) { - return false; + return; } $out = $r->getDateTime()->format('Y-m-d H:i:s.u'); diff --git a/system/ThirdParty/Kint/Renderer/Rich/Plugin.php b/system/ThirdParty/Kint/Renderer/Rich/Plugin.php index 06710bcc45c2..58e22cb276f4 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/Plugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/Plugin.php @@ -25,8 +25,8 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; use Kint\Renderer\RichRenderer; +use Kint\Zval\Value; abstract class Plugin implements PluginInterface { @@ -40,10 +40,9 @@ public function __construct(RichRenderer $r) /** * Renders a locked header. * - * @param BasicObject $o - * @param string $content + * @param string $content */ - public function renderLockedHeader(BasicObject $o, $content) + public function renderLockedHeader(Value $o, $content) { $header = '
    '; diff --git a/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php index 618d2176d917..baad2ecb57b8 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/RecursionPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -class RecursionPlugin extends Plugin implements ObjectPluginInterface +class RecursionPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { return '
    '.$this->renderLockedHeader($o, 'Recursion').'
    '; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php index 6c18931ee7af..718cd67aace3 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/SimpleXMLElementPlugin.php @@ -25,13 +25,13 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; use Kint\Renderer\RichRenderer; +use Kint\Utils; +use Kint\Zval\Value; -class SimpleXMLElementPlugin extends Plugin implements ObjectPluginInterface +class SimpleXMLElementPlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { $children = $this->renderer->renderChildren($o); @@ -63,15 +63,11 @@ public function renderObject(BasicObject $o) $header .= '('.$this->renderer->escape($s).') '; } - if (null === $s && $c = $o->getRepresentation('contents')) { - $c = \reset($c->contents); - - if ($c && null !== ($s = $c->getValueShort())) { - if (RichRenderer::$strlen_max && BlobObject::strlen($s) > RichRenderer::$strlen_max) { - $s = \substr($s, 0, RichRenderer::$strlen_max).'...'; - } - $header .= $this->renderer->escape($s); + if (null !== ($s = $o->getValueShort())) { + if (RichRenderer::$strlen_max) { + $s = Utils::truncateString($s, RichRenderer::$strlen_max); } + $header .= $this->renderer->escape($s); } $header = $this->renderer->renderHeaderWrapper($o, (bool) \strlen($children), $header); diff --git a/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php index 5443dbfd9a8e..4be024b627b2 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/SourcePlugin.php @@ -25,15 +25,15 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\Representation; -use Kint\Object\Representation\SourceRepresentation; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Representation\SourceRepresentation; class SourcePlugin extends Plugin implements TabPluginInterface { public function renderTab(Representation $r) { if (!($r instanceof SourceRepresentation) || empty($r->source)) { - return false; + return; } $source = $r->source; diff --git a/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php b/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php index 7cdbde72d2ad..779e13acd3a9 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TabPluginInterface.php @@ -25,9 +25,12 @@ namespace Kint\Renderer\Rich; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; interface TabPluginInterface extends PluginInterface { - public function renderTab(Representation $o); + /** + * @return null|string + */ + public function renderTab(Representation $r); } diff --git a/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php index cc3ee0f05da7..ac345a167f9d 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TablePlugin.php @@ -25,9 +25,9 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BlobObject; -use Kint\Object\Representation\Representation; use Kint\Renderer\RichRenderer; +use Kint\Utils; +use Kint\Zval\Representation\Representation; class TablePlugin extends Plugin implements TabPluginInterface { @@ -89,8 +89,8 @@ public function renderTab(Representation $r) case 'string': if ($field->encoding) { $val = $field->value->contents; - if (RichRenderer::$strlen_max && self::$respect_str_length && BlobObject::strlen($val) > RichRenderer::$strlen_max) { - $val = \substr($val, 0, RichRenderer::$strlen_max).'...'; + if (RichRenderer::$strlen_max && self::$respect_str_length) { + $val = Utils::truncateString($val, RichRenderer::$strlen_max); } $out .= $this->renderer->escape($val); diff --git a/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php b/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php index 6e3a2f8c5c83..f0c58e67a3cc 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TimestampPlugin.php @@ -27,7 +27,7 @@ use DateTime; use DateTimeZone; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; class TimestampPlugin extends Plugin implements TabPluginInterface { diff --git a/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php b/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php index 6ca19bb67157..ea7048bcdd09 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Rich/TraceFramePlugin.php @@ -25,14 +25,14 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; -use Kint\Object\TraceFrameObject; +use Kint\Zval\TraceFrameValue; +use Kint\Zval\Value; -class TraceFramePlugin extends Plugin implements ObjectPluginInterface +class TraceFramePlugin extends Plugin implements ValuePluginInterface { - public function renderObject(BasicObject $o) + public function renderValue(Value $o) { - if (!$o instanceof TraceFrameObject) { + if (!$o instanceof TraceFrameValue) { return; } diff --git a/system/ThirdParty/Kint/Renderer/Rich/ObjectPluginInterface.php b/system/ThirdParty/Kint/Renderer/Rich/ValuePluginInterface.php similarity index 88% rename from system/ThirdParty/Kint/Renderer/Rich/ObjectPluginInterface.php rename to system/ThirdParty/Kint/Renderer/Rich/ValuePluginInterface.php index f46aa2946ea3..8f750eda6bad 100644 --- a/system/ThirdParty/Kint/Renderer/Rich/ObjectPluginInterface.php +++ b/system/ThirdParty/Kint/Renderer/Rich/ValuePluginInterface.php @@ -25,9 +25,12 @@ namespace Kint\Renderer\Rich; -use Kint\Object\BasicObject; +use Kint\Zval\Value; -interface ObjectPluginInterface extends PluginInterface +interface ValuePluginInterface extends PluginInterface { - public function renderObject(BasicObject $o); + /** + * @return null|string + */ + public function renderValue(Value $o); } diff --git a/system/ThirdParty/Kint/Renderer/RichRenderer.php b/system/ThirdParty/Kint/Renderer/RichRenderer.php index dcd39eec8c53..94b7f98ab71f 100644 --- a/system/ThirdParty/Kint/Renderer/RichRenderer.php +++ b/system/ThirdParty/Kint/Renderer/RichRenderer.php @@ -26,18 +26,19 @@ namespace Kint\Renderer; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\BlobObject; -use Kint\Object\InstanceObject; -use Kint\Object\Representation\Representation; use Kint\Utils; +use Kint\Zval\BlobValue; +use Kint\Zval\InstanceValue; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Value; class RichRenderer extends Renderer { /** - * RichRenderer object plugins should implement Kint\Renderer\Rich\ObjectPluginInterface. + * RichRenderer value plugins should implement Kint\Renderer\Rich\ValuePluginInterface. */ - public static $object_plugins = array( + public static $value_plugins = [ + 'array_limit' => 'Kint\\Renderer\\Rich\\ArrayLimitPlugin', 'blacklist' => 'Kint\\Renderer\\Rich\\BlacklistPlugin', 'callable' => 'Kint\\Renderer\\Rich\\CallablePlugin', 'closure' => 'Kint\\Renderer\\Rich\\ClosurePlugin', @@ -46,12 +47,12 @@ class RichRenderer extends Renderer 'recursion' => 'Kint\\Renderer\\Rich\\RecursionPlugin', 'simplexml_element' => 'Kint\\Renderer\\Rich\\SimpleXMLElementPlugin', 'trace_frame' => 'Kint\\Renderer\\Rich\\TraceFramePlugin', - ); + ]; /** * RichRenderer tab plugins should implement Kint\Renderer\Rich\TabPluginInterface. */ - public static $tab_plugins = array( + public static $tab_plugins = [ 'binary' => 'Kint\\Renderer\\Rich\\BinaryPlugin', 'color' => 'Kint\\Renderer\\Rich\\ColorPlugin', 'docstring' => 'Kint\\Renderer\\Rich\\DocstringPlugin', @@ -59,18 +60,18 @@ class RichRenderer extends Renderer 'source' => 'Kint\\Renderer\\Rich\\SourcePlugin', 'table' => 'Kint\\Renderer\\Rich\\TablePlugin', 'timestamp' => 'Kint\\Renderer\\Rich\\TimestampPlugin', - ); - - public static $pre_render_sources = array( - 'script' => array( - array('Kint\\Renderer\\RichRenderer', 'renderJs'), - array('Kint\\Renderer\\Rich\\MicrotimePlugin', 'renderJs'), - ), - 'style' => array( - array('Kint\\Renderer\\RichRenderer', 'renderCss'), - ), - 'raw' => array(), - ); + ]; + + public static $pre_render_sources = [ + 'script' => [ + ['Kint\\Renderer\\RichRenderer', 'renderJs'], + ['Kint\\Renderer\\Rich\\MicrotimePlugin', 'renderJs'], + ], + 'style' => [ + ['Kint\\Renderer\\RichRenderer', 'renderCss'], + ], + 'raw' => [], + ]; /** * Whether or not to render access paths. @@ -118,7 +119,7 @@ class RichRenderer extends Renderer * * @var bool */ - public static $folder = true; + public static $folder = false; /** * Sort mode for object properties. @@ -132,7 +133,7 @@ class RichRenderer extends Renderer public static $always_pre_render = false; - protected $plugin_objs = array(); + protected $plugin_objs = []; protected $expand = false; protected $force_pre_render = false; protected $pre_render; @@ -193,7 +194,6 @@ public function setForcePreRender() public function setPreRender($pre_render) { - $this->setForcePreRender(); // TODO: Remove line in next major version $this->pre_render = $pre_render; } @@ -212,10 +212,11 @@ public function getUseFolder() return $this->use_folder; } - public function render(BasicObject $o) + public function render(Value $o) { - if ($plugin = $this->getPlugin(self::$object_plugins, $o->hints)) { - if (\strlen($output = $plugin->renderObject($o))) { + if ($plugin = $this->getPlugin(self::$value_plugins, $o->hints)) { + $output = $plugin->renderValue($o); + if (null !== $output && \strlen($output)) { return $output; } } @@ -231,7 +232,7 @@ public function renderNothing() return '
    No argument
    '; } - public function renderHeaderWrapper(BasicObject $o, $has_children, $contents) + public function renderHeaderWrapper(Value $o, $has_children, $contents) { $out = ''; } - public function renderHeader(BasicObject $o) + public function renderHeader(Value $o) { $output = ''; @@ -319,10 +320,10 @@ public function renderHeader(BasicObject $o) return \trim($output); } - public function renderChildren(BasicObject $o) + public function renderChildren(Value $o) { - $contents = array(); - $tabs = array(); + $contents = []; + $tabs = []; foreach ($o->getRepresentations() as $rep) { $result = $this->renderTab($o, $rep); @@ -353,10 +354,16 @@ public function renderChildren(BasicObject $o) $output .= $this->escape($tab->getLabel()).'
  • '; } - $output .= '
      '; + $output .= '
      '; - foreach ($contents as $tab) { - $output .= '
    • '.$tab.'
    • '; + foreach ($contents as $i => $tab) { + if (0 === $i) { + $output .= '
    • '; + } else { + $output .= '
    • '; + } + + $output .= $tab.'
    • '; } $output .= '
    '; @@ -441,7 +448,7 @@ public function postRender() !empty($this->call_info['callee']['class']) || !\in_array( $this->call_info['callee']['function'], - array('include', 'include_once', 'require', 'require_once'), + ['include', 'include_once', 'require', 'require_once'], true ) ) @@ -465,7 +472,7 @@ public function postRender() $output .= '
  • '.$this->ideLink($step['file'], $step['line']); // closing tag not required if (isset($step['function']) - && !\in_array($step['function'], array('include', 'include_once', 'require', 'require_once'), true) + && !\in_array($step['function'], ['include', 'include_once', 'require', 'require_once'], true) ) { $output .= ' ['; if (isset($step['class'])) { @@ -488,7 +495,7 @@ public function postRender() public function escape($string, $encoding = false) { if (false === $encoding) { - $encoding = BlobObject::detectEncoding($string); + $encoding = BlobValue::detectEncoding($string); } $original_encoding = $encoding; @@ -501,7 +508,7 @@ public function escape($string, $encoding = false) // this call converts all non-ASCII characters into numeirc htmlentities if (\function_exists('mb_encode_numericentity') && 'ASCII' !== $original_encoding) { - $string = \mb_encode_numericentity($string, array(0x80, 0xffff, 0, 0xffff), $encoding); + $string = \mb_encode_numericentity($string, [0x80, 0xFFFF, 0, 0xFFFF], $encoding); } return $string; @@ -525,10 +532,11 @@ public function ideLink($file, $line) return ''.$path.''; } - protected function renderTab(BasicObject $o, Representation $rep) + protected function renderTab(Value $o, Representation $rep) { if ($plugin = $this->getPlugin(self::$tab_plugins, $rep->hints)) { - if (\strlen($output = $plugin->renderTab($rep))) { + $output = $plugin->renderTab($rep); + if (null !== $output && \strlen($output)) { return $output; } } @@ -536,7 +544,7 @@ protected function renderTab(BasicObject $o, Representation $rep) if (\is_array($rep->contents)) { $output = ''; - if ($o instanceof InstanceObject && 'properties' === $rep->getName()) { + if ($o instanceof InstanceValue && 'properties' === $rep->getName()) { foreach (self::sortProperties($rep->contents, self::$sort) as $obj) { $output .= $this->render($obj); } @@ -559,7 +567,7 @@ protected function renderTab(BasicObject $o, Representation $rep) } else { if (\preg_match('/(:?[\\r\\n\\t\\f\\v]| {2})/', $rep->contents)) { $show_contents = true; - } elseif (self::$strlen_max && BlobObject::strlen($o->getValueShort()) > self::$strlen_max) { + } elseif (self::$strlen_max && null !== $o->getValueShort() && BlobValue::strlen($o->getValueShort()) > self::$strlen_max) { $show_contents = true; } @@ -573,9 +581,11 @@ protected function renderTab(BasicObject $o, Representation $rep) } } - if ($rep->contents instanceof BasicObject) { + if ($rep->contents instanceof Value) { return $this->render($rep->contents); } + + return ''; } protected function getPlugin(array $plugins, array $hints) @@ -607,6 +617,6 @@ protected static function renderCss() protected static function renderFolder() { - return '
    Kint
    '; + return '
    Kint
    '; } } diff --git a/system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php new file mode 100644 index 000000000000..12c16f397b1b --- /dev/null +++ b/system/ThirdParty/Kint/Renderer/Text/ArrayLimitPlugin.php @@ -0,0 +1,44 @@ +depth) { + $out .= $this->renderer->colorTitle($this->renderer->renderTitle($o)).PHP_EOL; + } + + $out .= $this->renderer->renderHeader($o).' '.$this->renderer->colorValue('ARRAY LIMIT').PHP_EOL; + + return $out; + } +} diff --git a/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php b/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php index 127d32a197f9..441368b10720 100644 --- a/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/BlacklistPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class BlacklistPlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php b/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php index 310b87e417b0..cea6cdf89a50 100644 --- a/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/DepthLimitPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class DepthLimitPlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php b/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php index 9128032c4ae0..ce63a5447d87 100644 --- a/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/MicrotimePlugin.php @@ -25,12 +25,12 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; -use Kint\Object\Representation\MicrotimeRepresentation; use Kint\Renderer\PlainRenderer; use Kint\Renderer\Rich\MicrotimePlugin as RichPlugin; use Kint\Renderer\TextRenderer; use Kint\Utils; +use Kint\Zval\Representation\MicrotimeRepresentation; +use Kint\Zval\Value; class MicrotimePlugin extends Plugin { @@ -45,12 +45,12 @@ public function __construct(TextRenderer $r) } } - public function render(BasicObject $o) + public function render(Value $o) { $r = $o->getRepresentation('microtime'); if (!$r instanceof MicrotimeRepresentation) { - return false; + return; } $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/Plugin.php b/system/ThirdParty/Kint/Renderer/Text/Plugin.php index 9de25c1a1147..61a1820f48c8 100644 --- a/system/ThirdParty/Kint/Renderer/Text/Plugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/Plugin.php @@ -25,8 +25,8 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; use Kint\Renderer\TextRenderer; +use Kint\Zval\Value; abstract class Plugin { @@ -37,5 +37,8 @@ public function __construct(TextRenderer $r) $this->renderer = $r; } - abstract public function render(BasicObject $o); + /** + * @return null|string + */ + abstract public function render(Value $o); } diff --git a/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php b/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php index 72c2257ca8fc..21956b6ec221 100644 --- a/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/RecursionPlugin.php @@ -25,11 +25,11 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; +use Kint\Zval\Value; class RecursionPlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; diff --git a/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php b/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php index 5833840cdf8f..b25f113e040b 100644 --- a/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php +++ b/system/ThirdParty/Kint/Renderer/Text/TracePlugin.php @@ -25,12 +25,12 @@ namespace Kint\Renderer\Text; -use Kint\Object\BasicObject; -use Kint\Object\MethodObject; +use Kint\Zval\MethodValue; +use Kint\Zval\Value; class TracePlugin extends Plugin { - public function render(BasicObject $o) + public function render(Value $o) { $out = ''; @@ -66,7 +66,7 @@ public function render(BasicObject $o) if (\is_string($frame->trace['function'])) { $framedesc .= $this->renderer->escape($frame->trace['function']).'(...)'; - } elseif ($frame->trace['function'] instanceof MethodObject) { + } elseif ($frame->trace['function'] instanceof MethodValue) { $framedesc .= $this->renderer->escape($frame->trace['function']->getName()); $framedesc .= '('.$this->renderer->escape($frame->trace['function']->getParams()).')'; } diff --git a/system/ThirdParty/Kint/Renderer/TextRenderer.php b/system/ThirdParty/Kint/Renderer/TextRenderer.php index 43b6c40d63b8..0cfba527c78b 100644 --- a/system/ThirdParty/Kint/Renderer/TextRenderer.php +++ b/system/ThirdParty/Kint/Renderer/TextRenderer.php @@ -26,33 +26,36 @@ namespace Kint\Renderer; use Kint\Kint; -use Kint\Object\BasicObject; -use Kint\Object\InstanceObject; use Kint\Utils; +use Kint\Zval\InstanceValue; +use Kint\Zval\Value; class TextRenderer extends Renderer { /** * TextRenderer plugins should be instances of Kint\Renderer\Text\Plugin. */ - public static $plugins = array( + public static $plugins = [ + 'array_limit' => 'Kint\\Renderer\\Text\\ArrayLimitPlugin', 'blacklist' => 'Kint\\Renderer\\Text\\BlacklistPlugin', 'depth_limit' => 'Kint\\Renderer\\Text\\DepthLimitPlugin', 'microtime' => 'Kint\\Renderer\\Text\\MicrotimePlugin', 'recursion' => 'Kint\\Renderer\\Text\\RecursionPlugin', 'trace' => 'Kint\\Renderer\\Text\\TracePlugin', - ); + ]; /** * Parser plugins must be instanceof one of these or * it will be removed for performance reasons. */ - public static $parser_plugin_whitelist = array( + public static $parser_plugin_whitelist = [ + 'Kint\\Parser\\ArrayLimitPlugin', + 'Kint\\Parser\\ArrayObjectPlugin', 'Kint\\Parser\\BlacklistPlugin', 'Kint\\Parser\\MicrotimePlugin', 'Kint\\Parser\\StreamPlugin', 'Kint\\Parser\\TracePlugin', - ); + ]; /** * The maximum length of a string before it is truncated. @@ -94,7 +97,7 @@ class TextRenderer extends Renderer public $header_width = 80; public $indent_width = 4; - protected $plugin_objs = array(); + protected $plugin_objs = []; public function __construct() { @@ -102,10 +105,11 @@ public function __construct() $this->indent_width = self::$default_indent; } - public function render(BasicObject $o) + public function render(Value $o) { if ($plugin = $this->getPlugin(self::$plugins, $o->hints)) { - if (\strlen($output = $plugin->render($o))) { + $output = $plugin->render($o); + if (null !== $output && \strlen($output)) { return $output; } } @@ -149,7 +153,7 @@ public function boxText($text, $width) return $out; } - public function renderTitle(BasicObject $o) + public function renderTitle(Value $o) { $name = (string) $o->getName(); @@ -160,9 +164,9 @@ public function renderTitle(BasicObject $o) return Utils::truncateString($name, $this->header_width); } - public function renderHeader(BasicObject $o) + public function renderHeader(Value $o) { - $output = array(); + $output = []; if ($o->depth) { if (null !== ($s = $o->getModifiers())) { @@ -200,7 +204,7 @@ public function renderHeader(BasicObject $o) return \str_repeat(' ', $o->depth * $this->indent_width).\implode(' ', $output); } - public function renderChildren(BasicObject $o) + public function renderChildren(Value $o) { if ('array' === $o->type) { $output = ' ['; @@ -213,7 +217,7 @@ public function renderChildren(BasicObject $o) $children = ''; if ($o->value && \is_array($o->value->contents)) { - if ($o instanceof InstanceObject && 'properties' === $o->value->getName()) { + if ($o instanceof InstanceValue && 'properties' === $o->value->getName()) { foreach (self::sortProperties($o->value->contents, self::$sort) as $obj) { $children .= $this->render($obj); } @@ -274,7 +278,7 @@ public function postRender() public function filterParserPlugins(array $plugins) { - $return = array(); + $return = []; foreach ($plugins as $index => $plugin) { foreach (self::$parser_plugin_whitelist as $whitelist) { @@ -313,7 +317,7 @@ protected function calledFrom() !empty($this->call_info['callee']['class']) || !\in_array( $this->call_info['callee']['function'], - array('include', 'include_once', 'require', 'require_once'), + ['include', 'include_once', 'require', 'require_once'], true ) ) diff --git a/system/ThirdParty/Kint/Utils.php b/system/ThirdParty/Kint/Utils.php index 27a24913fdb1..5143731c75c4 100644 --- a/system/ThirdParty/Kint/Utils.php +++ b/system/ThirdParty/Kint/Utils.php @@ -25,8 +25,7 @@ namespace Kint; -use InvalidArgumentException; -use Kint\Object\BlobObject; +use Kint\Zval\BlobValue; use ReflectionNamedType; use ReflectionType; @@ -51,15 +50,36 @@ private function __construct() */ public static function getHumanReadableBytes($value) { - static $unit = array('B', 'KB', 'MB', 'GB', 'TB'); + static $unit = ['B', 'KB', 'MB', 'GB', 'TB']; + + $negative = $value < 0; + $value = \abs($value); + + if ($value < 1024) { + $i = 0; + $value = \floor($value); + } elseif ($value < 0xFFFCCCCCCCCCCCC >> 40) { + $i = 1; + } elseif ($value < 0xFFFCCCCCCCCCCCC >> 30) { + $i = 2; + } elseif ($value < 0xFFFCCCCCCCCCCCC >> 20) { + $i = 3; + } else { + $i = 4; + } - $i = \floor(\log($value, 1024)); - $i = \min($i, 4); // Only go up to TB + if ($i) { + $value = $value / \pow(1024, $i); + } + + if ($negative) { + $value *= -1; + } - return array( - 'value' => (float) ($value / \pow(1024, $i)), + return [ + 'value' => \round($value, 1), 'unit' => $unit[$i], - ); + ]; } public static function isSequential(array $array) @@ -67,9 +87,14 @@ public static function isSequential(array $array) return \array_keys($array) === \range(0, \count($array) - 1); } + public static function isAssoc(array $array) + { + return (bool) \count(\array_filter(\array_keys($array), 'is_string')); + } + public static function composerGetExtras($key = 'kint') { - $extras = array(); + $extras = []; if (0 === \strpos(KINT_DIR, 'phar://')) { // Only run inside phar file, so skip for code coverage @@ -131,7 +156,7 @@ public static function isTrace(array $trace) return false; } - static $bt_structure = array( + static $bt_structure = [ 'function' => 'string', 'line' => 'integer', 'file' => 'string', @@ -139,7 +164,7 @@ public static function isTrace(array $trace) 'object' => 'object', 'type' => 'string', 'args' => 'array', - ); + ]; $file_found = false; @@ -169,7 +194,7 @@ public static function isTrace(array $trace) public static function traceFrameIsListed(array $frame, array $matches) { if (isset($frame['class'])) { - $called = array(\strtolower($frame['class']), \strtolower($frame['function'])); + $called = [\strtolower($frame['class']), \strtolower($frame['function'])]; } else { $called = \strtolower($frame['function']); } @@ -189,10 +214,10 @@ public static function normalizeAliases(array &$aliases) \preg_match('/^'.$name_regex.'$/', $alias[1]) && \preg_match('/^\\\\?('.$name_regex.'\\\\)*'.$name_regex.'$/', $alias[0]) ) { - $alias = array( + $alias = [ \strtolower(\ltrim($alias[0], '\\')), \strtolower($alias[1]), - ); + ]; } else { unset($aliases[$index]); continue; @@ -216,14 +241,15 @@ public static function normalizeAliases(array &$aliases) public static function truncateString($input, $length = PHP_INT_MAX, $end = '...', $encoding = false) { $length = (int) $length; - $endlength = BlobObject::strlen($end); + $endlength = BlobValue::strlen($end); if ($endlength >= $length) { - throw new InvalidArgumentException('Can\'t truncate a string to '.$length.' characters if ending with string '.$endlength.' characters long'); + $endlength = 0; + $end = ''; } - if (BlobObject::strlen($input, $encoding) > $length) { - return BlobObject::substr($input, 0, $length - $endlength, $encoding).$end; + if (BlobValue::strlen($input, $encoding) > $length) { + return BlobValue::substr($input, 0, $length - $endlength, $encoding).$end; } return $input; @@ -232,7 +258,12 @@ public static function truncateString($input, $length = PHP_INT_MAX, $end = '... public static function getTypeString(ReflectionType $type) { if ($type instanceof ReflectionNamedType) { - return $type->getName(); + $name = $type->getName(); + if ($type->allowsNull() && false === \strpos($name, '|')) { + $name = '?'.$name; + } + + return $name; } return (string) $type; // @codeCoverageIgnore diff --git a/system/ThirdParty/Kint/Object/BlobObject.php b/system/ThirdParty/Kint/Zval/BlobValue.php similarity index 95% rename from system/ThirdParty/Kint/Object/BlobObject.php rename to system/ThirdParty/Kint/Zval/BlobValue.php index 66d508ff70db..c5ac53acb096 100644 --- a/system/ThirdParty/Kint/Object/BlobObject.php +++ b/system/ThirdParty/Kint/Zval/BlobValue.php @@ -23,9 +23,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class BlobObject extends BasicObject +class BlobValue extends Value { /** * @var array Character encodings to detect @@ -51,10 +51,10 @@ class BlobObject extends BasicObject * * This depends on the mbstring extension */ - public static $char_encodings = array( + public static $char_encodings = [ 'ASCII', 'UTF-8', - ); + ]; /** * @var array Legacy character encodings to detect @@ -74,11 +74,11 @@ class BlobObject extends BasicObject * * This depends on the iconv extension */ - public static $legacy_encodings = array(); + public static $legacy_encodings = []; public $type = 'string'; public $encoding = false; - public $hints = array('string'); + public $hints = ['string']; public function getType() { @@ -100,7 +100,7 @@ public function getValueShort() } } - public function transplant(BasicObject $old) + public function transplant(Value $old) { parent::transplant($old); diff --git a/system/ThirdParty/Kint/Object/ClosureObject.php b/system/ThirdParty/Kint/Zval/ClosureValue.php similarity index 91% rename from system/ThirdParty/Kint/Object/ClosureObject.php rename to system/ThirdParty/Kint/Zval/ClosureValue.php index 344eceb21e77..95dd3fea9e39 100644 --- a/system/ThirdParty/Kint/Object/ClosureObject.php +++ b/system/ThirdParty/Kint/Zval/ClosureValue.php @@ -23,12 +23,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class ClosureObject extends InstanceObject +class ClosureValue extends InstanceValue { - public $parameters = array(); - public $hints = array('object', 'callable', 'closure'); + public $parameters = []; + public $hints = ['object', 'callable', 'closure']; private $paramcache; @@ -49,7 +49,7 @@ public function getParams() return $this->paramcache; } - $out = array(); + $out = []; foreach ($this->parameters as $p) { $type = $p->getType(); diff --git a/system/ThirdParty/Kint/Object/DateTimeObject.php b/system/ThirdParty/Kint/Zval/DateTimeValue.php similarity index 93% rename from system/ThirdParty/Kint/Object/DateTimeObject.php rename to system/ThirdParty/Kint/Zval/DateTimeValue.php index f8b1b3fd164f..1a8084ec3b9f 100644 --- a/system/ThirdParty/Kint/Object/DateTimeObject.php +++ b/system/ThirdParty/Kint/Zval/DateTimeValue.php @@ -23,15 +23,15 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use DateTime; -class DateTimeObject extends InstanceObject +class DateTimeValue extends InstanceValue { public $dt; - public $hints = array('object', 'datetime'); + public $hints = ['object', 'datetime']; public function __construct(DateTime $dt) { diff --git a/system/ThirdParty/Kint/Object/InstanceObject.php b/system/ThirdParty/Kint/Zval/InstanceValue.php similarity index 88% rename from system/ThirdParty/Kint/Object/InstanceObject.php rename to system/ThirdParty/Kint/Zval/InstanceValue.php index 943b33d8eabb..1c26600ca47e 100644 --- a/system/ThirdParty/Kint/Object/InstanceObject.php +++ b/system/ThirdParty/Kint/Zval/InstanceValue.php @@ -23,29 +23,29 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class InstanceObject extends BasicObject +class InstanceValue extends Value { public $type = 'object'; public $classname; - public $hash; + public $spl_object_hash; public $filename; public $startline; - public $hints = array('object'); + public $hints = ['object']; public function getType() { return $this->classname; } - public function transplant(BasicObject $old) + public function transplant(Value $old) { parent::transplant($old); if ($old instanceof self) { $this->classname = $old->classname; - $this->hash = $old->hash; + $this->spl_object_hash = $old->spl_object_hash; $this->filename = $old->filename; $this->startline = $old->startline; } @@ -56,7 +56,7 @@ public static function sortByHierarchy($a, $b) if (\is_string($a) && \is_string($b)) { $aclass = $a; $bclass = $b; - } elseif (!($a instanceof BasicObject) || !($b instanceof BasicObject)) { + } elseif (!($a instanceof Value) || !($b instanceof Value)) { return 0; } elseif ($a instanceof self && $b instanceof self) { $aclass = $a->classname; diff --git a/system/ThirdParty/Kint/Object/MethodObject.php b/system/ThirdParty/Kint/Zval/MethodValue.php similarity index 90% rename from system/ThirdParty/Kint/Object/MethodObject.php rename to system/ThirdParty/Kint/Zval/MethodValue.php index 78d49de22264..5d59a50765f2 100644 --- a/system/ThirdParty/Kint/Object/MethodObject.php +++ b/system/ThirdParty/Kint/Zval/MethodValue.php @@ -23,27 +23,27 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -use Kint\Object\Representation\DocstringRepresentation; use Kint\Utils; +use Kint\Zval\Representation\DocstringRepresentation; use ReflectionFunctionAbstract; use ReflectionMethod; -class MethodObject extends BasicObject +class MethodValue extends Value { public $type = 'method'; public $filename; public $startline; public $endline; - public $parameters = array(); + public $parameters = []; public $abstract; public $final; public $internal; public $docstring; public $returntype; public $return_reference = false; - public $hints = array('callable', 'method'); + public $hints = ['callable', 'method']; public $showparams = true; private $paramcache; @@ -61,7 +61,7 @@ public function __construct(ReflectionFunctionAbstract $method) $this->return_reference = $method->returnsReference(); foreach ($method->getParameters() as $param) { - $this->parameters[] = new ParameterObject($param); + $this->parameters[] = new ParameterValue($param); } if (KINT_PHP70) { @@ -73,15 +73,15 @@ public function __construct(ReflectionFunctionAbstract $method) if ($method instanceof ReflectionMethod) { $this->static = $method->isStatic(); - $this->operator = $this->static ? BasicObject::OPERATOR_STATIC : BasicObject::OPERATOR_OBJECT; + $this->operator = $this->static ? Value::OPERATOR_STATIC : Value::OPERATOR_OBJECT; $this->abstract = $method->isAbstract(); $this->final = $method->isFinal(); $this->owner_class = $method->getDeclaringClass()->name; - $this->access = BasicObject::ACCESS_PUBLIC; + $this->access = Value::ACCESS_PUBLIC; if ($method->isProtected()) { - $this->access = BasicObject::ACCESS_PROTECTED; + $this->access = Value::ACCESS_PROTECTED; } elseif ($method->isPrivate()) { - $this->access = BasicObject::ACCESS_PRIVATE; + $this->access = Value::ACCESS_PRIVATE; } } @@ -100,9 +100,9 @@ public function __construct(ReflectionFunctionAbstract $method) $this->value = $docstring; } - public function setAccessPathFrom(InstanceObject $parent) + public function setAccessPathFrom(InstanceValue $parent) { - static $magic = array( + static $magic = [ '__call' => true, '__callstatic' => true, '__clone' => true, @@ -118,7 +118,7 @@ public function setAccessPathFrom(InstanceObject $parent) '__tostring' => true, '__unset' => true, '__wakeup' => true, - ); + ]; $name = \strtolower($this->name); @@ -172,12 +172,12 @@ public function getValueShort() public function getModifiers() { - $mods = array( + $mods = [ $this->abstract ? 'abstract' : null, $this->final ? 'final' : null, $this->getAccess(), $this->static ? 'static' : null, - ); + ]; $out = ''; @@ -209,7 +209,7 @@ public function getParams() return $this->paramcache; } - $out = array(); + $out = []; foreach ($this->parameters as $p) { $type = $p->getType(); diff --git a/system/ThirdParty/Kint/Object/ParameterObject.php b/system/ThirdParty/Kint/Zval/ParameterValue.php similarity index 95% rename from system/ThirdParty/Kint/Object/ParameterObject.php rename to system/ThirdParty/Kint/Zval/ParameterValue.php index 4bed551f548b..29bcbe72bb2b 100644 --- a/system/ThirdParty/Kint/Object/ParameterObject.php +++ b/system/ThirdParty/Kint/Zval/ParameterValue.php @@ -23,18 +23,18 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use Kint\Utils; use ReflectionException; use ReflectionParameter; -class ParameterObject extends BasicObject +class ParameterValue extends Value { public $type_hint; public $default; public $position; - public $hints = array('parameter'); + public $hints = ['parameter']; public function __construct(ReflectionParameter $param) { @@ -64,7 +64,6 @@ public function __construct(ReflectionParameter $param) $this->position = $param->getPosition(); if ($param->isDefaultValueAvailable()) { - /** @var mixed Psalm bug workaround */ $default = $param->getDefaultValue(); switch (\gettype($default)) { case 'NULL': diff --git a/system/ThirdParty/Kint/Object/Representation/ColorRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php similarity index 96% rename from system/ThirdParty/Kint/Object/Representation/ColorRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php index d6a072f50891..533ccb35d940 100644 --- a/system/ThirdParty/Kint/Object/Representation/ColorRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/ColorRepresentation.php @@ -23,7 +23,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; use InvalidArgumentException; @@ -39,7 +39,7 @@ class ColorRepresentation extends Representation const COLOR_HEX_4 = 8; const COLOR_HEX_8 = 9; - public static $color_map = array( + public static $color_map = [ 'aliceblue' => 'f0f8ff', 'antiquewhite' => 'faebd7', 'aqua' => '00ffff', @@ -191,7 +191,7 @@ class ColorRepresentation extends Representation 'whitesmoke' => 'f5f5f5', 'yellow' => 'ffff00', 'yellowgreen' => '9acd32', - ); + ]; public $r = 0; public $g = 0; @@ -199,7 +199,7 @@ class ColorRepresentation extends Representation public $a = 1.0; public $variant; public $implicit_label = true; - public $hints = array('color'); + public $hints = ['color']; public function __construct($value) { @@ -254,7 +254,7 @@ public function getColor($variant = null) return \sprintf('hsla(%d, %d%%, %d%%, %s)', $val[0], $val[1], $val[2], \round($this->a, 4)); case self::COLOR_HEX_4: - if (0 === $this->r % 0x11 && 0 === $this->g % 0x11 && 0 === $this->b % 0x11 && 0 === ($this->a * 255) % 0x11) { + if (0 === $this->r % 0x11 && 0 === $this->g % 0x11 && 0 === $this->b % 0x11 && 0 === ((int) ($this->a * 255)) % 0x11) { return \sprintf( '#%1X%1X%1X%1X', \round($this->r / 0x11), @@ -413,21 +413,19 @@ protected function setValuesFromFunction($value) if (3 === $i) { $color = $color / 100; - } elseif (\in_array($variant, array(self::COLOR_RGB, self::COLOR_RGBA), true)) { + } elseif (\in_array($variant, [self::COLOR_RGB, self::COLOR_RGBA], true)) { $color = \round($color / 100 * 0xFF); } } $color = (float) $color; - if (0 === $i && \in_array($variant, array(self::COLOR_HSL, self::COLOR_HSLA), true)) { - $color = ($color % 360 + 360) % 360; + if (0 === $i && \in_array($variant, [self::COLOR_HSL, self::COLOR_HSLA], true)) { + $color = \fmod(\fmod($color, 360) + 360, 360); } } - /** @var float[] Psalm bug workaround */ - $params = \array_map('floatval', $params); - + /** @var non-empty-array $params Psalm bug workaround */ switch ($variant) { case self::COLOR_RGBA: case self::COLOR_RGB: @@ -486,11 +484,11 @@ public static function hslToRgb($h, $s, $l) $m2 = ($l <= 0.5) ? $l * ($s + 1) : $l + $s - $l * $s; $m1 = $l * 2 - $m2; - return array( + return [ (int) \round(self::hueToRgb($m1, $m2, $h + 1 / 3) * 0xFF), (int) \round(self::hueToRgb($m1, $m2, $h) * 0xFF), (int) \round(self::hueToRgb($m1, $m2, $h - 1 / 3) * 0xFF), - ); + ]; } /** @@ -541,17 +539,16 @@ public static function rgbToHsl($red, $green, $blue) } } - return array( - (float) ($H * 360 % 360), + return [ + \fmod($H * 360, 360), (float) ($S * 100), (float) ($L * 100), - ); + ]; } /** * Helper function for hslToRgb. Even blacker magic. * - * * @param float $m1 * @param float $m2 * @param float $hue diff --git a/system/ThirdParty/Kint/Object/Representation/DocstringRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/DocstringRepresentation.php similarity index 97% rename from system/ThirdParty/Kint/Object/Representation/DocstringRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/DocstringRepresentation.php index 488d8d6e0748..8acdcc1e8583 100644 --- a/system/ThirdParty/Kint/Object/Representation/DocstringRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/DocstringRepresentation.php @@ -23,14 +23,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; class DocstringRepresentation extends Representation { public $file; public $line; public $class; - public $hints = array('docstring'); + public $hints = ['docstring']; public function __construct($docstring, $file, $line, $class = null) { diff --git a/system/ThirdParty/Kint/Object/Representation/MicrotimeRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php similarity index 96% rename from system/ThirdParty/Kint/Object/Representation/MicrotimeRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php index b9f4dacb314b..aedc2edffb6e 100644 --- a/system/ThirdParty/Kint/Object/Representation/MicrotimeRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/MicrotimeRepresentation.php @@ -23,7 +23,7 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; use DateTime; @@ -40,7 +40,7 @@ class MicrotimeRepresentation extends Representation public $mem_real = 0; public $mem_peak = 0; public $mem_peak_real = 0; - public $hints = array('microtime'); + public $hints = ['microtime']; public function __construct($seconds, $microseconds, $group, $lap = null, $total = null, $i = 0) { diff --git a/system/ThirdParty/Kint/Object/Representation/Representation.php b/system/ThirdParty/Kint/Zval/Representation/Representation.php similarity index 95% rename from system/ThirdParty/Kint/Object/Representation/Representation.php rename to system/ThirdParty/Kint/Zval/Representation/Representation.php index 0c911a4eaa98..2d649d077c13 100644 --- a/system/ThirdParty/Kint/Object/Representation/Representation.php +++ b/system/ThirdParty/Kint/Zval/Representation/Representation.php @@ -23,14 +23,14 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; class Representation { public $label; public $implicit_label = false; - public $hints = array(); - public $contents = array(); + public $hints = []; + public $contents = []; protected $name; diff --git a/system/ThirdParty/Kint/Object/Representation/SourceRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php similarity index 96% rename from system/ThirdParty/Kint/Object/Representation/SourceRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php index c2cf1204f1a9..65077d6218c6 100644 --- a/system/ThirdParty/Kint/Object/Representation/SourceRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/SourceRepresentation.php @@ -23,12 +23,12 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; class SourceRepresentation extends Representation { - public $hints = array('source'); - public $source = array(); + public $hints = ['source']; + public $source = []; public $filename; public $line = 0; public $showfilename = false; diff --git a/system/ThirdParty/Kint/Object/Representation/SplFileInfoRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php similarity index 95% rename from system/ThirdParty/Kint/Object/Representation/SplFileInfoRepresentation.php rename to system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php index 3df50e6a1284..6208451b41ed 100644 --- a/system/ThirdParty/Kint/Object/Representation/SplFileInfoRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php @@ -23,29 +23,29 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object\Representation; +namespace Kint\Zval\Representation; use Kint\Utils; use SplFileInfo; class SplFileInfoRepresentation extends Representation { - public $perms; + public $perms = null; public $flags; public $path; - public $realpath; - public $linktarget; + public $realpath = null; + public $linktarget = null; public $size; public $is_dir = false; public $is_file = false; public $is_link = false; - public $owner; - public $group; + public $owner = null; + public $group = null; public $ctime; public $mtime; public $typename = 'Unknown file'; public $typeflag = '-'; - public $hints = array('fspath'); + public $hints = ['fspath']; public function __construct(SplFileInfo $fileInfo) { @@ -109,7 +109,7 @@ public function __construct(SplFileInfo $fileInfo) break; } - $this->flags = array($this->typeflag); + $this->flags = [$this->typeflag]; // User $this->flags[] = (($this->perms & 0400) ? 'r' : '-'); diff --git a/system/ThirdParty/Kint/Object/ResourceObject.php b/system/ThirdParty/Kint/Zval/ResourceValue.php similarity index 93% rename from system/ThirdParty/Kint/Object/ResourceObject.php rename to system/ThirdParty/Kint/Zval/ResourceValue.php index a43f85d900ee..ef1c5541e476 100644 --- a/system/ThirdParty/Kint/Object/ResourceObject.php +++ b/system/ThirdParty/Kint/Zval/ResourceValue.php @@ -23,9 +23,9 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class ResourceObject extends BasicObject +class ResourceValue extends Value { public $resource_type; @@ -38,7 +38,7 @@ public function getType() return 'resource'; } - public function transplant(BasicObject $old) + public function transplant(Value $old) { parent::transplant($old); diff --git a/system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php b/system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php new file mode 100644 index 000000000000..b385bc6daa2e --- /dev/null +++ b/system/ThirdParty/Kint/Zval/SimpleXMLElementValue.php @@ -0,0 +1,48 @@ +is_string_value = $is_string_value; + } + + public function getValueShort() + { + if ($this->is_string_value && ($rep = $this->value) && 'contents' === $rep->getName() && 'string' === \gettype($rep->contents)) { + return '"'.$rep->contents.'"'; + } + } +} diff --git a/system/ThirdParty/Kint/Object/StreamObject.php b/system/ThirdParty/Kint/Zval/StreamValue.php similarity index 96% rename from system/ThirdParty/Kint/Object/StreamObject.php rename to system/ThirdParty/Kint/Zval/StreamValue.php index 358f2743e94f..af909c84f39a 100644 --- a/system/ThirdParty/Kint/Object/StreamObject.php +++ b/system/ThirdParty/Kint/Zval/StreamValue.php @@ -23,11 +23,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use Kint\Kint; -class StreamObject extends ResourceObject +class StreamValue extends ResourceValue { public $stream_meta; diff --git a/system/ThirdParty/Kint/Object/ThrowableObject.php b/system/ThirdParty/Kint/Zval/ThrowableValue.php similarity index 88% rename from system/ThirdParty/Kint/Object/ThrowableObject.php rename to system/ThirdParty/Kint/Zval/ThrowableValue.php index 2a86d57538df..26676481c26d 100644 --- a/system/ThirdParty/Kint/Object/ThrowableObject.php +++ b/system/ThirdParty/Kint/Zval/ThrowableValue.php @@ -23,21 +23,21 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; use Exception; use InvalidArgumentException; use Throwable; -class ThrowableObject extends InstanceObject +class ThrowableValue extends InstanceValue { public $message; - public $hints = array('object', 'throwable'); + public $hints = ['object', 'throwable']; public function __construct($throw) { if (!$throw instanceof Exception && (!KINT_PHP70 || !$throw instanceof Throwable)) { - throw new InvalidArgumentException('ThrowableObject must be constructed with a Throwable'); + throw new InvalidArgumentException('ThrowableValue must be constructed with a Throwable'); } parent::__construct(); diff --git a/system/ThirdParty/Kint/Object/TraceFrameObject.php b/system/ThirdParty/Kint/Zval/TraceFrameValue.php similarity index 81% rename from system/ThirdParty/Kint/Object/TraceFrameObject.php rename to system/ThirdParty/Kint/Zval/TraceFrameValue.php index 4259aeeec1aa..62f7829192d2 100644 --- a/system/ThirdParty/Kint/Object/TraceFrameObject.php +++ b/system/ThirdParty/Kint/Zval/TraceFrameValue.php @@ -23,52 +23,57 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -use Kint\Object\Representation\Representation; -use Kint\Object\Representation\SourceRepresentation; +use InvalidArgumentException; +use Kint\Zval\Representation\Representation; +use Kint\Zval\Representation\SourceRepresentation; use ReflectionFunction; use ReflectionMethod; -class TraceFrameObject extends BasicObject +class TraceFrameValue extends Value { public $trace; - public $hints = array('trace_frame'); + public $hints = ['trace_frame']; - public function __construct(BasicObject $base, array $raw_frame) + public function __construct(Value $base, array $raw_frame) { parent::__construct(); $this->transplant($base); - $this->trace = array( - 'function' => isset($raw_frame['function']) ? $raw_frame['function'] : null, + if (!isset($this->value)) { + throw new InvalidArgumentException('Tried to create TraceFrameValue from Value with no value representation'); + } + + $this->trace = [ + 'function' => $raw_frame['function'], 'line' => isset($raw_frame['line']) ? $raw_frame['line'] : null, 'file' => isset($raw_frame['file']) ? $raw_frame['file'] : null, 'class' => isset($raw_frame['class']) ? $raw_frame['class'] : null, 'type' => isset($raw_frame['type']) ? $raw_frame['type'] : null, 'object' => null, 'args' => null, - ); + ]; if ($this->trace['class'] && \method_exists($this->trace['class'], $this->trace['function'])) { $func = new ReflectionMethod($this->trace['class'], $this->trace['function']); - $this->trace['function'] = new MethodObject($func); + $this->trace['function'] = new MethodValue($func); } elseif (!$this->trace['class'] && \function_exists($this->trace['function'])) { $func = new ReflectionFunction($this->trace['function']); - $this->trace['function'] = new MethodObject($func); + $this->trace['function'] = new MethodValue($func); } foreach ($this->value->contents as $frame_prop) { if ('object' === $frame_prop->name) { $this->trace['object'] = $frame_prop; $this->trace['object']->name = null; - $this->trace['object']->operator = BasicObject::OPERATOR_NONE; + $this->trace['object']->operator = Value::OPERATOR_NONE; } if ('args' === $frame_prop->name) { $this->trace['args'] = $frame_prop->value->contents; - if ($this->trace['function'] instanceof MethodObject) { + if ($this->trace['function'] instanceof MethodValue) { foreach (\array_values($this->trace['function']->parameters) as $param) { if (isset($this->trace['args'][$param->position])) { $this->trace['args'][$param->position]->name = $param->getName(); diff --git a/system/ThirdParty/Kint/Object/TraceObject.php b/system/ThirdParty/Kint/Zval/TraceValue.php similarity index 93% rename from system/ThirdParty/Kint/Object/TraceObject.php rename to system/ThirdParty/Kint/Zval/TraceValue.php index a780b082bf9c..4d0edc42219a 100644 --- a/system/ThirdParty/Kint/Object/TraceObject.php +++ b/system/ThirdParty/Kint/Zval/TraceValue.php @@ -23,11 +23,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -class TraceObject extends BasicObject +class TraceValue extends Value { - public $hints = array('trace'); + public $hints = ['trace']; public function getType() { diff --git a/system/ThirdParty/Kint/Object/BasicObject.php b/system/ThirdParty/Kint/Zval/Value.php similarity index 91% rename from system/ThirdParty/Kint/Object/BasicObject.php rename to system/ThirdParty/Kint/Zval/Value.php index d69347eb8dfc..747efb5f718f 100644 --- a/system/ThirdParty/Kint/Object/BasicObject.php +++ b/system/ThirdParty/Kint/Zval/Value.php @@ -23,11 +23,11 @@ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -namespace Kint\Object; +namespace Kint\Zval; -use Kint\Object\Representation\Representation; +use Kint\Zval\Representation\Representation; -class BasicObject +class Value { const ACCESS_NONE = null; const ACCESS_PUBLIC = 1; @@ -51,9 +51,9 @@ class BasicObject public $depth = 0; public $size; public $value; - public $hints = array(); + public $hints = []; - protected $representations = array(); + protected $representations = []; public function __construct() { @@ -70,7 +70,7 @@ public function addRepresentation(Representation $rep, $pos = null) } else { $this->representations = \array_merge( \array_slice($this->representations, 0, $pos), - array($rep->getName() => $rep), + [$rep->getName() => $rep], \array_slice($this->representations, $pos) ); } @@ -111,7 +111,7 @@ public function getRepresentations() public function clearRepresentations() { - $this->representations = array(); + $this->representations = []; } public function getType() @@ -131,7 +131,7 @@ public function getModifiers() $out .= ' static'; } - if (\strlen($out)) { + if (null !== $out && \strlen($out)) { return \ltrim($out); } } @@ -188,7 +188,7 @@ public function getAccessPath() return $this->access_path; } - public function transplant(BasicObject $old) + public function transplant(Value $old) { $this->name = $old->name; $this->size = $old->size; @@ -212,7 +212,7 @@ public function transplant(BasicObject $old) * @param null|string $name * @param null|string $access_path * - * @return \Kint\Object\BasicObject + * @return \Kint\Zval\Value */ public static function blank($name = null, $access_path = null) { @@ -223,19 +223,19 @@ public static function blank($name = null, $access_path = null) return $o; } - public static function sortByAccess(BasicObject $a, BasicObject $b) + public static function sortByAccess(Value $a, Value $b) { - static $sorts = array( + static $sorts = [ self::ACCESS_PUBLIC => 1, self::ACCESS_PROTECTED => 2, self::ACCESS_PRIVATE => 3, self::ACCESS_NONE => 4, - ); + ]; return $sorts[$a->access] - $sorts[$b->access]; } - public static function sortByName(BasicObject $a, BasicObject $b) + public static function sortByName(Value $a, Value $b) { $ret = \strnatcasecmp($a->name, $b->name); diff --git a/system/ThirdParty/Kint/init.php b/system/ThirdParty/Kint/init.php index 952e041400ff..2e7c62b4b1c9 100644 --- a/system/ThirdParty/Kint/init.php +++ b/system/ThirdParty/Kint/init.php @@ -30,31 +30,33 @@ return; } -if (\version_compare(PHP_VERSION, '5.3') < 0) { - throw new Exception('Kint 3.0 requires PHP 5.3 or higher'); +if (\version_compare(PHP_VERSION, '5.6') < 0) { + throw new Exception('Kint 4.0 requires PHP 5.6 or higher'); } \define('KINT_DIR', __DIR__); \define('KINT_WIN', DIRECTORY_SEPARATOR !== '/'); -\define('KINT_PHP56', (\version_compare(PHP_VERSION, '5.6') >= 0)); \define('KINT_PHP70', (\version_compare(PHP_VERSION, '7.0') >= 0)); +\define('KINT_PHP71', (\version_compare(PHP_VERSION, '7.1') >= 0)); \define('KINT_PHP72', (\version_compare(PHP_VERSION, '7.2') >= 0)); \define('KINT_PHP73', (\version_compare(PHP_VERSION, '7.3') >= 0)); \define('KINT_PHP74', (\version_compare(PHP_VERSION, '7.4') >= 0)); +\define('KINT_PHP80', (\version_compare(PHP_VERSION, '8.0') >= 0)); +\define('KINT_PHP81', (\version_compare(PHP_VERSION, '8.1') >= 0)); // Dynamic default settings Kint::$file_link_format = \ini_get('xdebug.file_link_format'); if (isset($_SERVER['DOCUMENT_ROOT'])) { - Kint::$app_root_dirs = array( + Kint::$app_root_dirs = [ $_SERVER['DOCUMENT_ROOT'] => '', \realpath($_SERVER['DOCUMENT_ROOT']) => '', - ); + ]; } Utils::composerSkipFlags(); if ((!\defined('KINT_SKIP_FACADE') || !KINT_SKIP_FACADE) && !\class_exists('Kint')) { - \class_alias('Kint\\Kint', 'Kint'); + \class_alias(Kint::class, 'Kint'); } if (!\defined('KINT_SKIP_HELPERS') || !KINT_SKIP_HELPERS) { diff --git a/system/ThirdParty/Kint/init_helpers.php b/system/ThirdParty/Kint/init_helpers.php index b961d67f1af5..3dca84c35f08 100644 --- a/system/ThirdParty/Kint/init_helpers.php +++ b/system/ThirdParty/Kint/init_helpers.php @@ -24,6 +24,7 @@ */ use Kint\Kint; +use Kint\Renderer\CliRenderer; if (!\function_exists('d')) { /** @@ -35,7 +36,7 @@ function d() { $args = \func_get_args(); - return \call_user_func_array(array('Kint', 'dump'), $args); + return \call_user_func_array(['Kint', 'dump'], $args); } Kint::$aliases[] = 'd'; @@ -59,23 +60,28 @@ function d() */ function s() { - if (!Kint::$enabled_mode) { + if (false === Kint::$enabled_mode) { return 0; } - $stash = Kint::$enabled_mode; + $kstash = Kint::$enabled_mode; + $cstash = CliRenderer::$cli_colors; if (Kint::MODE_TEXT !== Kint::$enabled_mode) { Kint::$enabled_mode = Kint::MODE_PLAIN; + if (PHP_SAPI === 'cli' && true === Kint::$cli_detection) { Kint::$enabled_mode = Kint::$mode_default_cli; } } + CliRenderer::$cli_colors = false; + $args = \func_get_args(); - $out = \call_user_func_array(array('Kint', 'dump'), $args); + $out = \call_user_func_array(['Kint', 'dump'], $args); - Kint::$enabled_mode = $stash; + Kint::$enabled_mode = $kstash; + CliRenderer::$cli_colors = $cstash; return $out; } diff --git a/system/ThirdParty/Kint/resources/compiled/aante-light.css b/system/ThirdParty/Kint/resources/compiled/aante-light.css index 2de17accf9a9..dc7a40a73489 100644 --- a/system/ThirdParty/Kint/resources/compiled/aante-light.css +++ b/system/ThirdParty/Kint/resources/compiled/aante-light.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:none}.kint-rich.kint-folder.kint-show{display:block}.kint-rich.kint-folder dd.kint-folder{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#aaa;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#f8f8f8;border:1px solid #d7d7d7;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#aaa}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #d7d7d7}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#06f;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:red}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #d7d7d7;background:#f8f8f8;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#f8f8f8;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#f8f8f8}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #d7d7d7;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#f8f8f8;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#f8f8f8;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f8f8f8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#f8f8f8;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #d7d7d7}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#f8f8f8;border:1px solid #d7d7d7;border-top:0}.kint-rich ul.kint-tabs>li{background:#f8f8f8;border:1px solid #d7d7d7;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#aaa;color:red}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#f8f8f8;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#aaa;color:red}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #d7d7d7;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#aaa}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #d7d7d7;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#f8f8f8;color:#1d1e1e}.kint-rich table td{background:#f8f8f8;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #aaa inset}.kint-rich table tr:hover var{color:red}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #f8f8f8}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #aaa;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#f8f8f8}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #aaa,0 1px #aaa,1px 0 #aaa,0 -1px #aaa;color:#f8f8f8;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#f8f8f8}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#f8f8f8;border:1px solid #d7d7d7;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #d7d7d7;background:#fff;font-weight:bold;padding-top:0;border-bottom:1px solid #fff !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #fff}.kint-rich ul>li>pre{border:1px solid #d7d7d7}.kint-rich dt:hover+dd>ul{border-color:#aaa}.kint-rich pre{background:#fff;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#cfc}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#fff}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#fff}.kint-rich table tr:hover>td{box-shadow:none;background:#cfc} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#aaa;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#f8f8f8;border:1px solid #d7d7d7;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#aaa}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #d7d7d7}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#06f;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:red}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #d7d7d7;background:#f8f8f8;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#f8f8f8;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#f8f8f8}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #d7d7d7;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#f8f8f8;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#f8f8f8;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f8f8f8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#f8f8f8;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #d7d7d7}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#f8f8f8;border:1px solid #d7d7d7;border-top:0}.kint-rich ul.kint-tabs>li{background:#f8f8f8;border:1px solid #d7d7d7;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#aaa;color:red}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#f8f8f8;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#aaa;color:red}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #d7d7d7;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#aaa}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #d7d7d7;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#f8f8f8;color:#1d1e1e}.kint-rich table td{background:#f8f8f8;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #aaa inset}.kint-rich table tr:hover var{color:red}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #f8f8f8}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #aaa;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#f8f8f8}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #aaa,0 1px #aaa,1px 0 #aaa,0 -1px #aaa;color:#f8f8f8;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px red}.kint-rich dt{font-weight:normal}.kint-rich dt.kint-parent{margin-top:4px}.kint-rich dl dl{margin-top:4px;padding-left:25px;border-left:none}.kint-rich>dl>dt{background:#f8f8f8}.kint-rich ul{margin:0;padding-left:0}.kint-rich ul:not(.kint-tabs)>li{border-left:0}.kint-rich ul.kint-tabs{background:#f8f8f8;border:1px solid #d7d7d7;border-width:0 1px 1px 1px;padding:4px 0 0 12px;margin-left:-1px;margin-top:-1px}.kint-rich ul.kint-tabs li,.kint-rich ul.kint-tabs li+li{margin:0 0 0 4px}.kint-rich ul.kint-tabs li{border-bottom-width:0;height:25px}.kint-rich ul.kint-tabs li:first-child{margin-left:0}.kint-rich ul.kint-tabs li.kint-active-tab{border-top:1px solid #d7d7d7;background:#fff;font-weight:bold;padding-top:0;border-bottom:1px solid #fff !important;margin-bottom:-1px}.kint-rich ul.kint-tabs li.kint-active-tab:hover{border-bottom:1px solid #fff}.kint-rich ul>li>pre{border:1px solid #d7d7d7}.kint-rich dt:hover+dd>ul{border-color:#aaa}.kint-rich pre{background:#fff;margin-top:4px;margin-left:25px}.kint-rich .kint-source{margin-left:-1px}.kint-rich .kint-source .kint-highlight{background:#cfc}.kint-rich .kint-parent.kint-show>.kint-search{border-bottom-width:1px}.kint-rich table td{background:#fff}.kint-rich table td>dl{padding:0;margin:0}.kint-rich table td>dl>dt.kint-parent{margin:0}.kint-rich table td:first-child,.kint-rich table td,.kint-rich table th{padding:2px 4px}.kint-rich table dd,.kint-rich table dt{background:#fff}.kint-rich table tr:hover>td{box-shadow:none;background:#cfc} diff --git a/system/ThirdParty/Kint/resources/compiled/microtime.js b/system/ThirdParty/Kint/resources/compiled/microtime.js index 20e3445b2b05..c9b8f00a58d7 100644 --- a/system/ThirdParty/Kint/resources/compiled/microtime.js +++ b/system/ThirdParty/Kint/resources/compiled/microtime.js @@ -1 +1 @@ -void 0===window.kintMicrotimeInitialized&&(window.kintMicrotimeInitialized=1,window.addEventListener("load",function(){"use strict";var c={},i=Array.prototype.slice.call(document.querySelectorAll("[data-kint-microtime-group]"),0);i.forEach(function(i){if(i.querySelector(".kint-microtime-lap")){var t=i.getAttribute("data-kint-microtime-group"),e=parseFloat(i.querySelector(".kint-microtime-lap").innerHTML),r=parseFloat(i.querySelector(".kint-microtime-avg").innerHTML);void 0===c[t]&&(c[t]={}),(void 0===c[t].min||c[t].min>e)&&(c[t].min=e),(void 0===c[t].max||c[t].maxe)&&(a[i].min=e),(void 0===a[i].max||a[i].maxdl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxnIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0iI0ZGRiI+PHBhdGggZD0iTTEgMWgyOHYyOEgxem01IDE0aDE4bS05IDlWNk0xIDYxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzM3OSIvPjxwYXRoIGQ9Ik0xIDMxaDI4djI4SDF6bTUgMTRoMThtLTkgOVYzNk0xIDkxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzVBMyIvPjxwYXRoIGQ9Ik0xIDEyMWgyOHYyOEgxem01IDVsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZT0iI0NDQyIvPjwvZz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #b6cedb}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#0092db;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#5cb730}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#e0eaef;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#e0eaef}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #b6cedb;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#c1d4df;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#d0d0d0;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#e8e8e8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#c1d4df;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #b6cedb}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint-rich ul.kint-tabs>li{background:#c1d4df;border:1px solid #b6cedb;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#0092db;color:#5cb730}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#e0eaef;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db;color:#5cb730}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #b6cedb;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#0092db}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #b6cedb;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-rich table td{background:#e0eaef;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-rich table tr:hover var{color:#5cb730}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #c1d4df}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #0092db;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#c1d4df}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #0092db,0 1px #0092db,1px 0 #0092db,0 -1px #0092db;color:#e0eaef;font-weight:bold}.kint-rich>dl>dt{background:linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%)}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li{background:#e0eaef}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint-rich>dl.kint-trace>dt{background:linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%)}.kint-rich .kint-source .kint-highlight{background:#f0eb96} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:8px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#0092db;color:#1d1e1e}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #5cb730}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#1d1e1e;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:8px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#e0eaef;border:1px solid #b6cedb;color:#1d1e1e;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:4px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#0092db}.kint-rich>dl dl{padding:0 0 0 12px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxnIHN0cm9rZS13aWR0aD0iMiIgZmlsbD0iI0ZGRiI+PHBhdGggZD0iTTEgMWgyOHYyOEgxem01IDE0aDE4bS05IDlWNk0xIDYxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzM3OSIvPjxwYXRoIGQ9Ik0xIDMxaDI4djI4SDF6bTUgMTRoMThtLTkgOVYzNk0xIDkxaDI4djI4SDF6bTUgMTRoMTgiIHN0cm9rZT0iIzVBMyIvPjxwYXRoIGQ9Ik0xIDEyMWgyOHYyOEgxem01IDVsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZT0iI0NDQyIvPjwvZz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #b6cedb}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#0092db;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#5cb730}.kint-rich dfn{font-style:normal;font-family:monospace;color:#1d1e1e}.kint-rich pre{color:#1d1e1e;margin:0 0 0 12px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #b6cedb;background:#e0eaef;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(29,30,30,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#e0eaef;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#1d1e1e;background:#e0eaef}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #b6cedb;border-top-width:0;border-bottom-width:0;padding:4px;float:right !important;margin:-4px 0;color:#1d1e1e;background:#c1d4df;height:24px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#d0d0d0;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#e8e8e8}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#c1d4df;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#1d1e1e}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#1d1e1e;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#1d1e1e;border-bottom:1px dotted #1d1e1e}.kint-rich ul{list-style:none;padding-left:12px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #b6cedb}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 12px;padding-left:0;background:#e0eaef;border:1px solid #b6cedb;border-top:0}.kint-rich ul.kint-tabs>li{background:#c1d4df;border:1px solid #b6cedb;cursor:pointer;display:inline-block;height:24px;margin:2px;padding:0 12px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#0092db;color:#5cb730}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#e0eaef;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:20px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#0092db;color:#5cb730}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #b6cedb;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#0092db}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #b6cedb;padding:2px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#c1d4df;color:#1d1e1e}.kint-rich table td{background:#e0eaef;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #0092db inset}.kint-rich table tr:hover var{color:#5cb730}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:4px;padding-bottom:4px;border-bottom:1px solid #c1d4df}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #0092db;padding-right:8px;margin-right:8px}.kint-rich pre.kint-source>div.kint-highlight{background:#c1d4df}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #0092db,0 1px #0092db,1px 0 #0092db,0 -1px #0092db;color:#e0eaef;font-weight:bold}.kint-rich>dl>dt{background:linear-gradient(to bottom, #e3ecf0 0, #c0d4df 100%)}.kint-rich ul.kint-tabs{background:linear-gradient(to bottom, #9dbed0 0px, #b2ccda 100%)}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li{background:#e0eaef}.kint-rich>dl:not(.kint-trace)>dd>ul.kint-tabs li.kint-active-tab{background:#c1d4df}.kint-rich>dl.kint-trace>dt{background:linear-gradient(to bottom, #c0d4df 0px, #e3ecf0 100%)}.kint-rich .kint-source .kint-highlight{background:#f0eb96} diff --git a/system/ThirdParty/Kint/resources/compiled/rich.js b/system/ThirdParty/Kint/resources/compiled/rich.js index 18fb072ead95..5648cda6de9e 100644 --- a/system/ThirdParty/Kint/resources/compiled/rich.js +++ b/system/ThirdParty/Kint/resources/compiled/rich.js @@ -1 +1 @@ -void 0===window.kintRich&&(window.kintRich=function(){"use strict";var n={selectText:function(e){var t=window.getSelection(),a=document.createRange();a.selectNodeContents(e),t.removeAllRanges(),t.addRange(a)},each:function(e,t){Array.prototype.slice.call(document.querySelectorAll(e),0).forEach(t)},hasClass:function(e,t){return!!e.classList&&(void 0===t&&(t="kint-show"),e.classList.contains(t))},addClass:function(e,t){void 0===t&&(t="kint-show"),e.classList.add(t)},removeClass:function(e,t){return void 0===t&&(t="kint-show"),e.classList.remove(t),e},toggle:function(e,t){var a=n.getChildren(e);a&&(void 0===t&&(t=n.hasClass(e)),t?n.removeClass(e):n.addClass(e),1===a.childNodes.length&&(a=a.childNodes[0].childNodes[0])&&n.hasClass(a,"kint-parent")&&n.toggle(a,t))},toggleChildren:function(e,t){var a=n.getChildren(e);if(a){var r=a.getElementsByClassName("kint-parent"),o=r.length;for(void 0===t&&(t=!n.hasClass(e));o--;)n.toggle(r[o],t)}},toggleAll:function(e){for(var t=document.getElementsByClassName("kint-parent"),a=t.length,r=!n.hasClass(e.parentNode);a--;)n.toggle(t[a],r)},switchTab:function(e){var t,a=e.previousSibling,r=0;for(n.removeClass(e.parentNode.getElementsByClassName("kint-active-tab")[0],"kint-active-tab"),n.addClass(e,"kint-active-tab");a;)1===a.nodeType&&r++,a=a.previousSibling;t=e.parentNode.nextSibling.childNodes;for(var o=0;o"},openInNewWindow:function(e){var t=window.open();t&&(t.document.open(),t.document.write(n.mktag("html")+n.mktag("head")+n.mktag("title")+"Kint ("+(new Date).toISOString()+")"+n.mktag("/title")+n.mktag('meta charset="utf-8"')+document.getElementsByClassName("kint-rich-script")[0].outerHTML+document.getElementsByClassName("kint-rich-style")[0].outerHTML+n.mktag("/head")+n.mktag("body")+'
    '+e.parentNode.outerHTML+"
    "+n.mktag("/body")),t.document.close())},sortTable:function(e,a){var t=e.tBodies[0];[].slice.call(e.tBodies[0].rows).sort(function(e,t){if(e=e.cells[a].textContent.trim().toLocaleLowerCase(),t=t.cells[a].textContent.trim().toLocaleLowerCase(),isNaN(e)||isNaN(t)){if(isNaN(e)&&!isNaN(t))return 1;if(isNaN(t)&&!isNaN(e))return-1}else e=parseFloat(e),t=parseFloat(t);return eli:not(.kint-active-tab)",function(e){0===e.offsetWidth&&0===e.offsetHeight||n.keyboardNav.targets.push(e)})},sync:function(e){var t=document.querySelector(".kint-focused");if(t&&n.removeClass(t,"kint-focused"),n.keyboardNav.active){var a=n.keyboardNav.targets[n.keyboardNav.target];n.addClass(a,"kint-focused"),e||n.keyboardNav.scroll(a)}},scroll:function(e){var t=function(e){return e.offsetTop+(e.offsetParent?t(e.offsetParent):0)},a=t(e);if(n.folder){var r=n.folder.querySelector("dd.kint-folder");r.scrollTo(0,a-r.clientHeight/2)}else window.scrollTo(0,a-window.innerHeight/2)},moveCursor:function(e){for(n.keyboardNav.target+=e;n.keyboardNav.target<0;)n.keyboardNav.target+=n.keyboardNav.targets.length;for(;n.keyboardNav.target>=n.keyboardNav.targets.length;)n.keyboardNav.target-=n.keyboardNav.targets.length;n.keyboardNav.sync()},setCursor:function(e){n.keyboardNav.fetchTargets();for(var t=0;t"},openInNewWindow:function(e){var t=window.open();t&&(t.document.open(),t.document.write(i.mktag("html")+i.mktag("head")+i.mktag("title")+"Kint ("+(new Date).toISOString()+")"+i.mktag("/title")+i.mktag('meta charset="utf-8"')+document.getElementsByClassName("kint-rich-script")[0].outerHTML+document.getElementsByClassName("kint-rich-style")[0].outerHTML+i.mktag("/head")+i.mktag("body")+'
    '+e.parentNode.outerHTML+"
    "+i.mktag("/body")),t.document.close())},sortTable:function(e,a){var t=e.tBodies[0];[].slice.call(e.tBodies[0].rows).sort(function(e,t){if(e=e.cells[a].textContent.trim().toLocaleLowerCase(),t=t.cells[a].textContent.trim().toLocaleLowerCase(),isNaN(e)||isNaN(t)){if(isNaN(e)&&!isNaN(t))return 1;if(isNaN(t)&&!isNaN(e))return-1}else e=parseFloat(e),t=parseFloat(t);return eli:not(.kint-active-tab)",function(e){i.isFolderOpen()&&!i.folder.contains(e)||0===e.offsetWidth&&0===e.offsetHeight||i.keyboardNav.targets.push(e)}),e&&-1!==i.keyboardNav.targets.indexOf(e)&&(i.keyboardNav.target=i.keyboardNav.targets.indexOf(e))},sync:function(e){var t=document.querySelector(".kint-focused");t&&i.removeClass(t,"kint-focused"),i.keyboardNav.active&&(t=i.keyboardNav.targets[i.keyboardNav.target],i.addClass(t,"kint-focused"),e||i.keyboardNav.scroll(t))},scroll:function(e){var t,a;e!==i.folder.querySelector("dt > nav")&&(a=(t=function(e){return e.offsetTop+(e.offsetParent?t(e.offsetParent):0)})(e),i.isFolderOpen()?(e=i.folder.querySelector("dd.kint-foldout")).scrollTo(0,a-e.clientHeight/2):window.scrollTo(0,a-window.innerHeight/2))},moveCursor:function(e){for(i.keyboardNav.target+=e;i.keyboardNav.target<0;)i.keyboardNav.target+=i.keyboardNav.targets.length;for(;i.keyboardNav.target>=i.keyboardNav.targets.length;)i.keyboardNav.target-=i.keyboardNav.targets.length;i.keyboardNav.sync()},setCursor:function(e){if(i.isFolderOpen()&&!i.folder.contains(e))return!1;i.keyboardNav.fetchTargets();for(var t=0;tdl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #586e75}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint-rich pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(131,148,150,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#002b36;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#839496;background:#002b36}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #586e75;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#93a1a1;background:#073642;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#252525;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#1b1b1b}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#073642;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#839496}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#839496;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #586e75}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint-rich ul.kint-tabs>li{background:#073642;border:1px solid #586e75;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#002b36;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #586e75;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #586e75;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#073642;color:#93a1a1}.kint-rich table td{background:#002b36;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #073642}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#073642}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#002b36;font-weight:bold}body{background:#073642;color:#fff}.kint-rich{box-shadow:0 0 5px 3px #073642}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:#073642}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#839496}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#839496;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#002b36;border:1px solid #586e75;color:#839496;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #586e75}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#93a1a1}.kint-rich pre{color:#839496;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #586e75;background:#002b36;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(131,148,150,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#002b36;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#839496;background:#002b36}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #586e75;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#93a1a1;background:#073642;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#252525;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#1b1b1b}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#073642;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#839496}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#839496;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#93a1a1;border-bottom:1px dotted #93a1a1}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #586e75}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#002b36;border:1px solid #586e75;border-top:0}.kint-rich ul.kint-tabs>li{background:#073642;border:1px solid #586e75;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#002b36;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #586e75;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #586e75;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#073642;color:#93a1a1}.kint-rich table td{background:#002b36;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #073642}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#073642}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#002b36;font-weight:bold}body{background:#073642;color:#fff}.kint-rich{box-shadow:0 0 5px 3px #073642}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px}.kint-rich footer li{color:#ddd} diff --git a/system/ThirdParty/Kint/resources/compiled/solarized.css b/system/ThirdParty/Kint/resources/compiled/solarized.css index db5da0d2d3b7..fa04f2de8f4d 100644 --- a/system/ThirdParty/Kint/resources/compiled/solarized.css +++ b/system/ThirdParty/Kint/resources/compiled/solarized.css @@ -1 +1 @@ -.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:none}.kint-rich.kint-folder.kint-show{display:block}.kint-rich.kint-folder dd.kint-folder{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#657b83}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#657b83;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #93a1a1}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#586e75}.kint-rich pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(101,123,131,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#fdf6e3;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#657b83;background:#fdf6e3}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #93a1a1;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#586e75;background:#eee8d5;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#e2e2e2;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f0f0f0}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#eee8d5;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#657b83}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#657b83;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #93a1a1}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint-rich ul.kint-tabs>li{background:#eee8d5;border:1px solid #93a1a1;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#fdf6e3;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul:not(.kint-tabs)>li:not(:first-child){display:none}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #93a1a1;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #93a1a1;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-rich table td{background:#fdf6e3;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #eee8d5}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#eee8d5}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#fdf6e3;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px} +.kint-rich{font-size:13px;overflow-x:auto;white-space:nowrap;background:rgba(255,255,255,0.9)}.kint-rich.kint-folder{position:fixed;bottom:0;left:0;right:0;z-index:999999;width:100%;margin:0;display:block}.kint-rich.kint-folder dd.kint-foldout{max-height:calc(100vh - 100px);padding-right:10px;overflow-y:scroll;display:none}.kint-rich.kint-folder dd.kint-foldout.kint-show{display:block}.kint-rich::selection,.kint-rich::-moz-selection,.kint-rich::-webkit-selection{background:#268bd2;color:#657b83}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #2aa198}.kint-rich,.kint-rich::before,.kint-rich::after,.kint-rich *,.kint-rich *::before,.kint-rich *::after{box-sizing:border-box;border-radius:0;color:#657b83;float:none !important;font-family:Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;line-height:15px;margin:0;padding:0;text-align:left}.kint-rich{margin:10px 0}.kint-rich dt,.kint-rich dl{width:auto}.kint-rich dt,.kint-rich div.access-path{background:#fdf6e3;border:1px solid #93a1a1;color:#657b83;display:block;font-weight:bold;list-style:none outside none;overflow:auto;padding:5px}.kint-rich dt:hover,.kint-rich div.access-path:hover{border-color:#268bd2}.kint-rich>dl dl{padding:0 0 0 15px}.kint-rich dt.kint-parent>nav,.kint-rich>footer>nav{background:url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2aWV3Qm94PSIwIDAgMzAgMTUwIj48ZGVmcz48cGF0aCBzdHJva2UtbGluZWpvaW49InJvdW5kIiBkPSJNNCAzYTI0IDMyIDAgMCAxIDAgMjQgNDAgMjAtMTAgMCAxIDIzLTEyQTQwIDIwIDEwIDAgMSA0IDN6IiBpZD0iYSIvPjwvZGVmcz48ZyBmaWxsPSIjOTNhMWExIiBzdHJva2U9IiM5M2ExYTEiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxnIGZpbGw9IiM1ODZlNzUiIHN0cm9rZT0iIzU4NmU3NSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAzMCkiPjx1c2UgeGxpbms6aHJlZj0iI2EiLz48dXNlIHhsaW5rOmhyZWY9IiNhIiB0cmFuc2Zvcm09InJvdGF0ZSg5MCAtMTUgNDUpIi8+PC9nPjxwYXRoIGQ9Ik02IDEyNmwxOCAxOG0tMTggMGwxOC0xOCIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2U9IiM1ODZlNzUiLz48L3N2Zz4=") no-repeat scroll 0 0/15px 75px transparent;cursor:pointer;display:inline-block;height:15px;width:15px;margin-right:3px;vertical-align:middle}.kint-rich dt.kint-parent:hover>nav,.kint-rich>footer>nav:hover{background-position:0 25%}.kint-rich dt.kint-parent.kint-show>nav,.kint-rich>footer.kint-show>nav{background-position:0 50%}.kint-rich dt.kint-parent.kint-show:hover>nav,.kint-rich>footer.kint-show>nav:hover{background-position:0 75%}.kint-rich dt.kint-parent.kint-locked>nav{background-position:0 100%}.kint-rich dt.kint-parent+dd{display:none;border-left:1px dashed #93a1a1}.kint-rich dt.kint-parent.kint-show+dd{display:block}.kint-rich var,.kint-rich var a{color:#268bd2;font-style:normal}.kint-rich dt:hover var,.kint-rich dt:hover var a{color:#2aa198}.kint-rich dfn{font-style:normal;font-family:monospace;color:#586e75}.kint-rich pre{color:#657b83;margin:0 0 0 15px;padding:5px;overflow-y:hidden;border-top:0;border:1px solid #93a1a1;background:#fdf6e3;display:block;word-break:normal}.kint-rich .kint-popup-trigger,.kint-rich .kint-access-path-trigger,.kint-rich .kint-search-trigger{background:rgba(101,123,131,0.8);border-radius:3px;height:16px;font-size:16px;margin-left:5px;font-weight:bold;width:16px;text-align:center;float:right !important;cursor:pointer;color:#fdf6e3;position:relative;overflow:hidden;line-height:17.6px}.kint-rich .kint-popup-trigger:hover,.kint-rich .kint-access-path-trigger:hover,.kint-rich .kint-search-trigger:hover{color:#657b83;background:#fdf6e3}.kint-rich dt.kint-parent>.kint-popup-trigger{line-height:19.2px}.kint-rich .kint-search-trigger{font-size:20px}.kint-rich input.kint-search{display:none;border:1px solid #93a1a1;border-top-width:0;border-bottom-width:0;padding:5px;float:right !important;margin:-5px 0;color:#586e75;background:#eee8d5;height:26px;width:160px;position:relative;z-index:100}.kint-rich input.kint-search.kint-show{display:block}.kint-rich .kint-search-root ul.kint-tabs>li:not(.kint-search-match){background:#e2e2e2;opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match){opacity:0.5}.kint-rich .kint-search-root dl:not(.kint-search-match)>dt{background:#f0f0f0}.kint-rich .kint-search-root dl:not(.kint-search-match) dl,.kint-rich .kint-search-root dl:not(.kint-search-match) ul.kint-tabs>li:not(.kint-search-match){opacity:1}.kint-rich div.access-path{background:#eee8d5;display:none;margin-top:5px;padding:4px;white-space:pre}.kint-rich div.access-path.kint-show{display:block}.kint-rich footer{padding:0 3px 3px;font-size:9px;background:transparent}.kint-rich footer>.kint-popup-trigger{background:transparent;color:#657b83}.kint-rich footer nav{height:10px;width:10px;background-size:10px 50px}.kint-rich footer>ol{display:none;margin-left:32px}.kint-rich footer.kint-show>ol{display:block}.kint-rich a{color:#657b83;text-shadow:none;text-decoration:underline}.kint-rich a:hover{color:#586e75;border-bottom:1px dotted #586e75}.kint-rich ul{list-style:none;padding-left:15px}.kint-rich ul:not(.kint-tabs) li{border-left:1px dashed #93a1a1}.kint-rich ul:not(.kint-tabs) li>dl{border-left:none}.kint-rich ul.kint-tabs{margin:0 0 0 15px;padding-left:0;background:#fdf6e3;border:1px solid #93a1a1;border-top:0}.kint-rich ul.kint-tabs>li{background:#eee8d5;border:1px solid #93a1a1;cursor:pointer;display:inline-block;height:30px;margin:3px;padding:0 15px;vertical-align:top}.kint-rich ul.kint-tabs>li:hover,.kint-rich ul.kint-tabs>li.kint-active-tab:hover{border-color:#268bd2;color:#2aa198}.kint-rich ul.kint-tabs>li.kint-active-tab{background:#fdf6e3;border-top:0;margin-top:-1px;height:27px;line-height:24px}.kint-rich ul.kint-tabs>li:not(.kint-active-tab){line-height:25px}.kint-rich ul.kint-tabs li+li{margin-left:0}.kint-rich ul.kint-tab-contents>li{display:none}.kint-rich ul.kint-tab-contents>li.kint-show{display:block}.kint-rich dt:hover+dd>ul>li.kint-active-tab{border-color:#268bd2;color:#2aa198}.kint-rich dt>.kint-color-preview{width:16px;height:16px;display:inline-block;vertical-align:middle;margin-left:10px;border:1px solid #93a1a1;background-color:#ccc;background-image:url('data:image/svg+xml;utf8,');background-size:100%}.kint-rich dt>.kint-color-preview:hover{border-color:#268bd2}.kint-rich dt>.kint-color-preview>div{width:100%;height:100%}.kint-rich table{border-collapse:collapse;empty-cells:show;border-spacing:0}.kint-rich table *{font-size:12px}.kint-rich table dt{background:none;padding:2.5px}.kint-rich table dt .kint-parent{min-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.kint-rich table td,.kint-rich table th{border:1px solid #93a1a1;padding:2.5px;vertical-align:center}.kint-rich table th{cursor:alias}.kint-rich table td:first-child,.kint-rich table th{font-weight:bold;background:#eee8d5;color:#586e75}.kint-rich table td{background:#fdf6e3;white-space:pre}.kint-rich table td>dl{padding:0}.kint-rich table pre{border-top:0;border-right:0}.kint-rich table thead th:first-child{background:none;border:0}.kint-rich table tr:hover>td{box-shadow:0 0 1px 0 #268bd2 inset}.kint-rich table tr:hover var{color:#2aa198}.kint-rich table ul.kint-tabs li.kint-active-tab{height:20px;line-height:17px}.kint-rich pre.kint-source{margin-left:-1px}.kint-rich pre.kint-source[data-kint-filename]:before{display:block;content:attr(data-kint-filename);margin-bottom:5px;padding-bottom:5px;border-bottom:1px solid #eee8d5}.kint-rich pre.kint-source>div:before{display:inline-block;content:counter(kint-l);counter-increment:kint-l;border-right:1px solid #268bd2;padding-right:10px;margin-right:10px}.kint-rich pre.kint-source>div.kint-highlight{background:#eee8d5}.kint-rich .kint-microtime-lap{text-shadow:-1px 0 #268bd2,0 1px #268bd2,1px 0 #268bd2,0 -1px #268bd2;color:#fdf6e3;font-weight:bold}.kint-rich .kint-focused{box-shadow:0 0 3px 2px #859900 inset;border-radius:7px}.kint-rich>dl>dt,.kint-rich ul.kint-tabs{box-shadow:4px 0 2px -3px #268bd2 inset}.kint-rich ul.kint-tabs li.kint-active-tab{padding-top:7px;height:34px} From d542514edb6c05b6fbc6a9039de5dce9d4f84ca8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Dec 2021 16:28:11 +0900 Subject: [PATCH 1014/2325] chore: rename changed property names in Kint --- system/CodeIgniter.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 41e775dbf58d..d309ca81c27a 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -249,7 +249,7 @@ protected function initializeKint() */ $config = config('Config\Kint'); - Kint::$max_depth = $config->maxDepth; + Kint::$depth_limit = $config->maxDepth; Kint::$display_called_from = $config->displayCalledFrom; Kint::$expanded = $config->expanded; @@ -261,7 +261,7 @@ protected function initializeKint() RichRenderer::$folder = $config->richFolder; RichRenderer::$sort = $config->richSort; if (! empty($config->richObjectPlugins) && is_array($config->richObjectPlugins)) { - RichRenderer::$object_plugins = $config->richObjectPlugins; + RichRenderer::$value_plugins = $config->richObjectPlugins; } if (! empty($config->richTabPlugins) && is_array($config->richTabPlugins)) { RichRenderer::$tab_plugins = $config->richTabPlugins; From 67ce1b025511a16271caea5dbb37058f9aab190f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Dec 2021 21:40:46 +0900 Subject: [PATCH 1015/2325] docs: fix by proof reading Co-authored-by: MGatner --- user_guide_src/source/incoming/filters.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index b8b16bb1c9ce..8677f1925dee 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -207,7 +207,7 @@ The filters bundled with CodeIgniter4 are: :doc:`Honeypot <../libraries/honeypot InvalidChars ============= -This filter checks if user input data (``$_GET``, ``$_POST``, ``$_COOKIE``, ``php://input``) do not contain the following characters: +This filter prohibits user input data (``$_GET``, ``$_POST``, ``$_COOKIE``, ``php://input``) from containing the following characters: - invalid UTF-8 characters - control characters except line break and tab code From 068f1d8a2ee3a7c84fe29e2d1a999ccf54934ac1 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Sun, 19 Dec 2021 22:42:49 -0600 Subject: [PATCH 1016/2325] Update index.rst --- user_guide_src/source/index.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst index 3f337e5b1f2a..e6240dd4e56b 100644 --- a/user_guide_src/source/index.rst +++ b/user_guide_src/source/index.rst @@ -114,3 +114,5 @@ Advanced Topics license changelogs/index + +UNNECCESSARY CHANGES From 2118d682bd065697d7f6d858f21bb54f933f0cc0 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Sun, 19 Dec 2021 22:47:11 -0600 Subject: [PATCH 1017/2325] Update index.rst --- user_guide_src/source/index.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst index e6240dd4e56b..3f337e5b1f2a 100644 --- a/user_guide_src/source/index.rst +++ b/user_guide_src/source/index.rst @@ -114,5 +114,3 @@ Advanced Topics license changelogs/index - -UNNECCESSARY CHANGES From 37fe5bb223faa6303c14303023fe9bbf53d21de3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Dec 2021 13:48:34 +0900 Subject: [PATCH 1018/2325] docs: fix incorrect sample code --- user_guide_src/source/general/logging.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/logging.rst b/user_guide_src/source/general/logging.rst index 761500ac722a..08e60d60988c 100644 --- a/user_guide_src/source/general/logging.rst +++ b/user_guide_src/source/general/logging.rst @@ -97,7 +97,7 @@ into the message string:: // Generates a message like: User 123 logged into the system from 127.0.0.1 $info = [ 'id' => $user->id, - 'ip_address' => $this->request->ip_address() + 'ip_address' => $this->request->getIPAddress() ]; log_message('info', 'User {id} logged into the system from {ip_address}', $info); From a2df301abae87d308c4c501f4c65b1b06f50f612 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Dec 2021 17:30:24 +0900 Subject: [PATCH 1019/2325] docs: change text decoration --- user_guide_src/source/general/environments.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/environments.rst b/user_guide_src/source/general/environments.rst index 6abd709a00a9..ae9c877c81fd 100644 --- a/user_guide_src/source/general/environments.rst +++ b/user_guide_src/source/general/environments.rst @@ -99,7 +99,7 @@ Error Reporting Setting the ENVIRONMENT constant to a value of ``development`` will cause all PHP errors to be rendered to the browser when they occur. -Conversely, setting the constant to 'production' will disable all error +Conversely, setting the constant to ``production`` will disable all error output. Disabling error reporting in production is a :doc:`good security practice `. From 499f4a031f7ba8a076afa58a0f8b3b3c86d80283 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Dec 2021 16:36:32 +0900 Subject: [PATCH 1020/2325] test: fix doc comment --- tests/system/API/ResponseTraitTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index 1db28686eafe..abff4ce0c1a9 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\API; +use CodeIgniter\Format\FormatterInterface; use CodeIgniter\Format\JSONFormatter; use CodeIgniter\Format\XMLFormatter; use CodeIgniter\HTTP\URI; @@ -30,7 +31,7 @@ final class ResponseTraitTest extends CIUnitTestCase protected $response; /** - * @var Response formatter + * @var FormatterInterface|null */ protected $formatter; From b75b9aff45d381e134348cc29eadc49051f98bf7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Dec 2021 17:38:19 +0900 Subject: [PATCH 1021/2325] docs: depreacted Seeder::faker() See #5456 --- system/Database/Seeder.php | 4 +++ tests/system/Database/DatabaseSeederTest.php | 3 ++ user_guide_src/source/changelogs/v4.1.6.rst | 2 ++ user_guide_src/source/dbmgmt/seeds.rst | 35 -------------------- 4 files changed, 9 insertions(+), 35 deletions(-) diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index b6127af2cd91..92d281965c7e 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -68,6 +68,8 @@ class Seeder * Faker Generator instance. * * @var Generator|null + * + * @deprecated */ private static $faker; @@ -98,6 +100,8 @@ public function __construct(Database $config, ?BaseConnection $db = null) /** * Gets the Faker Generator instance. + * + * @deprecated */ public static function faker(): ?Generator { diff --git a/tests/system/Database/DatabaseSeederTest.php b/tests/system/Database/DatabaseSeederTest.php index d17ff71fe61a..7e08d6648508 100644 --- a/tests/system/Database/DatabaseSeederTest.php +++ b/tests/system/Database/DatabaseSeederTest.php @@ -38,6 +38,9 @@ public function testInstantiateNotDirSeedPath() new Seeder($config); } + /** + * @TODO remove this when Seeder::faker() is removed + */ public function testFakerGet() { $this->assertInstanceOf(Generator::class, Seeder::faker()); diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 82b03127cda2..d53378a6b624 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -42,6 +42,8 @@ Changes Deprecations ************ +- ``Seeder::faker()`` and ``Seeder::$faker`` are deprecated. + Sending Cookies =============== diff --git a/user_guide_src/source/dbmgmt/seeds.rst b/user_guide_src/source/dbmgmt/seeds.rst index 95afc23104b7..e79496efbffb 100644 --- a/user_guide_src/source/dbmgmt/seeds.rst +++ b/user_guide_src/source/dbmgmt/seeds.rst @@ -67,41 +67,6 @@ anywhere the autoloader can find them. This is great for more modular code bases $this->call('My\Database\Seeds\CountrySeeder'); } -Using Faker -=========== - -If you want to automate the generation of seed data, you can use -the `Faker library `_. - -To install Faker into your project:: - - > composer require --dev fakerphp/faker - -After installation, an instance of ``Faker\Generator`` is available in the main ``Seeder`` -class and is accessible by all child seeders. You must use the static method ``faker()`` -to access the instance. - -:: - - insert([ - 'email' => static::faker()->email, - 'ip_address' => static::faker()->ipv4, - ]); - } - } - Using Seeders ============= From 2591d65c091f8f5b95353bc2ed82cd5f2e0e9d7a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Dec 2021 19:48:22 +0900 Subject: [PATCH 1022/2325] docs: fix sample code --- user_guide_src/source/extending/core_classes.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index a51c9e825b34..9ef3330e23bc 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -68,7 +68,7 @@ Then you would add the ``routes`` service in **app/Config/Services.php** to load return static::getSharedInstance('routes'); } - return new RouteCollection(static::locator(), config('Modules')); + return new \App\Libraries\RouteCollection(static::locator(), config('Modules')); } Extending Core Classes From 39ce053fbb018b6afcb2d6aaffdb0df61a616832 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 22 Dec 2021 09:08:13 +0900 Subject: [PATCH 1023/2325] fix: directory_mirror() throws an error if destination directory exists Fixes #5478 --- system/Helpers/filesystem_helper.php | 4 ++- tests/system/Helpers/FilesystemHelperTest.php | 29 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 52341b848e06..89d4d507f961 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -91,7 +91,9 @@ function directory_mirror(string $originDir, string $targetDir, bool $overwrite $target = $targetDir . substr($origin, $dirLen); if ($file->isDir()) { - mkdir($target, 0755); + if (! is_dir($target)) { + mkdir($target, 0755); + } } elseif (! is_file($target) || ($overwrite && is_file($target))) { copy($origin, $target); } diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index c48ccd1ff328..7b837064a410 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -14,6 +14,7 @@ use CodeIgniter\Test\CIUnitTestCase; use InvalidArgumentException; use org\bovigo\vfs\vfsStream; +use org\bovigo\vfs\visitor\vfsStreamStructureVisitor; /** * @internal @@ -161,6 +162,34 @@ public function testDirectoryMirrorNotOverwrites() $this->assertSame($this->structure['boo']['faz'], $result); } + public function testDirectoryMirrorSkipExistingFolder() + { + $this->assertTrue(function_exists('directory_mirror')); + + $this->structure = [ + 'src' => [ + 'AnEmptyFolder' => [], + ], + 'dest' => [ + 'AnEmptyFolder' => [], + ], + ]; + vfsStream::setup('root', null, $this->structure); + $root = rtrim(vfsStream::url('root') . DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; + + // skips the existing folder + directory_mirror($root . 'src', $root . 'dest'); + + $structure = vfsStream::inspect(new vfsStreamStructureVisitor())->getStructure(); + $this->assertSame([], $structure['root']['dest']['AnEmptyFolder']); + + // skips the existing folder (the same as overwrite = true) + directory_mirror($root . 'src', $root . 'dest', false); + + $structure = vfsStream::inspect(new vfsStreamStructureVisitor())->getStructure(); + $this->assertSame([], $structure['root']['dest']['AnEmptyFolder']); + } + public function testWriteFileSuccess() { $vfs = vfsStream::setup('root'); From 66bc13d94c5f6a3d18af620bc650db4f37b63576 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 22 Dec 2021 08:47:05 +0700 Subject: [PATCH 1024/2325] Update rector to 0.12.9 and clean up skip config --- composer.json | 2 +- rector.php | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/composer.json b/composer.json index 330209cb21a6..984520972a46 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.8" + "rector/rector": "0.12.9" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" diff --git a/rector.php b/rector.php index 92636b0bfdd5..8be24cd7024d 100644 --- a/rector.php +++ b/rector.php @@ -42,7 +42,6 @@ use Rector\Php71\Rector\FuncCall\CountOnNullRector; use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; -use Rector\PHPUnit\Rector\MethodCall\AssertIssetToSpecificMethodRector; use Rector\PHPUnit\Set\PHPUnitSetList; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; @@ -113,15 +112,6 @@ // use mt_rand instead of random_int on purpose on non-cryptographically random RandomFunctionRector::class, - - // $this->assertTrue(isset($bar['foo'])) - // and $this->assertArrayHasKey('foo', $bar) - // or $this->assertObjectHasAttribute('foo', $bar); - // are not the same - AssertIssetToSpecificMethodRector::class => [ - __DIR__ . '/tests/system/Entity/EntityTest.php', - __DIR__ . '/tests/system/Session/SessionTest.php', - ], ]); // auto import fully qualified class names From b1ab3533e62851323b3759da4584fced0c9ee30f Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Tue, 21 Dec 2021 22:34:15 -0600 Subject: [PATCH 1025/2325] Update destination folder. --- .github/workflows/deploy-userguide.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-userguide.yml b/.github/workflows/deploy-userguide.yml index 0fc7900197a8..ad0b48ae6559 100644 --- a/.github/workflows/deploy-userguide.yml +++ b/.github/workflows/deploy-userguide.yml @@ -49,5 +49,5 @@ jobs: remote_server_ip: ${{ secrets.DEPLOY_SSH_BOX }} ssh_port: ${{ secrets.DEPLOY_PORT }} ssh_private_key: ${{ secrets.DEPLOY_KEY }} - source_path: "./user_guide_src/build/html/*" - destination_path: "/home/public_html/userguides/v4/" + source_path: "user_guide_src/build/html/*" + destination_path: "/home/public_html/userguides/user_guide_4/" From f7151ab591ef36055aee25cae7082b191ae24c14 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Mon, 20 Dec 2021 17:51:36 +0800 Subject: [PATCH 1026/2325] BaseBuilder instance as subquery. --- system/Database/BaseBuilder.php | 58 ++++++++---- tests/system/Database/Builder/WhereTest.php | 81 ++++++++++++++-- .../source/database/query_builder.rst | 94 ++++++++++++++----- 3 files changed, 182 insertions(+), 51 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index fecf3e10718f..6d97db101cbb 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -693,9 +693,8 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type $op = ' ='; } - if ($v instanceof Closure) { - $builder = $this->cleanClone(); - $v = ' (' . strtr($v($builder)->getCompiledSelect(), "\n", ' ') . ')'; + if ($this->isSubQuery($v)) { + $v = $this->buildSubQuery($v, true); } else { $bind = $this->setBind($k, $v, $escape); $v = " :{$bind}:"; @@ -723,7 +722,7 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type * Generates a WHERE field IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -736,7 +735,7 @@ public function whereIn(?string $key = null, $values = null, ?bool $escape = nul * Generates a WHERE field IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -749,7 +748,7 @@ public function orWhereIn(?string $key = null, $values = null, ?bool $escape = n * Generates a WHERE field NOT IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -762,7 +761,7 @@ public function whereNotIn(?string $key = null, $values = null, ?bool $escape = * Generates a WHERE field NOT IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -775,7 +774,7 @@ public function orWhereNotIn(?string $key = null, $values = null, ?bool $escape * Generates a HAVING field IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -788,7 +787,7 @@ public function havingIn(?string $key = null, $values = null, ?bool $escape = nu * Generates a HAVING field IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -801,7 +800,7 @@ public function orHavingIn(?string $key = null, $values = null, ?bool $escape = * Generates a HAVING field NOT IN('item', 'item') SQL query, * joined with 'AND' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -814,7 +813,7 @@ public function havingNotIn(?string $key = null, $values = null, ?bool $escape = * Generates a HAVING field NOT IN('item', 'item') SQL query, * joined with 'OR' if appropriate. * - * @param array|Closure|string $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|string $values The values searched on, or anonymous function with subquery * * @return $this */ @@ -829,7 +828,7 @@ public function orHavingNotIn(?string $key = null, $values = null, ?bool $escape * @used-by whereNotIn() * @used-by orWhereNotIn() * - * @param array|Closure|null $values The values searched on, or anonymous function with subquery + * @param array|BaseBuilder|Closure|null $values The values searched on, or anonymous function with subquery * * @throws InvalidArgumentException * @@ -845,7 +844,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal return $this; // @codeCoverageIgnore } - if ($values === null || (! is_array($values) && ! ($values instanceof Closure))) { + if ($values === null || (! is_array($values) && ! $this->isSubQuery($values))) { if (CI_DEBUG) { throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); } @@ -865,9 +864,8 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal $not = ($not) ? ' NOT' : ''; - if ($values instanceof Closure) { - $builder = $this->cleanClone(); - $ok = strtr($values($builder)->getCompiledSelect(), "\n", ' '); + if ($this->isSubQuery($values)) { + $ok = $this->buildSubQuery($values); } else { $whereIn = array_values($values); $ok = $this->setBind($ok, $whereIn, $escape); @@ -876,7 +874,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); $whereIn = [ - 'condition' => $prefix . $key . $not . ($values instanceof Closure ? " IN ({$ok})" : " IN :{$ok}:"), + 'condition' => $prefix . $key . $not . ($this->isSubQuery($values) ? " IN ({$ok})" : " IN :{$ok}:"), 'escape' => false, ]; @@ -2724,9 +2722,35 @@ protected function setBind(string $key, $value = null, bool $escape = true): str * Returns a clone of a Base Builder with reset query builder values. * * @return $this + * + * @deprecated */ protected function cleanClone() { return (clone $this)->from([], true)->resetQuery(); } + + /** + * @param mixed $value + */ + protected function isSubQuery($value): bool + { + return $value instanceof BaseBuilder || $value instanceof Closure; + } + + /** + * @param BaseBuilder|Closure $builder + * @param bool $wrapped Wrap the subquery in brackets + */ + protected function buildSubQuery($builder, bool $wrapped = false): string + { + if ($builder instanceof Closure) { + $instance = (clone $this)->from([], true)->resetQuery(); + $builder = $builder($instance); + } + + $subQuery = strtr($builder->getCompiledSelect(), "\n", ' '); + + return $wrapped ? '(' . $subQuery . ')' : $subQuery; + } } diff --git a/tests/system/Database/Builder/WhereTest.php b/tests/system/Database/Builder/WhereTest.php index e58af53cadab..70463776a3ac 100644 --- a/tests/system/Database/Builder/WhereTest.php +++ b/tests/system/Database/Builder/WhereTest.php @@ -141,14 +141,27 @@ public function testWhereCustomString() $this->assertSame($expectedBinds, $builder->getBinds()); } - public function testWhereValueClosure() + public function testWhereValueSubQuery() { + $expectedSQL = 'SELECT * FROM "neworder" WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2)'; + + // Closure $builder = $this->db->table('neworder'); $builder->where('advance_amount <', static function (BaseBuilder $builder) { return $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); }); - $expectedSQL = 'SELECT * FROM "neworder" WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2)'; + + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + + // Builder + $builder = $this->db->table('neworder'); + + $subQuery = $this->db->table('orders') + ->select('MAX(advance_amount)', false) + ->where('id >', 2); + + $builder->where('advance_amount <', $subQuery); $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } @@ -218,15 +231,27 @@ public function testWhereIn() $this->assertSame($expectedBinds, $builder->getBinds()); } - public function testWhereInClosure() + public function testWhereInSubQuery() { + $expectedSQL = 'SELECT * FROM "jobs" WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + + // Closure $builder = $this->db->table('jobs'); $builder->whereIn('id', static function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - $expectedSQL = 'SELECT * FROM "jobs" WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + + // Builder + $builder = $this->db->table('jobs'); + + $subQuery = $this->db->table('users_jobs') + ->select('job_id') + ->where('user_id', 3); + + $builder->whereIn('id', $subQuery); $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } @@ -295,15 +320,27 @@ public function testWhereNotIn() $this->assertSame($expectedBinds, $builder->getBinds()); } - public function testWhereNotInClosure() + public function testWhereNotInSubQuery() { + $expectedSQL = 'SELECT * FROM "jobs" WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + + // Closure $builder = $this->db->table('jobs'); $builder->whereNotIn('id', static function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - $expectedSQL = 'SELECT * FROM "jobs" WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + + // Builder + $builder = $this->db->table('jobs'); + + $subQuery = $this->db->table('users_jobs') + ->select('job_id') + ->where('user_id', 3); + + $builder->whereNotIn('id', $subQuery); $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } @@ -333,15 +370,27 @@ public function testOrWhereIn() $this->assertSame($expectedBinds, $builder->getBinds()); } - public function testOrWhereInClosure() + public function testOrWhereInSubQuery() { + $expectedSQL = 'SELECT * FROM "jobs" WHERE "deleted_at" IS NULL OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + + // Closure $builder = $this->db->table('jobs'); $builder->where('deleted_at', null)->orWhereIn('id', static function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - $expectedSQL = 'SELECT * FROM "jobs" WHERE "deleted_at" IS NULL OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + + // Builder + $builder = $this->db->table('jobs'); + + $subQuery = $this->db->table('users_jobs') + ->select('job_id') + ->where('user_id', 3); + + $builder->where('deleted_at', null)->orWhereIn('id', $subQuery); $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } @@ -371,15 +420,27 @@ public function testOrWhereNotIn() $this->assertSame($expectedBinds, $builder->getBinds()); } - public function testOrWhereNotInClosure() + public function testOrWhereNotInSubQuery() { + $expectedSQL = 'SELECT * FROM "jobs" WHERE "deleted_at" IS NULL OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + + // Closure $builder = $this->db->table('jobs'); $builder->where('deleted_at', null)->orWhereNotIn('id', static function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - $expectedSQL = 'SELECT * FROM "jobs" WHERE "deleted_at" IS NULL OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3)'; + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + + // Builder + $builder = $this->db->table('jobs'); + + $subQuery = $this->db->table('users_jobs') + ->select('job_id') + ->where('user_id', 3); + + $builder->where('deleted_at', null)->orWhereNotIn('id', $subQuery); $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); } diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 7aa8cf69dcdb..63d9c25f501b 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -306,13 +306,22 @@ methods: #. **Subqueries:** - You can use an anonymous function to create a subquery:: + :: + + // With closure $builder->where('advance_amount <', function (BaseBuilder $builder) { return $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); }); + // Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) + // With builder directly + $subQuery = $db->table('orders')->select('MAX(advance_amount)', false)->where('id >', 2) + + $builder->where('advance_amount <', $subQuery); + + **$builder->orWhere()** This function is identical to the one above, except that multiple @@ -333,11 +342,17 @@ appropriate:: You can use subqueries instead of an array of values:: + // With closure $builder->whereIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); // Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); + + $builder->whereIn('id', $subQuery); + **$builder->orWhereIn()** Generates a ``WHERE field IN ('item', 'item')`` SQL query joined with OR if @@ -349,12 +364,18 @@ appropriate:: You can use subqueries instead of an array of values:: + // With closure $builder->orWhereIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); // Produces: OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); + + $builder->orWhereIn('id', $subQuery); + **$builder->whereNotIn()** Generates a WHERE field NOT IN ('item', 'item') SQL query joined with @@ -366,12 +387,18 @@ AND if appropriate:: You can use subqueries instead of an array of values:: + // With closure $builder->whereNotIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); // Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); + + $builder->whereNotIn('id', $subQuery); + **$builder->orWhereNotIn()** Generates a ``WHERE field NOT IN ('item', 'item')`` SQL query joined with OR @@ -383,12 +410,18 @@ if appropriate:: You can use subqueries instead of an array of values:: + // With closure $builder->orWhereNotIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); // Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); + + $builder->orWhereNotIn('id', $subQuery); + ************************ Looking for Similar Data ************************ @@ -512,23 +545,25 @@ Identical to ``having()``, only separates multiple clauses with "OR". **$builder->havingIn()** Generates a ``HAVING field IN ('item', 'item')`` SQL query joined with AND if -appropriate - -:: +appropriate:: $groups = [1, 2, 3]; $builder->havingIn('group_id', $groups); // Produces: HAVING group_id IN (1, 2, 3) -You can use subqueries instead of an array of values. - -:: +You can use subqueries instead of an array of values.:: + // With closure $builder->havingIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); // Produces: HAVING "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); + + $builder->havingIn('id', $subQuery); + **$builder->orHavingIn()** Generates a ``HAVING field IN ('item', 'item')`` SQL query joined with OR if @@ -540,16 +575,20 @@ appropriate $builder->orHavingIn('group_id', $groups); // Produces: OR group_id IN (1, 2, 3) -You can use subqueries instead of an array of values. - -:: +You can use subqueries instead of an array of values.:: + //With closure $builder->orHavingIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); // Produces: OR "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); + + $builder->orHavingIn('id', $subQuery); + **$builder->havingNotIn()** Generates a ``HAVING field NOT IN ('item', 'item')`` SQL query joined with @@ -561,16 +600,19 @@ AND if appropriate $builder->havingNotIn('group_id', $groups); // Produces: HAVING group_id NOT IN (1, 2, 3) -You can use subqueries instead of an array of values. - -:: +You can use subqueries instead of an array of values.:: + //With closure $builder->havingNotIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); // Produces: HAVING "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); + + $builder->havingNotIn('id', $subQuery); **$builder->orHavingNotIn()** @@ -583,16 +625,20 @@ if appropriate $builder->havingNotIn('group_id', $groups); // Produces: OR group_id NOT IN (1, 2, 3) -You can use subqueries instead of an array of values. - -:: +You can use subqueries instead of an array of values.:: + //With closure $builder->orHavingNotIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); // Produces: OR "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + // With builder directly + $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); + + $builder->orHavingNotIn('id', $subQuery); + **$builder->havingLike()** This method enables you to generate **LIKE** clauses for HAVING part or the query, useful for doing @@ -1397,7 +1443,7 @@ Class Reference .. php:method:: orWhereIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: The field to search - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1407,7 +1453,7 @@ Class Reference .. php:method:: orWhereNotIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: The field to search - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1417,7 +1463,7 @@ Class Reference .. php:method:: whereIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: Name of field to examine - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1427,7 +1473,7 @@ Class Reference .. php:method:: whereNotIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: Name of field to examine - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1540,7 +1586,7 @@ Class Reference .. php:method:: orHavingIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: The field to search - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1550,7 +1596,7 @@ Class Reference .. php:method:: orHavingNotIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: The field to search - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1560,7 +1606,7 @@ Class Reference .. php:method:: havingIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: Name of field to examine - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :returns: ``BaseBuilder`` instance (method chaining) :rtype: ``BaseBuilder`` @@ -1570,7 +1616,7 @@ Class Reference .. php:method:: havingNotIn([$key = null[, $values = null[, $escape = null]]]) :param string $key: Name of field to examine - :param array|Closure $values: Array of target values, or anonymous function for subquery + :param array|BaseBulder|Closure $values: Array of target values, or anonymous function for subquery :param bool $escape: Whether to escape values and identifiers :param bool $insensitiveSearch: Whether to force a case-insensitive search :returns: ``BaseBuilder`` instance (method chaining) From d4fe9895d592c0a6a3da88132dea59a9c6d62686 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Mon, 20 Dec 2021 18:10:03 +0800 Subject: [PATCH 1027/2325] Rename method --- system/Database/BaseBuilder.php | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 6d97db101cbb..a2a021ea9630 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -693,8 +693,8 @@ protected function whereHaving(string $qbKey, $key, $value = null, string $type $op = ' ='; } - if ($this->isSubQuery($v)) { - $v = $this->buildSubQuery($v, true); + if ($this->isSubquery($v)) { + $v = $this->buildSubquery($v, true); } else { $bind = $this->setBind($k, $v, $escape); $v = " :{$bind}:"; @@ -844,7 +844,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal return $this; // @codeCoverageIgnore } - if ($values === null || (! is_array($values) && ! $this->isSubQuery($values))) { + if ($values === null || (! is_array($values) && ! $this->isSubquery($values))) { if (CI_DEBUG) { throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); } @@ -864,8 +864,8 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal $not = ($not) ? ' NOT' : ''; - if ($this->isSubQuery($values)) { - $ok = $this->buildSubQuery($values); + if ($this->isSubquery($values)) { + $ok = $this->buildSubquery($values); } else { $whereIn = array_values($values); $ok = $this->setBind($ok, $whereIn, $escape); @@ -874,7 +874,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); $whereIn = [ - 'condition' => $prefix . $key . $not . ($this->isSubQuery($values) ? " IN ({$ok})" : " IN :{$ok}:"), + 'condition' => $prefix . $key . $not . ($this->isSubquery($values) ? " IN ({$ok})" : " IN :{$ok}:"), 'escape' => false, ]; @@ -2733,7 +2733,7 @@ protected function cleanClone() /** * @param mixed $value */ - protected function isSubQuery($value): bool + protected function isSubquery($value): bool { return $value instanceof BaseBuilder || $value instanceof Closure; } @@ -2742,15 +2742,15 @@ protected function isSubQuery($value): bool * @param BaseBuilder|Closure $builder * @param bool $wrapped Wrap the subquery in brackets */ - protected function buildSubQuery($builder, bool $wrapped = false): string + protected function buildSubquery($builder, bool $wrapped = false): string { if ($builder instanceof Closure) { $instance = (clone $this)->from([], true)->resetQuery(); $builder = $builder($instance); } - $subQuery = strtr($builder->getCompiledSelect(), "\n", ' '); + $subquery = strtr($builder->getCompiledSelect(), "\n", ' '); - return $wrapped ? '(' . $subQuery . ')' : $subQuery; + return $wrapped ? '(' . $subquery . ')' : $subquery; } } From 2aa2de794ea6039d0fd237e24da61bab85cb1fe5 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Thu, 23 Dec 2021 12:58:19 +0800 Subject: [PATCH 1028/2325] Changelog and fix doc --- user_guide_src/source/changelogs/v4.1.6.rst | 2 ++ user_guide_src/source/database/query_builder.rst | 11 +---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index d53378a6b624..09cd48ceae80 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -33,6 +33,7 @@ Enhancements ************ - Database pane on debug toolbar now displays location where Query was called from. Also displays full backtrace. +- :ref:`Subqueries` in QueryBuilder can now be an instance of the BaseBuilder class. Changes ******* @@ -43,6 +44,7 @@ Deprecations ************ - ``Seeder::faker()`` and ``Seeder::$faker`` are deprecated. +- ``BaseBuilder::cleanClone()`` is deprecated. Sending Cookies =============== diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 63d9c25f501b..4d0fd69ce2f9 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -304,6 +304,7 @@ methods: $where = "name={$name} AND status='boss' OR status='active'"; $builder->where($where); +.. _query-builder-where-subquery: #. **Subqueries:** :: @@ -318,10 +319,8 @@ methods: // With builder directly $subQuery = $db->table('orders')->select('MAX(advance_amount)', false)->where('id >', 2) - $builder->where('advance_amount <', $subQuery); - **$builder->orWhere()** This function is identical to the one above, except that multiple @@ -350,7 +349,6 @@ You can use subqueries instead of an array of values:: // With builder directly $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); - $builder->whereIn('id', $subQuery); **$builder->orWhereIn()** @@ -373,7 +371,6 @@ You can use subqueries instead of an array of values:: // With builder directly $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); - $builder->orWhereIn('id', $subQuery); **$builder->whereNotIn()** @@ -396,7 +393,6 @@ You can use subqueries instead of an array of values:: // With builder directly $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); - $builder->whereNotIn('id', $subQuery); **$builder->orWhereNotIn()** @@ -419,7 +415,6 @@ You can use subqueries instead of an array of values:: // With builder directly $subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); - $builder->orWhereNotIn('id', $subQuery); ************************ @@ -561,7 +556,6 @@ You can use subqueries instead of an array of values.:: // With builder directly $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); - $builder->havingIn('id', $subQuery); **$builder->orHavingIn()** @@ -586,7 +580,6 @@ You can use subqueries instead of an array of values.:: // With builder directly $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); - $builder->orHavingIn('id', $subQuery); **$builder->havingNotIn()** @@ -611,7 +604,6 @@ You can use subqueries instead of an array of values.:: // With builder directly $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); - $builder->havingNotIn('id', $subQuery); **$builder->orHavingNotIn()** @@ -636,7 +628,6 @@ You can use subqueries instead of an array of values.:: // With builder directly $subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); - $builder->orHavingNotIn('id', $subQuery); **$builder->havingLike()** From fbaab7705a64448bc973c3cfefc7f408d9c07914 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Thu, 23 Dec 2021 15:14:41 +0800 Subject: [PATCH 1029/2325] Update user_guide_src/source/changelogs/v4.1.6.rst Co-authored-by: kenjis --- user_guide_src/source/changelogs/v4.1.6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 09cd48ceae80..61214596ea97 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -33,7 +33,7 @@ Enhancements ************ - Database pane on debug toolbar now displays location where Query was called from. Also displays full backtrace. -- :ref:`Subqueries` in QueryBuilder can now be an instance of the BaseBuilder class. +- :ref:`Subqueries ` in QueryBuilder can now be an instance of the BaseBuilder class. Changes ******* From 5eb8c822c64c0f1500d40bfaeb9542c85567d53c Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Thu, 23 Dec 2021 15:14:51 +0800 Subject: [PATCH 1030/2325] Update user_guide_src/source/database/query_builder.rst Co-authored-by: kenjis --- user_guide_src/source/database/query_builder.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 4d0fd69ce2f9..2c85a58e63e6 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -305,6 +305,7 @@ methods: $builder->where($where); .. _query-builder-where-subquery: + #. **Subqueries:** :: From 864d366c87ab432a2a97ad92dd32603ea14a71ae Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Fri, 24 Dec 2021 09:45:58 +0800 Subject: [PATCH 1031/2325] Excluding a condition from a query string. --- system/Database/BaseBuilder.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index a2a021ea9630..2a431accd2f5 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -865,16 +865,18 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal $not = ($not) ? ' NOT' : ''; if ($this->isSubquery($values)) { - $ok = $this->buildSubquery($values); + $whereIn = $this->buildSubquery($values, true); + $escape = false; } else { $whereIn = array_values($values); - $ok = $this->setBind($ok, $whereIn, $escape); } + $ok = $this->setBind($ok, $whereIn, $escape); + $prefix = empty($this->{$clause}) ? $this->groupGetType('') : $this->groupGetType($type); $whereIn = [ - 'condition' => $prefix . $key . $not . ($this->isSubquery($values) ? " IN ({$ok})" : " IN :{$ok}:"), + 'condition' => "{$prefix}{$key}{$not} IN :{$ok}:", 'escape' => false, ]; From 70625366ae5fa901bc901c435903b008c417353f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Dec 2021 11:57:59 +0900 Subject: [PATCH 1032/2325] fix: KINT visual error when activating CSP --- rector.php | 1 + system/CodeIgniter.php | 4 +- system/Debug/Kint/RichRenderer.php | 75 ++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 system/Debug/Kint/RichRenderer.php diff --git a/rector.php b/rector.php index 8be24cd7024d..68d16bbb66e4 100644 --- a/rector.php +++ b/rector.php @@ -71,6 +71,7 @@ $parameters->set(Option::SKIP, [ __DIR__ . '/app/Views', __DIR__ . '/system/Debug/Toolbar/Views/toolbar.tpl.php', + __DIR__ . '/system/Debug/Kint/RichRenderer.php', __DIR__ . '/system/ThirdParty', __DIR__ . '/tests/system/Config/fixtures', __DIR__ . '/tests/_support', diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index d309ca81c27a..56cb0df4b7bd 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -12,6 +12,7 @@ namespace CodeIgniter; use Closure; +use CodeIgniter\Debug\Kint\RichRenderer; use CodeIgniter\Debug\Timer; use CodeIgniter\Events\Events; use CodeIgniter\Exceptions\FrameworkException; @@ -33,7 +34,6 @@ use Exception; use Kint; use Kint\Renderer\CliRenderer; -use Kint\Renderer\RichRenderer; /** * This class is the core of the framework, and will analyse the @@ -257,6 +257,8 @@ protected function initializeKint() Kint::$plugins = $config->plugins; } + Kint::$renderers[Kint::MODE_RICH] = RichRenderer::class; + RichRenderer::$theme = $config->richTheme; RichRenderer::$folder = $config->richFolder; RichRenderer::$sort = $config->richSort; diff --git a/system/Debug/Kint/RichRenderer.php b/system/Debug/Kint/RichRenderer.php new file mode 100644 index 000000000000..756cac75e144 --- /dev/null +++ b/system/Debug/Kint/RichRenderer.php @@ -0,0 +1,75 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Debug\Kint; + +use Kint\Renderer\RichRenderer as KintRichRenderer; + +/** + * Overrides RichRenderer::preRender() for CSP + */ +class RichRenderer extends KintRichRenderer +{ + public function preRender() + { + $output = ''; + + if ($this->pre_render) { + foreach (self::$pre_render_sources as $type => $values) { + $contents = ''; + + foreach ($values as $v) { + $contents .= $v($this); + } + + if (! \strlen($contents)) { + continue; + } + + switch ($type) { + case 'script': + $output .= ''; + break; + + case 'style': + $output .= ''; + break; + + default: + $output .= $contents; + } + } + + // Don't pre-render on every dump + if (! $this->force_pre_render) { + self::$needs_pre_render = false; + } + } + + $output .= '
    '; + + return $output; + } +} From 9cd87553c1902c69cdbc0bed3fc9d691b9f07cde Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Dec 2021 18:43:41 +0900 Subject: [PATCH 1033/2325] docs: fix typo --- user_guide_src/source/general/common_functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index b9b21e29ba38..24d90ed654e1 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -309,7 +309,7 @@ Miscellaneous Functions // Go back to the previous page return redirect()->back(); - // Go to specific UI + // Go to specific URI return redirect()->to('/admin'); // Go to a named/reverse-routed URI From 34209c8b6dfc03141040b231767e03514a8061db Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Dec 2021 18:43:59 +0900 Subject: [PATCH 1034/2325] docs: fix comment This code uses named route. --- user_guide_src/source/general/common_functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index 24d90ed654e1..cf99aaddda49 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -312,7 +312,7 @@ Miscellaneous Functions // Go to specific URI return redirect()->to('/admin'); - // Go to a named/reverse-routed URI + // Go to a named route return redirect()->route('named_route'); // Keep the old input values upon redirect so they can be used by the `old()` function From a01b3313d220bf82181b7f8002b8d07880eff8cf Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 25 Dec 2021 18:45:33 +0900 Subject: [PATCH 1035/2325] docs: decorate method --- user_guide_src/source/general/common_functions.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index cf99aaddda49..96a16fde77b6 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -328,7 +328,7 @@ Miscellaneous Functions return redirect()->back()->withHeaders(); When passing an argument into the function, it is treated as a named/reverse-routed route, not a relative/full URI, - treating it the same as using redirect()->route():: + treating it the same as using ``redirect()->route()``:: // Go to a named/reverse-routed URI return redirect('named_route'); From aaf9cb2b4ede06b82b287016f04a5b7abdf7d8d3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Dec 2021 06:58:17 +0900 Subject: [PATCH 1036/2325] docs: change text decoration --- user_guide_src/source/dbmgmt/forge.rst | 42 ++++++++++++-------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index bbaa01490b0e..aadaf08d707b 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -40,7 +40,7 @@ Returns true/false based on success or failure:: echo 'Database created!'; } -An optional second parameter set to true will add IF EXISTS statement +An optional second parameter set to true will add ``IF EXISTS`` statement or will check if a database exists before create it (depending on DBMS). :: @@ -95,9 +95,9 @@ Adding fields ============= Fields are normally created via an associative array. Within the array, you must -include a 'type' key that relates to the datatype of the field. For +include a ``type`` key that relates to the datatype of the field. For example, INT, VARCHAR, TEXT, etc. Many datatypes (for example VARCHAR) -also require a 'constraint' key. +also require a ``constraint`` key. :: @@ -111,14 +111,14 @@ also require a 'constraint' key. Additionally, the following key/values can be used: -- unsigned/true : to generate "UNSIGNED" in the field definition. -- default/value : to generate a default value in the field definition. -- null/true : to generate "null" in the field definition. Without this, +- ``unsigned``/true : to generate "UNSIGNED" in the field definition. +- ``default``/value : to generate a default value in the field definition. +- ``null``/true : to generate "null" in the field definition. Without this, the field will default to "NOT null". -- auto_increment/true : generates an auto_increment flag on the +- ``auto_increment``/true : generates an auto_increment flag on the field. Note that the field type must be a type that supports this, such as integer. -- unique/true : to generate a unique key for the field definition. +- ``unique``/true : to generate a unique key for the field definition. :: @@ -162,15 +162,13 @@ Passing strings as fields ------------------------- If you know exactly how you want a field to be created, you can pass the -string into the field definitions with addField() - -:: +string into the field definitions with ``addField()``:: $forge->addField("label varchar(100) NOT NULL DEFAULT 'default label'"); .. note:: Passing raw strings as fields cannot be followed by ``addKey()`` calls on those fields. -.. note:: Multiple calls to addField() are cumulative. +.. note:: Multiple calls to ``addField()`` are cumulative. Creating an id field -------------------- @@ -188,10 +186,10 @@ Adding Keys =========== Generally speaking, you'll want your table to have Keys. This is -accomplished with $forge->addKey('field'). The optional second +accomplished with ``$forge->addKey('field')``. The optional second parameter set to true will make it a primary key and the third -parameter set to true will make it a unique key. Note that addKey() -must be followed by a call to createTable(). +parameter set to true will make it a unique key. Note that ``addKey()`` +must be followed by a call to ``createTable()``. Multiple column non-primary keys must be sent as an array. Sample output below is for MySQL. @@ -256,7 +254,7 @@ with $forge->createTable('table_name'); // gives CREATE TABLE table_name -An optional second parameter set to true adds an "IF NOT EXISTS" clause +An optional second parameter set to true adds an ``IF NOT EXISTS`` clause into the definition :: @@ -277,7 +275,7 @@ You could also pass optional table attributes, such as MySQL's ``ENGINE``:: Dropping a table ================ -Execute a DROP TABLE statement and optionally add an IF EXISTS clause. +Execute a ``DROP TABLE`` statement and optionally add an ``IF EXISTS`` clause. :: @@ -287,7 +285,7 @@ Execute a DROP TABLE statement and optionally add an IF EXISTS clause. // Produces: DROP TABLE IF EXISTS `table_name` $forge->dropTable('table_name', true); -A third parameter can be passed to add a "CASCADE" option, which might be required for some +A third parameter can be passed to add a ``CASCADE`` option, which might be required for some drivers to handle removal of tables with foreign keys. :: @@ -348,7 +346,7 @@ number of additional fields. // Executes: ALTER TABLE `table_name` ADD `preferences` TEXT If you are using MySQL or CUBIRD, then you can take advantage of their -AFTER and FIRST clauses to position the new column. +``AFTER`` and ``FIRST`` clauses to position the new column. Examples:: @@ -464,7 +462,7 @@ Class Reference .. php:method:: createDatabase($dbName[, $ifNotExists = false]) :param string $db_name: Name of the database to create - :param string $ifNotExists: Set to true to add an 'IF NOT EXISTS' clause or check if database exists + :param string $ifNotExists: Set to true to add an ``IF NOT EXISTS`` clause or check if database exists :returns: true on success, false on failure :rtype: bool @@ -473,7 +471,7 @@ Class Reference .. php:method:: createTable($table[, $if_not_exists = false[, array $attributes = []]]) :param string $table: Name of the table to create - :param string $if_not_exists: Set to true to add an 'IF NOT EXISTS' clause + :param string $if_not_exists: Set to true to add an ``IF NOT EXISTS`` clause :param string $attributes: An associative array of table attributes :returns: Query object on success, false on failure :rtype: mixed @@ -500,7 +498,7 @@ Class Reference .. php:method:: dropTable($table_name[, $if_exists = false]) :param string $table: Name of the table to drop - :param string $if_exists: Set to true to add an 'IF EXISTS' clause + :param string $if_exists: Set to true to add an ``IF EXISTS`` clause :returns: true on success, false on failure :rtype: bool From 63d3bf605e72be076de33fd6dd0fd33011d37346 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Dec 2021 07:00:35 +0900 Subject: [PATCH 1037/2325] docs: remove `;` --- user_guide_src/source/dbmgmt/forge.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index aadaf08d707b..c74fada3551d 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -151,7 +151,7 @@ Additionally, the following key/values can be used: ]; After the fields have been defined, they can be added using -``$forge->addField($fields);`` followed by a call to the +``$forge->addField($fields)`` followed by a call to the ``createTable()`` method. **$forge->addField()** From 5876539b3b6dea4c69c07328da5b3fc2d0410cd0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Dec 2021 07:00:56 +0900 Subject: [PATCH 1038/2325] docs: change lowercase to uppercase --- user_guide_src/source/dbmgmt/forge.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index c74fada3551d..2dedbc9af2dc 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -13,7 +13,7 @@ Initializing the Forge Class **************************** .. important:: In order to initialize the Forge class, your database - driver must already be running, since the forge class relies on it. + driver must already be running, since the Forge class relies on it. Load the Forge Class as follows:: @@ -91,7 +91,7 @@ There are several things you may wish to do when creating tables. Add fields, add keys to the table, alter columns. CodeIgniter provides a mechanism for this. -Adding fields +Adding Fields ============= Fields are normally created via an associative array. Within the array, you must @@ -243,7 +243,7 @@ You can specify the desired action for the "on delete" and "on update" propertie $forge->addForeignKey(['users_id', 'users_name'], 'users', ['id', 'name'], 'CASCADE', 'CASCADE'); // gives CONSTRAINT `TABLENAME_users_foreign` FOREIGN KEY(`users_id`, `users_name`) REFERENCES `users`(`id`, `name`) ON DELETE CASCADE ON UPDATE CASCADE -Creating a table +Creating a Table ================ After fields and keys have been declared, you can create a new table @@ -272,7 +272,7 @@ You could also pass optional table attributes, such as MySQL's ``ENGINE``:: ``createTable()`` will always add them with your configured *charset* and *DBCollat* values, as long as they are not empty (MySQL only). -Dropping a table +Dropping a Table ================ Execute a ``DROP TABLE`` statement and optionally add an ``IF EXISTS`` clause. @@ -314,7 +314,7 @@ Execute a DROP KEY. // Produces: DROP INDEX `users_index` ON `tablename` $forge->dropKey('tablename', 'users_index'); -Renaming a table +Renaming a Table ================ Executes a TABLE rename @@ -419,7 +419,7 @@ Class Reference :returns: \CodeIgniter\Database\Forge instance (method chaining) :rtype: \CodeIgniter\Database\Forge - Adds a field to the set that will be used to create a table. Usage: See `Adding fields`_. + Adds a field to the set that will be used to create a table. Usage: See `Adding Fields`_. .. php:method:: addForeignKey($fieldName, $tableName, $tableField[, $onUpdate = '', $onDelete = '']) @@ -476,7 +476,7 @@ Class Reference :returns: Query object on success, false on failure :rtype: mixed - Creates a new table. Usage: See `Creating a table`_. + Creates a new table. Usage: See `Creating a Table`_. .. php:method:: dropColumn($table, $column_name) @@ -502,7 +502,7 @@ Class Reference :returns: true on success, false on failure :rtype: bool - Drops a table. Usage: See `Dropping a table`_. + Drops a table. Usage: See `Dropping a Table`_. .. php:method:: modifyColumn($table, $field) @@ -520,4 +520,4 @@ Class Reference :returns: Query object on success, false on failure :rtype: mixed - Renames a table. Usage: See `Renaming a table`_. + Renames a table. Usage: See `Renaming a Table`_. From 3a03e452a944429df0ee85f7ad95e3274e357bc1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Dec 2021 09:50:10 +0900 Subject: [PATCH 1039/2325] chore: add third party license files --- system/ComposerScripts.php | 19 +++++++++++++------ system/ThirdParty/Escaper/LICENSE.md | 26 ++++++++++++++++++++++++++ system/ThirdParty/Kint/LICENSE | 20 ++++++++++++++++++++ system/ThirdParty/PSR/Log/LICENSE | 19 +++++++++++++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 system/ThirdParty/Escaper/LICENSE.md create mode 100644 system/ThirdParty/Kint/LICENSE create mode 100644 system/ThirdParty/PSR/Log/LICENSE diff --git a/system/ComposerScripts.php b/system/ComposerScripts.php index 6972395b5444..ef4dfe1a801b 100644 --- a/system/ComposerScripts.php +++ b/system/ComposerScripts.php @@ -43,20 +43,23 @@ final class ComposerScripts */ private static $dependencies = [ 'kint-src' => [ - 'from' => __DIR__ . '/../vendor/kint-php/kint/src/', - 'to' => __DIR__ . '/ThirdParty/Kint/', + 'license' => __DIR__ . '/../vendor/kint-php/kint/LICENSE', + 'from' => __DIR__ . '/../vendor/kint-php/kint/src/', + 'to' => __DIR__ . '/ThirdParty/Kint/', ], 'kint-resources' => [ 'from' => __DIR__ . '/../vendor/kint-php/kint/resources/', 'to' => __DIR__ . '/ThirdParty/Kint/resources/', ], 'escaper' => [ - 'from' => __DIR__ . '/../vendor/laminas/laminas-escaper/src/', - 'to' => __DIR__ . '/ThirdParty/Escaper/', + 'license' => __DIR__ . '/../vendor/laminas/laminas-escaper/LICENSE.md', + 'from' => __DIR__ . '/../vendor/laminas/laminas-escaper/src/', + 'to' => __DIR__ . '/ThirdParty/Escaper/', ], 'psr-log' => [ - 'from' => __DIR__ . '/../vendor/psr/log/Psr/Log/', - 'to' => __DIR__ . '/ThirdParty/PSR/Log/', + 'license' => __DIR__ . '/../vendor/psr/log/LICENSE', + 'from' => __DIR__ . '/../vendor/psr/log/Psr/Log/', + 'to' => __DIR__ . '/ThirdParty/PSR/Log/', ], ]; @@ -70,6 +73,10 @@ public static function postUpdate() foreach (self::$dependencies as $dependency) { self::recursiveMirror($dependency['from'], $dependency['to']); + if (isset($dependency['license'])) { + $license = basename($dependency['license']); + copy($dependency['license'], $dependency['to'] . '/' . $license); + } } self::copyKintInitFiles(); diff --git a/system/ThirdParty/Escaper/LICENSE.md b/system/ThirdParty/Escaper/LICENSE.md new file mode 100644 index 000000000000..10b40f1423b5 --- /dev/null +++ b/system/ThirdParty/Escaper/LICENSE.md @@ -0,0 +1,26 @@ +Copyright (c) 2020 Laminas Project a Series of LF Projects, LLC. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +- Neither the name of Laminas Foundation nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/system/ThirdParty/Kint/LICENSE b/system/ThirdParty/Kint/LICENSE new file mode 100644 index 000000000000..01718d4953c4 --- /dev/null +++ b/system/ThirdParty/Kint/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2013 Jonathan Vollebregt (jnvsor@gmail.com), Rokas Šleinius (raveren@gmail.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/system/ThirdParty/PSR/Log/LICENSE b/system/ThirdParty/PSR/Log/LICENSE new file mode 100644 index 000000000000..474c952b4b50 --- /dev/null +++ b/system/ThirdParty/PSR/Log/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2012 PHP Framework Interoperability Group + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. From 9c379088e8afa6cbfa470cbda79359f800ab5b24 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Dec 2021 11:37:44 +0900 Subject: [PATCH 1040/2325] test: add tests for Kint with CSP --- tests/system/CommonFunctionsTest.php | 34 ++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index c6f1d6b9b2e1..b7f4f381c233 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -29,6 +29,7 @@ use Config\Logger; use Config\Modules; use InvalidArgumentException; +use Kint; use stdClass; use Tests\Support\Models\JobModel; @@ -482,4 +483,37 @@ public function testIsCli() $this->assertIsBool(is_cli()); $this->assertTrue(is_cli()); } + + public function testDWithCSP() + { + /** @var App $config */ + $config = config(App::class); + $CSPEnabled = $config->CSPEnabled; + $cliDetection = Kint::$cli_detection; + + $config->CSPEnabled = true; + Kint::$cli_detection = false; + + $this->expectOutputRegex('/'; + $output .= ''; + $output .= '' - . '' - . '' + . '' + . '' . $kintScript . PHP_EOL; From e7b0727e8d42833bbee5a38476a76ade10bd4f5b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 31 Dec 2021 13:55:42 +0900 Subject: [PATCH 1119/2325] config: fix incorrect property name --- env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/env b/env index 7b52d6690441..e11bb08e0493 100644 --- a/env +++ b/env @@ -60,7 +60,7 @@ # contentsecuritypolicy.scriptSrc = 'self' # contentsecuritypolicy.styleSrc = 'self' # contentsecuritypolicy.imageSrc = 'self' -# contentsecuritypolicy.base_uri = null +# contentsecuritypolicy.baseURI = null # contentsecuritypolicy.childSrc = null # contentsecuritypolicy.connectSrc = 'self' # contentsecuritypolicy.fontSrc = null From d548118c264dedc1dde45b6ca0afcd550462b49f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 31 Dec 2021 14:01:36 +0900 Subject: [PATCH 1120/2325] feat: add config for disabling to replace nonce tag automatically --- app/Config/ContentSecurityPolicy.php | 7 ++++ env | 1 + system/HTTP/ContentSecurityPolicy.php | 11 +++++++ .../system/HTTP/ContentSecurityPolicyTest.php | 32 +++++++++++++++++++ 4 files changed, 51 insertions(+) diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php index b4450d5ed422..aa18ba9f1060 100644 --- a/app/Config/ContentSecurityPolicy.php +++ b/app/Config/ContentSecurityPolicy.php @@ -178,4 +178,11 @@ class ContentSecurityPolicy extends BaseConfig * @var string */ public $scriptNonceTag = '{csp-script-nonce}'; + + /** + * Replace nonce tag automatically + * + * @var bool + */ + public $autoNonce = true; } diff --git a/env b/env index e11bb08e0493..83def018081f 100644 --- a/env +++ b/env @@ -75,6 +75,7 @@ # contentsecuritypolicy.upgradeInsecureRequests = false # contentsecuritypolicy.styleNonceTag = '{csp-style-nonce}' # contentsecuritypolicy.scriptNonceTag = '{csp-script-nonce}' +# contentsecuritypolicy.autoNonce = true #-------------------------------------------------------------------- # COOKIE diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index fb70c613549a..341411013d0e 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -204,6 +204,13 @@ class ContentSecurityPolicy */ protected $scriptNonceTag = '{csp-script-nonce}'; + /** + * Replace nonce tag automatically + * + * @var bool + */ + protected $autoNonce = true; + /** * An array of header info since we have * to build ourself before passing to Response. @@ -288,6 +295,10 @@ public function getScriptNonce(): string */ public function finalize(ResponseInterface &$response) { + if ($this->autoNonce === false) { + return; + } + $this->generateNonces($response); $this->buildHeaders($response); } diff --git a/tests/system/HTTP/ContentSecurityPolicyTest.php b/tests/system/HTTP/ContentSecurityPolicyTest.php index 5525309d7a2f..fa95d9ba9fb6 100644 --- a/tests/system/HTTP/ContentSecurityPolicyTest.php +++ b/tests/system/HTTP/ContentSecurityPolicyTest.php @@ -480,6 +480,38 @@ public function testBodyScriptNonceCustomScriptTag() $this->assertStringContainsString('nonce=', $response->getBody()); } + public function testBodyScriptNonceDisableAutoNonce() + { + $config = new CSPConfig(); + $config->autoNonce = false; + $csp = new ContentSecurityPolicy($config); + + $response = new Response(new App()); + $response->pretend(true); + $body = 'Blah blah {csp-script-nonce} blah blah'; + $response->setBody($body); + + $csp->finalize($response); + + $this->assertStringContainsString('{csp-script-nonce}', $response->getBody()); + } + + public function testBodyStyleNonceDisableAutoNonce() + { + $config = new CSPConfig(); + $config->autoNonce = false; + $csp = new ContentSecurityPolicy($config); + + $response = new Response(new App()); + $response->pretend(true); + $body = 'Blah blah {csp-style-nonce} blah blah'; + $response->setBody($body); + + $csp->finalize($response); + + $this->assertStringContainsString('{csp-style-nonce}', $response->getBody()); + } + /** * @runInSeparateProcess * @preserveGlobalState disabled From bc52fad6678b3600e2d62139a032dbd5a2482192 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 31 Dec 2021 14:13:57 +0900 Subject: [PATCH 1121/2325] refactor: use csp_script_nonce() and csp_script_nonce() in Kint --- system/Debug/Kint/RichRenderer.php | 4 ++-- tests/system/CommonFunctionsTest.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Debug/Kint/RichRenderer.php b/system/Debug/Kint/RichRenderer.php index 756cac75e144..8210fb21e1c2 100644 --- a/system/Debug/Kint/RichRenderer.php +++ b/system/Debug/Kint/RichRenderer.php @@ -36,11 +36,11 @@ public function preRender() switch ($type) { case 'script': - $output .= ''; + $output .= ''; break; case 'style': - $output .= ''; + $output .= ''; break; default: diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index f55f55fb45b4..51eb7f94938f 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -527,7 +527,7 @@ public function testDWithCSP() $config->CSPEnabled = true; Kint::$cli_detection = false; - $this->expectOutputRegex('/ + .. literalinclude:: html_helper/010.php + :lines: 2- Alternately, an associative array can be passed to the ``script_tag()`` function - for complete control over all attributes and values:: + for complete control over all attributes and values: - $script = ['src' => 'js/printer.js']; - - echo script_tag($script); - // + .. literalinclude:: html_helper/011.php + :lines: 2- .. php:function:: ul($list[, $attributes = '']) @@ -162,21 +142,10 @@ The following functions are available: :rtype: string Permits you to generate unordered HTML lists from simple or - multi-dimensional arrays. Example:: - - $list = [ - 'red', - 'blue', - 'green', - 'yellow', - ]; + multi-dimensional arrays. Example: - $attributes = [ - 'class' => 'boldlist', - 'id' => 'mylist', - ]; - - echo ul($list, $attributes); + .. literalinclude:: html_helper/012.php + :lines: 2- The above code will produce this: @@ -189,44 +158,10 @@ The following functions are available:
  • yellow
  • - Here is a more complex example, using a multi-dimensional array:: - - $attributes = [ - 'class' => 'boldlist', - 'id' => 'mylist', - ]; - - $list = [ - 'colors' => [ - 'red', - 'blue', - 'green', - ], - 'shapes' => [ - 'round', - 'square', - 'circles' => [ - 'ellipse', - 'oval', - 'sphere', - ], - ], - 'moods' => [ - 'happy', - 'upset' => [ - 'defeated' => [ - 'dejected', - 'disheartened', - 'depressed', - ], - 'annoyed', - 'cross', - 'angry', - ] - ] - ]; - - echo ul($list, $attributes); + Here is a more complex example, using a multi-dimensional array: + + .. literalinclude:: html_helper/013.php + :lines: 2- The above code will produce this: @@ -295,32 +230,10 @@ The following functions are available: :rtype: string Permits you to generate HTML video element from simple or - source arrays. Example:: - - $tracks = [ - track('subtitles_no.vtt', 'subtitles', 'no', 'Norwegian No'), - track('subtitles_yes.vtt', 'subtitles', 'yes', 'Norwegian Yes') - ]; - - echo video('test.mp4', 'Your browser does not support the video tag.', 'controls'); - - echo video( - 'http://www.codeigniter.com/test.mp4', - 'Your browser does not support the video tag.', - 'controls', - $tracks - ); - - echo video([ - source('movie.mp4', 'video/mp4', 'class="test"'), - source('movie.ogg', 'video/ogg'), - source('movie.mov', 'video/quicktime'), - source('movie.ogv', 'video/ogv; codecs=dirac, speex') - ], - 'Your browser does not support the video tag.', - 'class="test" controls', - $tracks - ); + source arrays. Example: + + .. literalinclude:: html_helper/014.php + :lines: 2- The above code will produce this: @@ -367,10 +280,10 @@ The following functions are available: :rtype: string Lets you create HTML ```` tags. The first parameter contains the - source source. Example:: + source source. Example: - echo source('movie.mp4', 'video/mp4', 'class="test"'); - // + .. literalinclude:: html_helper/015.php + :lines: 2- .. php:function:: embed($src = ''[, $type = false[, $attributes = ''[, $indexPage = false]]]) @@ -382,10 +295,10 @@ The following functions are available: :rtype: string Lets you create HTML ```` tags. The first parameter contains the - embed source. Example:: + embed source. Example: - echo embed('movie.mov', 'video/quicktime', 'class="test"'); - // + .. literalinclude:: html_helper/016.php + :lines: 2- .. php:function:: object($data = ''[, $type = false[, $attributes = '']]) @@ -397,19 +310,10 @@ The following functions are available: :rtype: string Lets you create HTML ```` tags. The first parameter contains the - object data. Example:: + object data. Example: - echo object('movie.swf', 'application/x-shockwave-flash', 'class="test"'); - - echo object( - 'movie.swf', - 'application/x-shockwave-flash', - 'class="test"', - [ - param('foo', 'bar', 'ref', 'class="test"'), - param('hello', 'world', 'ref', 'class="test"') - ] - ); + .. literalinclude:: html_helper/017.php + :lines: 2- The above code will produce this: @@ -431,10 +335,10 @@ The following functions are available: :rtype: string Lets you create HTML ```` tags. The first parameter contains the - param source. Example:: + param source. Example: - echo param('movie.mov', 'video/quicktime', 'class="test"'); - // + .. literalinclude:: html_helper/018.php + :lines: 2- .. php:function:: track($name = ''[, $type = false[, $attributes = '']]) @@ -445,10 +349,10 @@ The following functions are available: :rtype: string Generates a track element to specify timed tracks. The tracks are - formatted in WebVTT format. Example:: + formatted in WebVTT format. Example: - echo track('subtitles_no.vtt', 'subtitles', 'no', 'Norwegian No'); - // + .. literalinclude:: html_helper/019.php + :lines: 2- .. php:function:: doctype([$type = 'html5']) @@ -459,13 +363,10 @@ The following functions are available: Helps you generate document type declarations, or DTD's. HTML 5 is used by default, but many doctypes are available. - Example:: - - echo doctype(); - // + Example: - echo doctype('html4-trans'); - // + .. literalinclude:: html_helper/020.php + :lines: 2- The following is a list of the pre-defined doctype choices. These are configurable, pulled from **app/Config/DocTypes.php**, or they could be over-ridden in your **.env** configuration. diff --git a/user_guide_src/source/helpers/html_helper/001.php b/user_guide_src/source/helpers/html_helper/001.php new file mode 100644 index 000000000000..8163b563fc6e --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/001.php @@ -0,0 +1,3 @@ + diff --git a/user_guide_src/source/helpers/html_helper/003.php b/user_guide_src/source/helpers/html_helper/003.php new file mode 100644 index 000000000000..1cf332ede621 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/003.php @@ -0,0 +1,4 @@ + diff --git a/user_guide_src/source/helpers/html_helper/004.php b/user_guide_src/source/helpers/html_helper/004.php new file mode 100644 index 000000000000..79769391f49f --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/004.php @@ -0,0 +1,14 @@ + 'images/picture.jpg', + 'alt' => 'Me, demonstrating how to eat 4 slices of pizza at one time', + 'class' => 'post_images', + 'width' => '200', + 'height' => '200', + 'title' => 'That was quite a night', + 'rel' => 'lightbox', +]; + +img($imageProperties); +// Me, demonstrating how to eat 4 slices of pizza at one time diff --git a/user_guide_src/source/helpers/html_helper/005.php b/user_guide_src/source/helpers/html_helper/005.php new file mode 100644 index 000000000000..07c05813e74b --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/005.php @@ -0,0 +1,4 @@ + diff --git a/user_guide_src/source/helpers/html_helper/008.php b/user_guide_src/source/helpers/html_helper/008.php new file mode 100644 index 000000000000..ec6741ede834 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/008.php @@ -0,0 +1,7 @@ + + +echo link_tag('feed', 'alternate', 'application/rss+xml', 'My RSS Feed'); +// diff --git a/user_guide_src/source/helpers/html_helper/009.php b/user_guide_src/source/helpers/html_helper/009.php new file mode 100644 index 000000000000..b598137dba11 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/009.php @@ -0,0 +1,11 @@ + 'css/printer.css', + 'rel' => 'stylesheet', + 'type' => 'text/css', + 'media' => 'print', +]; + +echo link_tag($link); +// diff --git a/user_guide_src/source/helpers/html_helper/010.php b/user_guide_src/source/helpers/html_helper/010.php new file mode 100644 index 000000000000..45e68400e6c9 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/010.php @@ -0,0 +1,4 @@ + diff --git a/user_guide_src/source/helpers/html_helper/011.php b/user_guide_src/source/helpers/html_helper/011.php new file mode 100644 index 000000000000..0d15fc0e6c69 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/011.php @@ -0,0 +1,6 @@ + 'js/printer.js']; + +echo script_tag($script); +// diff --git a/user_guide_src/source/helpers/html_helper/012.php b/user_guide_src/source/helpers/html_helper/012.php new file mode 100644 index 000000000000..941de51da134 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/012.php @@ -0,0 +1,15 @@ + 'boldlist', + 'id' => 'mylist', +]; + +echo ul($list, $attributes); diff --git a/user_guide_src/source/helpers/html_helper/013.php b/user_guide_src/source/helpers/html_helper/013.php new file mode 100644 index 000000000000..435ebc5535d2 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/013.php @@ -0,0 +1,38 @@ + 'boldlist', + 'id' => 'mylist', +]; + +$list = [ + 'colors' => [ + 'red', + 'blue', + 'green', + ], + 'shapes' => [ + 'round', + 'square', + 'circles' => [ + 'ellipse', + 'oval', + 'sphere', + ], + ], + 'moods' => [ + 'happy', + 'upset' => [ + 'defeated' => [ + 'dejected', + 'disheartened', + 'depressed', + ], + 'annoyed', + 'cross', + 'angry', + ] + ] +]; + +echo ul($list, $attributes); diff --git a/user_guide_src/source/helpers/html_helper/014.php b/user_guide_src/source/helpers/html_helper/014.php new file mode 100644 index 000000000000..505b771d5f1b --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/014.php @@ -0,0 +1,26 @@ + diff --git a/user_guide_src/source/helpers/html_helper/016.php b/user_guide_src/source/helpers/html_helper/016.php new file mode 100644 index 000000000000..6e8c60a8dd7c --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/016.php @@ -0,0 +1,4 @@ + diff --git a/user_guide_src/source/helpers/html_helper/017.php b/user_guide_src/source/helpers/html_helper/017.php new file mode 100644 index 000000000000..a0b38b79e672 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/017.php @@ -0,0 +1,13 @@ + diff --git a/user_guide_src/source/helpers/html_helper/019.php b/user_guide_src/source/helpers/html_helper/019.php new file mode 100644 index 000000000000..d073fa12df96 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/019.php @@ -0,0 +1,4 @@ + diff --git a/user_guide_src/source/helpers/html_helper/020.php b/user_guide_src/source/helpers/html_helper/020.php new file mode 100644 index 000000000000..1bd614043095 --- /dev/null +++ b/user_guide_src/source/helpers/html_helper/020.php @@ -0,0 +1,7 @@ + + +echo doctype('html4-trans'); +// diff --git a/user_guide_src/source/helpers/inflector_helper.rst b/user_guide_src/source/helpers/inflector_helper.rst index 924ee5b75559..690430ea1b63 100755 --- a/user_guide_src/source/helpers/inflector_helper.rst +++ b/user_guide_src/source/helpers/inflector_helper.rst @@ -12,9 +12,10 @@ The Inflector Helper file contains functions that permit you to change Loading this Helper =================== -This helper is loaded using the following code:: +This helper is loaded using the following code: - helper('inflector'); +.. literalinclude:: inflector_helper/001.php + :lines: 2- Available Functions =================== @@ -27,9 +28,10 @@ The following functions are available: :returns: A singular word :rtype: string - Changes a plural word to singular. Example:: + Changes a plural word to singular. Example: - echo singular('dogs'); // Prints 'dog' + .. literalinclude:: inflector_helper/002.php + :lines: 2- .. php:function:: plural($string) @@ -37,9 +39,10 @@ The following functions are available: :returns: A plural word :rtype: string - Changes a singular word to plural. Example:: + Changes a singular word to plural. Example: - echo plural('dog'); // Prints 'dogs' + .. literalinclude:: inflector_helper/003.php + :lines: 2- .. php:function:: counted($count, $string) @@ -48,9 +51,10 @@ The following functions are available: :returns: A singular or plural phrase :rtype: string - Changes a word and its count to a phrase. Example:: + Changes a word and its count to a phrase. Example: - echo counted(3, 'dog'); // Prints '3 dogs' + .. literalinclude:: inflector_helper/004.php + :lines: 2- .. php:function:: camelize($string) @@ -59,9 +63,10 @@ The following functions are available: :rtype: string Changes a string of words separated by spaces or underscores to camel - case. Example:: + case. Example: - echo camelize('my_dog_spot'); // Prints 'myDogSpot' + .. literalinclude:: inflector_helper/005.php + :lines: 2- .. php:function:: pascalize($string) @@ -70,9 +75,10 @@ The following functions are available: :rtype: string Changes a string of words separated by spaces or underscores to Pascal - case, which is camel case with the first letter capitalized. Example:: + case, which is camel case with the first letter capitalized. Example: - echo pascalize('my_dog_spot'); // Prints 'MyDogSpot' + .. literalinclude:: inflector_helper/006.php + :lines: 2- .. php:function:: underscore($string) @@ -81,9 +87,10 @@ The following functions are available: :rtype: string Takes multiple words separated by spaces and underscores them. - Example:: + Example: - echo underscore('my dog spot'); // Prints 'my_dog_spot' + .. literalinclude:: inflector_helper/007.php + :lines: 2- .. php:function:: humanize($string[, $separator = '_']) @@ -95,13 +102,15 @@ The following functions are available: Takes multiple words separated by underscores and adds spaces between them. Each word is capitalized. - Example:: + Example: - echo humanize('my_dog_spot'); // Prints 'My Dog Spot' + .. literalinclude:: inflector_helper/008.php + :lines: 2- - To use dashes instead of underscores:: + To use dashes instead of underscores: - echo humanize('my-dog-spot', '-'); // Prints 'My Dog Spot' + .. literalinclude:: inflector_helper/009.php + :lines: 2- .. php:function:: is_pluralizable($word) @@ -109,9 +118,10 @@ The following functions are available: :returns: true if the word is countable or false if not :rtype: bool - Checks if the given word has a plural version. Example:: + Checks if the given word has a plural version. Example: - is_pluralizable('equipment'); // Returns false + .. literalinclude:: inflector_helper/010.php + :lines: 2- .. php:function:: dasherize($string) @@ -119,9 +129,10 @@ The following functions are available: :returns: Dasherized string :rtype: string - Replaces underscores with dashes in the string. Example:: + Replaces underscores with dashes in the string. Example: - dasherize('hello_world'); // Returns 'hello-world' + .. literalinclude:: inflector_helper/011.php + :lines: 2- .. php:function:: ordinal($integer) @@ -131,9 +142,10 @@ The following functions are available: Returns the suffix that should be added to a number to denote the position such as - 1st, 2nd, 3rd, 4th. Example:: + 1st, 2nd, 3rd, 4th. Example: - ordinal(1); // Returns 'st' + .. literalinclude:: inflector_helper/012.php + :lines: 2- .. php:function:: ordinalize($integer) @@ -143,6 +155,7 @@ The following functions are available: Turns a number into an ordinal string used to denote the position such as 1st, 2nd, 3rd, 4th. - Example:: + Example: - ordinalize(1); // Returns '1st' + .. literalinclude:: inflector_helper/013.php + :lines: 2- diff --git a/user_guide_src/source/helpers/inflector_helper/001.php b/user_guide_src/source/helpers/inflector_helper/001.php new file mode 100644 index 000000000000..985243995503 --- /dev/null +++ b/user_guide_src/source/helpers/inflector_helper/001.php @@ -0,0 +1,3 @@ +/Number.php* @@ -72,20 +67,20 @@ The following functions are available: :rtype: string Converts a number into a human-readable version, like **123.4 trillion** - for numbers up to the quadrillions. Examples:: + for numbers up to the quadrillions. Examples: - echo number_to_amount(123456); // Returns 123 thousand - echo number_to_amount(123456789); // Returns 123 million - echo number_to_amount(1234567890123, 2); // Returns 1.23 trillion - echo number_to_amount('123,456,789,012', 2); // Returns 123.46 billion + .. literalinclude:: number_helper/005.php + :lines: 2- - An optional second parameter allows you to set the precision of the result:: + An optional second parameter allows you to set the precision of the result: - echo number_to_amount(45678, 2); // Returns 45.68 thousand + .. literalinclude:: number_helper/006.php + :lines: 2- - An optional third parameter allows the locale to be specified:: + An optional third parameter allows the locale to be specified: - echo number_to_amount('123,456,789,012', 2, 'de_DE'); // Returns 123,46 billion + .. literalinclude:: number_helper/007.php + :lines: 2- .. php:function:: number_to_currency($num, $currency[, $locale = null[, $fraction = 0]]) @@ -96,12 +91,10 @@ The following functions are available: :returns: The number as the appropriate currency for the locale :rtype: string - Converts a number in common currency formats, like USD, EUR, GBP, etc:: + Converts a number in common currency formats, like USD, EUR, GBP, etc: - echo number_to_currency(1234.56, 'USD', 'en_US', 2); // Returns $1,234.56 - echo number_to_currency(1234.56, 'EUR', 'de_DE', 2); // Returns 1.234,56 € - echo number_to_currency(1234.56, 'GBP', 'en_GB', 2); // Returns £1,234.56 - echo number_to_currency(1234.56, 'YEN', 'ja_JP', 2); // Returns YEN 1,234.56 + .. literalinclude:: number_helper/008.php + :lines: 2- If you don't specify a locale, the Request locale is used. @@ -111,11 +104,10 @@ The following functions are available: :returns: The roman number converted from given parameter :rtype: string|null - Converts a number into roman:: + Converts a number into roman: - echo number_to_roman(23); // Returns XXIII - echo number_to_roman(324); // Returns CCCXXIV - echo number_to_roman(2534); // Returns MMDXXXIV + .. literalinclude:: number_helper/009.php + :lines: 2- This function only handles numbers in the range 1 through 3999. It will return null for any value outside that range. diff --git a/user_guide_src/source/helpers/number_helper/001.php b/user_guide_src/source/helpers/number_helper/001.php new file mode 100644 index 000000000000..9ff7e68b56c6 --- /dev/null +++ b/user_guide_src/source/helpers/number_helper/001.php @@ -0,0 +1,3 @@ +assertTrue($this->userHasAccess($user)); - } + .. literalinclude:: test_helper/002.php + :lines: 2- diff --git a/user_guide_src/source/helpers/test_helper/001.php b/user_guide_src/source/helpers/test_helper/001.php new file mode 100644 index 000000000000..6bbc62605b25 --- /dev/null +++ b/user_guide_src/source/helpers/test_helper/001.php @@ -0,0 +1,3 @@ +assertTrue($this->userHasAccess($user)); +} diff --git a/user_guide_src/source/helpers/text_helper.rst b/user_guide_src/source/helpers/text_helper.rst index 0c842677a001..ebc1784c305c 100755 --- a/user_guide_src/source/helpers/text_helper.rst +++ b/user_guide_src/source/helpers/text_helper.rst @@ -11,9 +11,10 @@ The Text Helper file contains functions that assist in working with Text. Loading this Helper =================== -This helper is loaded using the following code:: +This helper is loaded using the following code: - helper('text'); +.. literalinclude:: text_helper/001.php + :lines: 2- Available Functions =================== @@ -42,9 +43,10 @@ The following functions are available: - **sha1**: An encrypted random number based on ``sha1()`` (fixed length of 40). - **crypto**: A random string based on ``random_bytes()``. - Usage example:: + Usage example: - echo random_string('alnum', 16); + .. literalinclude:: text_helper/002.php + :lines: 2- .. php:function:: increment_string($str[, $separator = '_'[, $first = 1]]) @@ -58,11 +60,10 @@ The following functions are available: number. Useful for creating "copies" or a file or duplicating database content which has unique titles or slugs. - Usage example:: + Usage example: - echo increment_string('file', '_'); // "file_1" - echo increment_string('file', '-', 2); // "file-2" - echo increment_string('file_4'); // "file_5" + .. literalinclude:: text_helper/003.php + :lines: 2- .. php:function:: alternator($args) @@ -71,20 +72,16 @@ The following functions are available: :rtype: mixed Allows two or more items to be alternated between, when cycling through - a loop. Example:: + a loop. Example: - for ($i = 0; $i < 10; $i++) {      - echo alternator('string one', 'string two'); - } + .. literalinclude:: text_helper/004.php + :lines: 2- You can add as many parameters as you want, and with each iteration of your loop the next item will be returned. - :: - - for ($i = 0; $i < 10; $i++) {      - echo alternator('one', 'two', 'three', 'four', 'five'); - } + .. literalinclude:: text_helper/005.php + :lines: 2- .. note:: To use multiple separate calls to this function simply call the function with no arguments to re-initialize. @@ -98,10 +95,10 @@ The following functions are available: Converts double slashes in a string to a single slash, except those found in URL protocol prefixes (e.g., http://). - Example:: + Example: - $string = "http://example.com//index.php"; - echo reduce_double_slashes($string); // results in "http://example.com/index.php" + .. literalinclude:: text_helper/006.php + :lines: 2- .. php:function:: strip_slashes($data) @@ -111,21 +108,15 @@ The following functions are available: Removes any slashes from an array of strings. - Example:: - - $str = [ - 'question' => "Is your name O\'reilly?", - 'answer' => "No, my name is O\'connor." - ]; + Example: - $str = strip_slashes($str); + .. literalinclude:: text_helper/007.php + :lines: 2- - The above will return the following array:: + The above will return the following array: - [ - 'question' => "Is your name O'reilly?", - 'answer' => "No, my name is O'connor." - ]; + .. literalinclude:: text_helper/008.php + :lines: 2- .. note:: For historical reasons, this function will also accept and handle string inputs. This however makes it just an @@ -140,16 +131,16 @@ The following functions are available: :rtype: string Reduces multiple instances of a particular character occurring directly - after each other. Example:: + after each other. Example: - $string = "Fred, Bill,, Joe, Jimmy"; - $string = reduce_multiples($string, ","); // results in "Fred, Bill, Joe, Jimmy" + .. literalinclude:: text_helper/009.php + :lines: 2- If the third parameter is set to true it will remove occurrences of the - character at the beginning and the end of the string. Example:: + character at the beginning and the end of the string. Example: - $string = ",Fred, Bill,, Joe, Jimmy,"; - $string = reduce_multiples($string, ", ", true); // results in "Fred, Bill, Joe, Jimmy" + .. literalinclude:: text_helper/010.php + :lines: 2- .. php:function:: quotes_to_entities($str) @@ -158,10 +149,10 @@ The following functions are available: :rtype: string Converts single and double quotes in a string to the corresponding HTML - entities. Example:: + entities. Example: - $string = "Joe's \"dinner\""; - $string = quotes_to_entities($string); //results in "Joe's "dinner"" + .. literalinclude:: text_helper/011.php + :lines: 2- .. php:function:: strip_quotes($str) @@ -169,10 +160,10 @@ The following functions are available: :returns: String with quotes stripped :rtype: string - Removes single and double quotes from a string. Example:: + Removes single and double quotes from a string. Example: - $string = "Joe's \"dinner\""; - $string = strip_quotes($string); //results in "Joes dinner" + .. literalinclude:: text_helper/012.php + :lines: 2- .. php:function:: word_limiter($str[, $limit = 100[, $end_char = '…']]) @@ -182,11 +173,10 @@ The following functions are available: :returns: Word-limited string :rtype: string - Truncates a string to the number of *words* specified. Example:: + Truncates a string to the number of *words* specified. Example: - $string = "Here is a nice text string consisting of eleven words."; - $string = word_limiter($string, 4); - // Returns: Here is a nice + .. literalinclude:: text_helper/013.php + :lines: 2- The third parameter is an optional suffix added to the string. By default it adds an ellipsis. @@ -203,11 +193,10 @@ The following functions are available: maintains the integrity of words so the character count may be slightly more or less than what you specify. - Example:: + Example: - $string = "Here is a nice text string consisting of eleven words."; - $string = character_limiter($string, 20); - // Returns: Here is a nice text string + .. literalinclude:: text_helper/014.php + :lines: 2- The third parameter is an optional suffix added to the string, if undeclared this helper uses an ellipsis. @@ -229,9 +218,10 @@ The following functions are available: but for the most part, it should correctly identify characters outside the normal range (like accented characters). - Example:: + Example: - $string = ascii_to_entities($string); + .. literalinclude:: text_helper/015.php + :lines: 2- .. php:function:: entities_to_ascii($str[, $all = true]) @@ -253,9 +243,10 @@ The following functions are available: when non-English characters need to be used where only standard ASCII characters are safely used, for instance, in URLs. - Example:: + Example: - $string = convert_accented_characters($string); + .. literalinclude:: text_helper/016.php + :lines: 2- .. note:: This function uses a companion config file **app/Config/ForeignCharacters.php** to define the to and @@ -275,10 +266,10 @@ The following functions are available: a replacement value for the words. If not specified they are replaced with pound signs: ####. - Example:: + Example: - $disallowed = ['darn', 'shucks', 'golly', 'phooey']; - $string = word_censor($string, $disallowed, 'Beep!'); + .. literalinclude:: text_helper/017.php + :lines: 2- .. php:function:: highlight_code($str) @@ -286,9 +277,10 @@ The following functions are available: :returns: String with code highlighted via HTML :rtype: string - Colorizes a string of code (PHP, HTML, etc.). Example:: + Colorizes a string of code (PHP, HTML, etc.). Example: - $string = highlight_code($string); + .. literalinclude:: text_helper/018.php + :lines: 2- The function uses PHP's ``highlight_string()`` function, so the colors used are the ones specified in your php.ini file. @@ -307,10 +299,10 @@ The following functions are available: to highlight. The third and fourth parameters will contain the opening/closing HTML tags you would like the phrase wrapped in. - Example:: + Example: - $string = "Here is a nice text string about nothing in particular."; - echo highlight_phrase($string, "nice text", '', ''); + .. literalinclude:: text_helper/019.php + :lines: 2- The above code prints:: @@ -336,18 +328,10 @@ The following functions are available: Wraps text at the specified *character* count while maintaining complete words. - Example:: - - $string = "Here is a simple string of text that will help us demonstrate this function."; - echo word_wrap($string, 25); + Example: - // Would produce: - // Here is a simple string - // of text that will help us - // demonstrate this - // function. - - Excessively long words will be split, but URLs will not be. + .. literalinclude:: text_helper/020.php + :lines: 2- .. php:function:: ellipsize($str, $max_length[, $position = 1[, $ellipsis = '…']]) @@ -370,10 +354,10 @@ The following functions are available: An optional fourth parameter is the kind of ellipsis. By default, … will be inserted. - Example:: + Example: - $str = 'this_string_is_entirely_too_long_and_might_break_my_design.jpg'; - echo ellipsize($str, 32, .5); + .. literalinclude:: text_helper/021.php + :lines: 2- Produces:: @@ -397,18 +381,10 @@ The following functions are available: passed, the excerpt will include the first $radius characters with the ellipsis at the end. - Example:: - - $text = 'Ut vel faucibus odio. Quisque quis congue libero. Etiam gravida - eros lorem, eget porttitor augue dignissim tincidunt. In eget risus eget - mauris faucibus molestie vitae ultricies odio. Vestibulum id ultricies diam. - Curabitur non mauris lectus. Phasellus eu sodales sem. Integer dictum purus - ac enim hendrerit gravida. Donec ac magna vel nunc tincidunt molestie sed - vitae nisl. Cras sed auctor mauris, non dictum tortor. Nulla vel scelerisque - arcu. Cras ac ipsum sit amet augue laoreet laoreet. Aenean a risus lacus. - Sed ut tortor diam.'; + Example: - echo excerpt($text, 'Donec'); + .. literalinclude:: text_helper/022.php + :lines: 2- Produces:: diff --git a/user_guide_src/source/helpers/text_helper/001.php b/user_guide_src/source/helpers/text_helper/001.php new file mode 100644 index 000000000000..fdf999c3d9c6 --- /dev/null +++ b/user_guide_src/source/helpers/text_helper/001.php @@ -0,0 +1,3 @@ + "Is your name O\'reilly?", + 'answer' => "No, my name is O\'connor." +]; + +$str = strip_slashes($str); diff --git a/user_guide_src/source/helpers/text_helper/008.php b/user_guide_src/source/helpers/text_helper/008.php new file mode 100644 index 000000000000..073f97ff0046 --- /dev/null +++ b/user_guide_src/source/helpers/text_helper/008.php @@ -0,0 +1,6 @@ + "Is your name O'reilly?", + 'answer' => "No, my name is O'connor." +]; diff --git a/user_guide_src/source/helpers/text_helper/009.php b/user_guide_src/source/helpers/text_helper/009.php new file mode 100644 index 000000000000..8081482f17eb --- /dev/null +++ b/user_guide_src/source/helpers/text_helper/009.php @@ -0,0 +1,4 @@ +', ''); diff --git a/user_guide_src/source/helpers/text_helper/020.php b/user_guide_src/source/helpers/text_helper/020.php new file mode 100644 index 000000000000..a6de1d0f67f0 --- /dev/null +++ b/user_guide_src/source/helpers/text_helper/020.php @@ -0,0 +1,12 @@ +My News - - echo anchor('news/local/123', 'My News', ['title' => 'The best news!']); - // Prints: My News - - echo anchor('', 'Click here'); - // Prints: Click here + .. literalinclude:: url_helper/005.php + :lines: 2- As above, you may specify an alternate configuration. You may find the alternate configuration useful if generating links for a @@ -210,20 +209,10 @@ The following functions are available: If the third parameter is not set it will simply open a new window with your own browser settings. - Here is an example with attributes:: - - $atts = [ - 'width' => 800, - 'height' => 600, - 'scrollbars' => 'yes', - 'status'      => 'yes', - 'resizable'   => 'yes', - 'screenx' => 0, - 'screeny' => 0, - 'window_name' => '_blank', - ]; + Here is an example with attributes: - echo anchor_popup('news/local/123', 'Click Me!', $atts); + .. literalinclude:: url_helper/006.php + :lines: 2- As above, you may specify an alternate configuration. You may find the alternate configuration useful if generating links for a @@ -233,9 +222,10 @@ The following functions are available: .. note:: The above attributes are the function defaults so you only need to set the ones that are different from what you need. If you want the function to use all of its defaults simply pass an empty array in the - third parameter:: + third parameter: - echo anchor_popup('news/local/123', 'Click Me!', []); + .. literalinclude:: url_helper/007.php + :lines: 2- .. note:: The **window_name** is not really an attribute, but an argument to the JavaScript `window.open() `_ @@ -254,15 +244,16 @@ The following functions are available: :returns: A "mail to" hyperlink :rtype: string - Creates a standard HTML e-mail link. Usage example:: + Creates a standard HTML e-mail link. Usage example: - echo mailto('me@my-site.com', 'Click Here to Contact Me'); + .. literalinclude:: url_helper/008.php + :lines: 2- As with the :php:func:`anchor()` tab above, you can set attributes using the - third parameter:: + third parameter: - $attributes = ['title' => 'Mail me']; - echo mailto('me@my-site.com', 'Contact Me', $attributes); + .. literalinclude:: url_helper/009.php + :lines: 2- .. note:: Attributes passed into the mailto function are automatically escaped to protected against XSS attacks. @@ -287,27 +278,31 @@ The following functions are available: :rtype: string Automatically turns URLs and e-mail addresses contained in a string into - links. Example:: + links. Example: - $string = auto_link($string); + .. literalinclude:: url_helper/010.php + :lines: 2- The second parameter determines whether URLs and e-mails are converted or just one or the other. The default behavior is both if the parameter is not specified. E-mail links are encoded as :php:func:`safe_mailto()` as shown above. - Converts only URLs:: + Converts only URLs: - $string = auto_link($string, 'url'); + .. literalinclude:: url_helper/011.php + :lines: 2- - Converts only e-mail addresses:: + Converts only e-mail addresses: - $string = auto_link($string, 'email'); + .. literalinclude:: url_helper/012.php + :lines: 2- The third parameter determines whether links are shown in a new window. - The value can be true or false (boolean):: + The value can be true or false (boolean): - $string = auto_link($string, 'both', true); + .. literalinclude:: url_helper/013.php + :lines: 2- .. note:: The only URLs recognized are those that start with "www." or with "://". @@ -321,29 +316,26 @@ The following functions are available: Takes a string as input and creates a human-friendly URL string. This is useful if, for example, you have a blog in which you'd like to use the - title of your entries in the URL. Example:: + title of your entries in the URL. Example: - $title = "What's wrong with CSS?"; - $url_title = url_title($title); - // Produces: Whats-wrong-with-CSS + .. literalinclude:: url_helper/014.php + :lines: 2- The second parameter determines the word delimiter. By default dashes are used. Preferred options are: **-** (dash) or **_** (underscore). - Example:: + Example: - $title = "What's wrong with CSS?"; - $url_title = url_title($title, '_'); - // Produces: Whats_wrong_with_CSS + .. literalinclude:: url_helper/015.php + :lines: 2- The third parameter determines whether or not lowercase characters are forced. By default they are not. Options are boolean true/false. - Example:: + Example: - $title = "What's wrong with CSS?"; - $url_title = url_title($title, '-', true); - // Produces: whats-wrong-with-css + .. literalinclude:: url_helper/016.php + :lines: 2- .. php:function:: mb_url_title($str[, $separator = '-'[, $lowercase = false]]) @@ -366,9 +358,10 @@ The following functions are available: This function will add *http://* or *https://* in the event that a protocol prefix is missing from a URL. - Pass the URL string to the function like this:: + Pass the URL string to the function like this: - $url = prep_url('example.com'); + .. literalinclude:: url_helper/017.php + :lines: 2- .. php:function:: url_to($controller[, ...$args]) @@ -377,14 +370,16 @@ The following functions are available: :returns: Absolute URL :rtype: string - Builds an absolute URL to a controller method in your app. Example:: + Builds an absolute URL to a controller method in your app. Example: - echo url_to('Home::index'); + .. literalinclude:: url_helper/018.php + :lines: 2- You can also add arguments to the route. - Here is an example:: + Here is an example: - echo url_to('Page::index', 'home'); + .. literalinclude:: url_helper/019.php + :lines: 2- The above example would return something like: *http://example.com/page/home* @@ -397,14 +392,16 @@ The following functions are available: :param string $path: The path to check the current URI path against. :rtype: boolean - Compares the current URL's path against the given path to see if they match. Example:: + Compares the current URL's path against the given path to see if they match. Example: - if (url_is('admin')) { ... } + .. literalinclude:: url_helper/020.php + :lines: 2- This would match ``http://example.com/admin``. You can use the ``*`` wildcard to match - any other applicable characters in the URL:: + any other applicable characters in the URL: - if (url_is('admin*')) { ... } + .. literalinclude:: url_helper/021.php + :lines: 2- This would match any of the following: diff --git a/user_guide_src/source/helpers/url_helper/001.php b/user_guide_src/source/helpers/url_helper/001.php new file mode 100644 index 000000000000..cf11aa2d2541 --- /dev/null +++ b/user_guide_src/source/helpers/url_helper/001.php @@ -0,0 +1,3 @@ +My News + +echo anchor('news/local/123', 'My News', ['title' => 'The best news!']); +// Prints: My News + +echo anchor('', 'Click here'); +// Prints: Click here diff --git a/user_guide_src/source/helpers/url_helper/006.php b/user_guide_src/source/helpers/url_helper/006.php new file mode 100644 index 000000000000..960bc6f0430e --- /dev/null +++ b/user_guide_src/source/helpers/url_helper/006.php @@ -0,0 +1,14 @@ + 800, + 'height' => 600, + 'scrollbars' => 'yes', + 'status'      => 'yes', + 'resizable'   => 'yes', + 'screenx' => 0, + 'screeny' => 0, + 'window_name' => '_blank', +]; + +echo anchor_popup('news/local/123', 'Click Me!', $atts); diff --git a/user_guide_src/source/helpers/url_helper/007.php b/user_guide_src/source/helpers/url_helper/007.php new file mode 100644 index 000000000000..cb1e202af757 --- /dev/null +++ b/user_guide_src/source/helpers/url_helper/007.php @@ -0,0 +1,3 @@ + 'Mail me']; +echo mailto('me@my-site.com', 'Contact Me', $attributes); diff --git a/user_guide_src/source/helpers/url_helper/010.php b/user_guide_src/source/helpers/url_helper/010.php new file mode 100644 index 000000000000..65bf083b99cf --- /dev/null +++ b/user_guide_src/source/helpers/url_helper/010.php @@ -0,0 +1,3 @@ +Here is a paragraph & an entity ({).

    '; - $string = xml_convert($string); - echo $string; + .. literalinclude:: xml_helper/002.php + :lines: 2- outputs: diff --git a/user_guide_src/source/helpers/xml_helper/001.php b/user_guide_src/source/helpers/xml_helper/001.php new file mode 100644 index 000000000000..f92f3a7da3c2 --- /dev/null +++ b/user_guide_src/source/helpers/xml_helper/001.php @@ -0,0 +1,3 @@ +Here is a paragraph & an entity ({).

    '; +$string = xml_convert($string); +echo $string; diff --git a/user_guide_src/source/incoming/content_negotiation.rst b/user_guide_src/source/incoming/content_negotiation.rst index 8122a4a910b5..0db8e8f23c5d 100644 --- a/user_guide_src/source/incoming/content_negotiation.rst +++ b/user_guide_src/source/incoming/content_negotiation.rst @@ -13,17 +13,19 @@ can handle this for you. Loading the Class ================= -You can load an instance of the class manually through the Service class:: +You can load an instance of the class manually through the Service class: - $negotiate = \Config\Services::negotiator(); +.. literalinclude:: content_negotiation/001.php + :lines: 2- This will grab the current request instance and automatically inject it into the Negotiator class. This class does not need to be loaded on it's own. Instead, it can be accessed through this request's ``IncomingRequest`` instance. While you cannot access it directly this way, you can easily access all of methods through the ``negotiate()`` -method:: +method: - $request->negotiate('media', ['foo', 'bar']); +.. literalinclude:: content_negotiation/002.php + :lines: 2- When accessed this way, the first parameter is the type of content you're trying to find a match for, while the second is an array of supported values. @@ -47,26 +49,18 @@ from an API endpoint:: Accept: application/json The server now needs to provide a list of what type of content it can provide. In this example, the API might -be able to return data as raw HTML, JSON, or XML. This list should be provided in order of preference:: +be able to return data as raw HTML, JSON, or XML. This list should be provided in order of preference: - $supported = [ - 'application/json', - 'text/html', - 'application/xml', - ]; - - $format = $request->negotiate('media', $supported); - // or - $format = $negotiate->media($supported); +.. literalinclude:: content_negotiation/003.php + :lines: 2- In this case, both the client and the server can agree on formatting the data as JSON so 'json' is returned from the negotiate method. By default, if no match is found, the first element in the ``$supported`` array would be returned. In some cases, though, you might need to enforce the format to be a strict match. If you pass ``true`` as the -final value, it will return an empty string if no match is found:: +final value, it will return an empty string if no match is found: - $format = $request->negotiate('media', $supported, true); - // or - $format = $negotiate->media($supported, true); +.. literalinclude:: content_negotiation/004.php + :lines: 2- Language ======== @@ -80,16 +74,10 @@ header:: Accept-Language: fr; q=1.0, en; q=0.5 In this example, the browser would prefer French, with a second choice of English. If your website supports English -and German you would do something like:: - - $supported = [ - 'en', - 'de', - ]; +and German you would do something like: - $lang = $request->negotiate('language', $supported); - // or - $lang = $negotiate->language($supported); +.. literalinclude:: content_negotiation/005.php + :lines: 2- In this example, 'en' would be returned as the current language. If no match is found, it will return the first element in the ``$supported`` array, so that should always be the preferred language. @@ -103,11 +91,10 @@ specify the type of compression the client supports:: GET /foo HTTP/1.1 Accept-Encoding: compress, gzip -Your web server will define what types of compression you can use. Some, like Apache, only support **gzip**:: +Your web server will define what types of compression you can use. Some, like Apache, only support **gzip**: - $type = $request->negotiate('encoding', ['gzip']); - // or - $type = $negotiate->encoding(['gzip']); +.. literalinclude:: content_negotiation/006.php + :lines: 2- See more at `Wikipedia `_. @@ -119,8 +106,7 @@ The desired character set is passed through the ``Accept-Charset`` header:: GET /foo HTTP/1.1 Accept-Charset: utf-16, utf-8 -By default, if no matches are found, **utf-8** will be returned:: +By default, if no matches are found, **utf-8** will be returned: - $charset = $request->negotiate('charset', ['utf-8']); - // or - $charset = $negotiate->charset(['utf-8']); +.. literalinclude:: content_negotiation/007.php + :lines: 2- diff --git a/user_guide_src/source/incoming/content_negotiation/001.php b/user_guide_src/source/incoming/content_negotiation/001.php new file mode 100644 index 000000000000..3c55e788eff9 --- /dev/null +++ b/user_guide_src/source/incoming/content_negotiation/001.php @@ -0,0 +1,3 @@ +negotiate('media', ['foo', 'bar']); diff --git a/user_guide_src/source/incoming/content_negotiation/003.php b/user_guide_src/source/incoming/content_negotiation/003.php new file mode 100644 index 000000000000..262a4d74f3be --- /dev/null +++ b/user_guide_src/source/incoming/content_negotiation/003.php @@ -0,0 +1,11 @@ +negotiate('media', $supported); +// or +$format = $negotiate->media($supported); diff --git a/user_guide_src/source/incoming/content_negotiation/004.php b/user_guide_src/source/incoming/content_negotiation/004.php new file mode 100644 index 000000000000..c02b2219fb2b --- /dev/null +++ b/user_guide_src/source/incoming/content_negotiation/004.php @@ -0,0 +1,5 @@ +negotiate('media', $supported, true); +// or +$format = $negotiate->media($supported, true); diff --git a/user_guide_src/source/incoming/content_negotiation/005.php b/user_guide_src/source/incoming/content_negotiation/005.php new file mode 100644 index 000000000000..a5413d43f94d --- /dev/null +++ b/user_guide_src/source/incoming/content_negotiation/005.php @@ -0,0 +1,10 @@ +negotiate('language', $supported); +// or +$lang = $negotiate->language($supported); diff --git a/user_guide_src/source/incoming/content_negotiation/006.php b/user_guide_src/source/incoming/content_negotiation/006.php new file mode 100644 index 000000000000..3cd6d0378617 --- /dev/null +++ b/user_guide_src/source/incoming/content_negotiation/006.php @@ -0,0 +1,5 @@ +negotiate('encoding', ['gzip']); +// or +$type = $negotiate->encoding(['gzip']); diff --git a/user_guide_src/source/incoming/content_negotiation/007.php b/user_guide_src/source/incoming/content_negotiation/007.php new file mode 100644 index 000000000000..eeaf3a26c876 --- /dev/null +++ b/user_guide_src/source/incoming/content_negotiation/007.php @@ -0,0 +1,5 @@ +negotiate('charset', ['utf-8']); +// or +$charset = $negotiate->charset(['utf-8']); diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 2fee4580dffb..6d0dbcc8e055 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -8,7 +8,6 @@ Controllers are the heart of your application, as they determine how HTTP reques :local: :depth: 2 - What is a Controller? ===================== @@ -32,19 +31,9 @@ also extend the ``CodeIgniter\Controller`` if you do not need the functionality The BaseController provides a convenient place for loading components and performing functions that are needed by all your controllers. You can extend this class in any new controller. -For security reasons be sure to declare any new utility methods as ``protected`` or ``private``.:: - - ` feature. - Here is an example based on PSR-4 Autoloader:: - - \(\)*\ + Here is an example based on PSR-4 Autoloader: - $routes->get('helloworld', '\App\Controllers\HelloWorld::index'); + .. literalinclude:: controllers/005.php + :lines: 2- Methods ======= @@ -121,24 +88,9 @@ empty. Another way to show your "Hello World" message would be this:: **The second segment of the URI determines which method in the controller gets called.** -Let's try it. Add a new method to your controller:: +Let's try it. Add a new method to your controller: - ` feature, the segments passed to your method will be the re-routed @@ -183,15 +124,17 @@ present, as will be the case when only your site root URL is requested. Let's tr with the ``Helloworld`` controller. To specify a default controller open your **app/Config/Routes.php** -file and set this variable:: +file and set this variable: - $routes->setDefaultController('Helloworld'); +.. literalinclude:: controllers/008.php + :lines: 2- Where ``Helloworld`` is the name of the controller class you want to be used. -A few lines further down **Routes.php** in the "Route Definitions" section, comment out the line:: +A few lines further down **Routes.php** in the "Route Definitions" section, comment out the line: - $routes->get('/', 'Home::index'); +.. literalinclude:: controllers/009.php + :lines: 2- If you now browse to your site without specifying any URI segments you'll see the “Hello World” message. @@ -206,12 +149,10 @@ Remapping Method Calls As noted above, the second segment of the URI typically determines which method in the controller gets called. CodeIgniter permits you to override -this behavior through the use of the ``_remap()`` method:: +this behavior through the use of the ``_remap()`` method: - public function _remap() - { - // Some code here... - } +.. literalinclude:: controllers/010.php + :lines: 2- .. important:: If your controller contains a method named ``_remap()``, it will **always** get called regardless of what your URI contains. It @@ -219,32 +160,18 @@ this behavior through the use of the ``_remap()`` method:: is called, allowing you to define your own method routing rules. The overridden method call (typically the second segment of the URI) will -be passed as a parameter to the ``_remap()`` method:: +be passed as a parameter to the ``_remap()`` method: - public function _remap($method) - { - if ($method === 'some_method') { - return $this->$method(); - } else { - return $this->default_method(); - } - } +.. literalinclude:: controllers/011.php + :lines: 2- Any extra segments after the method name are passed into ``_remap()``. These parameters can be passed to the method to emulate CodeIgniter's default behavior. -Example:: - - public function _remap($method, ...$params) - { - $method = 'process_'.$method; +Example: - if (method_exists($this, $method)) { - return $this->$method(...$params); - } - - throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); - } +.. literalinclude:: controllers/012.php + :lines: 2- Private methods =============== @@ -252,12 +179,10 @@ Private methods In some cases, you may want certain methods hidden from public access. To achieve this, simply declare the method as ``private`` or ``protected``. That will prevent it from being served by a URL request. For example, -if you were to define a method like this for the ``Helloworld`` controller:: +if you were to define a method like this for the ``Helloworld`` controller: - protected function utility() - { - // some code - } +.. literalinclude:: controllers/013.php + :lines: 2- then trying to access it using the following URL will not work:: @@ -295,7 +220,6 @@ your **app/Config/Routes.php** file. CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. - Included Properties =================== @@ -320,19 +244,17 @@ An instance of the :doc:`Logger <../general/logging>` class is available as a cl **forceHTTPS** A convenience method for forcing a method to be accessed via HTTPS is available within all -controllers:: +controllers: - if (! $this->request->isSecure()) { - $this->forceHTTPS(); - } +.. literalinclude:: controllers/014.php + :lines: 2- By default, and in modern browsers that support the HTTP Strict Transport Security header, this call should force the browser to convert non-HTTPS calls to HTTPS calls for one year. You can -modify this by passing the duration (in seconds) as the first parameter:: +modify this by passing the duration (in seconds) as the first parameter: - if (! $this->request->isSecure()) { - $this->forceHTTPS(31536000); // one year - } +.. literalinclude:: controllers/015.php + :lines: 2- .. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. @@ -341,14 +263,10 @@ Helpers You can define an array of helper files as a class property. Whenever the controller is loaded these helper files will be automatically loaded into memory so that you can use their methods anywhere -inside the controller:: - - namespace App\Controllers; +inside the controller: - class MyController extends BaseController - { - protected $helpers = ['url', 'form']; - } +.. literalinclude:: controllers/016.php + :lines: 2- .. _controllers-validating-data: @@ -364,35 +282,16 @@ and in the optional second parameter, an array of custom error messages to displ if the items are not valid. Internally, this uses the controller's ``$this->request`` instance to get the data to be validated. The :doc:`Validation Library docs ` have details on -rule and message array formats, as well as available rules.:: - - public function updateUser(int $userID) - { - if (! $this->validate([ - 'email' => "required|is_unique[users.email,id,{$userID}]", - 'name' => 'required|alpha_numeric_spaces' - ])) { - return view('users/update', [ - 'errors' => $this->validator->getErrors() - ]); - } - - // do something here if successful... - } +rule and message array formats, as well as available rules.: -If you find it simpler to keep the rules in the configuration file, you can replace -the ``$rules`` array with the name of the group as defined in ``Config\Validation.php``:: +.. literalinclude:: controllers/017.php + :lines: 2- - public function updateUser(int $userID) - { - if (! $this->validate('userRules')) { - return view('users/update', [ - 'errors' => $this->validator->getErrors() - ]); - } +If you find it simpler to keep the rules in the configuration file, you can replace +the ``$rules`` array with the name of the group as defined in ``Config\Validation.php``: - // do something here if successful... - } +.. literalinclude:: controllers/018.php + :lines: 2- .. note:: Validation can also be handled automatically in the model, but sometimes it's easier to do it in the controller. Where is up to you. @@ -401,25 +300,10 @@ $this->validateData() Sometimes you may want to check the controller method parameters or other custom data. In that case, you can use the ``$this->validateData()`` method. -The method accepts an array of data to validate in the first parameter:: - - public function product(int $id) - { - $data = [ - 'id' => $id, - 'name' => $this->request->getVar('name'), - ]; - $rule = [ - 'id' => 'integer', - 'name' => 'required|max_length[255]', - ]; - - if (! $this->validateData($data, $rule) { - // ... - } - - // ... - } +The method accepts an array of data to validate in the first parameter: + +.. literalinclude:: controllers/019.php + :lines: 2- That's it! ========== diff --git a/user_guide_src/source/incoming/controllers/001.php b/user_guide_src/source/incoming/controllers/001.php new file mode 100644 index 000000000000..926de1e9fbdf --- /dev/null +++ b/user_guide_src/source/incoming/controllers/001.php @@ -0,0 +1,11 @@ +(\)*\ + +$routes->get('helloworld', '\App\Controllers\HelloWorld::index'); diff --git a/user_guide_src/source/incoming/controllers/006.php b/user_guide_src/source/incoming/controllers/006.php new file mode 100644 index 000000000000..e43c3e4f2b34 --- /dev/null +++ b/user_guide_src/source/incoming/controllers/006.php @@ -0,0 +1,16 @@ +setDefaultController('Helloworld'); diff --git a/user_guide_src/source/incoming/controllers/009.php b/user_guide_src/source/incoming/controllers/009.php new file mode 100644 index 000000000000..d799d1cf0fb5 --- /dev/null +++ b/user_guide_src/source/incoming/controllers/009.php @@ -0,0 +1,3 @@ +get('/', 'Home::index'); diff --git a/user_guide_src/source/incoming/controllers/010.php b/user_guide_src/source/incoming/controllers/010.php new file mode 100644 index 000000000000..e017dcd45cdb --- /dev/null +++ b/user_guide_src/source/incoming/controllers/010.php @@ -0,0 +1,6 @@ +$method(); + } else { + return $this->default_method(); + } +} diff --git a/user_guide_src/source/incoming/controllers/012.php b/user_guide_src/source/incoming/controllers/012.php new file mode 100644 index 000000000000..25d064b859cd --- /dev/null +++ b/user_guide_src/source/incoming/controllers/012.php @@ -0,0 +1,12 @@ +$method(...$params); + } + + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); +} diff --git a/user_guide_src/source/incoming/controllers/013.php b/user_guide_src/source/incoming/controllers/013.php new file mode 100644 index 000000000000..eed95b673ad2 --- /dev/null +++ b/user_guide_src/source/incoming/controllers/013.php @@ -0,0 +1,6 @@ +request->isSecure()) { + $this->forceHTTPS(); +} diff --git a/user_guide_src/source/incoming/controllers/015.php b/user_guide_src/source/incoming/controllers/015.php new file mode 100644 index 000000000000..c3309ddbf201 --- /dev/null +++ b/user_guide_src/source/incoming/controllers/015.php @@ -0,0 +1,5 @@ +request->isSecure()) { + $this->forceHTTPS(31536000); // one year +} diff --git a/user_guide_src/source/incoming/controllers/016.php b/user_guide_src/source/incoming/controllers/016.php new file mode 100644 index 000000000000..ff3ab9edfcf1 --- /dev/null +++ b/user_guide_src/source/incoming/controllers/016.php @@ -0,0 +1,8 @@ +validate([ + 'email' => "required|is_unique[users.email,id,{$userID}]", + 'name' => 'required|alpha_numeric_spaces' + ])) { + return view('users/update', [ + 'errors' => $this->validator->getErrors() + ]); + } + + // do something here if successful... +} diff --git a/user_guide_src/source/incoming/controllers/018.php b/user_guide_src/source/incoming/controllers/018.php new file mode 100644 index 000000000000..54697409827a --- /dev/null +++ b/user_guide_src/source/incoming/controllers/018.php @@ -0,0 +1,12 @@ +validate('userRules')) { + return view('users/update', [ + 'errors' => $this->validator->getErrors() + ]); + } + + // do something here if successful... +} diff --git a/user_guide_src/source/incoming/controllers/019.php b/user_guide_src/source/incoming/controllers/019.php new file mode 100644 index 000000000000..e5a96084c2c2 --- /dev/null +++ b/user_guide_src/source/incoming/controllers/019.php @@ -0,0 +1,19 @@ + $id, + 'name' => $this->request->getVar('name'), + ]; + $rule = [ + 'id' => 'integer', + 'name' => 'required|max_length[255]', + ]; + + if (! $this->validateData($data, $rule) { + // ... + } + + // ... +} \ No newline at end of file diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 1b01d7c81e2e..df45851ea514 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -25,28 +25,9 @@ Creating a Filter Filters are simple classes that implement ``CodeIgniter\Filters\FilterInterface``. They contain two methods: ``before()`` and ``after()`` which hold the code that will run before and after the controller respectively. Your class must contain both methods -but may leave the methods empty if they are not needed. A skeleton filter class looks like:: +but may leave the methods empty if they are not needed. A skeleton filter class looks like: - isLoggedIn()) { - return redirect()->to(site_url('login')); - } - } +.. literalinclude:: filters/002.php + :lines: 2- If a ``Response`` instance is returned, the Response will be sent back to the client and script execution will stop. This can be useful for implementing rate limiting for APIs. See :doc:`Throttler ` for an @@ -102,24 +77,19 @@ $aliases ======== The ``$aliases`` array is used to associate a simple name with one or more fully-qualified class names that are the -filters to run:: +filters to run: - public $aliases = [ - 'csrf' => \CodeIgniter\Filters\CSRF::class, - ]; +.. literalinclude:: filters/003.php + :lines: 2- Aliases are mandatory and if you try to use a full class name later, the system will throw an error. Defining them in this way makes it simple to switch out the class used. Great for when you decided you need to change to a different authentication system since you only change the filter's class and you're done. -You can combine multiple filters into one alias, making complex sets of filters simple to apply:: +You can combine multiple filters into one alias, making complex sets of filters simple to apply: - public $aliases = [ - 'apiPrep' => [ - \App\Filters\Negotiate::class, - \App\Filters\ApiAuth::class, - ] - ]; +.. literalinclude:: filters/004.php + :lines: 2- You should define as many aliases as you need. @@ -128,50 +98,36 @@ $globals The second section allows you to define any filters that should be applied to every request made by the framework. You should take care with how many you use here, since it could have performance implications to have too many -run on every request. Filters can be specified by adding their alias to either the before or after array:: +run on every request. Filters can be specified by adding their alias to either the before or after array: - public $globals = [ - 'before' => [ - 'csrf', - ], - 'after' => [], - ]; +.. literalinclude:: filters/005.php + :lines: 2- There are times where you want to apply a filter to almost every request, but have a few that should be left alone. One common example is if you need to exclude a few URI's from the CSRF protection filter to allow requests from third-party websites to hit one or two specific URI's, while keeping the rest of them protected. To do this, add -an array with the 'except' key and a URI to match as the value alongside the alias:: +an array with the 'except' key and a URI to match as the value alongside the alias: - public $globals = [ - 'before' => [ - 'csrf' => ['except' => 'api/*'], - ], - 'after' => [], - ]; +.. literalinclude:: filters/006.php + :lines: 2- Any place you can use a URI in the filter settings, you can use a regular expression or, like in this example, use an asterisk for a wildcard that will match all characters after that. In this example, any URL's starting with ``api/`` would be exempted from CSRF protection, but the site's forms would all be protected. If you need to specify multiple -URI's you can use an array of URI patterns:: +URI's you can use an array of URI patterns: - public $globals = [ - 'before' => [ - 'csrf' => ['except' => ['foo/*', 'bar/*']], - ], - 'after' => [], - ]; +.. literalinclude:: filters/007.php + :lines: 2- $methods ======== You can apply filters to all requests of a certain HTTP method, like POST, GET, PUT, etc. In this array, you would specify the method name in lowercase. It's value would be an array of filters to run. Unlike the ``$globals`` or the -``$filters`` properties, these will only run as before filters:: +``$filters`` properties, these will only run as before filters: - public $methods = [ - 'post' => ['foo', 'bar'], - 'get' => ['baz'], - ] +.. literalinclude:: filters/008.php + :lines: 2- In addition to the standard HTTP methods, this also supports one special case: 'cli'. The 'cli' method would apply to all requests that were run from the command line. @@ -184,19 +140,18 @@ $filters ======== This property is an array of filter aliases. For each alias, you can specify before and after arrays that contain -a list of URI patterns that filter should apply to:: +a list of URI patterns that filter should apply to: - public filters = [ - 'foo' => ['before' => ['admin/*'], 'after' => ['users/*']], - 'bar' => ['before' => ['api/*', 'admin/*']], - ]; +.. literalinclude:: filters/009.php + :lines: 2- Filter arguments ================= -When configuring filters, additional arguments may be passed to a filter when setting up the route:: +When configuring filters, additional arguments may be passed to a filter when setting up the route: - $routes->add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); +.. literalinclude:: filters/010.php + :lines: 2- In this example, the array ``['dual', 'noreturn']`` will be passed in ``$arguments`` to the filter's ``before()`` and ``after()`` implementation methods. @@ -228,11 +183,9 @@ SecureHeaders This filter adds HTTP response headers that your application can use to increase the security of your application. -If you want to customize the headers, extend ``CodeIgniter\Filters\SecureHeaders`` and override the ``$headers`` property. And change the ``$aliases`` property in **app/Config/Filters.php**:: +If you want to customize the headers, extend ``CodeIgniter\Filters\SecureHeaders`` and override the ``$headers`` property. And change the ``$aliases`` property in **app/Config/Filters.php**: - public $aliases = [ - ... - 'secureheaders' => \App\Filters\SecureHeaders::class, - ]; +.. literalinclude:: filters/011.php + :lines: 2- If you want to know about secure headers, see `OWASP Secure Headers Project `_. diff --git a/user_guide_src/source/incoming/filters/001.php b/user_guide_src/source/incoming/filters/001.php new file mode 100644 index 000000000000..442cbadb89be --- /dev/null +++ b/user_guide_src/source/incoming/filters/001.php @@ -0,0 +1,20 @@ +isLoggedIn()) { + return redirect()->to(site_url('login')); + } +} diff --git a/user_guide_src/source/incoming/filters/003.php b/user_guide_src/source/incoming/filters/003.php new file mode 100644 index 000000000000..1ef6a461f3c6 --- /dev/null +++ b/user_guide_src/source/incoming/filters/003.php @@ -0,0 +1,5 @@ + \CodeIgniter\Filters\CSRF::class, +]; diff --git a/user_guide_src/source/incoming/filters/004.php b/user_guide_src/source/incoming/filters/004.php new file mode 100644 index 000000000000..a7f31363edad --- /dev/null +++ b/user_guide_src/source/incoming/filters/004.php @@ -0,0 +1,8 @@ + [ + \App\Filters\Negotiate::class, + \App\Filters\ApiAuth::class, + ] +]; diff --git a/user_guide_src/source/incoming/filters/005.php b/user_guide_src/source/incoming/filters/005.php new file mode 100644 index 000000000000..3f3801f5ce59 --- /dev/null +++ b/user_guide_src/source/incoming/filters/005.php @@ -0,0 +1,8 @@ + [ + 'csrf', + ], + 'after' => [], +]; diff --git a/user_guide_src/source/incoming/filters/006.php b/user_guide_src/source/incoming/filters/006.php new file mode 100644 index 000000000000..3706979688cd --- /dev/null +++ b/user_guide_src/source/incoming/filters/006.php @@ -0,0 +1,8 @@ + [ + 'csrf' => ['except' => 'api/*'], + ], + 'after' => [], +]; diff --git a/user_guide_src/source/incoming/filters/007.php b/user_guide_src/source/incoming/filters/007.php new file mode 100644 index 000000000000..a6790adbf9b7 --- /dev/null +++ b/user_guide_src/source/incoming/filters/007.php @@ -0,0 +1,8 @@ + [ + 'csrf' => ['except' => ['foo/*', 'bar/*']], + ], + 'after' => [], +]; diff --git a/user_guide_src/source/incoming/filters/008.php b/user_guide_src/source/incoming/filters/008.php new file mode 100644 index 000000000000..2f216281e982 --- /dev/null +++ b/user_guide_src/source/incoming/filters/008.php @@ -0,0 +1,6 @@ + ['foo', 'bar'], + 'get' => ['baz'], +] diff --git a/user_guide_src/source/incoming/filters/009.php b/user_guide_src/source/incoming/filters/009.php new file mode 100644 index 000000000000..258edd689d3c --- /dev/null +++ b/user_guide_src/source/incoming/filters/009.php @@ -0,0 +1,6 @@ + ['before' => ['admin/*'], 'after' => ['users/*']], + 'bar' => ['before' => ['api/*', 'admin/*']], +]; diff --git a/user_guide_src/source/incoming/filters/010.php b/user_guide_src/source/incoming/filters/010.php new file mode 100644 index 000000000000..7a486fb1d7c3 --- /dev/null +++ b/user_guide_src/source/incoming/filters/010.php @@ -0,0 +1,3 @@ +add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); diff --git a/user_guide_src/source/incoming/filters/011.php b/user_guide_src/source/incoming/filters/011.php new file mode 100644 index 000000000000..4065ef7d1743 --- /dev/null +++ b/user_guide_src/source/incoming/filters/011.php @@ -0,0 +1,6 @@ + \App\Filters\SecureHeaders::class, +]; diff --git a/user_guide_src/source/incoming/incomingrequest/001.php b/user_guide_src/source/incoming/incomingrequest/001.php new file mode 100644 index 000000000000..5513e012fb0e --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/001.php @@ -0,0 +1,15 @@ +request->isAJAX()) { + // ... + } + } +} diff --git a/user_guide_src/source/incoming/incomingrequest/002.php b/user_guide_src/source/incoming/incomingrequest/002.php new file mode 100644 index 000000000000..94d680abbdc3 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/002.php @@ -0,0 +1,3 @@ +request = $request; + } +} + +$someClass = new SomeClass(\Config\Services::request()); diff --git a/user_guide_src/source/incoming/incomingrequest/004.php b/user_guide_src/source/incoming/incomingrequest/004.php new file mode 100644 index 000000000000..9f54a85874cb --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/004.php @@ -0,0 +1,11 @@ +isAJAX()) { + // ... +} + +// Check for CLI Request +if ($request->isCLI()) { + // ... +} diff --git a/user_guide_src/source/incoming/incomingrequest/005.php b/user_guide_src/source/incoming/incomingrequest/005.php new file mode 100644 index 000000000000..3c93e74b7664 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/005.php @@ -0,0 +1,4 @@ +getMethod(); diff --git a/user_guide_src/source/incoming/incomingrequest/006.php b/user_guide_src/source/incoming/incomingrequest/006.php new file mode 100644 index 000000000000..99e269157152 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/006.php @@ -0,0 +1,4 @@ +getMethod()); diff --git a/user_guide_src/source/incoming/incomingrequest/007.php b/user_guide_src/source/incoming/incomingrequest/007.php new file mode 100644 index 000000000000..d2956fab66d4 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/007.php @@ -0,0 +1,5 @@ +isSecure()) { + force_https(); +} diff --git a/user_guide_src/source/incoming/incomingrequest/008.php b/user_guide_src/source/incoming/incomingrequest/008.php new file mode 100644 index 000000000000..1c7a14b45ed5 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/008.php @@ -0,0 +1,3 @@ +getVar('foo'); diff --git a/user_guide_src/source/incoming/incomingrequest/010.php b/user_guide_src/source/incoming/incomingrequest/010.php new file mode 100644 index 000000000000..f9c2c4a22fa1 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/010.php @@ -0,0 +1,3 @@ +getJSON(); diff --git a/user_guide_src/source/incoming/incomingrequest/011.php b/user_guide_src/source/incoming/incomingrequest/011.php new file mode 100644 index 000000000000..56f9522366b0 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/011.php @@ -0,0 +1,14 @@ +getVar('foo'); +// $data = "bar" + +$data = $request->getVar('fizz.buzz'); +// $data = "baz" diff --git a/user_guide_src/source/incoming/incomingrequest/012.php b/user_guide_src/source/incoming/incomingrequest/012.php new file mode 100644 index 000000000000..a4ca2686f6e8 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/012.php @@ -0,0 +1,8 @@ +getJsonVar('fizz'); +// $data->buzz = "baz" + +$data = $request->getJsonVar('fizz', true); +// $data = ["buzz" => "baz"] diff --git a/user_guide_src/source/incoming/incomingrequest/013.php b/user_guide_src/source/incoming/incomingrequest/013.php new file mode 100644 index 000000000000..8a46e0d01114 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/013.php @@ -0,0 +1,3 @@ +getRawInput(); diff --git a/user_guide_src/source/incoming/incomingrequest/014.php b/user_guide_src/source/incoming/incomingrequest/014.php new file mode 100644 index 000000000000..2b5ffb8498e0 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/014.php @@ -0,0 +1,8 @@ +getRawInput()); + +[ + 'Param1' => 'Value1', + 'Param2' => 'Value2' +] diff --git a/user_guide_src/source/incoming/incomingrequest/015.php b/user_guide_src/source/incoming/incomingrequest/015.php new file mode 100644 index 000000000000..564fc543143b --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/015.php @@ -0,0 +1,3 @@ +getVar('email', FILTER_SANITIZE_EMAIL); diff --git a/user_guide_src/source/incoming/incomingrequest/016.php b/user_guide_src/source/incoming/incomingrequest/016.php new file mode 100644 index 000000000000..1584967d3bd8 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/016.php @@ -0,0 +1,9 @@ +headers()); + +[ + 'Host' => CodeIgniter\HTTP\Header, + 'Cache-Control' => CodeIgniter\HTTP\Header, + 'Accept' => CodeIgniter\HTTP\Header, +] diff --git a/user_guide_src/source/incoming/incomingrequest/017.php b/user_guide_src/source/incoming/incomingrequest/017.php new file mode 100644 index 000000000000..3fd3b6d81ff2 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/017.php @@ -0,0 +1,6 @@ +header('host'); +$host = $request->header('Host'); +$host = $request->header('HOST'); diff --git a/user_guide_src/source/incoming/incomingrequest/018.php b/user_guide_src/source/incoming/incomingrequest/018.php new file mode 100644 index 000000000000..a557845e482e --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/018.php @@ -0,0 +1,5 @@ +hasHeader('DNT')) { + // Don't track something... +} diff --git a/user_guide_src/source/incoming/incomingrequest/019.php b/user_guide_src/source/incoming/incomingrequest/019.php new file mode 100644 index 000000000000..80243598d821 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/019.php @@ -0,0 +1,4 @@ +getHeaderLine('accept-encoding'); diff --git a/user_guide_src/source/incoming/incomingrequest/020.php b/user_guide_src/source/incoming/incomingrequest/020.php new file mode 100644 index 000000000000..14e917083397 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/020.php @@ -0,0 +1,3 @@ +getUri(); diff --git a/user_guide_src/source/incoming/incomingrequest/022.php b/user_guide_src/source/incoming/incomingrequest/022.php new file mode 100644 index 000000000000..672efa42b02e --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/022.php @@ -0,0 +1,14 @@ +getUri(); + +echo $uri->getScheme(); // http +echo $uri->getAuthority(); // snoopy:password@example.com:88 +echo $uri->getUserInfo(); // snoopy:password +echo $uri->getHost(); // example.com +echo $uri->getPort(); // 88 +echo $uri->getPath(); // /path/to/page +echo $uri->getQuery(); // foo=bar&bar=baz +echo $uri->getSegments(); // ['path', 'to', 'page'] +echo $uri->getSegment(1); // 'path' +echo $uri->getTotalSegments(); // 3 diff --git a/user_guide_src/source/incoming/incomingrequest/023.php b/user_guide_src/source/incoming/incomingrequest/023.php new file mode 100644 index 000000000000..55484f98a10b --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/023.php @@ -0,0 +1,11 @@ +setPath('users/list'); + $menu = new MyMenu(); + $this->assertTrue('users/list', $menu->getActiveLink()); + } +} diff --git a/user_guide_src/source/incoming/incomingrequest/024.php b/user_guide_src/source/incoming/incomingrequest/024.php new file mode 100644 index 000000000000..e29f87b9f419 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/024.php @@ -0,0 +1,18 @@ +getFiles(); + +// Grab the file by name given in HTML form +if ($files->hasFile('userfile')) { + $file = $files->getFile('userfile'); + + // Generate a new secure name + $name = $file->getRandomName(); + + // Move the file to it's new home + $file->move('/path/to/dir', $name); + + echo $file->getSize('mb'); // 1.23 + echo $file->getExtension(); // jpg + echo $file->getType(); // image/jpg +} diff --git a/user_guide_src/source/incoming/incomingrequest/025.php b/user_guide_src/source/incoming/incomingrequest/025.php new file mode 100644 index 000000000000..cfa3525255ae --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/025.php @@ -0,0 +1,3 @@ +getFile('userfile'); diff --git a/user_guide_src/source/incoming/incomingrequest/026.php b/user_guide_src/source/incoming/incomingrequest/026.php new file mode 100644 index 000000000000..912a709d2729 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/026.php @@ -0,0 +1,3 @@ +getFileMultiple('userfile'); diff --git a/user_guide_src/source/incoming/incomingrequest/027.php b/user_guide_src/source/incoming/incomingrequest/027.php new file mode 100644 index 000000000000..f5d9b96f3315 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/027.php @@ -0,0 +1,7 @@ +negotiate('language', ['en-US', 'en-GB', 'fr', 'es-mx']); +$imageType = $request->negotiate('media', ['image/png', 'image/jpg']); +$charset = $request->negotiate('charset', ['UTF-8', 'UTF-16']); +$contentType = $request->negotiate('media', ['text/html', 'text/xml']); +$encoding = $request->negotiate('encoding', ['gzip', 'compress']); diff --git a/user_guide_src/source/incoming/incomingrequest/028.php b/user_guide_src/source/incoming/incomingrequest/028.php new file mode 100644 index 000000000000..aa4f01787b4b --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/028.php @@ -0,0 +1,3 @@ +getVar('some_data'); diff --git a/user_guide_src/source/incoming/incomingrequest/029.php b/user_guide_src/source/incoming/incomingrequest/029.php new file mode 100644 index 000000000000..3bc49822b301 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/029.php @@ -0,0 +1,3 @@ +getVar('some_data', FILTER_SANITIZE_FULL_SPECIAL_CHARS); diff --git a/user_guide_src/source/incoming/incomingrequest/030.php b/user_guide_src/source/incoming/incomingrequest/030.php new file mode 100644 index 000000000000..62390522b9b6 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/030.php @@ -0,0 +1,4 @@ +getVar(null, FILTER_SANITIZE_FULL_SPECIAL_CHARS); +// returns all POST items with string sanitation diff --git a/user_guide_src/source/incoming/incomingrequest/031.php b/user_guide_src/source/incoming/incomingrequest/031.php new file mode 100644 index 000000000000..9e555a2f3143 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/031.php @@ -0,0 +1,3 @@ +getVar(['field1', 'field2']); diff --git a/user_guide_src/source/incoming/incomingrequest/032.php b/user_guide_src/source/incoming/incomingrequest/032.php new file mode 100644 index 000000000000..98c6f35e367d --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/032.php @@ -0,0 +1,3 @@ +getVar(['field1', 'field2'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); diff --git a/user_guide_src/source/incoming/incomingrequest/033.php b/user_guide_src/source/incoming/incomingrequest/033.php new file mode 100644 index 000000000000..27d669d99406 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/033.php @@ -0,0 +1,3 @@ +getPostGet('field1'); diff --git a/user_guide_src/source/incoming/incomingrequest/034.php b/user_guide_src/source/incoming/incomingrequest/034.php new file mode 100644 index 000000000000..837ca9c26b40 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/034.php @@ -0,0 +1,3 @@ +getGetPost('field1'); diff --git a/user_guide_src/source/incoming/incomingrequest/035.php b/user_guide_src/source/incoming/incomingrequest/035.php new file mode 100644 index 000000000000..befc56fd551f --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/035.php @@ -0,0 +1,4 @@ +getCookie('some_cookie'); +$request->getCookie('some_cookie', FILTER_SANITIZE_FULL_SPECIAL_CHARS); // with filter diff --git a/user_guide_src/source/incoming/incomingrequest/036.php b/user_guide_src/source/incoming/incomingrequest/036.php new file mode 100644 index 000000000000..e0c3b50803d6 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/036.php @@ -0,0 +1,3 @@ +getCookie(['some_cookie', 'some_cookie2']); diff --git a/user_guide_src/source/incoming/incomingrequest/037.php b/user_guide_src/source/incoming/incomingrequest/037.php new file mode 100644 index 000000000000..e05381317b95 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/037.php @@ -0,0 +1,3 @@ +getServer('some_data'); diff --git a/user_guide_src/source/incoming/incomingrequest/038.php b/user_guide_src/source/incoming/incomingrequest/038.php new file mode 100644 index 000000000000..0dabcaa7d528 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/038.php @@ -0,0 +1,3 @@ +getServer(['SERVER_PROTOCOL', 'REQUEST_URI']); diff --git a/user_guide_src/source/incoming/incomingrequest/039.php b/user_guide_src/source/incoming/incomingrequest/039.php new file mode 100644 index 000000000000..bbb5fcc909e7 --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/039.php @@ -0,0 +1,3 @@ +getUserAgent(); diff --git a/user_guide_src/source/incoming/message.rst b/user_guide_src/source/incoming/message.rst index e5f5a49ab4af..8333a51d7157 100644 --- a/user_guide_src/source/incoming/message.rst +++ b/user_guide_src/source/incoming/message.rst @@ -41,9 +41,10 @@ Class Reference :returns: The current message body :rtype: mixed - Returns the current message body, if any has been set. If not body exists, returns null:: + Returns the current message body, if any has been set. If not body exists, returns null: - echo $message->getBody(); + .. literalinclude:: message/001.php + :lines: 2- .. php:method:: setBody($data) @@ -88,37 +89,21 @@ Class Reference :rtype: \CodeIgniter\\HTTP\\Header|array Allows you to retrieve the current value of a single message header. ``$name`` is the case-insensitive header name. - While the header is converted internally as described above, you can access the header with any type of case:: + While the header is converted internally as described above, you can access the header with any type of case: - // These are all the same: - $message->header('HOST'); - $message->header('Host'); - $message->header('host'); + .. literalinclude:: message/002.php + :lines: 2- If the header has multiple values, ``getValue()`` will return as an array of values. You can use the ``getValueLine()`` - method to retrieve the values as a string:: + method to retrieve the values as a string: - echo $message->header('Accept-Language'); + .. literalinclude:: message/003.php + :lines: 2- - // Outputs something like: - 'Accept-Language: en,en-US' + You can filter the header by passing a filter value in as the second parameter: - echo $message->header('Accept-Language')->getValue(); - - // Outputs something like: - [ - 'en', - 'en-US' - ] - - echo $message->header('Accept-Language')->getValueLine(); - - // Outputs something like: - 'en,en-US' - - You can filter the header by passing a filter value in as the second parameter:: - - $message->header('Document-URI', FILTER_SANITIZE_URL); + .. literalinclude:: message/004.php + :lines: 2- .. php:method:: hasHeader($name) @@ -133,12 +118,10 @@ Class Reference :rtype: string Returns the value(s) of the header as a string. This method allows you to easily get a string representation - of the header values when the header has multiple values. The values are appropriately joined:: - - echo $message->getHeaderLine('Accept-Language'); + of the header values when the header has multiple values. The values are appropriately joined: - // Outputs: - en, en-US + .. literalinclude:: message/005.php + :lines: 2- .. php:method:: setHeader($name, $value) @@ -149,9 +132,10 @@ Class Reference Sets the value of a single header. ``$name`` is the case-insensitive name of the header. If the header doesn't already exist in the collection, it will be created. The ``$value`` can be either a string - or an array of strings:: + or an array of strings: - $message->setHeader('Host', 'codeigniter.com'); + .. literalinclude:: message/006.php + :lines: 2- .. php:method:: removeHeader($name) @@ -159,9 +143,10 @@ Class Reference :returns: The current message instance :rtype: CodeIgniter\\HTTP\\Message - Removes the header from the Message. ``$name`` is the case-insensitive name of the header:: + Removes the header from the Message. ``$name`` is the case-insensitive name of the header: - $message->removeHeader('Host'); + .. literalinclude:: message/007.php + :lines: 2- .. php:method:: appendHeader($name, $value) @@ -172,9 +157,9 @@ Class Reference Adds a value to an existing header. The header must already be an array of values instead of a single string. If it is a string then a LogicException will be thrown. - :: - $message->appendHeader('Accept-Language', 'en-US; q=0.8'); + .. literalinclude:: message/008.php + :lines: 2- .. php:method:: prependHeader($name, $value) @@ -185,9 +170,9 @@ Class Reference Prepends a value to an existing header. The header must already be an array of values instead of a single string. If it is a string then a LogicException will be thrown. - :: - $message->prependHeader('Accept-Language', 'en,'); + .. literalinclude:: message/009.php + :lines: 2- .. php:method:: getProtocolVersion() @@ -203,6 +188,7 @@ Class Reference :returns: The current message instance :rtype: CodeIgniter\\HTTP\\Message - Sets the HTTP protocol version this Message uses. Valid values are ``1.0``, ``1.1`` and ``2.0``:: + Sets the HTTP protocol version this Message uses. Valid values are ``1.0``, ``1.1`` and ``2.0``: - $message->setProtocolVersion('1.1'); + .. literalinclude:: message/010.php + :lines: 2- diff --git a/user_guide_src/source/incoming/message/001.php b/user_guide_src/source/incoming/message/001.php new file mode 100644 index 000000000000..a54dc3212036 --- /dev/null +++ b/user_guide_src/source/incoming/message/001.php @@ -0,0 +1,3 @@ +getBody(); diff --git a/user_guide_src/source/incoming/message/002.php b/user_guide_src/source/incoming/message/002.php new file mode 100644 index 000000000000..0a55ae7824a9 --- /dev/null +++ b/user_guide_src/source/incoming/message/002.php @@ -0,0 +1,6 @@ +header('HOST'); +$message->header('Host'); +$message->header('host'); diff --git a/user_guide_src/source/incoming/message/003.php b/user_guide_src/source/incoming/message/003.php new file mode 100644 index 000000000000..3ef7db58835a --- /dev/null +++ b/user_guide_src/source/incoming/message/003.php @@ -0,0 +1,19 @@ +header('Accept-Language'); + +// Outputs something like: +'Accept-Language: en,en-US' + +echo $message->header('Accept-Language')->getValue(); + +// Outputs something like: +[ + 'en', + 'en-US' +] + +echo $message->header('Accept-Language')->getValueLine(); + +// Outputs something like: +'en,en-US' diff --git a/user_guide_src/source/incoming/message/004.php b/user_guide_src/source/incoming/message/004.php new file mode 100644 index 000000000000..534bbcf93349 --- /dev/null +++ b/user_guide_src/source/incoming/message/004.php @@ -0,0 +1,3 @@ +header('Document-URI', FILTER_SANITIZE_URL); diff --git a/user_guide_src/source/incoming/message/005.php b/user_guide_src/source/incoming/message/005.php new file mode 100644 index 000000000000..dd643a1250e4 --- /dev/null +++ b/user_guide_src/source/incoming/message/005.php @@ -0,0 +1,6 @@ +getHeaderLine('Accept-Language'); + +// Outputs: +en, en-US diff --git a/user_guide_src/source/incoming/message/006.php b/user_guide_src/source/incoming/message/006.php new file mode 100644 index 000000000000..74f6cde18eb0 --- /dev/null +++ b/user_guide_src/source/incoming/message/006.php @@ -0,0 +1,3 @@ +setHeader('Host', 'codeigniter.com'); diff --git a/user_guide_src/source/incoming/message/007.php b/user_guide_src/source/incoming/message/007.php new file mode 100644 index 000000000000..bd7a4f9052ce --- /dev/null +++ b/user_guide_src/source/incoming/message/007.php @@ -0,0 +1,3 @@ +removeHeader('Host'); diff --git a/user_guide_src/source/incoming/message/008.php b/user_guide_src/source/incoming/message/008.php new file mode 100644 index 000000000000..e14ed62b3636 --- /dev/null +++ b/user_guide_src/source/incoming/message/008.php @@ -0,0 +1,3 @@ +appendHeader('Accept-Language', 'en-US; q=0.8'); diff --git a/user_guide_src/source/incoming/message/009.php b/user_guide_src/source/incoming/message/009.php new file mode 100644 index 000000000000..c6cdd1ca6d05 --- /dev/null +++ b/user_guide_src/source/incoming/message/009.php @@ -0,0 +1,3 @@ +prependHeader('Accept-Language', 'en,'); diff --git a/user_guide_src/source/incoming/message/010.php b/user_guide_src/source/incoming/message/010.php new file mode 100644 index 000000000000..b5e056ab447d --- /dev/null +++ b/user_guide_src/source/incoming/message/010.php @@ -0,0 +1,3 @@ +setProtocolVersion('1.1'); diff --git a/user_guide_src/source/incoming/request.rst b/user_guide_src/source/incoming/request.rst index 109c22a7bd7e..d5af007b40bd 100644 --- a/user_guide_src/source/incoming/request.rst +++ b/user_guide_src/source/incoming/request.rst @@ -22,9 +22,10 @@ Class Reference :rtype: string Returns the IP address for the current user. If the IP address is not valid, the method - will return '0.0.0.0':: + will return '0.0.0.0': - echo $request->getIPAddress(); + .. literalinclude:: request/001.php + :lines: 2- .. important:: This method takes into account the ``App->proxyIPs`` setting and will return the reported HTTP_X_FORWARDED_FOR, HTTP_CLIENT_IP, HTTP_X_CLIENT_IP, or @@ -44,13 +45,8 @@ Class Reference .. note:: The $request->getIPAddress() method above automatically validates the IP address. - :: - - if (! $request->isValidIP($ip)) { - echo 'Not Valid'; - } else { - echo 'Valid'; - } + .. literalinclude:: request/002.php + :lines: 2- Accepts an optional second string parameter of 'ipv4' or 'ipv6' to specify an IP format. The default checks for both formats. @@ -65,11 +61,9 @@ Class Reference Returns the ``$_SERVER['REQUEST_METHOD']``, with the option to set it in uppercase or lowercase. - :: - echo $request->getMethod(true); // Outputs: POST - echo $request->getMethod(false); // Outputs: post - echo $request->getMethod(); // Outputs: post + .. literalinclude:: request/003.php + :lines: 2- .. php:method:: setMethod($method) @@ -86,15 +80,16 @@ Class Reference :rtype: mixed This method is identical to the ``post()``, ``get()`` and ``cookie()`` methods from the - :doc:`IncomingRequest Class `, only it fetches server data (``$_SERVER``):: + :doc:`IncomingRequest Class `, only it fetches server data (``$_SERVER``): - $request->getServer('some_data'); + .. literalinclude:: request/004.php + :lines: 2- To return an array of multiple ``$_SERVER`` values, pass all the required keys as an array. - :: - $require->getServer(['SERVER_PROTOCOL', 'REQUEST_URI']); + .. literalinclude:: request/005.php + :lines: 2- .. php:method:: getEnv([$index = null[, $filter = null[, $flags = null]]]) @@ -105,15 +100,16 @@ Class Reference :rtype: mixed This method is identical to the ``post()``, ``get()`` and ``cookie()`` methods from the - :doc:`IncomingRequest Class `, only it fetches getEnv data (``$_ENV``):: + :doc:`IncomingRequest Class `, only it fetches getEnv data (``$_ENV``): - $request->getEnv('some_data'); + .. literalinclude:: request/006.php + :lines: 2- To return an array of multiple ``$_ENV`` values, pass all the required keys as an array. - :: - $require->getEnv(['CI_ENVIRONMENT', 'S3_BUCKET']); + .. literalinclude:: request/007.php + :lines: 2- .. php:method:: setGlobal($method, $value) diff --git a/user_guide_src/source/incoming/request/001.php b/user_guide_src/source/incoming/request/001.php new file mode 100644 index 000000000000..09c19433908f --- /dev/null +++ b/user_guide_src/source/incoming/request/001.php @@ -0,0 +1,3 @@ +getIPAddress(); diff --git a/user_guide_src/source/incoming/request/002.php b/user_guide_src/source/incoming/request/002.php new file mode 100644 index 000000000000..4b2e39489f72 --- /dev/null +++ b/user_guide_src/source/incoming/request/002.php @@ -0,0 +1,7 @@ +isValidIP($ip)) { + echo 'Not Valid'; +} else { + echo 'Valid'; +} diff --git a/user_guide_src/source/incoming/request/003.php b/user_guide_src/source/incoming/request/003.php new file mode 100644 index 000000000000..fbfda408e272 --- /dev/null +++ b/user_guide_src/source/incoming/request/003.php @@ -0,0 +1,5 @@ +getMethod(true); // Outputs: POST +echo $request->getMethod(false); // Outputs: post +echo $request->getMethod(); // Outputs: post diff --git a/user_guide_src/source/incoming/request/004.php b/user_guide_src/source/incoming/request/004.php new file mode 100644 index 000000000000..e05381317b95 --- /dev/null +++ b/user_guide_src/source/incoming/request/004.php @@ -0,0 +1,3 @@ +getServer('some_data'); diff --git a/user_guide_src/source/incoming/request/005.php b/user_guide_src/source/incoming/request/005.php new file mode 100644 index 000000000000..ba2c43023c92 --- /dev/null +++ b/user_guide_src/source/incoming/request/005.php @@ -0,0 +1,3 @@ +getServer(['SERVER_PROTOCOL', 'REQUEST_URI']); diff --git a/user_guide_src/source/incoming/request/006.php b/user_guide_src/source/incoming/request/006.php new file mode 100644 index 000000000000..b503574b79cc --- /dev/null +++ b/user_guide_src/source/incoming/request/006.php @@ -0,0 +1,3 @@ +getEnv('some_data'); diff --git a/user_guide_src/source/incoming/request/007.php b/user_guide_src/source/incoming/request/007.php new file mode 100644 index 000000000000..95952d206a44 --- /dev/null +++ b/user_guide_src/source/incoming/request/007.php @@ -0,0 +1,3 @@ +getEnv(['CI_ENVIRONMENT', 'S3_BUCKET']); diff --git a/user_guide_src/source/incoming/restful.rst b/user_guide_src/source/incoming/restful.rst index 8992221590a0..93d31a76e957 100644 --- a/user_guide_src/source/incoming/restful.rst +++ b/user_guide_src/source/incoming/restful.rst @@ -28,19 +28,10 @@ Resource Routes You can quickly create a handful of RESTful routes for a single resource with the ``resource()`` method. This creates the five most common routes needed for full CRUD of a resource: create a new resource, update an existing one, list all of that resource, show a single resource, and delete a single resource. The first parameter is the resource -name:: +name: - $routes->resource('photos'); - - // Equivalent to the following: - $routes->get('photos/new', 'Photos::new'); - $routes->post('photos', 'Photos::create'); - $routes->get('photos', 'Photos::index'); - $routes->get('photos/(:segment)', 'Photos::show/$1'); - $routes->get('photos/(:segment)/edit', 'Photos::edit/$1'); - $routes->put('photos/(:segment)', 'Photos::update/$1'); - $routes->patch('photos/(:segment)', 'Photos::update/$1'); - $routes->delete('photos/(:segment)', 'Photos::delete/$1'); +.. literalinclude:: restful/001.php + :lines: 2- .. note:: The ordering above is for clarity, whereas the actual order the routes are created in, in RouteCollection, ensures proper route resolution @@ -48,47 +39,42 @@ name:: The second parameter accepts an array of options that can be used to modify the routes that are generated. While these routes are geared toward API-usage, where more methods are allowed, you can pass in the ``websafe`` option to have it -generate update and delete methods that work with HTML forms:: - - $routes->resource('photos', ['websafe' => 1]); +generate update and delete methods that work with HTML forms: - // The following equivalent routes are created: - $routes->post('photos/(:segment)/delete', 'Photos::delete/$1'); - $routes->post('photos/(:segment)', 'Photos::update/$1'); +.. literalinclude:: restful/002.php + :lines: 2- Change the Controller Used -------------------------- You can specify the controller that should be used by passing in the ``controller`` option with the name of -the controller that should be used:: - - $routes->resource('photos', ['controller' =>'App\Gallery']); +the controller that should be used: - // Would create routes like: - $routes->get('photos', 'App\Gallery::index'); +.. literalinclude:: restful/003.php + :lines: 2- Change the Placeholder Used --------------------------- By default, the ``(:segment)`` placeholder is used when a resource ID is needed. You can change this by passing -in the ``placeholder`` option with the new string to use:: +in the ``placeholder`` option with the new string to use: - $routes->resource('photos', ['placeholder' => '(:num)']); - - // Generates routes like: - $routes->get('photos/(:num)', 'Photos::show/$1'); +.. literalinclude:: restful/004.php + :lines: 2- Limit the Routes Made --------------------- You can restrict the routes generated with the ``only`` option. This should be **an array** or **comma separated list** of method names that should -be created. Only routes that match one of these methods will be created. The rest will be ignored:: +be created. Only routes that match one of these methods will be created. The rest will be ignored: - $routes->resource('photos', ['only' => ['index', 'show']]); +.. literalinclude:: restful/005.php + :lines: 2- -Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or **comma separated list** of method names. This option run after ``only``:: +Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or **comma separated list** of method names. This option run after ``only``: - $routes->resource('photos', ['except' => 'new,edit']); +.. literalinclude:: restful/006.php + :lines: 2- Valid methods are: ``index``, ``show``, ``create``, ``update``, ``new``, ``edit`` and ``delete``. @@ -99,30 +85,14 @@ The ``ResourceController`` provides a convenient starting point for your RESTful with methods that correspond to the resource routes above. Extend it, over-riding the ``modelName`` and ``format`` properties, and then -implement those methods that you want handled.:: - - respond($this->model->findAll()); - } - - // ... - } - -The routing for this would be:: - - $routes->resource('photos'); +.. literalinclude:: restful/008.php + :lines: 2- Presenter Routes ============================================================ @@ -134,30 +104,18 @@ for your resource, or process forms submitted from those views. It is not needed, since the presentation can be handled with a conventional controller - it is a convenience. -Its usage is similar to the resource routing:: - - $routes->presenter('photos'); - - // Equivalent to the following: - $routes->get('photos/new', 'Photos::new'); - $routes->post('photos/create', 'Photos::create'); - $routes->post('photos', 'Photos::create'); // alias - $routes->get('photos', 'Photos::index'); - $routes->get('photos/show/(:segment)', 'Photos::show/$1'); - $routes->get('photos/(:segment)', 'Photos::show/$1'); // alias - $routes->get('photos/edit/(:segment)', 'Photos::edit/$1'); - $routes->post('photos/update/(:segment)', 'Photos::update/$1'); - $routes->get('photos/remove/(:segment)', 'Photos::remove/$1'); - $routes->post('photos/delete/(:segment)', 'Photos::delete/$1'); +Its usage is similar to the resource routing: + +.. literalinclude:: restful/009.php + :lines: 2- .. note:: The ordering above is for clarity, whereas the actual order the routes are created in, in RouteCollection, ensures proper route resolution You would not have routes for `photos` for both a resource and a presenter -controller. You need to distinguish them, for instance:: - - $routes->resource('api/photo'); - $routes->presenter('admin/photos'); +controller. You need to distinguish them, for instance: +.. literalinclude:: restful/010.php + :lines: 2- The second parameter accepts an array of options that can be used to modify the routes that are generated. @@ -165,35 +123,33 @@ Change the Controller Used -------------------------- You can specify the controller that should be used by passing in the ``controller`` option with the name of -the controller that should be used:: - - $routes->presenter('photos', ['controller' =>'App\Gallery']); +the controller that should be used: - // Would create routes like: - $routes->get('photos', 'App\Gallery::index'); +.. literalinclude:: restful/011.php + :lines: 2- Change the Placeholder Used --------------------------- By default, the ``(:segment)`` placeholder is used when a resource ID is needed. You can change this by passing -in the ``placeholder`` option with the new string to use:: - - $routes->presenter('photos', ['placeholder' => '(:num)']); +in the ``placeholder`` option with the new string to use: - // Generates routes like: - $routes->get('photos/(:num)', 'Photos::show/$1'); +.. literalinclude:: restful/012.php + :lines: 2- Limit the Routes Made --------------------- You can restrict the routes generated with the ``only`` option. This should be **an array** or **comma separated list** of method names that should -be created. Only routes that match one of these methods will be created. The rest will be ignored:: +be created. Only routes that match one of these methods will be created. The rest will be ignored: - $routes->presenter('photos', ['only' => ['index', 'show']]); +.. literalinclude:: restful/013.php + :lines: 2- -Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or **comma separated list** of method names. This option run after ``only``:: +Otherwise you can remove unused routes with the ``except`` option. This should also be **an array** or **comma separated list** of method names. This option run after ``only``: - $routes->presenter('photos', ['except' => 'new,edit']); +.. literalinclude:: restful/014.php + :lines: 2- Valid methods are: ``index``, ``show``, ``new``, ``create``, ``edit``, ``update``, ``remove`` and ``delete``. @@ -205,30 +161,14 @@ of your resource, and processing data from forms in those views, with methods that align to the resource routes above. Extend it, over-riding the ``modelName`` property, and then -implement those methods that you want handled.:: - - model->findAll()); - } +implement those methods that you want handled.: - // ... - } +.. literalinclude:: restful/015.php -The routing for this would be:: +The routing for this would be: - $routes->presenter('photos'); +.. literalinclude:: restful/016.php + :lines: 2- Presenter/Controller Comparison ============================================================= diff --git a/user_guide_src/source/incoming/restful/001.php b/user_guide_src/source/incoming/restful/001.php new file mode 100644 index 000000000000..4a3ee8133b7d --- /dev/null +++ b/user_guide_src/source/incoming/restful/001.php @@ -0,0 +1,13 @@ +resource('photos'); + +// Equivalent to the following: +$routes->get('photos/new', 'Photos::new'); +$routes->post('photos', 'Photos::create'); +$routes->get('photos', 'Photos::index'); +$routes->get('photos/(:segment)', 'Photos::show/$1'); +$routes->get('photos/(:segment)/edit', 'Photos::edit/$1'); +$routes->put('photos/(:segment)', 'Photos::update/$1'); +$routes->patch('photos/(:segment)', 'Photos::update/$1'); +$routes->delete('photos/(:segment)', 'Photos::delete/$1'); diff --git a/user_guide_src/source/incoming/restful/002.php b/user_guide_src/source/incoming/restful/002.php new file mode 100644 index 000000000000..cc879a2ab667 --- /dev/null +++ b/user_guide_src/source/incoming/restful/002.php @@ -0,0 +1,7 @@ +resource('photos', ['websafe' => 1]); + +// The following equivalent routes are created: +$routes->post('photos/(:segment)/delete', 'Photos::delete/$1'); +$routes->post('photos/(:segment)', 'Photos::update/$1'); diff --git a/user_guide_src/source/incoming/restful/003.php b/user_guide_src/source/incoming/restful/003.php new file mode 100644 index 000000000000..1485f3c4edea --- /dev/null +++ b/user_guide_src/source/incoming/restful/003.php @@ -0,0 +1,6 @@ +resource('photos', ['controller' =>'App\Gallery']); + +// Would create routes like: +$routes->get('photos', 'App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/004.php b/user_guide_src/source/incoming/restful/004.php new file mode 100644 index 000000000000..540fbb84aeed --- /dev/null +++ b/user_guide_src/source/incoming/restful/004.php @@ -0,0 +1,6 @@ +resource('photos', ['placeholder' => '(:num)']); + +// Generates routes like: +$routes->get('photos/(:num)', 'Photos::show/$1'); diff --git a/user_guide_src/source/incoming/restful/005.php b/user_guide_src/source/incoming/restful/005.php new file mode 100644 index 000000000000..4ac8480f8ca2 --- /dev/null +++ b/user_guide_src/source/incoming/restful/005.php @@ -0,0 +1,3 @@ +resource('photos', ['only' => ['index', 'show']]); diff --git a/user_guide_src/source/incoming/restful/006.php b/user_guide_src/source/incoming/restful/006.php new file mode 100644 index 000000000000..a1a98809adc1 --- /dev/null +++ b/user_guide_src/source/incoming/restful/006.php @@ -0,0 +1,3 @@ +resource('photos', ['except' => 'new,edit']); diff --git a/user_guide_src/source/incoming/restful/007.php b/user_guide_src/source/incoming/restful/007.php new file mode 100644 index 000000000000..930c61f28e8c --- /dev/null +++ b/user_guide_src/source/incoming/restful/007.php @@ -0,0 +1,18 @@ +respond($this->model->findAll()); + } + + // ... +} diff --git a/user_guide_src/source/incoming/restful/008.php b/user_guide_src/source/incoming/restful/008.php new file mode 100644 index 000000000000..d1a6c08dd03c --- /dev/null +++ b/user_guide_src/source/incoming/restful/008.php @@ -0,0 +1,3 @@ +resource('photos'); diff --git a/user_guide_src/source/incoming/restful/009.php b/user_guide_src/source/incoming/restful/009.php new file mode 100644 index 000000000000..5918a044fab5 --- /dev/null +++ b/user_guide_src/source/incoming/restful/009.php @@ -0,0 +1,15 @@ +presenter('photos'); + +// Equivalent to the following: +$routes->get('photos/new', 'Photos::new'); +$routes->post('photos/create', 'Photos::create'); +$routes->post('photos', 'Photos::create'); // alias +$routes->get('photos', 'Photos::index'); +$routes->get('photos/show/(:segment)', 'Photos::show/$1'); +$routes->get('photos/(:segment)', 'Photos::show/$1'); // alias +$routes->get('photos/edit/(:segment)', 'Photos::edit/$1'); +$routes->post('photos/update/(:segment)', 'Photos::update/$1'); +$routes->get('photos/remove/(:segment)', 'Photos::remove/$1'); +$routes->post('photos/delete/(:segment)', 'Photos::delete/$1'); diff --git a/user_guide_src/source/incoming/restful/010.php b/user_guide_src/source/incoming/restful/010.php new file mode 100644 index 000000000000..b36c7ed8973e --- /dev/null +++ b/user_guide_src/source/incoming/restful/010.php @@ -0,0 +1,4 @@ +resource('api/photo'); +$routes->presenter('admin/photos'); diff --git a/user_guide_src/source/incoming/restful/011.php b/user_guide_src/source/incoming/restful/011.php new file mode 100644 index 000000000000..5c949d80cc29 --- /dev/null +++ b/user_guide_src/source/incoming/restful/011.php @@ -0,0 +1,6 @@ +presenter('photos', ['controller' =>'App\Gallery']); + +// Would create routes like: +$routes->get('photos', 'App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/012.php b/user_guide_src/source/incoming/restful/012.php new file mode 100644 index 000000000000..0bd42b5120f0 --- /dev/null +++ b/user_guide_src/source/incoming/restful/012.php @@ -0,0 +1,6 @@ +presenter('photos', ['placeholder' => '(:num)']); + +// Generates routes like: +$routes->get('photos/(:num)', 'Photos::show/$1'); diff --git a/user_guide_src/source/incoming/restful/013.php b/user_guide_src/source/incoming/restful/013.php new file mode 100644 index 000000000000..1a3cc23a9004 --- /dev/null +++ b/user_guide_src/source/incoming/restful/013.php @@ -0,0 +1,3 @@ +presenter('photos', ['only' => ['index', 'show']]); diff --git a/user_guide_src/source/incoming/restful/014.php b/user_guide_src/source/incoming/restful/014.php new file mode 100644 index 000000000000..0d88d4ba5cdc --- /dev/null +++ b/user_guide_src/source/incoming/restful/014.php @@ -0,0 +1,3 @@ +presenter('photos', ['except' => 'new,edit']); diff --git a/user_guide_src/source/incoming/restful/015.php b/user_guide_src/source/incoming/restful/015.php new file mode 100644 index 000000000000..fc5713b20d61 --- /dev/null +++ b/user_guide_src/source/incoming/restful/015.php @@ -0,0 +1,18 @@ +model->findAll()); + } + + // ... +} diff --git a/user_guide_src/source/incoming/restful/016.php b/user_guide_src/source/incoming/restful/016.php new file mode 100644 index 000000000000..d0511180ee22 --- /dev/null +++ b/user_guide_src/source/incoming/restful/016.php @@ -0,0 +1,3 @@ +presenter('photos'); diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index b48c5785780b..1dbfd47c1d80 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -52,38 +52,37 @@ it creates an instance of the RouteCollection class (``$routes``) that permits y Routes can be specified using placeholders or Regular Expressions. When you specify a route, you choose a method to corresponding to HTTP verbs (request method). -If you expect a GET request, you use the ``get()`` method:: +If you expect a GET request, you use the ``get()`` method: - $routes->get('/', 'Home::index'); +.. literalinclude:: routing/000.php + :lines: 2- A route simply takes the URI path on the left, and maps it to the controller and method on the right, along with any parameters that should be passed to the controller. The controller and method should be listed in the same way that you would use a static method, by separating the class and its method with a double-colon, like ``Users::list``. If that method requires parameters to be -passed to it, then they would be listed after the method name, separated by forward-slashes:: +passed to it, then they would be listed after the method name, separated by forward-slashes: - // Calls $Users->list() - $routes->get('users', 'Users::list'); +.. literalinclude:: routing/001.php + :lines: 2- - // Calls $Users->list(1, 23) - $routes->get('users/1/23', 'Users::list/1/23'); +You can use any standard HTTP verb (GET, POST, PUT, DELETE, etc): -You can use any standard HTTP verb (GET, POST, PUT, DELETE, etc):: +.. literalinclude:: routing/024.php + :lines: 2- - $routes->post('products', 'Product::feature'); - $routes->put('products/1', 'Product::feature'); - $routes->delete('products/1', 'Product::feature'); +You can supply multiple verbs that a route should match by passing them in as an array to the ``match()`` method: -You can supply multiple verbs that a route should match by passing them in as an array to the ``match()`` method:: - - $routes->match(['get', 'put'], 'products', 'Product::feature'); +.. literalinclude:: routing/025.php + :lines: 2- Placeholders ============ -A typical route might look something like this:: +A typical route might look something like this: - $routes->get('product/(:num)', 'Catalog::productLookup'); +.. literalinclude:: routing/002.php + :lines: 2- In a route, the first parameter contains the URI to be matched, while the second parameter contains the destination it should be routed to. In the above example, if the literal word @@ -116,42 +115,45 @@ Examples Here are a few basic routing examples. A URL containing the word **journals** in the first segment will be remapped to the ``\App\Controllers\Blogs`` class, -and the default method, which is usually ``index()``:: +and the default method, which is usually ``index()``: - $routes->get('journals', 'Blogs'); +.. literalinclude:: routing/003.php + :lines: 2- A URL containing the segments **blog/joe** will be remapped to the ``\App\Controllers\Blogs`` class and the ``users`` method. -The ID will be set to ``34``:: +The ID will be set to ``34``: - $routes->get('blog/joe', 'Blogs::users/34'); +.. literalinclude:: routing/004.php + :lines: 2- A URL with **product** as the first segment, and anything in the second will be remapped to the ``\App\Controllers\Catalog`` class -and the ``productLookup`` method:: +and the ``productLookup`` method: - $routes->get('product/(:any)', 'Catalog::productLookup'); +.. literalinclude:: routing/005.php + :lines: 2- A URL with **product** as the first segment, and a number in the second will be remapped to the ``\App\Controllers\Catalog`` class -and the ``productLookupByID`` method passing in the match as a variable to the method:: +and the ``productLookupByID`` method passing in the match as a variable to the method: - $routes->get('product/(:num)', 'Catalog::productLookupByID/$1'); +.. literalinclude:: routing/006.php + :lines: 2- -Note that a single ``(:any)`` will match multiple segments in the URL if present. For example the route:: +Note that a single ``(:any)`` will match multiple segments in the URL if present. For example the route: - $routes->get('product/(:any)', 'Catalog::productLookup/$1'); +.. literalinclude:: routing/007.php + :lines: 2- will match **product/123**, **product/123/456**, **product/123/456/789** and so on. The implementation in the -Controller should take into account the maximum parameters:: +Controller should take into account the maximum parameters: - public function productLookup($seg1 = false, $seg2 = false, $seg3 = false) { - echo $seg1; // Will be 123 in all examples - echo $seg2; // false in first, 456 in second and third example - echo $seg3; // false in first and second, 789 in third - } +.. literalinclude:: routing/008.php + :lines: 2- If matching multiple segments is not the intended behavior, ``(:segment)`` should be used when defining the -routes. With the examples URLs from above:: +routes. With the examples URLs from above: - $routes->get('product/(:segment)', 'Catalog::productLookup/$1'); +.. literalinclude:: routing/009.php + :lines: 2- will only match **product/123** and generate 404 errors for other example. @@ -163,10 +165,10 @@ and readability. You add new placeholders with the ``addPlaceholder()`` method. The first parameter is the string to be used as the placeholder. The second parameter is the Regular Expression pattern it should be replaced with. -This must be called before you add the route:: +This must be called before you add the route: - $routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); - $routes->get('users/(:uuid)', 'Users::show/$1'); +.. literalinclude:: routing/010.php + :lines: 2- Regular Expressions =================== @@ -175,9 +177,10 @@ If you prefer you can use regular expressions to define your routing rules. Any is allowed, as are back-references. .. important:: Note: If you use back-references you must use the dollar syntax rather than the double backslash syntax. - A typical RegEx route might look something like this:: + A typical RegEx route might look something like this: - $routes->get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); + .. literalinclude:: routing/011.php + :lines: 2- In the above example, a URI similar to **products/shirts/123** would instead call the ``show`` method of the ``Products`` controller class, with the original first and second segment passed as arguments to it. @@ -186,9 +189,10 @@ With regular expressions, you can also catch a segment containing a forward slas represent the delimiter between multiple segments. For example, if a user accesses a password protected area of your web application and you wish to be able to -redirect them back to the same page after they log in, you may find this example useful:: +redirect them back to the same page after they log in, you may find this example useful: - $routes->get('login/(.+)', 'Auth::login/$1'); +.. literalinclude:: routing/012.php + :lines: 2- For those of you who don’t know regular expressions and want to learn more about them, `regular-expressions.info `_ might be a good starting point. @@ -200,27 +204,20 @@ Closures You can use an anonymous function, or Closure, as the destination that a route maps to. This function will be executed when the user visits that URI. This is handy for quickly executing small tasks, or even just showing -a simple view:: - - $routes->get('feed', function () { - $rss = new RSSFeeder(); +a simple view: - return $rss->feed('general'); - }); +.. literalinclude:: routing/013.php + :lines: 2- Mapping multiple routes ======================= While the ``add()`` method is simple to use, it is often handier to work with multiple routes at once, using the ``map()`` method. Instead of calling the ``add()`` method for each route that you need to add, you can -define an array of routes and then pass it as the first parameter to the ``map()`` method:: - - $multipleRoutes = [ - 'product/(:num)' => 'Catalog::productLookupById', - 'product/(:alphanum)' => 'Catalog::productLookupByName', - ]; +define an array of routes and then pass it as the first parameter to the ``map()`` method: - $routes->map($multipleRoutes); +.. literalinclude:: routing/014.php + :lines: 2- Redirecting Routes ================== @@ -229,14 +226,10 @@ Any site that lives long enough is bound to have pages that move. You can specif to other routes with the ``addRedirect()`` method. The first parameter is the URI pattern for the old route. The second parameter is either the new URI to redirect to, or the name of a named route. The third parameter is the HTTP status code that should be sent along with the redirect. The default value is ``302`` which is a temporary -redirect and is recommended in most cases:: +redirect and is recommended in most cases: - $routes->get('users/profile', 'Users::profile', ['as' => 'profile']); - - // Redirect to a named route - $routes->addRedirect('users/about', 'profile'); - // Redirect to a URI - $routes->addRedirect('users/about', 'users/profile'); +.. literalinclude:: routing/015.php + :lines: 2- If a redirect route is matched during a page load, the user will be immediately redirected to the new page before a controller can be loaded. @@ -246,39 +239,32 @@ Grouping Routes You can group your routes under a common name with the ``group()`` method. The group name becomes a segment that appears prior to the routes defined inside of the group. This allows you to reduce the typing needed to build out an -extensive set of routes that all share the opening string, like when building an admin area:: +extensive set of routes that all share the opening string, like when building an admin area: - $routes->group('admin', function ($routes) { - $routes->get('users', 'Admin\Users::index'); - $routes->get('blog', 'Admin\Blog::index'); - }); +.. literalinclude:: routing/016.php + :lines: 2- This would prefix the **users** and **blog** URIs with **admin**, handling URLs like **admin/users** and **admin/blog**. -If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback:: +If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback: - $routes->group('api', ['namespace' => 'App\API\v1'], function ($routes) { - $routes->resource('users'); - }); +.. literalinclude:: routing/017.php + :lines: 2- This would handle a resource route to the ``App\API\v1\Users`` controller with the **api/users** URI. You can also use a specific :doc:`filter ` for a group of routes. This will always -run the filter before or after the controller. This is especially handy during authentication or api logging:: +run the filter before or after the controller. This is especially handy during authentication or api logging: - $routes->group('api', ['filter' => 'api-auth'], function ($routes) { - $routes->resource('users'); - }); +.. literalinclude:: routing/018.php + :lines: 2- The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. -It is possible to nest groups within groups for finer organization if you need it:: +It is possible to nest groups within groups for finer organization if you need it: - $routes->group('admin', function ($routes) { - $routes->group('users', function ($routes) { - $routes->get('list', 'Admin\Users::list'); - }); - }); +.. literalinclude:: routing/019.php + :lines: 2- This would handle the URL at **admin/users/list**. @@ -287,13 +273,10 @@ This would handle the URL at **admin/users/list**. At some point, you may want to group routes for the purpose of applying filters or other route config options like namespace, subdomain, etc. Without necessarily needing to add a prefix to the group, you can pass an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the -given route config options:: +given route config options: - $routes->group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { - $routes->get('login', 'AuthController::login', ['as' => 'login']); - $routes->post('login', 'AuthController::attemptLogin'); - $routes->get('logout', 'AuthController::logout'); - }); +.. literalinclude:: routing/020.php + :lines: 2- Environment Restrictions ======================== @@ -301,11 +284,10 @@ Environment Restrictions You can create a set of routes that will only be viewable in a certain environment. This allows you to create tools that only the developer can use on their local machines that are not reachable on testing or production servers. This can be done with the ``environment()`` method. The first parameter is the name of the environment. Any -routes defined within this closure are only accessible from the given environment:: +routes defined within this closure are only accessible from the given environment: - $routes->environment('development', function ($routes) { - $routes->get('builder', 'Tools\Builder::index'); - }); +.. literalinclude:: routing/021.php + :lines: 2- Reverse Routing =============== @@ -317,14 +299,10 @@ to update your application code. This is typically used within views to create l For example, if you have a route to a photo gallery that you want to link to, you can use the ``route_to()`` helper function to get the current route that should be used. The first parameter is the fully qualified Controller and method, separated by a double colon (``::``), much like you would use when writing the initial route itself. Any parameters that -should be passed to the route are passed in next:: - - // The route is defined as: - $routes->get('users/(:num)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2'); +should be passed to the route are passed in next: - // Generate the relative URL to link to user ID 15, gallery 12 - // Generates: /users/15/gallery/12 - View Gallery +.. literalinclude:: routing/022.php + :lines: 2- Using Named Routes ================== @@ -332,14 +310,10 @@ Using Named Routes You can name routes to make your application less fragile. This applies a name to a route that can be called later, and even if the route definition changes, all of the links in your application built with ``route_to()`` will still work without you having to make any changes. A route is named by passing in the ``as`` option -with the name of the route:: +with the name of the route: - // The route is defined as: - $routes->get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); - - // Generate the relative URL to link to user ID 15, gallery 12 - // Generates: /users/15/gallery/12 - View Gallery +.. literalinclude:: routing/023.php + :lines: 2- This has the added benefit of making the views more readable, too. @@ -347,9 +321,10 @@ Routes with any HTTP verbs ========================== It is possible to define a route with any HTTP verbs. -You can use the ``add()`` method:: +You can use the ``add()`` method: - $routes->add('products', 'Product::feature'); +.. literalinclude:: routing/023-2.php + :lines: 2- .. warning:: While the ``add()`` method seems to be convenient, it is recommended to always use the HTTP-verb-based routes, described above, as it is more secure. If you use the :doc:`CSRF protection `, it does not protect **GET** @@ -366,28 +341,19 @@ Command-Line only Routes You can create routes that work only from the command-line, and are inaccessible from the web browser, with the ``cli()`` method. This is great for building cron jobs or CLI-only tools. Any route created by any of the HTTP-verb-based route methods will also be inaccessible from the CLI, but routes created by the ``add()`` method will still be -available from the command line:: +available from the command line: - $routes->cli('migrate', 'App\Database::migrate'); +.. literalinclude:: routing/026.php + :lines: 2- Global Options ============== All of the methods for creating a route (add, get, post, :doc:`resource ` etc) can take an array of options that -can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter:: - - $routes->add('from', 'to', $options); - $routes->get('from', 'to', $options); - $routes->post('from', 'to', $options); - $routes->put('from', 'to', $options); - $routes->head('from', 'to', $options); - $routes->options('from', 'to', $options); - $routes->delete('from', 'to', $options); - $routes->patch('from', 'to', $options); - $routes->match(['get', 'put'], 'from', 'to', $options); - $routes->resource('photos', $options); - $routes->map($array, $options); - $routes->group('name', $options, function ()); +can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter: + +.. literalinclude:: routing/027.php + :lines: 2- .. _applying-filters: @@ -411,27 +377,31 @@ See :doc:`Controller filters ` for more information on setting up filte **Alias filter** -You specify an alias defined in **app/Config/Filters.php** for the filter value:: +You specify an alias defined in **app/Config/Filters.php** for the filter value: - $routes->get('admin',' AdminController::index', ['filter' => 'admin-auth']); +.. literalinclude:: routing/028.php + :lines: 2- -You may also supply arguments to be passed to the alias filter's ``before()`` and ``after()`` methods:: +You may also supply arguments to be passed to the alias filter's ``before()`` and ``after()`` methods: - $routes->post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); +.. literalinclude:: routing/029.php + :lines: 2- **Classname filter** -You specify a filter classname for the filter value:: +You specify a filter classname for the filter value: - $routes->get('admin',' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); +.. literalinclude:: routing/030.php + :lines: 2- **Multiple filters** .. important:: *Multiple filters* is disabled by default. Because it breaks backward compatibility. If you want to use it, you need to configure. See :ref:`upgrade-415-multiple-filters-for-a-route` for the details. -You specify an array for the filter value:: +You specify an array for the filter value: - $routes->get('admin',' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); +.. literalinclude:: routing/031.php + :lines: 2- .. _assigning-namespace: @@ -440,10 +410,10 @@ Assigning Namespace While a default namespace will be prepended to the generated controllers (see below), you can also specify a different namespace to be used in any options array, with the ``namespace`` option. The value should be the -namespace you want modified:: +namespace you want modified: - // Routes to \Admin\Users::index() - $routes->get('admin/users', 'Users::index', ['namespace' => 'Admin']); +.. literalinclude:: routing/032.php + :lines: 2- The new namespace is only applied during that call for any methods that create a single route, like get, post, etc. For any methods that create multiple routes, the new namespace is attached to all routes generated by that function @@ -453,9 +423,10 @@ Limit to Hostname ----------------- You can restrict groups of routes to function only in certain domain or sub-domains of your application -by passing the "hostname" option along with the desired domain to allow it on as part of the options array:: +by passing the "hostname" option along with the desired domain to allow it on as part of the options array: - $routes->get('from', 'to', ['hostname' => 'accounts.example.com']); +.. literalinclude:: routing/033.php + :lines: 2- This example would only allow the specified hosts to work if the domain exactly matched **accounts.example.com**. It would not work under the main site at **example.com**. @@ -464,16 +435,16 @@ Limit to Subdomains ------------------- When the ``subdomain`` option is present, the system will restrict the routes to only be available on that -sub-domain. The route will only be matched if the subdomain is the one the application is being viewed through:: +sub-domain. The route will only be matched if the subdomain is the one the application is being viewed through: - // Limit to media.example.com - $routes->get('from', 'to', ['subdomain' => 'media']); +.. literalinclude:: routing/034.php + :lines: 2- You can restrict it to any subdomain by setting the value to an asterisk, (``*``). If you are viewing from a URL -that does not have any subdomain present, this will not be matched:: +that does not have any subdomain present, this will not be matched: - // Limit to any sub-domain - $routes->get('from', 'to', ['subdomain' => '*']); +.. literalinclude:: routing/035.php + :lines: 2- .. important:: The system is not perfect and should be tested for your specific domain before being used in production. Most domains should work fine but some edge case ones, especially with a period in the domain itself (not used @@ -486,12 +457,10 @@ You can offset the matched parameters in your route by any numeric value with th value being the number of segments to offset. This can be beneficial when developing API's with the first URI segment being the version number. It can also -be used when the first parameter is a language string:: - - $routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]); +be used when the first parameter is a language string: - // Creates: - $routes['users/(:num)'] = 'users/show/$2'; +.. literalinclude:: routing/036.php + :lines: 2- .. _routing-priority: @@ -502,23 +471,15 @@ When working with modules, it can be a problem if the routes in the application Then the module routes will not be processed correctly. You can solve this problem by lowering the priority of route processing using the ``priority`` option. The parameter accepts positive integers and zero. The higher the number specified in the ``priority``, the lower -route priority in the processing queue:: - - // First you need to enable sorting. - $routes->setPrioritize(); - - // App\Config\Routes - $routes->get('(.*)', 'Posts::index', ['priority' => 1]); +route priority in the processing queue: - // Modules\Acme\Config\Routes - $routes->get('admin', 'Admin::index'); +.. literalinclude:: routing/037.php + :lines: 2- - // The "admin" route will now be processed before the wildcard router. +To disable this functionality, you must call the method with the parameter ``false``: - -To disable this functionality, you must call the method with the parameter ``false``:: - - $routes->setPrioritize(false); +.. literalinclude:: routing/038.php + :lines: 2- .. note:: By default, all routes have a priority of 0. Negative integers will be cast to the absolute value. @@ -539,36 +500,26 @@ When matching a controller to a route, the router will add the default namespace specified by the route. By default, this value is ``App\Controllers``. If you set the value empty string (``''``), it leaves each route to specify the fully namespaced -controller:: - - $routes->setDefaultNamespace(''); +controller: - // Controller is \Users - $routes->get('users', 'Users::index'); - - // Controller is \Admin\Users - $routes->get('users', 'Admin\Users::index'); +.. literalinclude:: routing/039.php + :lines: 2- If your controllers are not explicitly namespaced, there is no need to change this. If you namespace your controllers, -then you can change this value to save typing:: - - $routes->setDefaultNamespace('App'); +then you can change this value to save typing: - // Controller is \App\Users - $routes->get('users', 'Users::index'); - - // Controller is \App\Admin\Users - $routes->get('users', 'Admin\Users::index'); +.. literalinclude:: routing/040.php + :lines: 2- Default Controller ================== When a user visits the root of your site (i.e., example.com) the controller to use is determined by the value set by the ``setDefaultController()`` method, unless a route exists for it explicitly. The default value for this is ``Home`` -which matches the controller at **app/Controllers/Home.php**:: +which matches the controller at **app/Controllers/Home.php**: - // example.com routes to app/Controllers/Welcome.php - $routes->setDefaultController('Welcome'); +.. literalinclude:: routing/041.php + :lines: 2- The default controller is also used when no matching route has been found, and the URI would point to a directory in the controllers directory. For example, if the user visits **example.com/admin**, if a controller was found at @@ -582,18 +533,20 @@ when a controller is found that matches the URI, but no segment exists for the m ``index``. In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the -``Products::listAll()`` method would be executed:: +``Products::listAll()`` method would be executed: - $routes->setDefaultMethod('listAll'); +.. literalinclude:: routing/042.php + :lines: 2- Translate URI Dashes ==================== This option enables you to automatically replace dashes (``-``) with underscores in the controller and method URI segments, thus saving you additional route entries if you need to do that. This is required because the -dash isn’t a valid class or method name character and would cause a fatal error if you try to use it:: +dash isn’t a valid class or method name character and would cause a fatal error if you try to use it: - $routes->setTranslateURIDashes(true); +.. literalinclude:: routing/043.php + :lines: 2- .. _use-defined-routes-only: @@ -602,9 +555,10 @@ Use Defined Routes Only When no defined route is found that matches the URI, the system will attempt to match that URI against the controllers and methods as described above. You can disable this automatic matching, and restrict routes -to only those defined by you, by setting the ``setAutoRoute()`` option to false:: +to only those defined by you, by setting the ``setAutoRoute()`` option to false: - $routes->setAutoRoute(false); +.. literalinclude:: routing/044.php + :lines: 2- .. warning:: If you use the :doc:`CSRF protection `, it does not protect **GET** requests. If the URI is accessible by the GET method, the CSRF protection will not work. @@ -614,30 +568,20 @@ to only those defined by you, by setting the ``setAutoRoute()`` option to false: When a page is not found that matches the current URI, the system will show a generic 404 view. You can change what happens by specifying an action to happen with the ``set404Override()`` method. The value can be either -a valid class/method pair, just like you would show in any route, or a Closure:: - - // Would execute the show404 method of the App\Errors class - $routes->set404Override('App\Errors::show404'); - - // Will display a custom view - $routes->set404Override(function () - { - echo view('my_errors/not_found.html'); - }); +a valid class/method pair, just like you would show in any route, or a Closure: +.. literalinclude:: routing/045.php + :lines: 2- Route processing by priority ============================ Enables or disables processing of the routes queue by priority. Lowering the priority is defined in the route option. Disabled by default. This functionality affects all routes. -For an example use of lowering the priority see :ref:`routing-priority`:: - - // to enable - $routes->setPrioritize(); +For an example use of lowering the priority see :ref:`routing-priority`: - // to disable - $routes->setPrioritize(false); +.. literalinclude:: routing/046.php + :lines: 2- ***************** Confirming Routes @@ -675,4 +619,4 @@ But ``[/...]`` in the route of an auto route is indicates any number of segments .. note:: When auto routing is enabled, if you have the route ``home``, it can be also accessd by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. But the command shows only ``home``. -.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. But the filters defined in **app/Config/Routes.php** are always displayed correctly. +.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. But the filters defined in **app/Config/Routes.php** are always displayed correctly. \ No newline at end of file diff --git a/user_guide_src/source/incoming/routing/000.php b/user_guide_src/source/incoming/routing/000.php new file mode 100644 index 000000000000..d799d1cf0fb5 --- /dev/null +++ b/user_guide_src/source/incoming/routing/000.php @@ -0,0 +1,3 @@ +get('/', 'Home::index'); diff --git a/user_guide_src/source/incoming/routing/001.php b/user_guide_src/source/incoming/routing/001.php new file mode 100644 index 000000000000..4ddfd31abaed --- /dev/null +++ b/user_guide_src/source/incoming/routing/001.php @@ -0,0 +1,7 @@ +list() +$routes->get('users', 'Users::list'); + +// Calls $Users->list(1, 23) +$routes->get('users/1/23', 'Users::list/1/23'); \ No newline at end of file diff --git a/user_guide_src/source/incoming/routing/002.php b/user_guide_src/source/incoming/routing/002.php new file mode 100644 index 000000000000..ba4d8d98a28a --- /dev/null +++ b/user_guide_src/source/incoming/routing/002.php @@ -0,0 +1,3 @@ +get('product/(:num)', 'Catalog::productLookup'); diff --git a/user_guide_src/source/incoming/routing/003.php b/user_guide_src/source/incoming/routing/003.php new file mode 100644 index 000000000000..7a9075b57b2f --- /dev/null +++ b/user_guide_src/source/incoming/routing/003.php @@ -0,0 +1,3 @@ +get('journals', 'Blogs'); diff --git a/user_guide_src/source/incoming/routing/004.php b/user_guide_src/source/incoming/routing/004.php new file mode 100644 index 000000000000..4ee87c0af53a --- /dev/null +++ b/user_guide_src/source/incoming/routing/004.php @@ -0,0 +1,3 @@ +get('blog/joe', 'Blogs::users/34'); diff --git a/user_guide_src/source/incoming/routing/005.php b/user_guide_src/source/incoming/routing/005.php new file mode 100644 index 000000000000..d840165c7809 --- /dev/null +++ b/user_guide_src/source/incoming/routing/005.php @@ -0,0 +1,3 @@ +get('product/(:any)', 'Catalog::productLookup'); diff --git a/user_guide_src/source/incoming/routing/006.php b/user_guide_src/source/incoming/routing/006.php new file mode 100644 index 000000000000..638ed4492220 --- /dev/null +++ b/user_guide_src/source/incoming/routing/006.php @@ -0,0 +1,3 @@ +get('product/(:num)', 'Catalog::productLookupByID/$1'); diff --git a/user_guide_src/source/incoming/routing/007.php b/user_guide_src/source/incoming/routing/007.php new file mode 100644 index 000000000000..c88bc65573a3 --- /dev/null +++ b/user_guide_src/source/incoming/routing/007.php @@ -0,0 +1,3 @@ +get('product/(:any)', 'Catalog::productLookup/$1'); diff --git a/user_guide_src/source/incoming/routing/008.php b/user_guide_src/source/incoming/routing/008.php new file mode 100644 index 000000000000..11437a5881c2 --- /dev/null +++ b/user_guide_src/source/incoming/routing/008.php @@ -0,0 +1,7 @@ +get('product/(:segment)', 'Catalog::productLookup/$1'); diff --git a/user_guide_src/source/incoming/routing/010.php b/user_guide_src/source/incoming/routing/010.php new file mode 100644 index 000000000000..cb1cdda7c78c --- /dev/null +++ b/user_guide_src/source/incoming/routing/010.php @@ -0,0 +1,4 @@ +addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); +$routes->get('users/(:uuid)', 'Users::show/$1'); diff --git a/user_guide_src/source/incoming/routing/011.php b/user_guide_src/source/incoming/routing/011.php new file mode 100644 index 000000000000..a1619a4bf080 --- /dev/null +++ b/user_guide_src/source/incoming/routing/011.php @@ -0,0 +1,3 @@ +get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); diff --git a/user_guide_src/source/incoming/routing/012.php b/user_guide_src/source/incoming/routing/012.php new file mode 100644 index 000000000000..c9ddfae73610 --- /dev/null +++ b/user_guide_src/source/incoming/routing/012.php @@ -0,0 +1,3 @@ +get('login/(.+)', 'Auth::login/$1'); diff --git a/user_guide_src/source/incoming/routing/013.php b/user_guide_src/source/incoming/routing/013.php new file mode 100644 index 000000000000..2d0f48cb284e --- /dev/null +++ b/user_guide_src/source/incoming/routing/013.php @@ -0,0 +1,7 @@ +get('feed', function () { + $rss = new RSSFeeder(); + + return $rss->feed('general'); +}); diff --git a/user_guide_src/source/incoming/routing/014.php b/user_guide_src/source/incoming/routing/014.php new file mode 100644 index 000000000000..8ebc27e3f9f5 --- /dev/null +++ b/user_guide_src/source/incoming/routing/014.php @@ -0,0 +1,8 @@ + 'Catalog::productLookupById', + 'product/(:alphanum)' => 'Catalog::productLookupByName', +]; + +$routes->map($multipleRoutes); diff --git a/user_guide_src/source/incoming/routing/015.php b/user_guide_src/source/incoming/routing/015.php new file mode 100644 index 000000000000..d92d9934db5a --- /dev/null +++ b/user_guide_src/source/incoming/routing/015.php @@ -0,0 +1,8 @@ +get('users/profile', 'Users::profile', ['as' => 'profile']); + +// Redirect to a named route +$routes->addRedirect('users/about', 'profile'); +// Redirect to a URI +$routes->addRedirect('users/about', 'users/profile'); diff --git a/user_guide_src/source/incoming/routing/016.php b/user_guide_src/source/incoming/routing/016.php new file mode 100644 index 000000000000..8c770fd05f24 --- /dev/null +++ b/user_guide_src/source/incoming/routing/016.php @@ -0,0 +1,6 @@ +group('admin', function ($routes) { + $routes->get('users', 'Admin\Users::index'); + $routes->get('blog', 'Admin\Blog::index'); +}); diff --git a/user_guide_src/source/incoming/routing/017.php b/user_guide_src/source/incoming/routing/017.php new file mode 100644 index 000000000000..678e90700e74 --- /dev/null +++ b/user_guide_src/source/incoming/routing/017.php @@ -0,0 +1,5 @@ +group('api', ['namespace' => 'App\API\v1'], function ($routes) { + $routes->resource('users'); +}); diff --git a/user_guide_src/source/incoming/routing/018.php b/user_guide_src/source/incoming/routing/018.php new file mode 100644 index 000000000000..395ddfe6c8c8 --- /dev/null +++ b/user_guide_src/source/incoming/routing/018.php @@ -0,0 +1,5 @@ +group('api', ['filter' => 'api-auth'], function ($routes) { + $routes->resource('users'); +}); diff --git a/user_guide_src/source/incoming/routing/019.php b/user_guide_src/source/incoming/routing/019.php new file mode 100644 index 000000000000..08169acec275 --- /dev/null +++ b/user_guide_src/source/incoming/routing/019.php @@ -0,0 +1,7 @@ +group('admin', function ($routes) { + $routes->group('users', function ($routes) { + $routes->get('list', 'Admin\Users::list'); + }); +}); diff --git a/user_guide_src/source/incoming/routing/020.php b/user_guide_src/source/incoming/routing/020.php new file mode 100644 index 000000000000..d7624ddc6d5c --- /dev/null +++ b/user_guide_src/source/incoming/routing/020.php @@ -0,0 +1,7 @@ +group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { + $routes->get('login', 'AuthController::login', ['as' => 'login']); + $routes->post('login', 'AuthController::attemptLogin'); + $routes->get('logout', 'AuthController::logout'); +}); diff --git a/user_guide_src/source/incoming/routing/021.php b/user_guide_src/source/incoming/routing/021.php new file mode 100644 index 000000000000..69a4c184ab36 --- /dev/null +++ b/user_guide_src/source/incoming/routing/021.php @@ -0,0 +1,5 @@ +environment('development', function ($routes) { + $routes->get('builder', 'Tools\Builder::index'); +}); diff --git a/user_guide_src/source/incoming/routing/022.php b/user_guide_src/source/incoming/routing/022.php new file mode 100644 index 000000000000..0af87a58c3b5 --- /dev/null +++ b/user_guide_src/source/incoming/routing/022.php @@ -0,0 +1,8 @@ +get('users/(:num)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2'); + +// Generate the relative URL to link to user ID 15, gallery 12 +// Generates: /users/15/gallery/12 +View Gallery diff --git a/user_guide_src/source/incoming/routing/023-2.php b/user_guide_src/source/incoming/routing/023-2.php new file mode 100644 index 000000000000..e2a3784f335f --- /dev/null +++ b/user_guide_src/source/incoming/routing/023-2.php @@ -0,0 +1,3 @@ +add('products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/023.php b/user_guide_src/source/incoming/routing/023.php new file mode 100644 index 000000000000..5469c79db91a --- /dev/null +++ b/user_guide_src/source/incoming/routing/023.php @@ -0,0 +1,8 @@ +get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); + +// Generate the relative URL to link to user ID 15, gallery 12 +// Generates: /users/15/gallery/12 +View Gallery diff --git a/user_guide_src/source/incoming/routing/024.php b/user_guide_src/source/incoming/routing/024.php new file mode 100644 index 000000000000..7351142dea77 --- /dev/null +++ b/user_guide_src/source/incoming/routing/024.php @@ -0,0 +1,5 @@ +post('products', 'Product::feature'); +$routes->put('products/1', 'Product::feature'); +$routes->delete('products/1', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/025.php b/user_guide_src/source/incoming/routing/025.php new file mode 100644 index 000000000000..a071f75cd156 --- /dev/null +++ b/user_guide_src/source/incoming/routing/025.php @@ -0,0 +1,3 @@ +match(['get', 'put'], 'products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/026.php b/user_guide_src/source/incoming/routing/026.php new file mode 100644 index 000000000000..a82d57ebc5c7 --- /dev/null +++ b/user_guide_src/source/incoming/routing/026.php @@ -0,0 +1,3 @@ +cli('migrate', 'App\Database::migrate'); diff --git a/user_guide_src/source/incoming/routing/027.php b/user_guide_src/source/incoming/routing/027.php new file mode 100644 index 000000000000..31c1dda07a70 --- /dev/null +++ b/user_guide_src/source/incoming/routing/027.php @@ -0,0 +1,14 @@ +add('from', 'to', $options); +$routes->get('from', 'to', $options); +$routes->post('from', 'to', $options); +$routes->put('from', 'to', $options); +$routes->head('from', 'to', $options); +$routes->options('from', 'to', $options); +$routes->delete('from', 'to', $options); +$routes->patch('from', 'to', $options); +$routes->match(['get', 'put'], 'from', 'to', $options); +$routes->resource('photos', $options); +$routes->map($array, $options); +$routes->group('name', $options, function ()); diff --git a/user_guide_src/source/incoming/routing/028.php b/user_guide_src/source/incoming/routing/028.php new file mode 100644 index 000000000000..ca1121e0786d --- /dev/null +++ b/user_guide_src/source/incoming/routing/028.php @@ -0,0 +1,3 @@ +get('admin',' AdminController::index', ['filter' => 'admin-auth']); diff --git a/user_guide_src/source/incoming/routing/029.php b/user_guide_src/source/incoming/routing/029.php new file mode 100644 index 000000000000..b50db49bd962 --- /dev/null +++ b/user_guide_src/source/incoming/routing/029.php @@ -0,0 +1,3 @@ +post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); diff --git a/user_guide_src/source/incoming/routing/030.php b/user_guide_src/source/incoming/routing/030.php new file mode 100644 index 000000000000..14d5142de2f0 --- /dev/null +++ b/user_guide_src/source/incoming/routing/030.php @@ -0,0 +1,3 @@ +get('admin',' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); diff --git a/user_guide_src/source/incoming/routing/031.php b/user_guide_src/source/incoming/routing/031.php new file mode 100644 index 000000000000..24cf6c5dbc2d --- /dev/null +++ b/user_guide_src/source/incoming/routing/031.php @@ -0,0 +1,3 @@ +get('admin',' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); diff --git a/user_guide_src/source/incoming/routing/032.php b/user_guide_src/source/incoming/routing/032.php new file mode 100644 index 000000000000..b992deb96ecf --- /dev/null +++ b/user_guide_src/source/incoming/routing/032.php @@ -0,0 +1,4 @@ +get('admin/users', 'Users::index', ['namespace' => 'Admin']); diff --git a/user_guide_src/source/incoming/routing/033.php b/user_guide_src/source/incoming/routing/033.php new file mode 100644 index 000000000000..5b415a50138b --- /dev/null +++ b/user_guide_src/source/incoming/routing/033.php @@ -0,0 +1,3 @@ +get('from', 'to', ['hostname' => 'accounts.example.com']); diff --git a/user_guide_src/source/incoming/routing/034.php b/user_guide_src/source/incoming/routing/034.php new file mode 100644 index 000000000000..32a74934eb3a --- /dev/null +++ b/user_guide_src/source/incoming/routing/034.php @@ -0,0 +1,4 @@ +get('from', 'to', ['subdomain' => 'media']); diff --git a/user_guide_src/source/incoming/routing/035.php b/user_guide_src/source/incoming/routing/035.php new file mode 100644 index 000000000000..0d0fd0e67fb4 --- /dev/null +++ b/user_guide_src/source/incoming/routing/035.php @@ -0,0 +1,4 @@ +get('from', 'to', ['subdomain' => '*']); diff --git a/user_guide_src/source/incoming/routing/036.php b/user_guide_src/source/incoming/routing/036.php new file mode 100644 index 000000000000..ec7fa680f65e --- /dev/null +++ b/user_guide_src/source/incoming/routing/036.php @@ -0,0 +1,6 @@ +get('users/(:num)', 'users/show/$1', ['offset' => 1]); + +// Creates: +$routes['users/(:num)'] = 'users/show/$2'; diff --git a/user_guide_src/source/incoming/routing/037.php b/user_guide_src/source/incoming/routing/037.php new file mode 100644 index 000000000000..29fc83e59f17 --- /dev/null +++ b/user_guide_src/source/incoming/routing/037.php @@ -0,0 +1,12 @@ +setPrioritize(); + +// App\Config\Routes +$routes->get('(.*)', 'Posts::index', ['priority' => 1]); + +// Modules\Acme\Config\Routes +$routes->get('admin', 'Admin::index'); + +// The "admin" route will now be processed before the wildcard router. diff --git a/user_guide_src/source/incoming/routing/038.php b/user_guide_src/source/incoming/routing/038.php new file mode 100644 index 000000000000..9465f4147e2c --- /dev/null +++ b/user_guide_src/source/incoming/routing/038.php @@ -0,0 +1,3 @@ +setPrioritize(false); diff --git a/user_guide_src/source/incoming/routing/039.php b/user_guide_src/source/incoming/routing/039.php new file mode 100644 index 000000000000..98aef9276f9d --- /dev/null +++ b/user_guide_src/source/incoming/routing/039.php @@ -0,0 +1,9 @@ +setDefaultNamespace(''); + +// Controller is \Users +$routes->get('users', 'Users::index'); + +// Controller is \Admin\Users +$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/040.php b/user_guide_src/source/incoming/routing/040.php new file mode 100644 index 000000000000..fbbbee2300df --- /dev/null +++ b/user_guide_src/source/incoming/routing/040.php @@ -0,0 +1,9 @@ +setDefaultNamespace('App'); + +// Controller is \App\Users +$routes->get('users', 'Users::index'); + +// Controller is \App\Admin\Users +$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/041.php b/user_guide_src/source/incoming/routing/041.php new file mode 100644 index 000000000000..5d17df8130d4 --- /dev/null +++ b/user_guide_src/source/incoming/routing/041.php @@ -0,0 +1,4 @@ +setDefaultController('Welcome'); diff --git a/user_guide_src/source/incoming/routing/042.php b/user_guide_src/source/incoming/routing/042.php new file mode 100644 index 000000000000..e926e651287d --- /dev/null +++ b/user_guide_src/source/incoming/routing/042.php @@ -0,0 +1,3 @@ +setDefaultMethod('listAll'); diff --git a/user_guide_src/source/incoming/routing/043.php b/user_guide_src/source/incoming/routing/043.php new file mode 100644 index 000000000000..31d49508ab86 --- /dev/null +++ b/user_guide_src/source/incoming/routing/043.php @@ -0,0 +1,3 @@ +setTranslateURIDashes(true); diff --git a/user_guide_src/source/incoming/routing/044.php b/user_guide_src/source/incoming/routing/044.php new file mode 100644 index 000000000000..c331102cd9f4 --- /dev/null +++ b/user_guide_src/source/incoming/routing/044.php @@ -0,0 +1,3 @@ +setAutoRoute(false); diff --git a/user_guide_src/source/incoming/routing/045.php b/user_guide_src/source/incoming/routing/045.php new file mode 100644 index 000000000000..1f3758e244d4 --- /dev/null +++ b/user_guide_src/source/incoming/routing/045.php @@ -0,0 +1,10 @@ +set404Override('App\Errors::show404'); + +// Will display a custom view +$routes->set404Override(function () +{ + echo view('my_errors/not_found.html'); +}); diff --git a/user_guide_src/source/incoming/routing/046.php b/user_guide_src/source/incoming/routing/046.php new file mode 100644 index 000000000000..e3dd9f60c989 --- /dev/null +++ b/user_guide_src/source/incoming/routing/046.php @@ -0,0 +1,7 @@ +setPrioritize(); + +// to disable +$routes->setPrioritize(false); diff --git a/user_guide_src/source/index.rst b/user_guide_src/source/index.rst index 3f337e5b1f2a..7cc3b84742c4 100644 --- a/user_guide_src/source/index.rst +++ b/user_guide_src/source/index.rst @@ -75,7 +75,6 @@ Handling Databases dbmgmt/index - ******************* Libraries & Helpers ******************* diff --git a/user_guide_src/source/installation/installing_composer.rst b/user_guide_src/source/installation/installing_composer.rst index 7133e2cb80bf..ddda93bccf72 100644 --- a/user_guide_src/source/installation/installing_composer.rst +++ b/user_guide_src/source/installation/installing_composer.rst @@ -173,7 +173,6 @@ Folders in your project after set up: - app, public, writable (when using ``--prefer-source``) - vendor/codeigniter4/framework/system - Translations Installation ========================= diff --git a/user_guide_src/source/installation/installing_manual.rst b/user_guide_src/source/installation/installing_manual.rst index ebd231cdb2cf..c51f0964272e 100644 --- a/user_guide_src/source/installation/installing_manual.rst +++ b/user_guide_src/source/installation/installing_manual.rst @@ -52,7 +52,6 @@ Structure Folders in your project after set up: app, public, system, writable - Translations Installation ========================= diff --git a/user_guide_src/source/installation/troubleshooting.rst b/user_guide_src/source/installation/troubleshooting.rst index 0da650bdf07c..9ae2b5ac843a 100644 --- a/user_guide_src/source/installation/troubleshooting.rst +++ b/user_guide_src/source/installation/troubleshooting.rst @@ -34,13 +34,15 @@ first step, open your **app/Config/App.php** file and look for the URI Protocol information. It will recommend that you try a couple of alternate settings. If it still doesn't work after you've tried this you'll need to force CodeIgniter to add a question mark to your URLs. To -do this open your **app/Config/App.php** file and change this:: +do this open your **app/Config/App.php** file and change this: - public $indexPage = 'index.php'; +.. literalinclude:: troubleshooting/001.php + :lines: 2- -To this:: +To this: - public $indexPage = 'index.php?'; +.. literalinclude:: troubleshooting/002.php + :lines: 2- The tutorial gives 404 errors everywhere :( ------------------------------------------- diff --git a/user_guide_src/source/installation/troubleshooting/001.php b/user_guide_src/source/installation/troubleshooting/001.php new file mode 100644 index 000000000000..54798c261dae --- /dev/null +++ b/user_guide_src/source/installation/troubleshooting/001.php @@ -0,0 +1,3 @@ + ['csrf'], - 'post' => ['csrf'], - ]; +.. literalinclude:: upgrade_415/001.php + :lines: 2- Protecting **GET** method needs only when you use ``form_open()`` auto-generation of CSRF field. diff --git a/user_guide_src/source/installation/upgrade_415/001.php b/user_guide_src/source/installation/upgrade_415/001.php new file mode 100644 index 000000000000..e2b03e79ba25 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_415/001.php @@ -0,0 +1,6 @@ + ['csrf'], + 'post' => ['csrf'], +]; diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index fa168b2627ed..21ae6101c158 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -11,7 +11,6 @@ Documentations - `Config Documentation CodeIgniter 3.X `_ - :doc:`Configuration Documentation CodeIgniter 4.X ` - What has been changed ===================== @@ -39,28 +38,13 @@ Code Example CodeIgniter Version 3.x ------------------------ -Path: **application/config**:: - - `_ - :doc:`Working with Databases Documentation CodeIgniter 4.X ` - What has been changed ===================== - The functionality in CI3 is basically the same as in CI4. @@ -42,26 +40,17 @@ Upgrade Guide - ``$this->db->join('comments', 'comments.id = blogs.id');`` to ``$builder->join('comments', 'comments.id = blogs.id');`` - ``$this->db->having('user_id', 45);`` to ``$builder->having('user_id', 45);`` - Code Example ============ CodeIgniter Version 3.x ------------------------ -:: - $query = $this->db->select('title') - ->where('id', $id) - ->limit(10, 20) - ->get('mytable'); +.. literalinclude:: upgrade_database/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $builder = $db->table('mytable'); - $query = $builder->select('title') - ->where('id', $id) - ->limit(10, 20) - ->get(); +.. literalinclude:: upgrade_database/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_database/001.php b/user_guide_src/source/installation/upgrade_database/001.php new file mode 100644 index 000000000000..5dd7b11a60e7 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_database/001.php @@ -0,0 +1,6 @@ +db->select('title') + ->where('id', $id) + ->limit(10, 20) + ->get('mytable'); diff --git a/user_guide_src/source/installation/upgrade_database/002.php b/user_guide_src/source/installation/upgrade_database/002.php new file mode 100644 index 000000000000..65fdc4c24d1b --- /dev/null +++ b/user_guide_src/source/installation/upgrade_database/002.php @@ -0,0 +1,8 @@ +table('mytable'); + +$query = $builder->select('title') + ->where('id', $id) + ->limit(10, 20) + ->get(); diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index af5e532262aa..155562ba4a1a 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -5,14 +5,12 @@ Upgrade Emails :local: :depth: 2 - Documentations ============== - `Email Documentation CodeIgniter 3.X `_ - :doc:`Email Documentation CodeIgniter 4.X ` - What has been changed ===================== - Only small things like the method names and the loading of the library have changed. @@ -29,32 +27,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - $this->load->library('email'); - - $this->email->from('your@example.com', 'Your Name'); - $this->email->to('someone@example.com'); - $this->email->cc('another@another-example.com'); - $this->email->bcc('them@their-example.com'); - $this->email->subject('Email Test'); - $this->email->message('Testing the email class.'); - - $this->email->send(); +.. literalinclude:: upgrade_emails/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $email = service('email'); - - $email->setFrom('your@example.com', 'Your Name'); - $email->setTo('someone@example.com'); - $email->setCC('another@another-example.com'); - $email->setBCC('them@their-example.com'); - - $email->setSubject('Email Test'); - $email->setMessage('Testing the email class.'); - $email->send(); +.. literalinclude:: upgrade_emails/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_emails/001.php b/user_guide_src/source/installation/upgrade_emails/001.php new file mode 100644 index 000000000000..e9144bb87f6e --- /dev/null +++ b/user_guide_src/source/installation/upgrade_emails/001.php @@ -0,0 +1,13 @@ +load->library('email'); + +$this->email->from('your@example.com', 'Your Name'); +$this->email->to('someone@example.com'); +$this->email->cc('another@another-example.com'); +$this->email->bcc('them@their-example.com'); + +$this->email->subject('Email Test'); +$this->email->message('Testing the email class.'); + +$this->email->send(); diff --git a/user_guide_src/source/installation/upgrade_emails/002.php b/user_guide_src/source/installation/upgrade_emails/002.php new file mode 100644 index 000000000000..f7873714bab5 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_emails/002.php @@ -0,0 +1,13 @@ +setFrom('your@example.com', 'Your Name'); +$email->setTo('someone@example.com'); +$email->setCC('another@another-example.com'); +$email->setBCC('them@their-example.com'); + +$email->setSubject('Email Test'); +$email->setMessage('Testing the email class.'); + +$email->send(); diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index d9a29af62650..5915ca00dca1 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -5,14 +5,12 @@ Upgrade Encryption :local: :depth: 2 - Documentations ============== - `Encryption Library Documentation CodeIgniter 3.X `_ - :doc:`Encryption Service Documentation CodeIgniter 4.X ` - What has been changed ===================== - The support for ``MCrypt`` has been dropped, as that has been deprecated as of PHP 7.2. @@ -27,25 +25,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - $this->load->library('encryption'); - - $plain_text = 'This is a plain-text message!'; - $ciphertext = $this->encryption->encrypt($plain_text); - - // Outputs: This is a plain-text message! - echo $this->encryption->decrypt($ciphertext); +.. literalinclude:: upgrade_encryption/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $encrypter = service('encrypter'); - - $plainText = 'This is a plain-text message!'; - $ciphertext = $encrypter->encrypt($plainText); - // Outputs: This is a plain-text message! - echo $encrypter->decrypt($ciphertext); +.. literalinclude:: upgrade_encryption/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_encryption/001.php b/user_guide_src/source/installation/upgrade_encryption/001.php new file mode 100644 index 000000000000..b20ba8aec855 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_encryption/001.php @@ -0,0 +1,9 @@ +load->library('encryption'); + +$plain_text = 'This is a plain-text message!'; +$ciphertext = $this->encryption->encrypt($plain_text); + +// Outputs: This is a plain-text message! +echo $this->encryption->decrypt($ciphertext); diff --git a/user_guide_src/source/installation/upgrade_encryption/002.php b/user_guide_src/source/installation/upgrade_encryption/002.php new file mode 100644 index 000000000000..91b00ee54e83 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_encryption/002.php @@ -0,0 +1,9 @@ +encrypt($plainText); + +// Outputs: This is a plain-text message! +echo $encrypter->decrypt($ciphertext); diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index 27bd74e19a74..f0eb3a24c405 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -5,7 +5,6 @@ Upgrade Working with Uploaded Files :local: :depth: 2 - Documentations ============== - `Output Class Documentation CodeIgniter 3.X `_ @@ -27,76 +26,10 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - load->helper(array('form', 'url')); - } - - public function index() - { - $this->load->view('upload_form', array('error' => ' ' )); - } - - public function do_upload() - { - $config['upload_path'] = './uploads/'; - $config['allowed_types'] = 'png|jpg|gif'; - $config['max_size'] = 100; - $config['max_width'] = 1024; - $config['max_height'] = 768; - - $this->load->library('upload', $config); - - if (! $this->upload->do_upload('userfile')) { - $error = array('error' => $this->upload->display_errors()); - $this->load->view('upload_form', $error); - } else { - $data = array('upload_data' => $this->upload->data()); - - $this->load->view('upload_success', $data); - } - } - } +.. literalinclude:: upgrade_file_upload/001.php CodeIgniter Version 4.x ----------------------- -:: - - ' ']); - } - - public function do_upload() - { - $this->validate([ - 'userfile' => 'uploaded[userfile]|max_size[userfile,100]' - . '|mime_in[userfile,image/png,image/jpg,image/gif]' - . '|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]' - ]); - - $file = $this->request->getFile('userfile'); - - if (! $path = $file->store()) { - echo view('upload_form', ['error' => "upload failed"]); - } else { - $data = ['upload_file_path' => $path]; - echo view('upload_success', $data); - } - } - } +.. literalinclude:: upgrade_file_upload/002.php diff --git a/user_guide_src/source/installation/upgrade_file_upload/001.php b/user_guide_src/source/installation/upgrade_file_upload/001.php new file mode 100644 index 000000000000..f6bb20c64de3 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_file_upload/001.php @@ -0,0 +1,36 @@ +load->helper(array('form', 'url')); + } + + public function index() + { + $this->load->view('upload_form', array('error' => ' ' )); + } + + public function do_upload() + { + $config['upload_path'] = './uploads/'; + $config['allowed_types'] = 'png|jpg|gif'; + $config['max_size'] = 100; + $config['max_width'] = 1024; + $config['max_height'] = 768; + + $this->load->library('upload', $config); + + if (! $this->upload->do_upload('userfile')) { + $error = array('error' => $this->upload->display_errors()); + + $this->load->view('upload_form', $error); + } else { + $data = array('upload_data' => $this->upload->data()); + + $this->load->view('upload_success', $data); + } + } +} diff --git a/user_guide_src/source/installation/upgrade_file_upload/002.php b/user_guide_src/source/installation/upgrade_file_upload/002.php new file mode 100644 index 000000000000..29de4bf665dc --- /dev/null +++ b/user_guide_src/source/installation/upgrade_file_upload/002.php @@ -0,0 +1,30 @@ + ' ']); + } + + public function do_upload() + { + $this->validate([ + 'userfile' => 'uploaded[userfile]|max_size[userfile,100]' + . '|mime_in[userfile,image/png,image/jpg,image/gif]' + . '|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]' + ]); + + $file = $this->request->getFile('userfile'); + + if (! $path = $file->store()) { + echo view('upload_form', ['error' => "upload failed"]); + } else { + $data = ['upload_file_path' => $path]; + + echo view('upload_success', $data); + } + } +} diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst index 1fb70790ccbc..23e6aea3526b 100644 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -5,14 +5,12 @@ Upgrade HTML Tables :local: :depth: 2 - Documentations ============== - `HTML Table Documentation CodeIgniter 3.X `_ - :doc:`HTML Table Documentation CodeIgniter 4.X ` - What has been changed ===================== - Only small things like the method names and the loading of the library have changed. @@ -28,28 +26,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - $this->load->library('table'); - - $this->table->set_heading('Name', 'Color', 'Size'); - $this->table->add_row('Fred', 'Blue', 'Small'); - $this->table->add_row('Mary', 'Red', 'Large'); - $this->table->add_row('John', 'Green', 'Medium'); - - echo $this->table->generate(); +.. literalinclude:: upgrade_html_tables/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $table = new \CodeIgniter\View\Table(); - - $table->setHeading('Name', 'Color', 'Size'); - - $table->addRow('Fred', 'Blue', 'Small'); - $table->addRow('Mary', 'Red', 'Large'); - $table->addRow('John', 'Green', 'Medium'); - echo $table->generate(); +.. literalinclude:: upgrade_html_tables/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_html_tables/001.php b/user_guide_src/source/installation/upgrade_html_tables/001.php new file mode 100644 index 000000000000..5e607318c36f --- /dev/null +++ b/user_guide_src/source/installation/upgrade_html_tables/001.php @@ -0,0 +1,11 @@ +load->library('table'); + +$this->table->set_heading('Name', 'Color', 'Size'); + +$this->table->add_row('Fred', 'Blue', 'Small'); +$this->table->add_row('Mary', 'Red', 'Large'); +$this->table->add_row('John', 'Green', 'Medium'); + +echo $this->table->generate(); diff --git a/user_guide_src/source/installation/upgrade_html_tables/002.php b/user_guide_src/source/installation/upgrade_html_tables/002.php new file mode 100644 index 000000000000..0d0679305409 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_html_tables/002.php @@ -0,0 +1,11 @@ +setHeading('Name', 'Color', 'Size'); + +$table->addRow('Fred', 'Blue', 'Small'); +$table->addRow('Mary', 'Red', 'Large'); +$table->addRow('John', 'Green', 'Medium'); + +echo $table->generate(); diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index 8362b711aa3f..3fec8c15cce0 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -5,23 +5,22 @@ Upgrade Localization :local: :depth: 2 - Documentations ============== - `Language Documentation CodeIgniter 3.X `_ - :doc:`Localization Documentation CodeIgniter 4.X ` - What has been changed ===================== - In CI4 the language files return the language lines as array. Upgrade Guide ============= -1. Specify the default language in **Config/App.php**:: +1. Specify the default language in **Config/App.php**: - public $defaultLocale = 'en'; + .. literalinclude:: upgrade_localization/001.php + :lines: 2- 2. Now move your language files to **app/Language/**. 3. After that you have to change the syntax within the language files. Below in the Code Example you will see how the language array within the file should look like. @@ -33,34 +32,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - // error.php - $lang['error_email_missing'] = 'You must submit an email address'; - $lang['error_url_missing'] = 'You must submit a URL'; - $lang['error_username_missing'] = 'You must submit a username'; - ... - - $this->lang->load('error', $lang); - echo $this->lang->line('error_email_missing'); +.. literalinclude:: upgrade_localization/002.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - // Errors.php - return [ - 'errorEmailMissing' => 'You must submit an email address', - 'errorURLMissing' => 'You must submit a URL', - 'errorUsernameMissing' => 'You must submit a username', - 'nested' => [ - 'error' => [ - 'message' => 'A specific error message', - ], - ], - ]; - - ... - echo lang('Errors.errorEmailMissing'); +.. literalinclude:: upgrade_localization/003.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_localization/001.php b/user_guide_src/source/installation/upgrade_localization/001.php new file mode 100644 index 000000000000..c3b3de65be20 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_localization/001.php @@ -0,0 +1,3 @@ +lang->load('error', $lang); +echo $this->lang->line('error_email_missing'); diff --git a/user_guide_src/source/installation/upgrade_localization/003.php b/user_guide_src/source/installation/upgrade_localization/003.php new file mode 100644 index 000000000000..e0149516841d --- /dev/null +++ b/user_guide_src/source/installation/upgrade_localization/003.php @@ -0,0 +1,17 @@ + 'You must submit an email address', + 'errorURLMissing' => 'You must submit a URL', + 'errorUsernameMissing' => 'You must submit a username', + 'nested' => [ + 'error' => [ + 'message' => 'A specific error message', + ], + ], +]; + +... + +echo lang('Errors.errorEmailMissing'); diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index cf9b7c951511..07dc32e96675 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -51,82 +51,16 @@ Code Example CodeIgniter Version 3.x ------------------------ -Path: **application/migrations**:: - - dbforge->add_field(array( - 'blog_id' => array( - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true, - ), - 'blog_title' => array( - 'type' => 'VARCHAR', - 'constraint' => '100', - ), - 'blog_description' => array( - 'type' => 'TEXT', - 'null' => true, - ), - )); - $this->dbforge->add_key('blog_id', true); - $this->dbforge->create_table('blog'); - } - - public function down() - { - $this->dbforge->drop_table('blog'); - } - } +Path: **application/migrations**: + +.. literalinclude:: upgrade_migrations/001.php CodeIgniter Version 4.x ----------------------- -Path: **app/Database/Migrations**:: - - forge->addField([ - 'blog_id' => [ - 'type' => 'INT', - 'constraint' => 5, - 'unsigned' => true, - 'auto_increment' => true, - ], - 'blog_title' => [ - 'type' => 'VARCHAR', - 'constraint' => '100', - ], - 'blog_description' => [ - 'type' => 'TEXT', - 'null' => true, - ], - ]); - $this->forge->addKey('blog_id', true); - $this->forge->createTable('blog'); - } - - public function down() - { - $this->forge->dropTable('blog'); - } - } +Path: **app/Database/Migrations**: + +.. literalinclude:: upgrade_migrations/002.php Search & Replace ================ diff --git a/user_guide_src/source/installation/upgrade_migrations/001.php b/user_guide_src/source/installation/upgrade_migrations/001.php new file mode 100644 index 000000000000..2437a8d5fa99 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_migrations/001.php @@ -0,0 +1,33 @@ +dbforge->add_field(array( + 'blog_id' => array( + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => true, + 'auto_increment' => true, + ), + 'blog_title' => array( + 'type' => 'VARCHAR', + 'constraint' => '100', + ), + 'blog_description' => array( + 'type' => 'TEXT', + 'null' => true, + ), + )); + $this->dbforge->add_key('blog_id', true); + $this->dbforge->create_table('blog'); + } + + public function down() + { + $this->dbforge->drop_table('blog'); + } +} diff --git a/user_guide_src/source/installation/upgrade_migrations/002.php b/user_guide_src/source/installation/upgrade_migrations/002.php new file mode 100644 index 000000000000..3f73906231f1 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_migrations/002.php @@ -0,0 +1,35 @@ +forge->addField([ + 'blog_id' => [ + 'type' => 'INT', + 'constraint' => 5, + 'unsigned' => true, + 'auto_increment' => true, + ], + 'blog_title' => [ + 'type' => 'VARCHAR', + 'constraint' => '100', + ], + 'blog_description' => [ + 'type' => 'TEXT', + 'null' => true, + ], + ]); + $this->forge->addKey('blog_id', true); + $this->forge->createTable('blog'); + } + + public function down() + { + $this->forge->dropTable('blog'); + } +} diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst index dce4dd31377a..1b01819d9455 100644 --- a/user_guide_src/source/installation/upgrade_models.rst +++ b/user_guide_src/source/installation/upgrade_models.rst @@ -11,7 +11,6 @@ Documentations - `Model Documentation CodeIgniter 3.X `_ - :doc:`Model Documentation CodeIgniter 4.X ` - What has been changed ===================== @@ -41,36 +40,15 @@ Code Example CodeIgniter Version 3.x ------------------------ -Path: **application/models**:: - - db->insert('user_contacts', array( - 'name' => $name, - 'address' => $address, - 'email' => $email, - )); - } - } +.. literalinclude:: upgrade_models/001.php CodeIgniter Version 4.x ----------------------- -Path: **app/Models**:: - - insert()`` method because this method is built-in since CI4. diff --git a/user_guide_src/source/installation/upgrade_models/001.php b/user_guide_src/source/installation/upgrade_models/001.php new file mode 100644 index 000000000000..1ab3917c6a7f --- /dev/null +++ b/user_guide_src/source/installation/upgrade_models/001.php @@ -0,0 +1,13 @@ +db->insert('user_contacts', array( + 'name' => $name, + 'address' => $address, + 'email' => $email, + )); + } +} diff --git a/user_guide_src/source/installation/upgrade_models/002.php b/user_guide_src/source/installation/upgrade_models/002.php new file mode 100644 index 000000000000..0d7882ed2f52 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_models/002.php @@ -0,0 +1,10 @@ +`_ - :doc:`Pagination Documentation CodeIgniter 4.X ` - What has been changed ===================== - You have to change the views and also the controller in order to use the new pagination library. @@ -30,35 +28,17 @@ Upgrade Guide - You can use the built-in ``paginate()`` method on every Model. Have a look at the code example below to see how you setup the pagination on a specific model. - Code Example ============ CodeIgniter Version 3.x ------------------------ -:: - - $this->load->library('pagination'); - $config['base_url'] = base_url().'users/index/'; - $config['total_rows'] = $this->db->count_all('users'); - $config['per_page'] = 10; - $config['uri_segment'] = 3; - $config['attributes'] = array('class' => 'pagination-link'); - $this->pagination->initialize($config); - $data['users'] = $this->user_model->get_users(FALSE, $config['per_page'], $offset); - - $this->load->view('posts/index', $data); +.. literalinclude:: upgrade_pagination/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $model = new \App\Models\UserModel(); - - $data = [ - 'users' => $model->paginate(10), - 'pager' => $model->pager, - ]; - echo view('users/index', $data); +.. literalinclude:: upgrade_pagination/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_pagination/001.php b/user_guide_src/source/installation/upgrade_pagination/001.php new file mode 100644 index 000000000000..37a6f849c67c --- /dev/null +++ b/user_guide_src/source/installation/upgrade_pagination/001.php @@ -0,0 +1,13 @@ +load->library('pagination'); +$config['base_url'] = base_url().'users/index/'; +$config['total_rows'] = $this->db->count_all('users'); +$config['per_page'] = 10; +$config['uri_segment'] = 3; +$config['attributes'] = array('class' => 'pagination-link'); +$this->pagination->initialize($config); + +$data['users'] = $this->user_model->get_users(FALSE, $config['per_page'], $offset); + +$this->load->view('posts/index', $data); diff --git a/user_guide_src/source/installation/upgrade_pagination/002.php b/user_guide_src/source/installation/upgrade_pagination/002.php new file mode 100644 index 000000000000..fa1b373a5fc6 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_pagination/002.php @@ -0,0 +1,10 @@ + $model->paginate(10), + 'pager' => $model->pager, +]; + +echo view('users/index', $data); diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index 4518836371c9..9af660e35097 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -5,7 +5,6 @@ Upgrade HTTP Responses :local: :depth: 2 - Documentations ============== - `Output Class Documentation CodeIgniter 3.X `_ @@ -25,22 +24,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - $this->output->set_status_header(404); - - ... - $this->output - ->set_content_type('application/json') - ->set_output(json_encode(array('foo' => 'bar'))); +.. literalinclude:: upgrade_responses/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $this->response->setStatusCode(404); - - ... - return $this->response->setJSON(['foo' => 'bar']); +.. literalinclude:: upgrade_responses/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_responses/001.php b/user_guide_src/source/installation/upgrade_responses/001.php new file mode 100644 index 000000000000..f837ab8b6c3b --- /dev/null +++ b/user_guide_src/source/installation/upgrade_responses/001.php @@ -0,0 +1,9 @@ +output->set_status_header(404); + +... + +$this->output + ->set_content_type('application/json') + ->set_output(json_encode(array('foo' => 'bar'))); diff --git a/user_guide_src/source/installation/upgrade_responses/002.php b/user_guide_src/source/installation/upgrade_responses/002.php new file mode 100644 index 000000000000..e84279cf273c --- /dev/null +++ b/user_guide_src/source/installation/upgrade_responses/002.php @@ -0,0 +1,7 @@ +response->setStatusCode(404); + +... + +return $this->response->setJSON(['foo' => 'bar']); diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index b3fe276d6fcc..533826babd29 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -5,14 +5,12 @@ Upgrade Routing :local: :depth: 2 - Documentations ============== - `URI Routing Documentation CodeIgniter 3.X `_ - :doc:`URI Routing Documentation CodeIgniter 4.X ` - What has been changed ===================== - In CI4 the routing is no longer configured by setting the routes as array. @@ -30,46 +28,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -Path: **application/config/routes.php**:: - - add('posts/index', 'Posts::index'); - $routes->add('teams/create', 'Teams::create'); - $routes->add('teams/update', 'Teams::update'); +Path: **app/Config/Routes.php**: - $routes->add('posts/create', 'Posts::create'); - $routes->add('posts/update', 'Posts::update'); - $routes->add('drivers/create', 'Drivers::create'); - $routes->add('drivers/update', 'Drivers::update'); - $routes->add('posts/(:any)', 'Posts::view/$1'); +.. literalinclude:: upgrade_routing/002.php diff --git a/user_guide_src/source/installation/upgrade_routing/001.php b/user_guide_src/source/installation/upgrade_routing/001.php new file mode 100644 index 000000000000..31875312f013 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_routing/001.php @@ -0,0 +1,12 @@ +add('posts/index', 'Posts::index'); +$routes->add('teams/create', 'Teams::create'); +$routes->add('teams/update', 'Teams::update'); + +$routes->add('posts/create', 'Posts::create'); +$routes->add('posts/update', 'Posts::update'); +$routes->add('drivers/create', 'Drivers::create'); +$routes->add('drivers/update', 'Drivers::update'); +$routes->add('posts/(:any)', 'Posts::view/$1'); diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index ad1fc80e945b..6fbdbc2428a6 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -5,7 +5,6 @@ Upgrade Security :local: :depth: 2 - Documentations ============== @@ -21,14 +20,10 @@ What has been changed Upgrade Guide ============= -1. To enable CSRF protection in CI4 you have to enable it in **app/Config/Filters.php**:: +1. To enable CSRF protection in CI4 you have to enable it in **app/Config/Filters.php**: - public $globals = [ - 'before' => [ - //'honeypot', - 'csrf', - ] - ]; + .. literalinclude:: upgrade_security/001.php + :lines: 2- 2. Within your HTML forms you have to remove the CSRF input field which looks similar to ````. 3. Now, within your HTML forms you have to add ```` somewhere in the form body, unless you are using ``form_open()``. @@ -38,23 +33,9 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - $csrf = array( - 'name' => $this->security->get_csrf_token_name(), - 'hash' => $this->security->get_csrf_hash() - ); - ... - -
    - - - - - - - +.. literalinclude:: upgrade_security/002.php + :lines: 2- CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_security/001.php b/user_guide_src/source/installation/upgrade_security/001.php new file mode 100644 index 000000000000..d1bc3788b2ce --- /dev/null +++ b/user_guide_src/source/installation/upgrade_security/001.php @@ -0,0 +1,8 @@ + [ + //'honeypot', + 'csrf', + ] +]; diff --git a/user_guide_src/source/installation/upgrade_security/002.php b/user_guide_src/source/installation/upgrade_security/002.php new file mode 100644 index 000000000000..0419285423b0 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_security/002.php @@ -0,0 +1,17 @@ + $this->security->get_csrf_token_name(), + 'hash' => $this->security->get_csrf_hash() +); + +... + +
    + + + + + + + diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index 6785907ba061..447703854284 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -5,14 +5,12 @@ Upgrade Sessions :local: :depth: 2 - Documentations ============== - `Session Library Documentation CodeIgniter 3.X `_ - :doc:`Session Library Documentation CodeIgniter 4.X ` - What has been changed ===================== - Only small things like the method names and the loading of the library have changed. @@ -32,21 +30,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - $this->load->library('session'); - - $_SESSION['item']; - $this->session->item; - $this->session->userdata('item'); +.. literalinclude:: upgrade_sessions/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $session = session(); - $_SESSION['item']; - $session->get('item'); - $session->item; - session('item'); +.. literalinclude:: upgrade_sessions/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_sessions/001.php b/user_guide_src/source/installation/upgrade_sessions/001.php new file mode 100644 index 000000000000..73e69c5dfa9f --- /dev/null +++ b/user_guide_src/source/installation/upgrade_sessions/001.php @@ -0,0 +1,7 @@ +load->library('session'); + +$_SESSION['item']; +$this->session->item; +$this->session->userdata('item'); diff --git a/user_guide_src/source/installation/upgrade_sessions/002.php b/user_guide_src/source/installation/upgrade_sessions/002.php new file mode 100644 index 000000000000..0bfeeb7f9487 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_sessions/002.php @@ -0,0 +1,8 @@ +get('item'); +$session->item; +session('item'); diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 1a71ef0b5065..54b7281d4839 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -5,14 +5,12 @@ Upgrade Validations :local: :depth: 2 - Documentations of Library ========================= - `Form Validation Documentation CodeIgniter 3.X `_ - :doc:`Validation Documentation CodeIgniter 4.X ` - What has been changed ===================== - If you want to change validation error display, you have to set CI4 validation View templates. @@ -33,13 +31,10 @@ Upgrade Guide - ``if ($this->form_validation->run() == FALSE)`` to ``if (! $this->validate([]))`` - ``$this->load->view('myform');`` to ``echo view('myform', ['validation' => $this->validator,]);`` -3. You have to change the validation rules. The new syntax is to set the rules as array in the controller:: +3. You have to change the validation rules. The new syntax is to set the rules as array in the controller: - $isValid = $this->validate([ - 'name' => 'required|min_length[3]', - 'email' => 'required|valid_email', - 'phone' => 'required|numeric|max_length[10]' - ]); + .. literalinclude:: upgrade_validations/001.php + :lines: 2- Code Example ============ @@ -77,27 +72,9 @@ Path: **application/views**:: -Path: **application/controllers**:: - - load->helper(array('form', 'url')); - - $this->load->library('form_validation'); +Path: **application/controllers**: - // Set validation rules - - if ($this->form_validation->run() == FALSE) { - $this->load->view('myform'); - } else { - $this->load->view('formsuccess'); - } - } - } +.. literalinclude:: upgrade_validations/002.php CodeIgniter Version 4.x ----------------------- @@ -132,28 +109,6 @@ Path: **app/Views**:: -Path: **app/Controllers**:: - - validate([ - // Validation rules - ])) { - echo view('myform', [ - 'validation' => $this->validator, - ]); - } else { - echo view('formsuccess'); - } - } - } +.. literalinclude:: upgrade_validations/003.php diff --git a/user_guide_src/source/installation/upgrade_validations/001.php b/user_guide_src/source/installation/upgrade_validations/001.php new file mode 100644 index 000000000000..f9730b8f3e3f --- /dev/null +++ b/user_guide_src/source/installation/upgrade_validations/001.php @@ -0,0 +1,7 @@ +validate([ + 'name' => 'required|min_length[3]', + 'email' => 'required|valid_email', + 'phone' => 'required|numeric|max_length[10]' +]); diff --git a/user_guide_src/source/installation/upgrade_validations/002.php b/user_guide_src/source/installation/upgrade_validations/002.php new file mode 100644 index 000000000000..3c6505455d91 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_validations/002.php @@ -0,0 +1,19 @@ +load->helper(array('form', 'url')); + + $this->load->library('form_validation'); + + // Set validation rules + + if ($this->form_validation->run() == FALSE) { + $this->load->view('myform'); + } else { + $this->load->view('formsuccess'); + } + } +} diff --git a/user_guide_src/source/installation/upgrade_validations/003.php b/user_guide_src/source/installation/upgrade_validations/003.php new file mode 100644 index 000000000000..ddbed1ede5fc --- /dev/null +++ b/user_guide_src/source/installation/upgrade_validations/003.php @@ -0,0 +1,23 @@ +validate([ + // Validation rules + ])) { + echo view('myform', [ + 'validation' => $this->validator, + ]); + } else { + echo view('formsuccess'); + } + } +} diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index b2c57adbf0e6..4931eb467ede 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -5,14 +5,12 @@ Upgrade View Parser :local: :depth: 2 - Documentations ============== - `Template Parser Documentation CodeIgniter 3.X `_ - :doc:`View Parser Documentation CodeIgniter 4.X ` - What has been changed ===================== - You have to change the implementation and loading of the Parser Library. @@ -28,28 +26,12 @@ Code Example CodeIgniter Version 3.x ------------------------ -:: - - $this->load->library('parser'); - $data = array( - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading' - ); - - $this->parser - ->parse('blog_template', $data); +.. literalinclude:: upgrade_view_parser/001.php + :lines: 2- CodeIgniter Version 4.x ----------------------- -:: - - $parser = service('parser'); - - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading' - ]; - echo $parser->setData($data) - ->render('blog_template'); +.. literalinclude:: upgrade_view_parser/002.php + :lines: 2- diff --git a/user_guide_src/source/installation/upgrade_view_parser/001.php b/user_guide_src/source/installation/upgrade_view_parser/001.php new file mode 100644 index 000000000000..c44e00968315 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_view_parser/001.php @@ -0,0 +1,11 @@ +load->library('parser'); + +$data = array( + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading' +); + +$this->parser + ->parse('blog_template', $data); diff --git a/user_guide_src/source/installation/upgrade_view_parser/002.php b/user_guide_src/source/installation/upgrade_view_parser/002.php new file mode 100644 index 000000000000..2f4607092635 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_view_parser/002.php @@ -0,0 +1,11 @@ + 'My Blog Title', + 'blog_heading' => 'My Blog Heading' +]; + +echo $parser->setData($data) + ->render('blog_template'); diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index 0aef96b113e8..773ad6541931 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -34,45 +34,13 @@ Code Example CodeIgniter Version 3.x ------------------------ -Path: **application/views**:: +Path: **application/views**: - - - <?php echo $title; ?> - - -

    - -

    My Todo List

    - -
      - -
    • - -
    - - - +.. literalinclude:: upgrade_views/001.php CodeIgniter Version 4.x ----------------------- -Path: **app/Views**:: - - - - <?= esc($title) ?> - - -

    - -

    My Todo List

    - -
      - -
    • - -
    +Path: **app/Views**: - - +.. literalinclude:: upgrade_views/002.php diff --git a/user_guide_src/source/installation/upgrade_views/001.php b/user_guide_src/source/installation/upgrade_views/001.php new file mode 100644 index 000000000000..f0b7c348666d --- /dev/null +++ b/user_guide_src/source/installation/upgrade_views/001.php @@ -0,0 +1,17 @@ + + + <?php echo $title; ?> + + +

    + +

    My Todo List

    + +
      + +
    • + +
    + + + diff --git a/user_guide_src/source/installation/upgrade_views/002.php b/user_guide_src/source/installation/upgrade_views/002.php new file mode 100644 index 000000000000..d4d043fea310 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_views/002.php @@ -0,0 +1,17 @@ + + + <?= esc($title) ?> + + +

    + +

    My Todo List

    + +
      + +
    • + +
    + + + diff --git a/user_guide_src/source/libraries/caching.rst b/user_guide_src/source/libraries/caching.rst index cc9049ee9a5d..6f4fb8071c74 100644 --- a/user_guide_src/source/libraries/caching.rst +++ b/user_guide_src/source/libraries/caching.rst @@ -17,23 +17,13 @@ Example Usage The following example shows a common usage pattern within your controllers. -:: +.. literalinclude:: caching/001.php + :lines: 2- - if (! $foo = cache('foo')) { - echo 'Saving to the cache!
    '; - $foo = 'foobarbaz!'; +You can grab an instance of the cache engine directly through the Services class: - // Save into the cache for 5 minutes - cache()->save('foo', $foo, 300); - } - - echo $foo; - -You can grab an instance of the cache engine directly through the Services class:: - - $cache = \Config\Services::cache(); - - $foo = $cache->get('foo'); +.. literalinclude:: caching/002.php + :lines: 2- ===================== Configuring the Cache @@ -94,9 +84,10 @@ Class Reference This method will attempt to fetch an item from the cache store. If the item does not exist, the method will return null. - Example:: + Example: - $foo = $cache->get('my_cached_item'); + .. literalinclude:: caching/003.php + :lines: 2- .. php:method:: remember(string $key, int $ttl, Closure $callback) @@ -121,9 +112,10 @@ Class Reference This method will save an item to the cache store. If saving fails, the method will return ``false``. - Example:: + Example: - $cache->save('cache_item_id', 'data_to_cache'); + .. literalinclude:: caching/004.php + :lines: 2- .. note:: The ``$raw`` parameter is only utilized by Memcache, in order to allow usage of ``increment()`` and ``decrement()``. @@ -137,9 +129,10 @@ Class Reference This method will delete a specific item from the cache store. If item deletion fails, the method will return false. - Example:: + Example: - $cache->delete('cache_item_id'); + .. literalinclude:: caching/005.php + :lines: 2- .. php:method:: deleteMatching($pattern): integer @@ -153,10 +146,10 @@ Class Reference .. important:: This method is only implemented for File, Redis and Predis handlers. Due to limitations, it couldn't be implemented for Memcached and Wincache handlers. - Example:: + Example: - $cache->deleteMatching('prefix_*'); // deletes all items of which keys start with "prefix_" - $cache->deleteMatching('*_suffix'); // deletes all items of which keys end with "_suffix" + .. literalinclude:: caching/006.php + :lines: 2- For more information on glob-style syntax, please see `Glob (programming) `_. @@ -170,11 +163,10 @@ Class Reference Performs atomic incrementation of a raw stored value. - Example:: + Example: - // 'iterator' has a value of 2 - $cache->increment('iterator'); // 'iterator' is now 3 - $cache->increment('iterator', 3); // 'iterator' is now 6 + .. literalinclude:: caching/007.php + :lines: 2- .. php:method:: decrement($key[, $offset = 1]): mixed @@ -185,11 +177,10 @@ Class Reference Performs atomic decrementation of a raw stored value. - Example:: + Example: - // 'iterator' has a value of 6 - $cache->decrement('iterator'); // 'iterator' is now 5 - $cache->decrement('iterator', 2); // 'iterator' is now 3 + .. literalinclude:: caching/008.php + :lines: 2- .. php:method:: clean() @@ -199,9 +190,10 @@ Class Reference This method will 'clean' the entire cache. If the deletion of the cache files fails, the method will return false. - Example:: + Example: - $cache->clean(); + .. literalinclude:: caching/009.php + :lines: 2- .. php:method:: getCacheInfo() @@ -210,9 +202,10 @@ Class Reference This method will return information on the entire cache. - Example:: + Example: - var_dump($cache->getCacheInfo()); + .. literalinclude:: caching/010.php + :lines: 2- .. note:: The information returned and the structure of the data is dependent on which adapter is being used. @@ -226,9 +219,10 @@ Class Reference This method will return detailed information on a specific item in the cache. - Example:: + Example: - var_dump($cache->getMetadata('my_cached_item')); + .. literalinclude:: caching/011.php + :lines: 2- .. note:: The information returned and the structure of the data is dependent on which adapter is being used. Some adapters (File, Memcached, Wincache) @@ -244,10 +238,10 @@ Class Reference This method is used by handler methods to check that keys are valid. It will throw an ``InvalidArgumentException`` for non-strings, invalid characters, and empty lengths. - Example:: - - $prefixedKey = BaseHandler::validateKey($key, $prefix); + Example: + .. literalinclude:: caching/012.php + :lines: 2- ******* Drivers @@ -267,14 +261,10 @@ directory to be really writable by the application. Memcached Caching ================= -Memcached servers can be specified in the cache configuration file. Available options are:: +Memcached servers can be specified in the cache configuration file. Available options are: - public $memcached = [ - 'host' => '127.0.0.1', - 'port' => 11211, - 'weight' => 1, - 'raw' => false, - ]; +.. literalinclude:: caching/013.php + :lines: 2- For more information on Memcached, please see `https://www.php.net/memcached `_. @@ -295,15 +285,10 @@ Redis Caching Redis is an in-memory key-value store which can operate in LRU cache mode. To use it, you need `Redis server and phpredis PHP extension `_. -Config options to connect to redis server stored in the cache configuration file. Available options are:: +Config options to connect to redis server stored in the cache configuration file. Available options are: - public $redis = [ - 'host' => '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, - 'database' => 0, - ]; +.. literalinclude:: caching/014.php + :lines: 2- For more information on Redis, please see `https://redis.io `_. diff --git a/user_guide_src/source/libraries/caching/001.php b/user_guide_src/source/libraries/caching/001.php new file mode 100644 index 000000000000..491746ba14b4 --- /dev/null +++ b/user_guide_src/source/libraries/caching/001.php @@ -0,0 +1,11 @@ +'; + $foo = 'foobarbaz!'; + + // Save into the cache for 5 minutes + cache()->save('foo', $foo, 300); +} + +echo $foo; diff --git a/user_guide_src/source/libraries/caching/002.php b/user_guide_src/source/libraries/caching/002.php new file mode 100644 index 000000000000..ed453264b505 --- /dev/null +++ b/user_guide_src/source/libraries/caching/002.php @@ -0,0 +1,5 @@ +get('foo'); diff --git a/user_guide_src/source/libraries/caching/003.php b/user_guide_src/source/libraries/caching/003.php new file mode 100644 index 000000000000..4913a816e5e2 --- /dev/null +++ b/user_guide_src/source/libraries/caching/003.php @@ -0,0 +1,3 @@ +get('my_cached_item'); diff --git a/user_guide_src/source/libraries/caching/004.php b/user_guide_src/source/libraries/caching/004.php new file mode 100644 index 000000000000..f343a5bee486 --- /dev/null +++ b/user_guide_src/source/libraries/caching/004.php @@ -0,0 +1,3 @@ +save('cache_item_id', 'data_to_cache'); diff --git a/user_guide_src/source/libraries/caching/005.php b/user_guide_src/source/libraries/caching/005.php new file mode 100644 index 000000000000..1d8a3b905588 --- /dev/null +++ b/user_guide_src/source/libraries/caching/005.php @@ -0,0 +1,3 @@ +delete('cache_item_id'); diff --git a/user_guide_src/source/libraries/caching/006.php b/user_guide_src/source/libraries/caching/006.php new file mode 100644 index 000000000000..1afc08644ace --- /dev/null +++ b/user_guide_src/source/libraries/caching/006.php @@ -0,0 +1,4 @@ +deleteMatching('prefix_*'); // deletes all items of which keys start with "prefix_" +$cache->deleteMatching('*_suffix'); // deletes all items of which keys end with "_suffix" diff --git a/user_guide_src/source/libraries/caching/007.php b/user_guide_src/source/libraries/caching/007.php new file mode 100644 index 000000000000..6256d6e0e721 --- /dev/null +++ b/user_guide_src/source/libraries/caching/007.php @@ -0,0 +1,5 @@ +increment('iterator'); // 'iterator' is now 3 +$cache->increment('iterator', 3); // 'iterator' is now 6 diff --git a/user_guide_src/source/libraries/caching/008.php b/user_guide_src/source/libraries/caching/008.php new file mode 100644 index 000000000000..4e74cbb0a47f --- /dev/null +++ b/user_guide_src/source/libraries/caching/008.php @@ -0,0 +1,5 @@ +decrement('iterator'); // 'iterator' is now 5 +$cache->decrement('iterator', 2); // 'iterator' is now 3 diff --git a/user_guide_src/source/libraries/caching/009.php b/user_guide_src/source/libraries/caching/009.php new file mode 100644 index 000000000000..a5a9e5725f23 --- /dev/null +++ b/user_guide_src/source/libraries/caching/009.php @@ -0,0 +1,3 @@ +clean(); diff --git a/user_guide_src/source/libraries/caching/010.php b/user_guide_src/source/libraries/caching/010.php new file mode 100644 index 000000000000..22a5cb08b8b9 --- /dev/null +++ b/user_guide_src/source/libraries/caching/010.php @@ -0,0 +1,3 @@ +getCacheInfo()); diff --git a/user_guide_src/source/libraries/caching/011.php b/user_guide_src/source/libraries/caching/011.php new file mode 100644 index 000000000000..1fedd92c28b4 --- /dev/null +++ b/user_guide_src/source/libraries/caching/011.php @@ -0,0 +1,3 @@ +getMetadata('my_cached_item')); diff --git a/user_guide_src/source/libraries/caching/012.php b/user_guide_src/source/libraries/caching/012.php new file mode 100644 index 000000000000..90395ed77429 --- /dev/null +++ b/user_guide_src/source/libraries/caching/012.php @@ -0,0 +1,3 @@ + '127.0.0.1', + 'port' => 11211, + 'weight' => 1, + 'raw' => false, +]; diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php new file mode 100644 index 000000000000..20dfb69ce9b0 --- /dev/null +++ b/user_guide_src/source/libraries/caching/014.php @@ -0,0 +1,9 @@ + '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'database' => 0, +]; diff --git a/user_guide_src/source/libraries/cookies.rst b/user_guide_src/source/libraries/cookies.rst index 86d36dec9a25..a5baea10ce1d 100644 --- a/user_guide_src/source/libraries/cookies.rst +++ b/user_guide_src/source/libraries/cookies.rst @@ -28,84 +28,24 @@ Creating Cookies There are currently four (4) ways to create a new ``Cookie`` value object. -:: - - use CodeIgniter\Cookie\Cookie; - use DateTime; - - // Using the constructor - $cookie = new Cookie( - 'remember_token', - 'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6', - [ - 'expires' => new DateTime('+2 hours'), - 'prefix' => '__Secure-', - 'path' => '/', - 'domain' => '', - 'secure' => true, - 'httponly' => true, - 'raw' => false, - 'samesite' => Cookie::SAMESITE_LAX, - ] - ); - - // Supplying a Set-Cookie header string - $cookie = Cookie::fromHeaderString( - 'remember_token=f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6; Path=/; Secure; HttpOnly; SameSite=Lax', - false, // raw - ); - - // Using the fluent builder interface - $cookie = (new Cookie('remember_token')) - ->withValue('f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6') - ->withPrefix('__Secure-') - ->withExpires(new DateTime('+2 hours')) - ->withPath('/') - ->withDomain('') - ->withSecure(true) - ->withHTTPOnly(true) - ->withSameSite(Cookie::SAMESITE_LAX); - - // Using the global function `cookie` which implicitly calls `new Cookie()` - $cookie = cookie('remember_token', 'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6'); +.. literalinclude:: cookies/001.php + :lines: 2- When constructing the ``Cookie`` object, only the ``name`` attribute is required. All other else are optional. If the optional attributes are not modified, their values will be filled up by the default values saved in the ``Cookie`` class. To override the defaults currently stored in the class, you can pass a ``Config\Cookie`` instance or an array of defaults to the static ``Cookie::setDefaults()`` method. -:: - - use CodeIgniter\Cookie\Cookie; - use Config\Cookie as CookieConfig; - - // pass in an Config\Cookie instance before constructing a Cookie class - Cookie::setDefaults(new CookieConfig()); - $cookie = new Cookie('login_token'); - - // pass in an array of defaults - $myDefaults = [ - 'expires' => 0, - 'samesite' => Cookie::SAMESITE_STRICT, - ]; - Cookie::setDefaults($myDefaults); - $cookie = new Cookie('login_token'); +.. literalinclude:: cookies/002.php + :lines: 2- Passing the ``Config\Cookie`` instance or an array to ``Cookie::setDefaults()`` will effectively overwrite your defaults and will persist until new defaults are passed. If you do not want this behavior but only want to change defaults for a limited time, you can take advantage of ``Cookie::setDefaults()`` return which returns the old defaults array. -:: - - use CodeIgniter\Cookie\Cookie; - use Config\Cookie as CookieConfig; - - $oldDefaults = Cookie::setDefaults(new CookieConfig()); - $cookie = new Cookie('my_token', 'muffins'); - - // return the old defaults - Cookie::setDefaults($oldDefaults); +.. literalinclude:: cookies/003.php + :lines: 2- ***************************** Accessing Cookie's Attributes @@ -113,48 +53,8 @@ Accessing Cookie's Attributes Once instantiated, you can easily access a ``Cookie``'s attribute by using one of its getter methods. -:: - - use CodeIgniter\Cookie\Cookie; - use DateTime; - use DateTimeZone; - - $cookie = new Cookie( - 'remember_token', - 'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6', - [ - 'expires' => new DateTime('2025-02-14 00:00:00', new DateTimeZone('UTC')), - 'prefix' => '__Secure-', - 'path' => '/', - 'domain' => '', - 'secure' => true, - 'httponly' => true, - 'raw' => false, - 'samesite' => Cookie::SAMESITE_LAX, - ] - ); - - $cookie->getName(); // 'remember_token' - $cookie->getPrefix(); // '__Secure-' - $cookie->getPrefixedName(); // '__Secure-remember_token' - $cookie->getExpiresTimestamp(); // Unix timestamp - $cookie->getExpiresString(); // 'Fri, 14-Feb-2025 00:00:00 GMT' - $cookie->isExpired(); // false - $cookie->getMaxAge(); // the difference from time() to expires - $cookie->isRaw(); // false - $cookie->isSecure(); // true - $cookie->getPath(); // '/' - $cookie->getDomain(); // '' - $cookie->isHTTPOnly(); // true - $cookie->getSameSite(); // 'Lax' - - // additional getter - $cookie->getId(); // '__Secure-remember_token;;/' - - // when using `setcookie()`'s alternative signature on PHP 7.3+ - // you can easily use the `getOptions()` method to supply the - // $options parameter - $cookie->getOptions(); +.. literalinclude:: cookies/004.php + :lines: 2- ***************** Immutable Cookies @@ -164,18 +64,8 @@ A new ``Cookie`` instance is an immutable value object representation of an HTTP modifying any of the instance's attributes will not affect the original instance. The modification **always** returns a new instance. You need to retain this new instance in order to use it. -:: - - use CodeIgniter\Cookie\Cookie; - - $cookie = new Cookie('login_token', 'admin'); - $cookie->getName(); // 'login_token' - - $cookie->withName('remember_token'); - $cookie->getName(); // 'login_token' - - $new = $cookie->withName('remember_token'); - $new->getName(); // 'remember_token' +.. literalinclude:: cookies/005.php + :lines: 2- ******************************** Validating a Cookie's Attributes @@ -232,13 +122,8 @@ If the SameSite is set to ``None`` you need to make sure that ``Secure`` is also When writing the SameSite attribute, the ``Cookie`` class accepts any of the values case-insensitively. You can also take advantage of the class's constants to make it not a hassle. -:: - - use CodeIgniter\Cookie\Cookie; - - Cookie::SAMESITE_LAX; // 'lax' - Cookie::SAMESITE_STRICT; // 'strict' - Cookie::SAMESITE_NONE; // 'none' +.. literalinclude:: cookies/006.php + :lines: 2- ********************** Using the Cookie Store @@ -247,36 +132,13 @@ Using the Cookie Store The ``CookieStore`` class represents an immutable collection of ``Cookie`` objects. The ``CookieStore`` instance can be accessed from the current ``Response`` object. -:: - - use Config\Services; - - $cookieStore = Services::response()->getCookieStore(); +.. literalinclude:: cookies/007.php + :lines: 2- CodeIgniter provides three (3) other ways to create a new instance of the ``CookieStore``. -:: - - use CodeIgniter\Cookie\Cookie; - use CodeIgniter\Cookie\CookieStore; - - // Passing an array of `Cookie` objects in the constructor - $store = new CookieStore([ - new Cookie('login_token'), - new Cookie('remember_token'), - ]); - - // Passing an array of `Set-Cookie` header strings - $store = CookieStore::fromCookieHeaders([ - 'remember_token=me; Path=/; SameSite=Lax', - 'login_token=admin; Path=/; SameSite=Lax', - ]); - - // using the global `cookies` function - $store = cookies([new Cookie('login_token')], false); - - // retrieving the `CookieStore` instance saved in our current `Response` object - $store = cookies(); +.. literalinclude:: cookies/008.php + :lines: 2- .. note:: When using the global ``cookies()`` function, the passed ``Cookie`` array will only be considered if the second argument, ``$getGlobal``, is set to ``false``. @@ -284,79 +146,36 @@ CodeIgniter provides three (3) other ways to create a new instance of the ``Cook Checking Cookies in Store ========================= -To check whether a ``Cookie`` object exists in the ``CookieStore`` instance, you can use several ways:: - - use CodeIgniter\Cookie\Cookie; - use CodeIgniter\Cookie\CookieStore; - use Config\Services; +To check whether a ``Cookie`` object exists in the ``CookieStore`` instance, you can use several ways: - // check if cookie is in the current cookie collection - $store = new CookieStore([ - new Cookie('login_token'), - new Cookie('remember_token'), - ]); - $store->has('login_token'); - - // check if cookie is in the current Response's cookie collection - cookies()->has('login_token'); - Services::response()->hasCookie('remember_token'); - - // using the cookie helper to check the current Response - // not available to v4.1.1 and lower - helper('cookie'); - has_cookie('login_token'); +.. literalinclude:: cookies/009.php + :lines: 2- Getting Cookies in Store ======================== -Retrieving a ``Cookie`` instance in a cookie collection is very easy:: - - use CodeIgniter\Cookie\Cookie; - use CodeIgniter\Cookie\CookieStore; - use Config\Services; - - // getting cookie in the current cookie collection - $store = new CookieStore([ - new Cookie('login_token'), - new Cookie('remember_token'), - ]); - $store->get('login_token'); - - // getting cookie in the current Response's cookie collection - cookies()->get('login_token'); - Services::response()->getCookie('remember_token'); +Retrieving a ``Cookie`` instance in a cookie collection is very easy: - // using the cookie helper to get cookie from the Response's cookie collection - helper('cookie'); - get_cookie('remember_token'); +.. literalinclude:: cookies/010.php + :lines: 2- When getting a ``Cookie`` instance directly from a ``CookieStore``, an invalid name will throw a ``CookieException``. -:: - - // throws CookieException - $store->get('unknown_cookie'); +.. literalinclude:: cookies/011.php + :lines: 2- When getting a ``Cookie`` instance from the current ``Response``'s cookie collection, an invalid name will just return ``null``. -:: - - cookies()->get('unknown_cookie'); // null +.. literalinclude:: cookies/012.php + :lines: 2- If no arguments are supplied in when getting cookies from the ``Response``, all ``Cookie`` objects in store will be displayed. -:: - - cookies()->get(); // array of Cookie objects - - // alternatively, you can use the display method - cookies()->display(); - - // or even from the Response - Services::response()->getCookies(); +.. literalinclude:: cookies/013.php + :lines: 2- .. note:: The helper function ``get_cookie()`` gets the cookie from the current ``Request`` object, not from ``Response``. This function checks the `$_COOKIE` array if that cookie is set and fetches it @@ -368,22 +187,8 @@ Adding/Removing Cookies in Store As previously mentioned, ``CookieStore`` objects are immutable. You need to save the modified instance in order to work on it. The original instance is left unchanged. -:: - - use CodeIgniter\Cookie\Cookie; - use CodeIgniter\Cookie\CookieStore; - use Config\Services; - - $store = new CookieStore([ - new Cookie('login_token'), - new Cookie('remember_token'), - ]); - - // adding a new Cookie instance - $new = $store->put(new Cookie('admin_token', 'yes')); - - // removing a Cookie instance - $new = $store->remove('login_token'); +.. literalinclude:: cookies/014.php + :lines: 2- .. note:: Removing a cookie from the store **DOES NOT** delete it from the browser. If you intend to delete a cookie *from the browser*, you must put an empty value @@ -393,17 +198,8 @@ When interacting with the cookies in store in the current ``Response`` object, y cookies without worrying the immutable nature of the cookie collection. The ``Response`` object will replace the instance with the modified instance. -:: - - use Config\Services; - - Services::response()->setCookie('admin_token', 'yes'); - Services::response()->deleteCookie('login_token'); - - // using the cookie helper - helper('cookie'); - set_cookie('admin_token', 'yes'); - delete_cookie('login_token'); +.. literalinclude:: cookies/015.php + :lines: 2- Dispatching Cookies in Store ============================ @@ -413,17 +209,8 @@ for you. However, if you really need to manually send cookies, you can use the ` in sending other headers, you need to make sure the headers are not yet sent by checking the value of ``headers_sent()``. -:: - - use CodeIgniter\Cookie\Cookie; - use CodeIgniter\Cookie\CookieStore; - - $store = new CookieStore([ - new Cookie('login_token'), - new Cookie('remember_token'), - ]); - - $store->dispatch(); // After dispatch, the collection is now empty. +.. literalinclude:: cookies/016.php + :lines: 2- ********************** Cookie Personalization diff --git a/user_guide_src/source/libraries/cookies/001.php b/user_guide_src/source/libraries/cookies/001.php new file mode 100644 index 000000000000..777e74f111f5 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/001.php @@ -0,0 +1,40 @@ + new DateTime('+2 hours'), + 'prefix' => '__Secure-', + 'path' => '/', + 'domain' => '', + 'secure' => true, + 'httponly' => true, + 'raw' => false, + 'samesite' => Cookie::SAMESITE_LAX, + ] +); + +// Supplying a Set-Cookie header string +$cookie = Cookie::fromHeaderString( + 'remember_token=f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6; Path=/; Secure; HttpOnly; SameSite=Lax', + false, // raw +); + +// Using the fluent builder interface +$cookie = (new Cookie('remember_token')) + ->withValue('f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6') + ->withPrefix('__Secure-') + ->withExpires(new DateTime('+2 hours')) + ->withPath('/') + ->withDomain('') + ->withSecure(true) + ->withHTTPOnly(true) + ->withSameSite(Cookie::SAMESITE_LAX); + +// Using the global function `cookie` which implicitly calls `new Cookie()` +$cookie = cookie('remember_token', 'f699c7fd18a8e082d0228932f3acd40e1ef5ef92efcedda32842a211d62f0aa6'); diff --git a/user_guide_src/source/libraries/cookies/002.php b/user_guide_src/source/libraries/cookies/002.php new file mode 100644 index 000000000000..3feb4347d330 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/002.php @@ -0,0 +1,16 @@ + 0, + 'samesite' => Cookie::SAMESITE_STRICT, +]; +Cookie::setDefaults($myDefaults); +$cookie = new Cookie('login_token'); diff --git a/user_guide_src/source/libraries/cookies/003.php b/user_guide_src/source/libraries/cookies/003.php new file mode 100644 index 000000000000..2b41c1e4209f --- /dev/null +++ b/user_guide_src/source/libraries/cookies/003.php @@ -0,0 +1,10 @@ + new DateTime('2025-02-14 00:00:00', new DateTimeZone('UTC')), + 'prefix' => '__Secure-', + 'path' => '/', + 'domain' => '', + 'secure' => true, + 'httponly' => true, + 'raw' => false, + 'samesite' => Cookie::SAMESITE_LAX, + ] +); + +$cookie->getName(); // 'remember_token' +$cookie->getPrefix(); // '__Secure-' +$cookie->getPrefixedName(); // '__Secure-remember_token' +$cookie->getExpiresTimestamp(); // Unix timestamp +$cookie->getExpiresString(); // 'Fri, 14-Feb-2025 00:00:00 GMT' +$cookie->isExpired(); // false +$cookie->getMaxAge(); // the difference from time() to expires +$cookie->isRaw(); // false +$cookie->isSecure(); // true +$cookie->getPath(); // '/' +$cookie->getDomain(); // '' +$cookie->isHTTPOnly(); // true +$cookie->getSameSite(); // 'Lax' + +// additional getter +$cookie->getId(); // '__Secure-remember_token;;/' + +// when using `setcookie()`'s alternative signature on PHP 7.3+ +// you can easily use the `getOptions()` method to supply the +// $options parameter +$cookie->getOptions(); diff --git a/user_guide_src/source/libraries/cookies/005.php b/user_guide_src/source/libraries/cookies/005.php new file mode 100644 index 000000000000..264d06782104 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/005.php @@ -0,0 +1,12 @@ +getName(); // 'login_token' + +$cookie->withName('remember_token'); +$cookie->getName(); // 'login_token' + +$new = $cookie->withName('remember_token'); +$new->getName(); // 'remember_token' diff --git a/user_guide_src/source/libraries/cookies/006.php b/user_guide_src/source/libraries/cookies/006.php new file mode 100644 index 000000000000..a8be634a9925 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/006.php @@ -0,0 +1,7 @@ +getCookieStore(); diff --git a/user_guide_src/source/libraries/cookies/008.php b/user_guide_src/source/libraries/cookies/008.php new file mode 100644 index 000000000000..d387a507abd0 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/008.php @@ -0,0 +1,22 @@ +has('login_token'); + +// check if cookie is in the current Response's cookie collection +cookies()->has('login_token'); +Services::response()->hasCookie('remember_token'); + +// using the cookie helper to check the current Response +// not available to v4.1.1 and lower +helper('cookie'); +has_cookie('login_token'); diff --git a/user_guide_src/source/libraries/cookies/010.php b/user_guide_src/source/libraries/cookies/010.php new file mode 100644 index 000000000000..8211a4a2b23e --- /dev/null +++ b/user_guide_src/source/libraries/cookies/010.php @@ -0,0 +1,20 @@ +get('login_token'); + +// getting cookie in the current Response's cookie collection +cookies()->get('login_token'); +Services::response()->getCookie('remember_token'); + +// using the cookie helper to get cookie from the Response's cookie collection +helper('cookie'); +get_cookie('remember_token'); diff --git a/user_guide_src/source/libraries/cookies/011.php b/user_guide_src/source/libraries/cookies/011.php new file mode 100644 index 000000000000..79937ad3f367 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/011.php @@ -0,0 +1,4 @@ +get('unknown_cookie'); diff --git a/user_guide_src/source/libraries/cookies/012.php b/user_guide_src/source/libraries/cookies/012.php new file mode 100644 index 000000000000..cde062c20bd0 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/012.php @@ -0,0 +1,3 @@ +get('unknown_cookie'); // null diff --git a/user_guide_src/source/libraries/cookies/013.php b/user_guide_src/source/libraries/cookies/013.php new file mode 100644 index 000000000000..e9c09b49052a --- /dev/null +++ b/user_guide_src/source/libraries/cookies/013.php @@ -0,0 +1,9 @@ +get(); // array of Cookie objects + +// alternatively, you can use the display method +cookies()->display(); + +// or even from the Response +Services::response()->getCookies(); diff --git a/user_guide_src/source/libraries/cookies/014.php b/user_guide_src/source/libraries/cookies/014.php new file mode 100644 index 000000000000..0e6ae6772146 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/014.php @@ -0,0 +1,16 @@ +put(new Cookie('admin_token', 'yes')); + +// removing a Cookie instance +$new = $store->remove('login_token'); diff --git a/user_guide_src/source/libraries/cookies/015.php b/user_guide_src/source/libraries/cookies/015.php new file mode 100644 index 000000000000..040a2f8a9882 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/015.php @@ -0,0 +1,11 @@ +setCookie('admin_token', 'yes'); +Services::response()->deleteCookie('login_token'); + +// using the cookie helper +helper('cookie'); +set_cookie('admin_token', 'yes'); +delete_cookie('login_token'); diff --git a/user_guide_src/source/libraries/cookies/016.php b/user_guide_src/source/libraries/cookies/016.php new file mode 100644 index 000000000000..ec04f12f1cb7 --- /dev/null +++ b/user_guide_src/source/libraries/cookies/016.php @@ -0,0 +1,11 @@ +dispatch(); // After dispatch, the collection is now empty. diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index 62e6ebbaa0c8..0d2789816953 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -30,9 +30,10 @@ Due to historical reasons, by default, the CURLRequest shares all the options be If you send more than one request with an instance of the class, this behavior may cause an error request with unnecessary headers. -You can change the behavior by editing the following config parameter value in **app/Config/CURLRequest.php** to ``false``:: +You can change the behavior by editing the following config parameter value in **app/Config/CURLRequest.php** to ``false``: - public $shareOptions = false; +.. literalinclude:: curlrequest/001.php + :lines: 2- ******************* Loading the Library @@ -40,31 +41,25 @@ Loading the Library The library can be loaded either manually or through the :doc:`Services class `. -To load with the Services class call the ``curlrequest()`` method:: +To load with the Services class call the ``curlrequest()`` method: - $client = \Config\Services::curlrequest(); +.. literalinclude:: curlrequest/002.php + :lines: 2- You can pass in an array of default options as the first parameter to modify how cURL will handle the request. -The options are described later in this document:: +The options are described later in this document: - $options = [ - 'baseURI' => 'http://example.com/api/v1/', - 'timeout' => 3, - ]; - $client = \Config\Services::curlrequest($options); +.. literalinclude:: curlrequest/003.php + :lines: 2- .. note:: When ``$shareOptions`` is false, the default options passed to the class constructor will be used for all requests. Other options will be reset after sending a request. When creating the class manually, you need to pass a few dependencies in. The first parameter is an instance of the ``Config\App`` class. The second parameter is a URI instance. The third -parameter is a Response object. The fourth parameter is the optional default ``$options`` array:: +parameter is a Response object. The fourth parameter is the optional default ``$options`` array: - $client = new \CodeIgniter\HTTP\CURLRequest( - new \Config\App(), - new \CodeIgniter\HTTP\URI(), - new \CodeIgniter\HTTP\Response(new \Config\App()), - $options - ); +.. literalinclude:: curlrequest/004.php + :lines: 2- ************************ Working with the Library @@ -79,51 +74,33 @@ Making Requests Most communication is done through the ``request()`` method, which fires off the request, and then returns a Response instance to you. This takes the HTTP method, the url and an array of options as the parameters. -:: - $client = \Config\Services::curlrequest(); - - $response = $client->request('GET', 'https://api.github.com/user', [ - 'auth' => ['user', 'pass'], - ]); +.. literalinclude:: curlrequest/005.php + :lines: 2- .. note:: When ``$shareOptions`` is false, the options passed to the method will be used for the request. After sending the request, they will be cleared. If you want to use the options to all requests, pass the options in the constructor. Since the response is an instance of ``CodeIgniter\HTTP\Response`` you have all of the normal information -available to you:: +available to you: - echo $response->getStatusCode(); - echo $response->getBody(); - echo $response->getHeader('Content-Type'); - $language = $response->negotiateLanguage(['en', 'fr']); +.. literalinclude:: curlrequest/006.php + :lines: 2- While the ``request()`` method is the most flexible, you can also use the following shortcut methods. They -each take the URL as the first parameter and an array of options as the second:: +each take the URL as the first parameter and an array of options as the second: - $client->get('http://example.com'); - $client->delete('http://example.com'); - $client->head('http://example.com'); - $client->options('http://example.com'); - $client->patch('http://example.com'); - $client->put('http://example.com'); - $client->post('http://example.com'); +.. literalinclude:: curlrequest/007.php + :lines: 2- Base URI -------- A ``baseURI`` can be set as one of the options during the instantiation of the class. This allows you to set a base URI, and then make all requests with that client using relative URLs. This is especially handy -when working with APIs:: - - $client = \Config\Services::curlrequest([ - 'baseURI' => 'https://example.com/api/v1/', - ]); +when working with APIs: - // GET http:example.com/api/v1/photos - $client->get('photos'); - - // GET http:example.com/api/v1/photos/13 - $client->delete('photos/13'); +.. literalinclude:: curlrequest/008.php + :lines: 2- When a relative URI is provided to the ``request()`` method or any of the shortcut methods, it will be combined with the baseURI according to the rules described by @@ -147,31 +124,26 @@ Using Responses Each ``request()`` call returns a Response object that contains a lot of useful information and some helpful methods. The most commonly used methods let you determine the response itself. -You can get the status code and reason phrase of the response:: - - $code = $response->getStatusCode(); // 200 - $reason = $response->getReason(); // OK +You can get the status code and reason phrase of the response: -You can retrieve headers from the response:: +.. literalinclude:: curlrequest/009.php + :lines: 2- - // Get a header line - echo $response->getHeaderLine('Content-Type'); +You can retrieve headers from the response: - // Get all headers - foreach ($response->getHeaders() as $name => $value) { - echo $name .': '. $response->getHeaderLine($name) ."\n"; - } +.. literalinclude:: curlrequest/010.php + :lines: 2- -The body can be retrieved using the ``getBody()`` method:: +The body can be retrieved using the ``getBody()`` method: - $body = $response->getBody(); +.. literalinclude:: curlrequest/011.php + :lines: 2- The body is the raw body provided by the remote server. If the content type requires formatting, you will need -to ensure that your script handles that:: +to ensure that your script handles that: - if (strpos($response->getHeader('content-type'), 'application/json') !== false) { - $body = json_decode($body); - } +.. literalinclude:: curlrequest/012.php + :lines: 2- *************** Request Options @@ -186,25 +158,20 @@ allow_redirects By default, cURL will follow all "Location:" headers the remote servers send back. The ``allow_redirects`` option allows you to modify how that works. -If you set the value to ``false``, then it will not follow any redirects at all:: +If you set the value to ``false``, then it will not follow any redirects at all: - $client->request('GET', 'http://example.com', ['allow_redirects' => false]); +.. literalinclude:: curlrequest/013.php + :lines: 2- -Setting it to ``true`` will apply the default settings to the request:: +Setting it to ``true`` will apply the default settings to the request: - $client->request('GET', 'http://example.com', ['allow_redirects' => true]); +.. literalinclude:: curlrequest/014.php + :lines: 2- - // Sets the following defaults: - 'max' => 5, // Maximum number of redirects to follow before stopping - 'strict' => true, // Ensure POST requests stay POST requests through redirects - 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols +You can pass in array as the value of the ``allow_redirects`` option to specify new settings in place of the defaults: -You can pass in array as the value of the ``allow_redirects`` option to specify new settings in place of the defaults:: - - $client->request('GET', 'http://example.com', ['allow_redirects' => [ - 'max' => 10, - 'protocols' => ['https'] // Force HTTPS domains only. - ]]); +.. literalinclude:: curlrequest/015.php + :lines: 2- .. note:: Following redirects does not work when PHP is in safe_mode or open_basedir is enabled. @@ -215,49 +182,55 @@ Allows you to provide Authentication details for `HTTP Basic `_ and authentication. Your script may have to do extra to support Digest authentication - this simply passes the username and password along for you. The value must be an array where the first element is the username, and the second is the password. The third parameter should be -the type of authentication to use, either ``basic`` or ``digest``:: +the type of authentication to use, either ``basic`` or ``digest``: - $client->request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]); +.. literalinclude:: curlrequest/016.php + :lines: 2- body ==== There are two ways to set the body of the request for request types that support them, like PUT, OR POST. -The first way is to use the ``setBody()`` method:: +The first way is to use the ``setBody()`` method: - $client->setBody($body) ->request('put', 'http://example.com'); +.. literalinclude:: curlrequest/017.php + :lines: 2- The second method is by passing a ``body`` option in. This is provided to maintain Guzzle API compatibility, -and functions the exact same way as the previous example. The value must be a string:: +and functions the exact same way as the previous example. The value must be a string: - $client->request('put', 'http://example.com', ['body' => $body]); +.. literalinclude:: curlrequest/018.php + :lines: 2- cert ==== To specify the location of a PEM formatted client-side certificate, pass a string with the full path to the file as the ``cert`` option. If a password is required, set the value to an array with the first element -as the path to the certificate, and the second as the password:: +as the path to the certificate, and the second as the password: - $client->request('get', '/', ['cert' => ['/path/server.pem', 'password']); +.. literalinclude:: curlrequest/019.php + :lines: 2- connect_timeout =============== By default, CodeIgniter does not impose a limit for cURL to attempt to connect to a website. If you need to modify this value, you can do so by passing the amount of time in seconds with the ``connect_timeout`` option. -You can pass 0 to wait indefinitely:: +You can pass 0 to wait indefinitely: - $response->request('GET', 'http://example.com', ['connect_timeout' => 0]); +.. literalinclude:: curlrequest/020.php + :lines: 2- cookie ====== This specifies the filename that CURL should use to read cookie values from, and to save cookie values to. This is done using the CURL_COOKIEJAR and CURL_COOKIEFILE options. -An example:: +An example: - $response->request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); +.. literalinclude:: curlrequest/021.php + :lines: 2- debug ===== @@ -269,31 +242,28 @@ the server's error log. $response->request('GET', 'http://example.com', ['debug' => true]); -You can pass a filename as the value for debug to have the output written to a file:: +You can pass a filename as the value for debug to have the output written to a file: - $response->request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); +.. literalinclude:: curlrequest/022.php + :lines: 2- delay ===== -Allows you to pause a number of milliseconds before sending the request:: +Allows you to pause a number of milliseconds before sending the request: - // Delay for 2 seconds - $response->request('GET', 'http://example.com', ['delay' => 2000]); +.. literalinclude:: curlrequest/023.php + :lines: 2- form_params =========== You can send form data in an application/x-www-form-urlencoded POST request by passing an associative array in the ``form_params`` option. This will set the ``Content-Type`` header to ``application/x-www-form-urlencoded`` -if it's not already set:: +if it's not already set: - $client->request('POST', '/post', [ - 'form_params' => [ - 'foo' => 'bar', - 'baz' => ['hi', 'there'], - ], - ]); +.. literalinclude:: curlrequest/024.php + :lines: 2- .. note:: ``form_params`` cannot be used with the ``multipart`` option. You will need to use one or the other. Use ``form_params`` for ``application/x-www-form-urlencoded`` request, and ``multipart`` for ``multipart/form-data`` @@ -306,15 +276,10 @@ headers While you can set any headers this request needs by using the ``setHeader()`` method, you can also pass an associative array of headers in as an option. Each key is the name of a header, and each value is a string or array of strings -representing the header field values:: +representing the header field values: - $client->request('get', '/', [ - 'headers' => [ - 'User-Agent' => 'testing/1.0', - 'Accept' => 'application/json', - 'X-Foo' => ['Bar', 'Baz'], - ], - ]); +.. literalinclude:: curlrequest/025.php + :lines: 2- If headers are passed into the constructor they are treated as default values that will be overridden later by any further headers arrays or calls to ``setHeader()``. @@ -323,23 +288,20 @@ http_errors =========== By default, CURLRequest will fail if the HTTP code returned is greater than or equal to 400. You can set -``http_errors`` to ``false`` to return the content instead:: - - $client->request('GET', '/status/500'); - // Will fail verbosely +``http_errors`` to ``false`` to return the content instead: - $res = $client->request('GET', '/status/500', ['http_errors' => false]); - echo $res->getStatusCode(); - // 500 +.. literalinclude:: curlrequest/026.php + :lines: 2- json ==== The ``json`` option is used to easily upload JSON encoded data as the body of a request. A Content-Type header of ``application/json`` is added, overwriting any Content-Type that might be already set. The data provided to -this option can be any value that ``json_encode()`` accepts:: +this option can be any value that ``json_encode()`` accepts: - $response = $client->request('PUT', '/put', ['json' => ['foo' => 'bar']]); +.. literalinclude:: curlrequest/027.php + :lines: 2- .. note:: This option does not allow for any customization of the ``json_encode()`` function, or the Content-Type header. If you need that ability, you will need to encode the data manually, passing it through the ``setBody()`` @@ -351,12 +313,10 @@ multipart When you need to send files and other data via a POST request, you can use the ``multipart`` option, along with the `CURLFile Class `_. The values should be an associative array of POST data to send. For safer usage, the legacy method of uploading files by prefixing their name with an `@` -has been disabled. Any files that you want to send must be passed as instances of CURLFile:: +has been disabled. Any files that you want to send must be passed as instances of CURLFile: - $post_data = [ - 'foo' => 'bar', - 'userfile' => new \CURLFile('/path/to/file.txt'), - ]; +.. literalinclude:: curlrequest/028.php + :lines: 2- .. note:: ``multipart`` cannot be used with the ``form_params`` option. You can only use one or the other. Use ``form_params`` for ``application/x-www-form-urlencoded`` requests, and ``multipart`` for ``multipart/form-data`` @@ -365,25 +325,27 @@ has been disabled. Any files that you want to send must be passed as instances o query ===== -You can pass along data to send as query string variables by passing an associative array as the ``query`` option:: +You can pass along data to send as query string variables by passing an associative array as the ``query`` option: - // Send a GET request to /get?foo=bar - $client->request('GET', '/get', ['query' => ['foo' => 'bar']]); +.. literalinclude:: curlrequest/029.php + :lines: 2- timeout ======= By default, cURL functions are allowed to run as long as they take, with no time limit. You can modify this with the ``timeout`` -option. The value should be the number of seconds you want the functions to execute for. Use 0 to wait indefinitely:: +option. The value should be the number of seconds you want the functions to execute for. Use 0 to wait indefinitely: - $response->request('GET', 'http://example.com', ['timeout' => 5]); +.. literalinclude:: curlrequest/030.php + :lines: 2- user_agent ========== -Allows specifying the User Agent for requests:: +Allows specifying the User Agent for requests: - $response->request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); +.. literalinclude:: curlrequest/031.php + :lines: 2- verify ====== @@ -392,22 +354,16 @@ This option describes the SSL certificate verification behavior. If the ``verify SSL certificate verification and uses the default CA bundle provided by the operating system. If set to ``false`` it will disable the certificate verification (this is insecure, and allows man-in-the-middle attacks!). You can set it to a string that contains the path to a CA bundle to enable verification with a custom certificate. The default value -is true:: - - // Use the system's CA bundle (this is the default setting) - $client->request('GET', '/', ['verify' => true]); - - // Use a custom SSL certificate on disk. - $client->request('GET', '/', ['verify' => '/path/to/cert.pem']); +is true: - // Disable validation entirely. (Insecure!) - $client->request('GET', '/', ['verify' => false]); +.. literalinclude:: curlrequest/032.php + :lines: 2- version ======= To set the HTTP protocol to use, you can pass a string or float with the version number (typically either 1.0 -or 1.1, 2.0 is currently unsupported.):: +or 1.1, 2.0 is currently unsupported.): - // Force HTTP/1.0 - $client->request('GET', '/', ['version' => 1.0]); +.. literalinclude:: curlrequest/033.php + :lines: 2- diff --git a/user_guide_src/source/libraries/curlrequest/001.php b/user_guide_src/source/libraries/curlrequest/001.php new file mode 100644 index 000000000000..43e1f74bc943 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/001.php @@ -0,0 +1,3 @@ + 'http://example.com/api/v1/', + 'timeout' => 3, +]; +$client = \Config\Services::curlrequest($options); diff --git a/user_guide_src/source/libraries/curlrequest/004.php b/user_guide_src/source/libraries/curlrequest/004.php new file mode 100644 index 000000000000..4d6a14fadbb0 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/004.php @@ -0,0 +1,8 @@ +request('GET', 'https://api.github.com/user', [ + 'auth' => ['user', 'pass'], +]); diff --git a/user_guide_src/source/libraries/curlrequest/006.php b/user_guide_src/source/libraries/curlrequest/006.php new file mode 100644 index 000000000000..114b14e2251d --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/006.php @@ -0,0 +1,6 @@ +getStatusCode(); +echo $response->getBody(); +echo $response->getHeader('Content-Type'); +$language = $response->negotiateLanguage(['en', 'fr']); diff --git a/user_guide_src/source/libraries/curlrequest/007.php b/user_guide_src/source/libraries/curlrequest/007.php new file mode 100644 index 000000000000..d509f3e3fa29 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/007.php @@ -0,0 +1,9 @@ +get('http://example.com'); +$client->delete('http://example.com'); +$client->head('http://example.com'); +$client->options('http://example.com'); +$client->patch('http://example.com'); +$client->put('http://example.com'); +$client->post('http://example.com'); diff --git a/user_guide_src/source/libraries/curlrequest/008.php b/user_guide_src/source/libraries/curlrequest/008.php new file mode 100644 index 000000000000..611909c2df7d --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/008.php @@ -0,0 +1,11 @@ + 'https://example.com/api/v1/', +]); + +// GET http:example.com/api/v1/photos +$client->get('photos'); + +// GET http:example.com/api/v1/photos/13 +$client->delete('photos/13'); diff --git a/user_guide_src/source/libraries/curlrequest/009.php b/user_guide_src/source/libraries/curlrequest/009.php new file mode 100644 index 000000000000..49eaa5ec7562 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/009.php @@ -0,0 +1,4 @@ +getStatusCode(); // 200 +$reason = $response->getReason(); // OK diff --git a/user_guide_src/source/libraries/curlrequest/010.php b/user_guide_src/source/libraries/curlrequest/010.php new file mode 100644 index 000000000000..e13fa1c5e7e3 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/010.php @@ -0,0 +1,9 @@ +getHeaderLine('Content-Type'); + +// Get all headers +foreach ($response->getHeaders() as $name => $value) { + echo $name .': '. $response->getHeaderLine($name) ."\n"; +} diff --git a/user_guide_src/source/libraries/curlrequest/011.php b/user_guide_src/source/libraries/curlrequest/011.php new file mode 100644 index 000000000000..ee93e3dac0e9 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/011.php @@ -0,0 +1,3 @@ +getBody(); diff --git a/user_guide_src/source/libraries/curlrequest/012.php b/user_guide_src/source/libraries/curlrequest/012.php new file mode 100644 index 000000000000..2dc0eea65d0d --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/012.php @@ -0,0 +1,5 @@ +getHeader('content-type'), 'application/json') !== false) { + $body = json_decode($body); +} diff --git a/user_guide_src/source/libraries/curlrequest/013.php b/user_guide_src/source/libraries/curlrequest/013.php new file mode 100644 index 000000000000..342b6af55ea7 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/013.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['allow_redirects' => false]); diff --git a/user_guide_src/source/libraries/curlrequest/014.php b/user_guide_src/source/libraries/curlrequest/014.php new file mode 100644 index 000000000000..452f30dd45ed --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/014.php @@ -0,0 +1,8 @@ +request('GET', 'http://example.com', ['allow_redirects' => true]); + +// Sets the following defaults: +'max' => 5, // Maximum number of redirects to follow before stopping +'strict' => true, // Ensure POST requests stay POST requests through redirects +'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols diff --git a/user_guide_src/source/libraries/curlrequest/015.php b/user_guide_src/source/libraries/curlrequest/015.php new file mode 100644 index 000000000000..c8c85ee7f116 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/015.php @@ -0,0 +1,6 @@ +request('GET', 'http://example.com', ['allow_redirects' => [ + 'max' => 10, + 'protocols' => ['https'] // Force HTTPS domains only. +]]); diff --git a/user_guide_src/source/libraries/curlrequest/016.php b/user_guide_src/source/libraries/curlrequest/016.php new file mode 100644 index 000000000000..3c3fa945f535 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/016.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['auth' => ['username', 'password', 'digest']]); diff --git a/user_guide_src/source/libraries/curlrequest/017.php b/user_guide_src/source/libraries/curlrequest/017.php new file mode 100644 index 000000000000..fbc6302a68ec --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/017.php @@ -0,0 +1,3 @@ +setBody($body) ->request('put', 'http://example.com'); diff --git a/user_guide_src/source/libraries/curlrequest/018.php b/user_guide_src/source/libraries/curlrequest/018.php new file mode 100644 index 000000000000..16fba53e2e8b --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/018.php @@ -0,0 +1,3 @@ +request('put', 'http://example.com', ['body' => $body]); diff --git a/user_guide_src/source/libraries/curlrequest/019.php b/user_guide_src/source/libraries/curlrequest/019.php new file mode 100644 index 000000000000..96f86c9ea6a2 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/019.php @@ -0,0 +1,3 @@ +request('get', '/', ['cert' => ['/path/server.pem', 'password']); diff --git a/user_guide_src/source/libraries/curlrequest/020.php b/user_guide_src/source/libraries/curlrequest/020.php new file mode 100644 index 000000000000..6e0b1e3726a7 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/020.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['connect_timeout' => 0]); diff --git a/user_guide_src/source/libraries/curlrequest/021.php b/user_guide_src/source/libraries/curlrequest/021.php new file mode 100644 index 000000000000..4acf82aa9e0b --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/021.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); diff --git a/user_guide_src/source/libraries/curlrequest/022.php b/user_guide_src/source/libraries/curlrequest/022.php new file mode 100644 index 000000000000..6acbcf0a7784 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/022.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); diff --git a/user_guide_src/source/libraries/curlrequest/023.php b/user_guide_src/source/libraries/curlrequest/023.php new file mode 100644 index 000000000000..b6846257ad83 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/023.php @@ -0,0 +1,4 @@ +request('GET', 'http://example.com', ['delay' => 2000]); diff --git a/user_guide_src/source/libraries/curlrequest/024.php b/user_guide_src/source/libraries/curlrequest/024.php new file mode 100644 index 000000000000..bbc6285e0eec --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/024.php @@ -0,0 +1,8 @@ +request('POST', '/post', [ + 'form_params' => [ + 'foo' => 'bar', + 'baz' => ['hi', 'there'], + ], +]); diff --git a/user_guide_src/source/libraries/curlrequest/025.php b/user_guide_src/source/libraries/curlrequest/025.php new file mode 100644 index 000000000000..acc8b40002ef --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/025.php @@ -0,0 +1,9 @@ +request('get', '/', [ + 'headers' => [ + 'User-Agent' => 'testing/1.0', + 'Accept' => 'application/json', + 'X-Foo' => ['Bar', 'Baz'], + ], +]); diff --git a/user_guide_src/source/libraries/curlrequest/026.php b/user_guide_src/source/libraries/curlrequest/026.php new file mode 100644 index 000000000000..36ea74cb9293 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/026.php @@ -0,0 +1,8 @@ +request('GET', '/status/500'); +// Will fail verbosely + +$res = $client->request('GET', '/status/500', ['http_errors' => false]); +echo $res->getStatusCode(); +// 500 diff --git a/user_guide_src/source/libraries/curlrequest/027.php b/user_guide_src/source/libraries/curlrequest/027.php new file mode 100644 index 000000000000..bd91655f3dbe --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/027.php @@ -0,0 +1,3 @@ +request('PUT', '/put', ['json' => ['foo' => 'bar']]); diff --git a/user_guide_src/source/libraries/curlrequest/028.php b/user_guide_src/source/libraries/curlrequest/028.php new file mode 100644 index 000000000000..fcce227c1d9a --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/028.php @@ -0,0 +1,6 @@ + 'bar', + 'userfile' => new \CURLFile('/path/to/file.txt'), +]; diff --git a/user_guide_src/source/libraries/curlrequest/029.php b/user_guide_src/source/libraries/curlrequest/029.php new file mode 100644 index 000000000000..7a19976bd0a2 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/029.php @@ -0,0 +1,4 @@ +request('GET', '/get', ['query' => ['foo' => 'bar']]); diff --git a/user_guide_src/source/libraries/curlrequest/030.php b/user_guide_src/source/libraries/curlrequest/030.php new file mode 100644 index 000000000000..83bf718e33e4 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/030.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['timeout' => 5]); diff --git a/user_guide_src/source/libraries/curlrequest/031.php b/user_guide_src/source/libraries/curlrequest/031.php new file mode 100644 index 000000000000..1709d6d90b9c --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/031.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); diff --git a/user_guide_src/source/libraries/curlrequest/032.php b/user_guide_src/source/libraries/curlrequest/032.php new file mode 100644 index 000000000000..13e2fba21f04 --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/032.php @@ -0,0 +1,10 @@ +request('GET', '/', ['verify' => true]); + +// Use a custom SSL certificate on disk. +$client->request('GET', '/', ['verify' => '/path/to/cert.pem']); + +// Disable validation entirely. (Insecure!) +$client->request('GET', '/', ['verify' => false]); diff --git a/user_guide_src/source/libraries/curlrequest/033.php b/user_guide_src/source/libraries/curlrequest/033.php new file mode 100644 index 000000000000..a7a8df45589c --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/033.php @@ -0,0 +1,4 @@ +request('GET', '/', ['version' => 1.0]); diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index e56af313b005..800816ed4bbd 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -30,19 +30,10 @@ Sending Email Sending email is not only simple, but you can configure it on the fly or set your preferences in the **app/Config/Email.php** file. -Here is a basic example demonstrating how you might send email:: +Here is a basic example demonstrating how you might send email: - $email = \Config\Services::email(); - - $email->setFrom('your@example.com', 'Your Name'); - $email->setTo('someone@example.com'); - $email->setCC('another@another-example.com'); - $email->setBCC('them@their-example.com'); - - $email->setSubject('Email Test'); - $email->setMessage('Testing the email class.'); - - $email->send(); +.. literalinclude:: email/001.php + :lines: 2- .. _setting-email-preferences: @@ -56,14 +47,10 @@ below: Preferences are set by passing an array of preference values to the email initialize method. Here is an example of how you might set some -preferences:: +preferences: - $config['protocol'] = 'sendmail'; - $config['mailPath'] = '/usr/sbin/sendmail'; - $config['charset'] = 'iso-8859-1'; - $config['wordWrap'] = true; - - $email->initialize($config); +.. literalinclude:: email/002.php + :lines: 2- .. note:: Most of the preferences have default values that will be used if you do not set them. @@ -167,7 +154,6 @@ message like this:: More text that will be wrapped normally. - Place the item you do not want word-wrapped between: {unwrap} {/unwrap} *************** @@ -184,13 +170,15 @@ Class Reference :returns: CodeIgniter\\Email\\Email instance (method chaining) :rtype: CodeIgniter\\Email\\Email - Sets the email address and name of the person sending the email:: + Sets the email address and name of the person sending the email: - $email->setFrom('you@example.com', 'Your Name'); + .. literalinclude:: email/003.php + :lines: 2- - You can also set a Return-Path, to help redirect undelivered mail:: + You can also set a Return-Path, to help redirect undelivered mail: - $email->setFrom('you@example.com', 'Your Name', 'returned_emails@example.com'); + .. literalinclude:: email/004.php + :lines: 2- .. note:: Return-Path can't be used if you've configured 'smtp' as your protocol. @@ -203,9 +191,10 @@ Class Reference :rtype: CodeIgniter\\Email\\Email Sets the reply-to address. If the information is not provided the - information in the `setFrom <#setFrom>`_ method is used. Example:: + information in the `setFrom <#setFrom>`_ method is used. Example: - $email->setReplyTo('you@example.com', 'Your Name'); + .. literalinclude:: email/005.php + :lines: 2- .. php:method:: setTo($to) @@ -214,17 +203,16 @@ Class Reference :rtype: CodeIgniter\\Email\\Email Sets the email address(s) of the recipient(s). Can be a single e-mail, - a comma-delimited list or an array:: - - $email->setTo('someone@example.com'); + a comma-delimited list or an array: - :: + .. literalinclude:: email/006.php + :lines: 2- - $email->setTo('one@example.com, two@example.com, three@example.com'); + .. literalinclude:: email/007.php + :lines: 2- - :: - - $email->setTo(['one@example.com', 'two@example.com', 'three@example.com']); + .. literalinclude:: email/008.php + :lines: 2- .. php:method:: setCC($cc) @@ -255,9 +243,10 @@ Class Reference :returns: CodeIgniter\\Email\\Email instance (method chaining) :rtype: CodeIgniter\\Email\\Email - Sets the email subject:: + Sets the email subject: - $email->setSubject('This is my subject'); + .. literalinclude:: email/009.php + :lines: 2- .. php:method:: setMessage($body) @@ -265,9 +254,10 @@ Class Reference :returns: CodeIgniter\\Email\\Email instance (method chaining) :rtype: CodeIgniter\\Email\\Email - Sets the e-mail message body:: + Sets the e-mail message body: - $email->setMessage('This is my message'); + .. literalinclude:: email/010.php + :lines: 2- .. php:method:: setAltMessage($str) @@ -275,9 +265,10 @@ Class Reference :returns: CodeIgniter\\Email\\Email instance (method chaining) :rtype: CodeIgniter\\Email\\Email - Sets the alternative e-mail message body:: + Sets the alternative e-mail message body: - $email->setAltMessage('This is the alternative message'); + .. literalinclude:: email/011.php + :lines: 2- This is an optional message string which can be used if you send HTML formatted email. It lets you specify an alternative message @@ -294,10 +285,10 @@ Class Reference :returns: CodeIgniter\\Email\\Email instance (method chaining) :rtype: CodeIgniter\\Email\\Email - Appends additional headers to the e-mail:: + Appends additional headers to the e-mail: - $email->setHeader('Header1', 'Value1'); - $email->setHeader('Header2', 'Value2'); + .. literalinclude:: email/012.php + :lines: 2- .. php:method:: clear($clearAttachments = false) @@ -309,23 +300,14 @@ Class Reference is intended for use if you run the email sending method in a loop, permitting the data to be reset between cycles. - :: - - foreach ($list as $name => $address) - { - $email->clear(); - - $email->setTo($address); - $email->setFrom('your@example.com'); - $email->setSubject('Here is your info '.$name); - $email->setMessage('Hi ' . $name . ' Here is the info you requested.'); - $email->send(); - } + .. literalinclude:: email/013.php + :lines: 2- If you set the parameter to true any attachments will be cleared as - well:: + well: - $email->clear(true); + .. literalinclude:: email/014.php + :lines: 2- .. php:method:: send($autoClear = true) @@ -334,18 +316,16 @@ Class Reference :rtype: bool The e-mail sending method. Returns boolean true or false based on - success or failure, enabling it to be used conditionally:: + success or failure, enabling it to be used conditionally: - if (! $email->send()) { - // Generate error - } + .. literalinclude:: email/015.php + :lines: 2- This method will automatically clear all parameters if the request was - successful. To stop this behaviour pass false:: + successful. To stop this behaviour pass false: - if ($email->send(false)) { - // Parameters won't be cleared - } + .. literalinclude:: email/016.php + :lines: 2- .. note:: In order to use the ``printDebugger()`` method, you need to avoid clearing the email parameters. @@ -367,30 +347,33 @@ Class Reference Enables you to send an attachment. Put the file path/name in the first parameter. For multiple attachments use the method multiple times. - For example:: + For example: - $email->attach('/path/to/photo1.jpg'); - $email->attach('/path/to/photo2.jpg'); - $email->attach('/path/to/photo3.jpg'); + .. literalinclude:: email/017.php + :lines: 2- To use the default disposition (attachment), leave the second parameter blank, - otherwise use a custom disposition:: + otherwise use a custom disposition: - $email->attach('image.jpg', 'inline'); + .. literalinclude:: email/018.php + :lines: 2- - You can also use a URL:: + You can also use a URL: - $email->attach('http://example.com/filename.pdf'); + .. literalinclude:: email/019.php + :lines: 2- - If you'd like to use a custom file name, you can use the third parameter:: + If you'd like to use a custom file name, you can use the third parameter: - $email->attach('filename.pdf', 'attachment', 'report.pdf'); + .. literalinclude:: email/020.php + :lines: 2- If you need to use a buffer string instead of a real - physical - file you can use the first parameter as buffer, the third parameter as file name and the fourth - parameter as mime-type:: + parameter as mime-type: - $email->attach($buffer, 'attachment', 'report.pdf', 'application/pdf'); + .. literalinclude:: email/021.php + :lines: 2- .. php:method:: setAttachmentCID($filename) @@ -400,17 +383,9 @@ Class Reference Sets and returns an attachment's Content-ID, which enables your to embed an inline (picture) attachment into HTML. First parameter must be the already attached file name. - :: - $filename = '/img/photo1.jpg'; - $email->attach($filename); - - foreach ($list as $address) { - $email->setTo($address); - $cid = $email->setAttachmentCID($filename); - $email->setMessage('photo1'); - $email->send(); - } + .. literalinclude:: email/022.php + :lines: 2- .. note:: Content-ID for each e-mail must be re-created for it to be unique. @@ -426,14 +401,9 @@ Class Reference You can optionally specify which parts of the message should be printed. Valid options are: **headers**, **subject**, **body**. - Example:: - - // You need to pass false while sending in order for the email data - // to not be cleared - if that happens, printDebugger() would have - // nothing to output. - $email->send(false); + Example: - // Will only print the email headers, excluding the message subject and body - $email->printDebugger(['headers']); + .. literalinclude:: email/023.php + :lines: 2- .. note:: By default, all of the raw data will be printed. diff --git a/user_guide_src/source/libraries/email/001.php b/user_guide_src/source/libraries/email/001.php new file mode 100644 index 000000000000..914193c15203 --- /dev/null +++ b/user_guide_src/source/libraries/email/001.php @@ -0,0 +1,13 @@ +setFrom('your@example.com', 'Your Name'); +$email->setTo('someone@example.com'); +$email->setCC('another@another-example.com'); +$email->setBCC('them@their-example.com'); + +$email->setSubject('Email Test'); +$email->setMessage('Testing the email class.'); + +$email->send(); diff --git a/user_guide_src/source/libraries/email/002.php b/user_guide_src/source/libraries/email/002.php new file mode 100644 index 000000000000..02268ee6079d --- /dev/null +++ b/user_guide_src/source/libraries/email/002.php @@ -0,0 +1,8 @@ +initialize($config); diff --git a/user_guide_src/source/libraries/email/003.php b/user_guide_src/source/libraries/email/003.php new file mode 100644 index 000000000000..b2ade5bab56b --- /dev/null +++ b/user_guide_src/source/libraries/email/003.php @@ -0,0 +1,3 @@ +setFrom('you@example.com', 'Your Name'); diff --git a/user_guide_src/source/libraries/email/004.php b/user_guide_src/source/libraries/email/004.php new file mode 100644 index 000000000000..9d8195de4ea5 --- /dev/null +++ b/user_guide_src/source/libraries/email/004.php @@ -0,0 +1,3 @@ +setFrom('you@example.com', 'Your Name', 'returned_emails@example.com'); diff --git a/user_guide_src/source/libraries/email/005.php b/user_guide_src/source/libraries/email/005.php new file mode 100644 index 000000000000..ba6033c281c0 --- /dev/null +++ b/user_guide_src/source/libraries/email/005.php @@ -0,0 +1,3 @@ +setReplyTo('you@example.com', 'Your Name'); diff --git a/user_guide_src/source/libraries/email/006.php b/user_guide_src/source/libraries/email/006.php new file mode 100644 index 000000000000..1998618a5b5f --- /dev/null +++ b/user_guide_src/source/libraries/email/006.php @@ -0,0 +1,3 @@ +setTo('someone@example.com'); diff --git a/user_guide_src/source/libraries/email/007.php b/user_guide_src/source/libraries/email/007.php new file mode 100644 index 000000000000..b0622d0ac56f --- /dev/null +++ b/user_guide_src/source/libraries/email/007.php @@ -0,0 +1,3 @@ +setTo('one@example.com, two@example.com, three@example.com'); diff --git a/user_guide_src/source/libraries/email/008.php b/user_guide_src/source/libraries/email/008.php new file mode 100644 index 000000000000..d3ac20661d04 --- /dev/null +++ b/user_guide_src/source/libraries/email/008.php @@ -0,0 +1,3 @@ +setTo(['one@example.com', 'two@example.com', 'three@example.com']); diff --git a/user_guide_src/source/libraries/email/009.php b/user_guide_src/source/libraries/email/009.php new file mode 100644 index 000000000000..566736474df4 --- /dev/null +++ b/user_guide_src/source/libraries/email/009.php @@ -0,0 +1,3 @@ +setSubject('This is my subject'); diff --git a/user_guide_src/source/libraries/email/010.php b/user_guide_src/source/libraries/email/010.php new file mode 100644 index 000000000000..6383ac2e112d --- /dev/null +++ b/user_guide_src/source/libraries/email/010.php @@ -0,0 +1,3 @@ +setMessage('This is my message'); diff --git a/user_guide_src/source/libraries/email/011.php b/user_guide_src/source/libraries/email/011.php new file mode 100644 index 000000000000..75f8fe87587d --- /dev/null +++ b/user_guide_src/source/libraries/email/011.php @@ -0,0 +1,3 @@ +setAltMessage('This is the alternative message'); diff --git a/user_guide_src/source/libraries/email/012.php b/user_guide_src/source/libraries/email/012.php new file mode 100644 index 000000000000..b5fdc3f86ddd --- /dev/null +++ b/user_guide_src/source/libraries/email/012.php @@ -0,0 +1,4 @@ +setHeader('Header1', 'Value1'); +$email->setHeader('Header2', 'Value2'); diff --git a/user_guide_src/source/libraries/email/013.php b/user_guide_src/source/libraries/email/013.php new file mode 100644 index 000000000000..744360f49cc1 --- /dev/null +++ b/user_guide_src/source/libraries/email/013.php @@ -0,0 +1,12 @@ + $address) +{ + $email->clear(); + + $email->setTo($address); + $email->setFrom('your@example.com'); + $email->setSubject('Here is your info '.$name); + $email->setMessage('Hi ' . $name . ' Here is the info you requested.'); + $email->send(); +} diff --git a/user_guide_src/source/libraries/email/014.php b/user_guide_src/source/libraries/email/014.php new file mode 100644 index 000000000000..01bf56c01116 --- /dev/null +++ b/user_guide_src/source/libraries/email/014.php @@ -0,0 +1,3 @@ +clear(true); diff --git a/user_guide_src/source/libraries/email/015.php b/user_guide_src/source/libraries/email/015.php new file mode 100644 index 000000000000..60512f6b6416 --- /dev/null +++ b/user_guide_src/source/libraries/email/015.php @@ -0,0 +1,5 @@ +send()) { + // Generate error +} diff --git a/user_guide_src/source/libraries/email/016.php b/user_guide_src/source/libraries/email/016.php new file mode 100644 index 000000000000..2eb092b49787 --- /dev/null +++ b/user_guide_src/source/libraries/email/016.php @@ -0,0 +1,5 @@ +send(false)) { + // Parameters won't be cleared +} diff --git a/user_guide_src/source/libraries/email/017.php b/user_guide_src/source/libraries/email/017.php new file mode 100644 index 000000000000..391cd43214c8 --- /dev/null +++ b/user_guide_src/source/libraries/email/017.php @@ -0,0 +1,5 @@ +attach('/path/to/photo1.jpg'); +$email->attach('/path/to/photo2.jpg'); +$email->attach('/path/to/photo3.jpg'); diff --git a/user_guide_src/source/libraries/email/018.php b/user_guide_src/source/libraries/email/018.php new file mode 100644 index 000000000000..5f17f0aae311 --- /dev/null +++ b/user_guide_src/source/libraries/email/018.php @@ -0,0 +1,3 @@ +attach('image.jpg', 'inline'); diff --git a/user_guide_src/source/libraries/email/019.php b/user_guide_src/source/libraries/email/019.php new file mode 100644 index 000000000000..d5fc39267e3c --- /dev/null +++ b/user_guide_src/source/libraries/email/019.php @@ -0,0 +1,3 @@ +attach('http://example.com/filename.pdf'); diff --git a/user_guide_src/source/libraries/email/020.php b/user_guide_src/source/libraries/email/020.php new file mode 100644 index 000000000000..e14badb97d6b --- /dev/null +++ b/user_guide_src/source/libraries/email/020.php @@ -0,0 +1,3 @@ +attach('filename.pdf', 'attachment', 'report.pdf'); diff --git a/user_guide_src/source/libraries/email/021.php b/user_guide_src/source/libraries/email/021.php new file mode 100644 index 000000000000..103d8bc02c45 --- /dev/null +++ b/user_guide_src/source/libraries/email/021.php @@ -0,0 +1,3 @@ +attach($buffer, 'attachment', 'report.pdf', 'application/pdf'); diff --git a/user_guide_src/source/libraries/email/022.php b/user_guide_src/source/libraries/email/022.php new file mode 100644 index 000000000000..a6d9bfadeb70 --- /dev/null +++ b/user_guide_src/source/libraries/email/022.php @@ -0,0 +1,11 @@ +attach($filename); + +foreach ($list as $address) { + $email->setTo($address); + $cid = $email->setAttachmentCID($filename); + $email->setMessage('photo1'); + $email->send(); +} diff --git a/user_guide_src/source/libraries/email/023.php b/user_guide_src/source/libraries/email/023.php new file mode 100644 index 000000000000..82813787c1c9 --- /dev/null +++ b/user_guide_src/source/libraries/email/023.php @@ -0,0 +1,9 @@ +send(false); + +// Will only print the email headers, excluding the message subject and body +$email->printDebugger(['headers']); diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 1a8bf834d94c..f14d433641b6 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -40,19 +40,17 @@ A more comprehensive package like `Halite ` Using the Encryption Library **************************** -Like all services in CodeIgniter, it can be loaded via ``Config\Services``:: +Like all services in CodeIgniter, it can be loaded via ``Config\Services``: - $encrypter = \Config\Services::encrypter(); +.. literalinclude:: encryption/001.php + :lines: 2- Assuming you have set your starting key (see :ref:`configuration`), encrypting and decrypting data is simple - pass the appropriate string to ``encrypt()`` -and/or ``decrypt()`` methods:: +and/or ``decrypt()`` methods: - $plainText = 'This is a plain-text message!'; - $ciphertext = $encrypter->encrypt($plainText); - - // Outputs: This is a plain-text message! - echo $encrypter->decrypt($ciphertext); +.. literalinclude:: encryption/002.php + :lines: 2- And that's it! The Encryption library will do everything necessary for the whole process to be cryptographically secure out-of-the-box. @@ -77,13 +75,9 @@ digest Message digest algorithm (``SHA512``) You can replace the config file's settings by passing a configuration object of your own to the ``Services`` call. The ``$config`` variable must be an instance of the ``Config\Encryption`` class. -:: - - $config = new \Config\Encryption(); - $config->key = 'aBigsecret_ofAtleast32Characters'; - $config->driver = 'OpenSSL'; - $encrypter = \Config\Services::encrypter($config); +.. literalinclude:: encryption/003.php + :lines: 2- Default Behavior ================ @@ -100,22 +94,18 @@ For AES-256, that's 256 bits or 32 bytes (characters) long. The key should be as random as possible, and it **must not** be a regular text string, nor the output of a hashing function, etc. To create a proper key, you can use the Encryption library's ``createKey()`` method. -:: - - // $key will be assigned a 32-byte (256-bit) random key - $key = \CodeIgniter\Encryption\Encryption::createKey(); - // for the SodiumHandler, you can use either: - $key = sodium_crypto_secretbox_keygen(); - $key = \CodeIgniter\Encryption\Encryption::createKey(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); +.. literalinclude:: encryption/004.php + :lines: 2- The key can be stored in **app/Config/Encryption.php**, or you can design a storage mechanism of your own and pass the key dynamically when encrypting/decrypting. To save your key to your **app/Config/Encryption.php**, open the file -and set:: +and set: - public $key = 'YOUR KEY'; +.. literalinclude:: encryption/005.php + :lines: 2- Encoding Keys or Results ------------------------ @@ -123,20 +113,16 @@ Encoding Keys or Results You'll notice that the ``createKey()`` method outputs binary data, which is hard to deal with (i.e., a copy-paste may damage it), so you may use ``bin2hex()``, or ``base64_encode`` to work with the key in -a more friendly manner. For example:: - - // Get a hex-encoded representation of the key: - $encoded = bin2hex(\CodeIgniter\Encryption\Encryption::createKey(32)); +a more friendly manner. For example: - // Put the same value with hex2bin(), - // so that it is still passed as binary to the library: - $key = hex2bin('your-hex-encoded-key'); +.. literalinclude:: encryption/006.php + :lines: 2- You might find the same technique useful for the results -of encryption:: +of encryption: - // Encrypt some text & make the results text - $encoded = base64_encode($encrypter->encrypt($plaintext)); +.. literalinclude:: encryption/007.php + :lines: 2- Using Prefixes in Storing Keys ------------------------------ @@ -146,13 +132,9 @@ encryption keys: ``hex2bin:`` and ``base64:``. When these prefixes immediately precede the value of your key, ``Encryption`` will intelligently parse the key and still pass a binary string to the library. -:: - - // In Encryption, you may use - public $key = 'hex2bin:' - // or - public $key = 'base64:' +.. literalinclude:: encryption/008.php + :lines: 2- Similarly, you can use these prefixes in your **.env** file, too! :: @@ -231,13 +213,9 @@ Using the Encryption Service Directly Instead of (or in addition to) using ``Services`` as described in :ref:`usage`, you can create an "Encrypter" directly, or change the settings of an existing instance. -:: - - // create an Encryption instance - $encryption = new \CodeIgniter\Encryption\Encryption(); - // reconfigure an instance with different settings - $encrypter = $encryption->initialize($config); +.. literalinclude:: encryption/009.php + :lines: 2- Remember, that ``$config`` must be an instance of ``Config\Encryption`` class. @@ -265,9 +243,10 @@ Class Reference Initializes (configures) the library to use different settings. - Example:: + Example: - $encrypter = $encryption->initialize(['cipher' => '3des']); + .. literalinclude:: encryption/010.php + :lines: 2- Please refer to the :ref:`configuration` section for detailed info. @@ -290,13 +269,10 @@ Class Reference If you are using the SodiumHandler and want to pass a different ``blockSize`` on runtime, pass the ``blockSize`` key in the ``$params`` array. - Examples:: + Examples: - $ciphertext = $encrypter->encrypt('My secret message'); - $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']); - $ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]); - $ciphertext = $encrypter->encrypt('My secret message', 'New secret key'); - $ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]); + .. literalinclude:: encryption/011.php + :lines: 2- .. php:method:: decrypt($data[, $params = null]) @@ -315,10 +291,7 @@ Class Reference If you are using the SodiumHandler and want to pass a different ``blockSize`` on runtime, pass the ``blockSize`` key in the ``$params`` array. - Examples:: + Examples: - echo $encrypter->decrypt($ciphertext); - echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']); - echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]); - echo $encrypter->decrypt($ciphertext, 'New secret key'); - echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]); + .. literalinclude:: encryption/012.php + :lines: 2- diff --git a/user_guide_src/source/libraries/encryption/001.php b/user_guide_src/source/libraries/encryption/001.php new file mode 100644 index 000000000000..8f840be59245 --- /dev/null +++ b/user_guide_src/source/libraries/encryption/001.php @@ -0,0 +1,3 @@ +encrypt($plainText); + +// Outputs: This is a plain-text message! +echo $encrypter->decrypt($ciphertext); diff --git a/user_guide_src/source/libraries/encryption/003.php b/user_guide_src/source/libraries/encryption/003.php new file mode 100644 index 000000000000..772a2172417f --- /dev/null +++ b/user_guide_src/source/libraries/encryption/003.php @@ -0,0 +1,7 @@ +key = 'aBigsecret_ofAtleast32Characters'; +$config->driver = 'OpenSSL'; + +$encrypter = \Config\Services::encrypter($config); diff --git a/user_guide_src/source/libraries/encryption/004.php b/user_guide_src/source/libraries/encryption/004.php new file mode 100644 index 000000000000..30d861e74a40 --- /dev/null +++ b/user_guide_src/source/libraries/encryption/004.php @@ -0,0 +1,8 @@ +encrypt($plaintext)); diff --git a/user_guide_src/source/libraries/encryption/008.php b/user_guide_src/source/libraries/encryption/008.php new file mode 100644 index 000000000000..3e5899ec4cdf --- /dev/null +++ b/user_guide_src/source/libraries/encryption/008.php @@ -0,0 +1,7 @@ +' + +// or +public $key = 'base64:' diff --git a/user_guide_src/source/libraries/encryption/009.php b/user_guide_src/source/libraries/encryption/009.php new file mode 100644 index 000000000000..ec40cae6127c --- /dev/null +++ b/user_guide_src/source/libraries/encryption/009.php @@ -0,0 +1,7 @@ +initialize($config); diff --git a/user_guide_src/source/libraries/encryption/010.php b/user_guide_src/source/libraries/encryption/010.php new file mode 100644 index 000000000000..1bc9ebbbb2a5 --- /dev/null +++ b/user_guide_src/source/libraries/encryption/010.php @@ -0,0 +1,3 @@ +initialize(['cipher' => '3des']); diff --git a/user_guide_src/source/libraries/encryption/011.php b/user_guide_src/source/libraries/encryption/011.php new file mode 100644 index 000000000000..8b675de0f16f --- /dev/null +++ b/user_guide_src/source/libraries/encryption/011.php @@ -0,0 +1,7 @@ +encrypt('My secret message'); +$ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key']); +$ciphertext = $encrypter->encrypt('My secret message', ['key' => 'New secret key', 'blockSize' => 32]); +$ciphertext = $encrypter->encrypt('My secret message', 'New secret key'); +$ciphertext = $encrypter->encrypt('My secret message', ['blockSize' => 32]); diff --git a/user_guide_src/source/libraries/encryption/012.php b/user_guide_src/source/libraries/encryption/012.php new file mode 100644 index 000000000000..491e16f876e4 --- /dev/null +++ b/user_guide_src/source/libraries/encryption/012.php @@ -0,0 +1,7 @@ +decrypt($ciphertext); +echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key']); +echo $encrypter->decrypt($ciphertext, ['key' => 'New secret key', 'blockSize' => 32]); +echo $encrypter->decrypt($ciphertext, 'New secret key'); +echo $encrypter->decrypt($ciphertext, ['blockSize' => 32]); diff --git a/user_guide_src/source/libraries/files.rst b/user_guide_src/source/libraries/files.rst index 6734e98d5fda..0cc766937028 100644 --- a/user_guide_src/source/libraries/files.rst +++ b/user_guide_src/source/libraries/files.rst @@ -17,32 +17,16 @@ You create a new File instance by passing in the path to the file in the constru By default, the file does not need to exist. However, you can pass an additional argument of "true" to check that the file exists and throw ``FileNotFoundException()`` if it does not. -:: - - $file = new \CodeIgniter\Files\File($path); +.. literalinclude:: files/001.php + :lines: 2- Taking Advantage of Spl ======================= -Once you have an instance, you have the full power of the SplFileInfo class at the ready, including:: - - // Get the file's basename - echo $file->getBasename(); - // Get last modified time - echo $file->getMTime(); - // Get the true real path - echo $file->getRealPath(); - // Get the file permissions - echo $file->getPerms(); +Once you have an instance, you have the full power of the SplFileInfo class at the ready, including: - // Write CSV rows to it. - if ($file->isWritable()) { - $csv = $file->openFile('w'); - - foreach ($rows as $row) { - $csv->fputcsv($row); - } - } +.. literalinclude:: files/002.php + :lines: 2- New Features ============ @@ -52,61 +36,62 @@ In addition to all of the methods in the SplFileInfo class, you get some new too **getRandomName()** You can generate a cryptographically secure random filename, with the current timestamp prepended, with the ``getRandomName()`` -method. This is especially useful to rename files when moving it so that the filename is unguessable:: +method. This is especially useful to rename files when moving it so that the filename is unguessable: - // Generates something like: 1465965676_385e33f741.jpg - $newName = $file->getRandomName(); +.. literalinclude:: files/003.php + :lines: 2- **getSize()** -Returns the size of the uploaded file in bytes:: +Returns the size of the uploaded file in bytes: - $size = $file->getSize(); // 256901 +.. literalinclude:: files/004.php + :lines: 2- **getSizeByUnit()** Returns the size of the uploaded file default in bytes. You can pass in either 'kb' or 'mb' as the first parameter to get -the results in kilobytes or megabytes, respectively:: +the results in kilobytes or megabytes, respectively: - $bytes = $file->getSizeByUnit(); // 256901 - $kilobytes = $file->getSizeByUnit('kb'); // 250.880 - $megabytes = $file->getSizeByUnit('mb'); // 0.245 +.. literalinclude:: files/005.php + :lines: 2- **getMimeType()** Retrieve the media type (mime type) of the file. Uses methods that are considered as secure as possible when determining -the type of file:: - - $type = $file->getMimeType(); +the type of file: - echo $type; // image/png +.. literalinclude:: files/006.php + :lines: 2- **guessExtension()** Attempts to determine the file extension based on the trusted ``getMimeType()`` method. If the mime type is unknown, will return null. This is often a more trusted source than simply using the extension provided by the filename. Uses -the values in **app/Config/Mimes.php** to determine extension:: +the values in **app/Config/Mimes.php** to determine extension: - // Returns 'jpg' (WITHOUT the period) - $ext = $file->guessExtension(); +.. literalinclude:: files/007.php + :lines: 2- Moving Files ------------ Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move -the file to as the first parameter:: +the file to as the first parameter: - $file->move(WRITEPATH . 'uploads'); +.. literalinclude:: files/008.php + :lines: 2- -By default, the original filename was used. You can specify a new filename by passing it as the second parameter:: +By default, the original filename was used. You can specify a new filename by passing it as the second parameter: - $newName = $file->getRandomName(); - $file->move(WRITEPATH . 'uploads', $newName); +.. literalinclude:: files/009.php + :lines: 2- The move() method returns a new File instance that for the relocated file, so you must capture the result if the -resulting location is needed:: +resulting location is needed: - $file = $file->move(WRITEPATH . 'uploads'); +.. literalinclude:: files/010.php + :lines: 2- **************** File Collections @@ -114,32 +99,22 @@ File Collections Working with groups of files can be cumbersome, so the framework supplies the ``FileCollection`` class to facilitate locating and working with groups of files across the filesystem. At its most basic, ``FileCollection`` is an index -of files you set or build:: +of files you set or build: - $files = new FileCollection([ - FCPATH . 'index.php', - ROOTPATH . 'spark', - ]); - $files->addDirectory(APPPATH . 'Filters'); +.. literalinclude:: files/011.php + :lines: 2- After you have input the files you would like to work with you may remove files or use the filtering commands to remove -or retain files matching a certain regex or glob-style pattern:: +or retain files matching a certain regex or glob-style pattern: - $files->removeFile(APPPATH . 'Filters/DevelopToolbar'); - - $files->removePattern('#\.gitkeep#'); - $files->retainPattern('*.php'); +.. literalinclude:: files/012.php + :lines: 2- When your collection is complete, you can use ``get()`` to retrieve the final list of file paths, or take advantage of -``FileCollection`` being countable and iterable to work directly with each ``File``:: - - echo 'My files: ' . implode(PHP_EOL, $files->get()); - echo 'I have ' . count($files) . ' files!'; +``FileCollection`` being countable and iterable to work directly with each ``File``: - foreach ($files as $file) { - echo 'Moving ' . $file->getBasename() . ', ' . $file->getSizeByUnit('mb'); - $file->move(WRITABLE . $file->getRandomName()); - } +.. literalinclude:: files/013.php + :lines: 2- Below are the specific methods for working with a ``FileCollection``. @@ -154,15 +129,10 @@ The constructor accepts an optional array of file paths to use as the initial co **define()** Allows child classes to define their own initial files. This method is called by the constructor and allows -predefined collections without having to use their methods. Example:: +predefined collections without having to use their methods. Example: - class ConfigCollection extends \CodeIgniter\Files\FileCollection - { - protected function define(): void - { - $this->add(APPPATH . 'Config', true)->retainPattern('*.php'); - } - } +.. literalinclude:: files/014.php + :lines: 2- Now you may use the ``ConfigCollection`` anywhere in your project to access all App Config files without having to re-call the collection methods every time. @@ -208,16 +178,10 @@ to ``glob()`` (like ``*.css``). If a ``$scope`` is provided then only files in or under that directory will be considered (i.e. files outside of ``$scope`` are always retained). When no scope is provided then all files are subject. -Examples:: - - $files = new FileCollection(); - $files->add(APPPATH . 'Config', true); // Adds all Config files and directories - - $files->removePattern('*tion.php'); // Would remove Encryption.php, Validation.php, and boot/production.php - $files->removePattern('*tion.php', APPPATH . 'Config/boot'); // Would only remove boot/production.php +Examples: - $files->retainPattern('#A.+php$#'); // Would keep only Autoload.php - $files->retainPattern('#d.+php$#', APPPATH . 'Config/boot'); // Would keep everything but boot/production.php and boot/testing.php +.. literalinclude:: files/015.php + :lines: 2- Retrieving Files ================ diff --git a/user_guide_src/source/libraries/files/001.php b/user_guide_src/source/libraries/files/001.php new file mode 100644 index 000000000000..643758d14ca8 --- /dev/null +++ b/user_guide_src/source/libraries/files/001.php @@ -0,0 +1,3 @@ +getBasename(); +// Get last modified time +echo $file->getMTime(); +// Get the true real path +echo $file->getRealPath(); +// Get the file permissions +echo $file->getPerms(); + +// Write CSV rows to it. +if ($file->isWritable()) { + $csv = $file->openFile('w'); + + foreach ($rows as $row) { + $csv->fputcsv($row); + } +} diff --git a/user_guide_src/source/libraries/files/003.php b/user_guide_src/source/libraries/files/003.php new file mode 100644 index 000000000000..53327d59bd0f --- /dev/null +++ b/user_guide_src/source/libraries/files/003.php @@ -0,0 +1,4 @@ +getRandomName(); diff --git a/user_guide_src/source/libraries/files/004.php b/user_guide_src/source/libraries/files/004.php new file mode 100644 index 000000000000..e73de3b6cd74 --- /dev/null +++ b/user_guide_src/source/libraries/files/004.php @@ -0,0 +1,3 @@ +getSize(); // 256901 diff --git a/user_guide_src/source/libraries/files/005.php b/user_guide_src/source/libraries/files/005.php new file mode 100644 index 000000000000..ee9043ff92a6 --- /dev/null +++ b/user_guide_src/source/libraries/files/005.php @@ -0,0 +1,5 @@ +getSizeByUnit(); // 256901 +$kilobytes = $file->getSizeByUnit('kb'); // 250.880 +$megabytes = $file->getSizeByUnit('mb'); // 0.245 diff --git a/user_guide_src/source/libraries/files/006.php b/user_guide_src/source/libraries/files/006.php new file mode 100644 index 000000000000..5c8ae9a08945 --- /dev/null +++ b/user_guide_src/source/libraries/files/006.php @@ -0,0 +1,5 @@ +getMimeType(); + +echo $type; // image/png diff --git a/user_guide_src/source/libraries/files/007.php b/user_guide_src/source/libraries/files/007.php new file mode 100644 index 000000000000..26be30a2c7bc --- /dev/null +++ b/user_guide_src/source/libraries/files/007.php @@ -0,0 +1,4 @@ +guessExtension(); diff --git a/user_guide_src/source/libraries/files/008.php b/user_guide_src/source/libraries/files/008.php new file mode 100644 index 000000000000..12499a3ca1ba --- /dev/null +++ b/user_guide_src/source/libraries/files/008.php @@ -0,0 +1,3 @@ +move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/files/009.php b/user_guide_src/source/libraries/files/009.php new file mode 100644 index 000000000000..2e6b39645a4b --- /dev/null +++ b/user_guide_src/source/libraries/files/009.php @@ -0,0 +1,4 @@ +getRandomName(); +$file->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/files/010.php b/user_guide_src/source/libraries/files/010.php new file mode 100644 index 000000000000..2a3fcab40957 --- /dev/null +++ b/user_guide_src/source/libraries/files/010.php @@ -0,0 +1,3 @@ +move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/files/011.php b/user_guide_src/source/libraries/files/011.php new file mode 100644 index 000000000000..fb15a5ca6cbd --- /dev/null +++ b/user_guide_src/source/libraries/files/011.php @@ -0,0 +1,7 @@ +addDirectory(APPPATH . 'Filters'); diff --git a/user_guide_src/source/libraries/files/012.php b/user_guide_src/source/libraries/files/012.php new file mode 100644 index 000000000000..db0f881014c0 --- /dev/null +++ b/user_guide_src/source/libraries/files/012.php @@ -0,0 +1,6 @@ +removeFile(APPPATH . 'Filters/DevelopToolbar'); + +$files->removePattern('#\.gitkeep#'); +$files->retainPattern('*.php'); diff --git a/user_guide_src/source/libraries/files/013.php b/user_guide_src/source/libraries/files/013.php new file mode 100644 index 000000000000..a529fd0bcd6c --- /dev/null +++ b/user_guide_src/source/libraries/files/013.php @@ -0,0 +1,9 @@ +get()); +echo 'I have ' . count($files) . ' files!'; + +foreach ($files as $file) { + echo 'Moving ' . $file->getBasename() . ', ' . $file->getSizeByUnit('mb'); + $file->move(WRITABLE . $file->getRandomName()); +} diff --git a/user_guide_src/source/libraries/files/014.php b/user_guide_src/source/libraries/files/014.php new file mode 100644 index 000000000000..a768829427f3 --- /dev/null +++ b/user_guide_src/source/libraries/files/014.php @@ -0,0 +1,9 @@ +add(APPPATH . 'Config', true)->retainPattern('*.php'); + } +} diff --git a/user_guide_src/source/libraries/files/015.php b/user_guide_src/source/libraries/files/015.php new file mode 100644 index 000000000000..7e5c65e9a3d6 --- /dev/null +++ b/user_guide_src/source/libraries/files/015.php @@ -0,0 +1,10 @@ +add(APPPATH . 'Config', true); // Adds all Config files and directories + +$files->removePattern('*tion.php'); // Would remove Encryption.php, Validation.php, and boot/production.php +$files->removePattern('*tion.php', APPPATH . 'Config/boot'); // Would only remove boot/production.php + +$files->retainPattern('#A.+php$#'); // Would keep only Autoload.php +$files->retainPattern('#d.+php$#', APPPATH . 'Config/boot'); // Would keep everything but boot/production.php and boot/testing.php diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index 0b9114456cf0..69c23e47ca03 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -15,18 +15,10 @@ Enabling Honeypot ===================== To enable a Honeypot, changes have to be made to the **app/Config/Filters.php**. Just uncomment honeypot -from the ``$globals`` array, like...:: - - public $globals = [ - 'before' => [ - 'honeypot' - // 'csrf', - ], - 'after' => [ - 'toolbar', - 'honeypot', - ], - ]; +from the ``$globals`` array, like...: + +.. literalinclude:: honeypot/001.php + :lines: 2- A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``. If it is not suitable, make your own at ``app/Filters/Honeypot.php``, diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php new file mode 100644 index 000000000000..1ed16460a9a4 --- /dev/null +++ b/user_guide_src/source/libraries/honeypot/001.php @@ -0,0 +1,12 @@ + [ + 'honeypot' + // 'csrf', + ], + 'after' => [ + 'toolbar', + 'honeypot', + ], +]; diff --git a/user_guide_src/source/libraries/images.rst b/user_guide_src/source/libraries/images.rst index bd71be9657f2..029c534cacbe 100644 --- a/user_guide_src/source/libraries/images.rst +++ b/user_guide_src/source/libraries/images.rst @@ -22,14 +22,16 @@ Initializing the Class ********************** Like most other classes in CodeIgniter, the image class is initialized -in your controller by calling the Services class:: +in your controller by calling the Services class: - $image = \Config\Services::image(); +.. literalinclude:: images/001.php + :lines: 2- You can pass the alias for the image library you wish to use into the -Service function:: +Service function: - $image = Config\Services::image('imagick'); +.. literalinclude:: images/002.php + :lines: 2- The available Handlers are as follows: @@ -50,12 +52,10 @@ Regardless of the type of processing you would like to perform (resizing, cropping, rotation, or watermarking), the general process is identical. You will set some preferences corresponding to the action you intend to perform, then call one of the available processing functions. -For example, to create an image thumbnail you'll do this:: +For example, to create an image thumbnail you'll do this: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->fit(100, 100, 'center') - ->save('/path/to/image/mypic_thumb.jpg'); +.. literalinclude:: images/003.php + :lines: 2- The above code tells the library to look for an image called *mypic.jpg* located in the source_image folder, then create a @@ -67,14 +67,10 @@ desired aspect ratio, and then crop and resize the result. An image can be processed through as many of the available methods as needed before saving. The original image is left untouched, and a new image is used and passed through each method, applying the results on top of the -previous results:: +previous results: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->reorient() - ->rotate(90) - ->crop(100, 100, 0, 0) - ->save('/path/to/image/mypic_thumb.jpg'); +.. literalinclude:: images/004.php + :lines: 2- This example would take the same image and first fix any mobile phone orientation issues, rotate the image by 90 degrees, and then crop the result into a 100x100 pixel image, @@ -94,22 +90,18 @@ Image Quality ``save()`` can take an additional parameter ``$quality`` to alter the resulting image quality. Values range from 0 to 100 with 90 being the framework default. This parameter -only applies to JPEG images and will be ignored otherwise:: +only applies to JPEG images and will be ignored otherwise: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - // processing methods - ->save('/path/to/image/my_low_quality_pic.jpg', 10); +.. literalinclude:: images/005.php + :lines: 2- .. note:: Higher quality will result in larger file sizes. See also https://www.php.net/manual/en/function.imagejpeg.php If you are only interested in changing the image quality without doing any processing. -You will need to include the image resource or you will end up with an exact copy:: +You will need to include the image resource or you will end up with an exact copy: - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->withResource() - ->save('/path/to/image/my_low_quality_pic.jpg', 10); +.. literalinclude:: images/006.php + :lines: 2- Processing Methods ================== @@ -128,16 +120,10 @@ There are seven available processing methods: These methods return the class instance so they can be chained together, as shown above. If they fail they will throw a ``CodeIgniter\Images\ImageException`` that contains the error message. A good practice is to catch the exceptions, showing an -error upon failure, like this:: +error upon failure, like this: - try { - $image = \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->fit(100, 100, 'center') - ->save('/path/to/image/mypic_thumb.jpg'); - } catch (CodeIgniter\Images\ImageException $e) { - echo $e->getMessage(); - } +.. literalinclude:: images/007.php + :lines: 2- Cropping Images --------------- @@ -155,20 +141,10 @@ thumbnail images that should match a certain size/aspect ratio. This is handled - **$masterDim** specifies which dimension should be left untouched when $maintainRatio is true. Values can be: 'width', 'height', or 'auto'. To take a 50x50 pixel square out of the center of an image, you would need to first calculate the appropriate x and y -offset values:: +offset values: - $info = \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->getFile() - ->getProperties(true); - - $xOffset = ($info['width'] / 2) - 25; - $yOffset = ($info['height'] / 2) - 25; - - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->crop(50, 50, $xOffset, $yOffset) - ->save('/path/to/new/image.jpg'); +.. literalinclude:: images/008.php + :lines: 2- Converting Images ----------------- @@ -177,12 +153,10 @@ The ``convert()`` method changes the library's internal indicator for the desire convert(int $imageType) -- **$imageType** is one of PHP's image type constants (see for example https://www.php.net/manual/en/function.image-type-to-mime-type.php):: +- **$imageType** is one of PHP's image type constants (see for example https://www.php.net/manual/en/function.image-type-to-mime-type.php): - \Config\Services::image() - ->withFile('/path/to/image/mypic.jpg') - ->convert(IMAGETYPE_PNG) - ->save('/path/to/new/image.png'); + .. literalinclude:: images/009.php + :lines: 2- .. note:: ImageMagick already saves files in the type indicated by their extension, ignoring **$imageType** @@ -204,12 +178,10 @@ The ``fit()`` method aims to help simplify cropping a portion of an image in a " - **$height** is the desired final height of the image. - **$position** determines the portion of the image to crop out. Allowed positions: 'top-left', 'top', 'top-right', 'left', 'center', 'right', 'bottom-left', 'bottom', 'bottom-right'. -This provides a much simpler way to crop that will always maintain the aspect ratio:: +This provides a much simpler way to crop that will always maintain the aspect ratio: - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->fit(100, 150, 'left') - ->save('/path/to/new/image.jpg'); +.. literalinclude:: images/010.php + :lines: 2- Flattening Images ----------------- @@ -226,17 +198,8 @@ The ``flatten()`` method aims to add a background color behind transparent image - **$green** is the green value of the background. - **$blue** is the blue value of the background. -:: - - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.png') - ->flatten() - ->save('/path/to/new/image.jpg'); - - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.png') - ->flatten(25,25,112) - ->save('/path/to/new/image.jpg'); +.. literalinclude:: images/011.php + :lines: 2- Flipping Images --------------- @@ -247,12 +210,8 @@ Images can be flipped along either their horizontal or vertical axis:: - **$dir** specifies the axis to flip along. Can be either 'vertical' or 'horizontal'. -:: - - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->flip('horizontal') - ->save('/path/to/new/image.jpg'); +.. literalinclude:: images/012.php + :lines: 2- Resizing Images --------------- @@ -270,12 +229,8 @@ When resizing images you can choose whether to maintain the ratio of the origina image to fit the desired dimensions. If $maintainRatio is true, the dimension specified by $masterDim will stay the same, while the other dimension will be altered to match the original image's aspect ratio. -:: - - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->resize(200, 100, true, 'height') - ->save('/path/to/new/image.jpg'); +.. literalinclude:: images/013.php + :lines: 2- Rotating Images --------------- @@ -301,19 +256,10 @@ products. text(string $text, array $options = []) The first parameter is the string of text that you wish to display. The second parameter is an array of options -that allow you to specify how the text should be displayed:: - - \Config\Services::image('imagick') - ->withFile('/path/to/image/mypic.jpg') - ->text('Copyright 2017 My Photo Co', [ - 'color' => '#fff', - 'opacity' => 0.5, - 'withShadow' => true, - 'hAlign' => 'center', - 'vAlign' => 'bottom', - 'fontSize' => 20 - ]) - ->save('/path/to/new/image.jpg'); +that allow you to specify how the text should be displayed: + +.. literalinclude:: images/014.php + :lines: 2- The possible options that are recognized are as follows: diff --git a/user_guide_src/source/libraries/images/001.php b/user_guide_src/source/libraries/images/001.php new file mode 100644 index 000000000000..780bb37b3a4d --- /dev/null +++ b/user_guide_src/source/libraries/images/001.php @@ -0,0 +1,3 @@ +withFile('/path/to/image/mypic.jpg') + ->fit(100, 100, 'center') + ->save('/path/to/image/mypic_thumb.jpg'); diff --git a/user_guide_src/source/libraries/images/004.php b/user_guide_src/source/libraries/images/004.php new file mode 100644 index 000000000000..ec6026592341 --- /dev/null +++ b/user_guide_src/source/libraries/images/004.php @@ -0,0 +1,8 @@ +withFile('/path/to/image/mypic.jpg') + ->reorient() + ->rotate(90) + ->crop(100, 100, 0, 0) + ->save('/path/to/image/mypic_thumb.jpg'); diff --git a/user_guide_src/source/libraries/images/005.php b/user_guide_src/source/libraries/images/005.php new file mode 100644 index 000000000000..3f7470ee82ac --- /dev/null +++ b/user_guide_src/source/libraries/images/005.php @@ -0,0 +1,6 @@ +withFile('/path/to/image/mypic.jpg') + // processing methods + ->save('/path/to/image/my_low_quality_pic.jpg', 10); diff --git a/user_guide_src/source/libraries/images/006.php b/user_guide_src/source/libraries/images/006.php new file mode 100644 index 000000000000..9bfcb18b3b7e --- /dev/null +++ b/user_guide_src/source/libraries/images/006.php @@ -0,0 +1,6 @@ +withFile('/path/to/image/mypic.jpg') + ->withResource() + ->save('/path/to/image/my_low_quality_pic.jpg', 10); diff --git a/user_guide_src/source/libraries/images/007.php b/user_guide_src/source/libraries/images/007.php new file mode 100644 index 000000000000..503c038cf81c --- /dev/null +++ b/user_guide_src/source/libraries/images/007.php @@ -0,0 +1,10 @@ +withFile('/path/to/image/mypic.jpg') + ->fit(100, 100, 'center') + ->save('/path/to/image/mypic_thumb.jpg'); +} catch (CodeIgniter\Images\ImageException $e) { + echo $e->getMessage(); +} diff --git a/user_guide_src/source/libraries/images/008.php b/user_guide_src/source/libraries/images/008.php new file mode 100644 index 000000000000..01406733d31b --- /dev/null +++ b/user_guide_src/source/libraries/images/008.php @@ -0,0 +1,14 @@ +withFile('/path/to/image/mypic.jpg') + ->getFile() + ->getProperties(true); + +$xOffset = ($info['width'] / 2) - 25; +$yOffset = ($info['height'] / 2) - 25; + +\Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.jpg') + ->crop(50, 50, $xOffset, $yOffset) + ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/009.php b/user_guide_src/source/libraries/images/009.php new file mode 100644 index 000000000000..6314181ef435 --- /dev/null +++ b/user_guide_src/source/libraries/images/009.php @@ -0,0 +1,6 @@ +withFile('/path/to/image/mypic.jpg') + ->convert(IMAGETYPE_PNG) + ->save('/path/to/new/image.png'); diff --git a/user_guide_src/source/libraries/images/010.php b/user_guide_src/source/libraries/images/010.php new file mode 100644 index 000000000000..b70b179815cd --- /dev/null +++ b/user_guide_src/source/libraries/images/010.php @@ -0,0 +1,6 @@ +withFile('/path/to/image/mypic.jpg') + ->fit(100, 150, 'left') + ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/011.php b/user_guide_src/source/libraries/images/011.php new file mode 100644 index 000000000000..c72932893af8 --- /dev/null +++ b/user_guide_src/source/libraries/images/011.php @@ -0,0 +1,11 @@ +withFile('/path/to/image/mypic.png') + ->flatten() + ->save('/path/to/new/image.jpg'); + +\Config\Services::image('imagick') + ->withFile('/path/to/image/mypic.png') + ->flatten(25,25,112) + ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/012.php b/user_guide_src/source/libraries/images/012.php new file mode 100644 index 000000000000..581a984238bd --- /dev/null +++ b/user_guide_src/source/libraries/images/012.php @@ -0,0 +1,6 @@ +withFile('/path/to/image/mypic.jpg') + ->flip('horizontal') + ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/013.php b/user_guide_src/source/libraries/images/013.php new file mode 100644 index 000000000000..c51a7126be8d --- /dev/null +++ b/user_guide_src/source/libraries/images/013.php @@ -0,0 +1,6 @@ +withFile('/path/to/image/mypic.jpg') + ->resize(200, 100, true, 'height') + ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/014.php b/user_guide_src/source/libraries/images/014.php new file mode 100644 index 000000000000..4afd1e12d420 --- /dev/null +++ b/user_guide_src/source/libraries/images/014.php @@ -0,0 +1,13 @@ +withFile('/path/to/image/mypic.jpg') + ->text('Copyright 2017 My Photo Co', [ + 'color' => '#fff', + 'opacity' => 0.5, + 'withShadow' => true, + 'hAlign' => 'center', + 'vAlign' => 'bottom', + 'fontSize' => 20 + ]) + ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index dfab3b6c80f4..8a79531326d6 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -14,9 +14,10 @@ Loading the Library ******************* Like all services in CodeIgniter, it can be loaded via ``Config\Services``, though you usually will not need -to load it manually:: +to load it manually: - $pager = \Config\Services::pager(); +.. literalinclude:: pagination/001.php + :lines: 2- *************************** Paginating Database Results @@ -27,28 +28,9 @@ When using the :doc:`Model ` class, you can use its built-in ``pa retrieve the current batch of results, as well as set up the Pager library so it's ready to use in your controllers. It even reads the current page it should display from the current URL via a ``page=X`` query variable. -To provide a paginated list of users in your application, your controller's method would look something like:: +To provide a paginated list of users in your application, your controller's method would look something like: - $model->paginate(10), - 'pager' => $model->pager, - ]; - - echo view('users/index', $data); - } - } +.. literalinclude:: pagination/002.php In this example, we first create a new instance of our ``UserModel``. Then we populate the data to send to the view. The first element is the results from the database, **users**, which is retrieved for the correct page, returning @@ -60,28 +42,10 @@ that and assign it to the ``$pager`` variable in the view. Therefore, trying to use ``$db->query()`` and Model::paginate() **will not work** because ``$db->query()`` executes the query immediately and is not associated with a QueryBuilder. -To define conditions for pagination in a model, you can:: +To define conditions for pagination in a model, you can: - // You can specify conditions directly. - $model = new \App\Models\UserModel(); - - $data = [ - 'users' => $model->where('ban', 1)->paginate(10), - 'pager' => $model->pager, - ]; - - // You can move the conditions to a separate method. - // Model method - public function banned() - { - $this->builder()->where('ban', 1); - return $this; // This will allow the call chain to be used. - } - - $data = [ - 'users' => $model->banned()->paginate(10), - 'pager' => $model->pager, - ]; +.. literalinclude:: pagination/003.php + :lines: 2- Within the view, we then need to tell it where to display the resulting links:: @@ -106,26 +70,10 @@ Paginating Multiple Results =========================== If you need to provide links from two different result sets, you can pass group names to most of the pagination -methods to keep the data separate:: - - // In the Controller - public function index() - { - $userModel = new \App\Models\UserModel(); - $pageModel = new \App\Models\PageModel(); - - $data = [ - 'users' => $userModel->paginate(10, 'group1'), - 'pages' => $pageModel->paginate(15, 'group2'), - 'pager' => $userModel->pager, - ]; +methods to keep the data separate: - echo view('users/index', $data); - } - - // In the views: - links('group1') ?> - simpleLinks('group2') ?> +.. literalinclude:: pagination/004.php + :lines: 2- Setting Page Manually ===================== @@ -133,12 +81,8 @@ Setting Page Manually If you need to specify which page of results to return you can specify the page as the 3rd argument. This can be handy when you have a different manner than the default ``$_GET`` varibable to control which page to show. -:: - - $userModel = new \App\Models\UserModel(); - $page = 3; - - $users = $userModel->paginate(10, 'group1', $page); +.. literalinclude:: pagination/005.php + :lines: 2- Specifying the URI Segment for Page =================================== @@ -147,9 +91,8 @@ It is also possible to use a URI segment for the page number, instead of the pag segment number to use as the fourth argument. URIs generated by the pager would then look like **https://domain.tld/foo/bar/[pageNumber]** instead of **https://domain.tld/foo/bar?page=[pageNumber]**. -:: - - $users = $userModel->paginate(10, 'group1', null, $segment); +.. literalinclude:: pagination/006.php + :lines: 2- Please note: ``$segment`` value cannot be greater than the number of URI segments plus 1. @@ -179,11 +122,10 @@ the previous section. Specify the segment number to use as the fifth parameter t Please note: ``$segment`` value cannot be greater than the number of URI segments plus 1. -If you in need to show many pagers on one page then additional parameter which will define a group could be helpful:: +If you in need to show many pagers on one page then additional parameter which will define a group could be helpful: - $pager = service('pager'); - $pager->setPath('path/for/my-group', 'my-group'); // Additionally you could define path for every group. - $pager->makeLinks($page, $perPage, $total, 'template_name', $segment, 'my-group'); +.. literalinclude:: pagination/007.php + :lines: 2- Pagination library uses **page** query parameter for HTTP queries by default (if no group or ``default`` group name given) or ``page_[groupName]`` for custom group names. @@ -192,15 +134,15 @@ Paginating with Only Expected Queries By default, all GET queries are shown in the pagination links. -For example, when accessing the URL **https://domain.tld?search=foo&order=asc&hello=i+am+here&page=2**, the page 3 link can be generated, along with the other links, as follows:: +For example, when accessing the URL **https://domain.tld?search=foo&order=asc&hello=i+am+here&page=2**, the page 3 link can be generated, along with the other links, as follows: - echo $pager->links(); - // Page 3 link: https://domain.tld?search=foo&order=asc&hello=i+am+here&page=3 +.. literalinclude:: pagination/008.php + :lines: 2- -The ``only()`` method allows you to limit this just to queries already expected:: +The ``only()`` method allows you to limit this just to queries already expected: - echo $pager->only(['search', 'order'])->links(); - // Page 3 link: https://domain.tld?search=foo&order=asc&page=3 +.. literalinclude:: pagination/009.php + :lines: 2- The *page* query is enabled by default. And ``only()`` acts in all pagination links. @@ -212,12 +154,10 @@ View Configuration ================== When the links are rendered out to the page, they use a view file to describe the HTML. You can easily change the view -that is used by editing **app/Config/Pager.php**:: +that is used by editing **app/Config/Pager.php**: - public $templates = [ - 'default_full' => 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', - ]; +.. literalinclude:: pagination/010.php + :lines: 2- This setting stores the alias and :doc:`namespaced view paths ` for the view that should be used. The ``default_full`` and ``default_simple`` views are used for the ``links()`` and ``simpleLinks()`` @@ -226,25 +166,23 @@ methods, respectively. To change the way those are displayed application-wide, y For example, say you create a new view file that works with the Foundation CSS framework, and you place that file at **app/Views/Pagers/foundation_full.php**. Since the **application** directory is namespaced as ``App``, and all directories underneath it map directly to segments of the namespace, you can locate -the view file through it's namespace:: +the view file through it's namespace: - 'default_full' => 'App\Views\Pagers\foundation_full', +.. literalinclude:: pagination/011.php + :lines: 2- Since it is under the standard **app/Views** directory, though, you do not need to namespace it since the -``view()`` method can locate it by filename. In that case, you can simply give the sub-directory and file name:: +``view()`` method can locate it by filename. In that case, you can simply give the sub-directory and file name: - 'default_full' => 'Pagers/foundation_full', +.. literalinclude:: pagination/012.php + :lines: 2- Once you have created the view and set it in the configuration, it will automatically be used. You don't have to replace the existing templates. You can create as many additional templates as you need in the configuration file. A common situation would be needing different styles for the frontend and the backend of your application. -:: - public $templates = [ - 'default_full' => 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', - 'front_full' => 'App\Views\Pagers\foundation_full', - ]; +.. literalinclude:: pagination/013.php + :lines: 2- Once configured, you can specify it as a the last parameter in the ``links()``, ``simpleLinks()``, and ``makeLinks()`` methods:: @@ -258,47 +196,9 @@ Creating the View When you create a new view, you only need to create the code that is needed for creating the pagination links themselves. You should not create unnecessary wrapping divs since it might be used in multiple places and you only limit their -usefulness. It is easiest to demonstrate creating a new view by showing you the existing ``default_full`` template:: - - setSurroundCount(2) ?> - - +usefulness. It is easiest to demonstrate creating a new view by showing you the existing ``default_full`` template: + +.. literalinclude:: pagination/014.php **setSurroundCount()** @@ -326,57 +226,18 @@ result set. **links()** Returns an array of data about all of the numbered links. Each link's array contains the uri for the link, the -title, which is just the number, and a boolean that tells whether the link is the current/active link or not:: +title, which is just the number, and a boolean that tells whether the link is the current/active link or not: - $link = [ - 'active' => false, - 'uri' => 'https://example.com/foo?page=2', - 'title' => 1, - ]; +.. literalinclude:: pagination/015.php + :lines: 2- In the code presented for the standard pagination structure, the methods ``getPrevious()`` and ``getNext()`` are used to obtain the links to the previous and next pagination groups respectively. If you want to use the pagination structure where prev and next will be links to the previous and next pages based on the current page, just replace the ``getPrevious()`` and ``getNext()`` methods with ``getPreviousPage()`` and ``getNextPage()``, and the methods ``hasPrevious()`` and ``hasNext()`` by ``hasPreviousPage()`` and ``hasNextPage()`` respectively. -See following an example with these changes:: - - +See following an example with these changes: + +.. literalinclude:: pagination/016.php **hasPreviousPage()** & **hasNextPage()** diff --git a/user_guide_src/source/libraries/pagination/001.php b/user_guide_src/source/libraries/pagination/001.php new file mode 100644 index 000000000000..ec86f0e73490 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/001.php @@ -0,0 +1,3 @@ + $model->paginate(10), + 'pager' => $model->pager, + ]; + + echo view('users/index', $data); + } +} diff --git a/user_guide_src/source/libraries/pagination/003.php b/user_guide_src/source/libraries/pagination/003.php new file mode 100644 index 000000000000..f0ea0d90ed76 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/003.php @@ -0,0 +1,22 @@ + $model->where('ban', 1)->paginate(10), + 'pager' => $model->pager, +]; + +// You can move the conditions to a separate method. +// Model method +public function banned() +{ + $this->builder()->where('ban', 1); + return $this; // This will allow the call chain to be used. +} + +$data = [ + 'users' => $model->banned()->paginate(10), + 'pager' => $model->pager, +]; diff --git a/user_guide_src/source/libraries/pagination/004.php b/user_guide_src/source/libraries/pagination/004.php new file mode 100644 index 000000000000..a61b3c3bad2a --- /dev/null +++ b/user_guide_src/source/libraries/pagination/004.php @@ -0,0 +1,20 @@ + $userModel->paginate(10, 'group1'), + 'pages' => $pageModel->paginate(15, 'group2'), + 'pager' => $userModel->pager, + ]; + + echo view('users/index', $data); +} + +// In the views: +links('group1') ?> +simpleLinks('group2') ?> diff --git a/user_guide_src/source/libraries/pagination/005.php b/user_guide_src/source/libraries/pagination/005.php new file mode 100644 index 000000000000..149f369b321c --- /dev/null +++ b/user_guide_src/source/libraries/pagination/005.php @@ -0,0 +1,6 @@ +paginate(10, 'group1', $page); diff --git a/user_guide_src/source/libraries/pagination/006.php b/user_guide_src/source/libraries/pagination/006.php new file mode 100644 index 000000000000..9d754431ce58 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/006.php @@ -0,0 +1,3 @@ +paginate(10, 'group1', null, $segment); diff --git a/user_guide_src/source/libraries/pagination/007.php b/user_guide_src/source/libraries/pagination/007.php new file mode 100644 index 000000000000..be726a996116 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/007.php @@ -0,0 +1,5 @@ +setPath('path/for/my-group', 'my-group'); // Additionally you could define path for every group. +$pager->makeLinks($page, $perPage, $total, 'template_name', $segment, 'my-group'); diff --git a/user_guide_src/source/libraries/pagination/008.php b/user_guide_src/source/libraries/pagination/008.php new file mode 100644 index 000000000000..0b8219ff43e3 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/008.php @@ -0,0 +1,4 @@ +links(); +// Page 3 link: https://domain.tld?search=foo&order=asc&hello=i+am+here&page=3 diff --git a/user_guide_src/source/libraries/pagination/009.php b/user_guide_src/source/libraries/pagination/009.php new file mode 100644 index 000000000000..6f309ca10552 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/009.php @@ -0,0 +1,4 @@ +only(['search', 'order'])->links(); +// Page 3 link: https://domain.tld?search=foo&order=asc&page=3 diff --git a/user_guide_src/source/libraries/pagination/010.php b/user_guide_src/source/libraries/pagination/010.php new file mode 100644 index 000000000000..95d27f8e4e3c --- /dev/null +++ b/user_guide_src/source/libraries/pagination/010.php @@ -0,0 +1,6 @@ + 'CodeIgniter\Pager\Views\default_full', + 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', +]; diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php new file mode 100644 index 000000000000..86c5e0bcd8b5 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/011.php @@ -0,0 +1,3 @@ + 'App\Views\Pagers\foundation_full', diff --git a/user_guide_src/source/libraries/pagination/012.php b/user_guide_src/source/libraries/pagination/012.php new file mode 100644 index 000000000000..841118b57ae1 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/012.php @@ -0,0 +1,3 @@ + 'Pagers/foundation_full', diff --git a/user_guide_src/source/libraries/pagination/013.php b/user_guide_src/source/libraries/pagination/013.php new file mode 100644 index 000000000000..fa59edbacf9b --- /dev/null +++ b/user_guide_src/source/libraries/pagination/013.php @@ -0,0 +1,7 @@ + 'CodeIgniter\Pager\Views\default_full', + 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', + 'front_full' => 'App\Views\Pagers\foundation_full', +]; diff --git a/user_guide_src/source/libraries/pagination/014.php b/user_guide_src/source/libraries/pagination/014.php new file mode 100644 index 000000000000..00bdee764c7f --- /dev/null +++ b/user_guide_src/source/libraries/pagination/014.php @@ -0,0 +1,39 @@ +setSurroundCount(2) ?> + + diff --git a/user_guide_src/source/libraries/pagination/015.php b/user_guide_src/source/libraries/pagination/015.php new file mode 100644 index 000000000000..43a8f2624d64 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/015.php @@ -0,0 +1,7 @@ + false, + 'uri' => 'https://example.com/foo?page=2', + 'title' => 1, +]; diff --git a/user_guide_src/source/libraries/pagination/016.php b/user_guide_src/source/libraries/pagination/016.php new file mode 100644 index 000000000000..e827bd15a457 --- /dev/null +++ b/user_guide_src/source/libraries/pagination/016.php @@ -0,0 +1,37 @@ + diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 895d74bee7b3..3657a124317c 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -13,9 +13,10 @@ Loading the Library ******************* Because Publisher instances are specific to their source and destination this library is not available -through ``Services`` but should be instantiated or extended directly. E.g.:: +through ``Services`` but should be instantiated or extended directly. E.g.: - $publisher = new \CodeIgniter\Publisher\Publisher(); +.. literalinclude:: publisher/001.php + :lines: 2- ***************** Concept and Usage @@ -36,43 +37,23 @@ the class and leveraging its discovery with ``spark publish``. On Demand ========= -Access ``Publisher`` directly by instantiating a new instance of the class:: +Access ``Publisher`` directly by instantiating a new instance of the class: - $publisher = new \CodeIgniter\Publisher\Publisher(); +.. literalinclude:: publisher/001.php + :lines: 2- By default the source and destination will be set to ``ROOTPATH`` and ``FCPATH`` respectively, giving ``Publisher`` easy access to take any file from your project and make it web-accessible. Alternatively you may pass a new source -or source and destination into the constructor:: +or source and destination into the constructor: - use CodeIgniter\Publisher\Publisher; - - $vendorPublisher = new Publisher(ROOTPATH . 'vendor'); - $filterPublisher = new Publisher('/path/to/module/Filters', APPPATH . 'Filters'); - - // Once the source and destination are set you may start adding relative input files - $frameworkPublisher = new Publisher(ROOTPATH . 'vendor/codeigniter4/codeigniter4'); - - // All "path" commands are relative to $source - $frameworkPublisher->addPath('app/Config/Cookie.php'); - - // You may also add from outside the source, but the files will not be merged into subdirectories - $frameworkPublisher->addFiles([ - '/opt/mail/susan', - '/opt/mail/ubuntu', - ]); - $frameworkPublisher->addDirectory(SUPPORTPATH . 'Images'); +.. literalinclude:: publisher/003.php + :lines: 2- Once all the files are staged use one of the output commands (**copy()** or **merge()**) to process the staged files -to their destination(s):: - - // Place all files into $destination - $frameworkPublisher->copy(); +to their destination(s): - // Place all files into $destination, overwriting existing files - $frameworkPublisher->copy(true); - - // Place files into their relative $destination directories, overwriting and saving the boolean result - $result = $frameworkPublisher->merge(true); +.. literalinclude:: publisher/004.php + :lines: 2- See the :ref:`reference` for a full description of available methods. @@ -80,24 +61,16 @@ Automation and Discovery ======================== You may have regular publication tasks embedded as part of your application deployment or upkeep. ``Publisher`` leverages -the powerful ``Autoloader`` to locate any child classes primed for publication:: - - use CodeIgniter\CLI\CLI; - use CodeIgniter\Publisher\Publisher; - - foreach (Publisher::discover() as $publisher) - { - $result = $publisher->publish(); +the powerful ``Autoloader`` to locate any child classes primed for publication: - if ($result === false) { - CLI::error(get_class($publisher) . ' failed to publish!', 'red'); - } - } +.. literalinclude:: publisher/005.php + :lines: 2- By default ``discover()`` will search for the "Publishers" directory across all namespaces, but you may specify a -different directory and it will return any child classes found:: +different directory and it will return any child classes found: - $memePublishers = Publisher::discover('CatGIFs'); +.. literalinclude:: publisher/006.php + :lines: 2- Most of the time you will not need to handle your own discovery, just use the provided "publish" command:: @@ -131,92 +104,25 @@ File Sync Example You want to display a "photo of the day" image on your homepage. You have a feed for daily photos but you need to get the actual file into a browsable location in your project at **public/images/daily_photo.jpg**. -You can set up :doc:`Custom Command ` to run daily that will handle this for you:: - - ` to run daily that will handle this for you: - use CodeIgniter\CLI\BaseCommand; - use CodeIgniter\Publisher\Publisher; - use Throwable; - - class DailyPhoto extends BaseCommand - { - protected $group = 'Publication'; - protected $name = 'publish:daily'; - protected $description = 'Publishes the latest daily photo to the homepage.'; - - public function run(array $params) - { - $publisher = new Publisher('/path/to/photos/', FCPATH . 'assets/images'); - - try { - $publisher->addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites - } catch (Throwable $e) { - $this->showError($e); - } - } - } +.. literalinclude:: publisher/007.php Now running ``spark publish:daily`` will keep your homepage's image up-to-date. What if the photo is coming from an external API? You can use ``addUri()`` in place of ``addPath()`` to download the remote -resource and publish it out instead:: +resource and publish it out instead: - $publisher->addUri('https://example.com/feeds/daily_photo.jpg')->copy(true); +.. literalinclude:: publisher/008.php + :lines: 2- Asset Dependencies Example ========================== You want to integrate the frontend library "Bootstrap" into your project, but the frequent updates makes it a hassle to keep up with. You can create a publication definition in your project to sync frontend assets by extending -``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this:: - - addPath('dist') - - // Indicate we only want the minimized versions - ->retainPattern('*.min.*') - - // Merge-and-replace to retain the original directory structure - ->merge(true); - } - } +``Publisher`` in your project. So **app/Publishers/BootstrapPublisher.php** might look like this: + +.. literalinclude:: publisher/009.php Now add the dependency via Composer and call ``spark publish`` to run the publication:: @@ -254,50 +160,9 @@ Module Deployment Example You want to allow developers using your popular authentication module the ability to expand on the default behavior of your Migration, Controller, and Model. You can create your own module "publish" command to inject these components -into an application for use:: - - getNamespace('Math\\Auth'); - - $publisher = new Publisher($source, APPATH); - - try { - // Add only the desired components - $publisher->addPaths([ - 'Controllers', - 'Database/Migrations', - 'Models', - ])->merge(false); // Be careful not to overwrite anything - } catch (Throwable $e) { - $this->showError($e); - return; - } - - // If publication succeeded then update namespaces - foreach ($publisher->getPublished() as $file) { - // Replace the namespace - $contents = file_get_contents($file); - $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, $contents); - file_put_contents($file, $contents); - } - } - } +into an application for use: + +.. literalinclude:: publisher/010.php Now when your module users run ``php spark auth:publish`` they will have the following added to their project:: @@ -370,16 +235,10 @@ Copies all files into the ``$destination``. This does not recreate the directory from the current list will end up in the same destination directory. Using ``$replace`` will cause files to overwrite when there is already an existing file. Returns success or failure, use ``getPublished()`` and ``getErrors()`` to troubleshoot failures. -Be mindful of duplicate basename collisions, for example:: - - $publisher = new Publisher('/home/source', '/home/destination'); - $publisher->addPaths([ - 'pencil/lead.png', - 'metal/lead.png', - ]); +Be mindful of duplicate basename collisions, for example: - // This is bad! Only one file will remain at /home/destination/lead.png - $publisher->copy(true); +.. literalinclude:: publisher/011.php + :lines: 2- **merge(bool $replace = true): bool** @@ -390,13 +249,7 @@ to overwrite when there is already an existing file; since directories are merge affect other files in the destination. Returns success or failure, use ``getPublished()`` and ``getErrors()`` to troubleshoot failures. -Example:: - - $publisher = new Publisher('/home/source', '/home/destination'); - $publisher->addPaths([ - 'pencil/lead.png', - 'metal/lead.png', - ]); +Example: - // Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png" - $publisher->merge(); +.. literalinclude:: publisher/012.php + :lines: 2- diff --git a/user_guide_src/source/libraries/publisher/001.php b/user_guide_src/source/libraries/publisher/001.php new file mode 100644 index 000000000000..6312e0d034f4 --- /dev/null +++ b/user_guide_src/source/libraries/publisher/001.php @@ -0,0 +1,3 @@ +addPath('app/Config/Cookie.php'); + +// You may also add from outside the source, but the files will not be merged into subdirectories +$frameworkPublisher->addFiles([ + '/opt/mail/susan', + '/opt/mail/ubuntu', +]); +$frameworkPublisher->addDirectory(SUPPORTPATH . 'Images'); diff --git a/user_guide_src/source/libraries/publisher/004.php b/user_guide_src/source/libraries/publisher/004.php new file mode 100644 index 000000000000..f516a8cab4aa --- /dev/null +++ b/user_guide_src/source/libraries/publisher/004.php @@ -0,0 +1,10 @@ +copy(); + +// Place all files into $destination, overwriting existing files +$frameworkPublisher->copy(true); + +// Place files into their relative $destination directories, overwriting and saving the boolean result +$result = $frameworkPublisher->merge(true); diff --git a/user_guide_src/source/libraries/publisher/005.php b/user_guide_src/source/libraries/publisher/005.php new file mode 100644 index 000000000000..5d598c3f7d1c --- /dev/null +++ b/user_guide_src/source/libraries/publisher/005.php @@ -0,0 +1,13 @@ +publish(); + + if ($result === false) { + CLI::error(get_class($publisher) . ' failed to publish!', 'red'); + } +} diff --git a/user_guide_src/source/libraries/publisher/006.php b/user_guide_src/source/libraries/publisher/006.php new file mode 100644 index 000000000000..9ec20cc403e2 --- /dev/null +++ b/user_guide_src/source/libraries/publisher/006.php @@ -0,0 +1,3 @@ +addPath('daily_photo.jpg')->copy(true); // `true` to enable overwrites + } catch (Throwable $e) { + $this->showError($e); + } + } +} diff --git a/user_guide_src/source/libraries/publisher/008.php b/user_guide_src/source/libraries/publisher/008.php new file mode 100644 index 000000000000..23467e5b28bf --- /dev/null +++ b/user_guide_src/source/libraries/publisher/008.php @@ -0,0 +1,3 @@ +addUri('https://example.com/feeds/daily_photo.jpg')->copy(true); diff --git a/user_guide_src/source/libraries/publisher/009.php b/user_guide_src/source/libraries/publisher/009.php new file mode 100644 index 000000000000..4756956740bd --- /dev/null +++ b/user_guide_src/source/libraries/publisher/009.php @@ -0,0 +1,45 @@ +addPath('dist') + + // Indicate we only want the minimized versions + ->retainPattern('*.min.*') + + // Merge-and-replace to retain the original directory structure + ->merge(true); + } +} diff --git a/user_guide_src/source/libraries/publisher/010.php b/user_guide_src/source/libraries/publisher/010.php new file mode 100644 index 000000000000..3ea9c40e24b6 --- /dev/null +++ b/user_guide_src/source/libraries/publisher/010.php @@ -0,0 +1,42 @@ +getNamespace('Math\\Auth'); + + $publisher = new Publisher($source, APPATH); + + try { + // Add only the desired components + $publisher->addPaths([ + 'Controllers', + 'Database/Migrations', + 'Models', + ])->merge(false); // Be careful not to overwrite anything + } catch (Throwable $e) { + $this->showError($e); + return; + } + + // If publication succeeded then update namespaces + foreach ($publisher->getPublished() as $file) { + // Replace the namespace + $contents = file_get_contents($file); + $contents = str_replace('namespace Math\\Auth', 'namespace ' . APP_NAMESPACE, $contents); + file_put_contents($file, $contents); + } + } +} diff --git a/user_guide_src/source/libraries/publisher/011.php b/user_guide_src/source/libraries/publisher/011.php new file mode 100644 index 000000000000..b48e43282de1 --- /dev/null +++ b/user_guide_src/source/libraries/publisher/011.php @@ -0,0 +1,10 @@ +addPaths([ + 'pencil/lead.png', + 'metal/lead.png', +]); + +// This is bad! Only one file will remain at /home/destination/lead.png +$publisher->copy(true); diff --git a/user_guide_src/source/libraries/publisher/012.php b/user_guide_src/source/libraries/publisher/012.php new file mode 100644 index 000000000000..32ec11f13b33 --- /dev/null +++ b/user_guide_src/source/libraries/publisher/012.php @@ -0,0 +1,10 @@ +addPaths([ + 'pencil/lead.png', + 'metal/lead.png', +]); + +// Results in "/home/destination/pencil/lead.png" and "/home/destination/metal/lead.png" +$publisher->merge(); diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 08c23d4ff337..d3a2b6cc0785 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -15,9 +15,10 @@ Loading the Library If your only interest in loading the library is to handle CSRF protection, then you will never need to load it, as it runs as a filter and has no manual interaction. -If you find a case where you do need direct access though, you may load it through the Services file:: +If you find a case where you do need direct access though, you may load it through the Services file: - $security = \Config\Services::security(); +.. literalinclude:: security/001.php + :lines: 2- .. _cross-site-request-forgery: @@ -44,9 +45,10 @@ You can also use Session based CSRF Protection. It is `Synchronizer Token Pattern `_. You can set to use the Session based CSRF protection by editing the following config parameter value in -**app/Config/Security.php**:: +**app/Config/Security.php**: - public $csrfProtection = 'session'; +.. literalinclude:: security/002.php + :lines: 2- Token Randomization ------------------- @@ -58,9 +60,10 @@ If you enable it, a random mask is added to the token and used to scramble it. .. _`BREACH`: https://en.wikipedia.org/wiki/BREACH You can enable it by editing the following config parameter value in -**app/Config/Security.php**:: +**app/Config/Security.php**: - public $tokenRandomize = true; +.. literalinclude:: security/003.php + :lines: 2- Token Regeneration ------------------ @@ -71,9 +74,10 @@ regeneration of tokens provides stricter security, but may result in usability concerns as other tokens become invalid (back/forward navigation, multiple tabs/windows, asynchronous actions, etc). You may alter this behavior by editing the following config parameter value in -**app/Config/Security.php**:: +**app/Config/Security.php**: - public $regenerate = true; +.. literalinclude:: security/004.php + :lines: 2- Redirection on Failure ---------------------- @@ -85,9 +89,10 @@ setting an ``error`` flash message that you can display to the end user with the This provides a nicer experience than simply crashing. This can be turned off by editing the following config parameter value in -**app/Config/Security.php**:: +**app/Config/Security.php**: - public $redirect = false; +.. literalinclude:: security/005.php + :lines: 2- Even when the redirect value is ``true``, AJAX calls will not redirect, but will throw an error. @@ -95,39 +100,27 @@ Enable CSRF Protection ====================== You can enable CSRF protection by altering your **app/Config/Filters.php** -and enabling the `csrf` filter globally:: +and enabling the `csrf` filter globally: - public $globals = [ - 'before' => [ - // 'honeypot', - 'csrf', - ], - ]; +.. literalinclude:: security/006.php + :lines: 2- Select URIs can be whitelisted from CSRF protection (for example API endpoints expecting externally POSTed content). You can add these URIs -by adding them as exceptions in the filter:: +by adding them as exceptions in the filter: - public $globals = [ - 'before' => [ - 'csrf' => ['except' => ['api/record/save']], - ], - ]; +.. literalinclude:: security/007.php + :lines: 2- -Regular expressions are also supported (case-insensitive):: +Regular expressions are also supported (case-insensitive): - public $globals = [ - 'before' => [ - 'csrf' => ['except' => ['api/record/[0-9]+']], - ], - ]; +.. literalinclude:: security/008.php + :lines: 2- -It is also possible to enable the CSRF filter only for specific methods:: +It is also possible to enable the CSRF filter only for specific methods: - public $methods = [ - 'get' => ['csrf'], - 'post' => ['csrf'], - ]; +.. literalinclude:: security/009.php + :lines: 2- .. Warning:: If you use ``$methods`` filters, you should :ref:`disable auto-routing ` because auto-routing permits any HTTP method to access a controller. @@ -188,6 +181,6 @@ particularly useful for files that were supplied via user input. The first param If it is acceptable for the user input to include relative paths, e.g., **file/in/some/approved/folder.txt**, you can set the second optional parameter, ``$relativePath`` to ``true``. -:: - $path = $security->sanitizeFilename($request->getVar('filepath')); +.. literalinclude:: security/010.php + :lines: 2- diff --git a/user_guide_src/source/libraries/security/001.php b/user_guide_src/source/libraries/security/001.php new file mode 100644 index 000000000000..fe504ef35a8e --- /dev/null +++ b/user_guide_src/source/libraries/security/001.php @@ -0,0 +1,3 @@ + [ + // 'honeypot', + 'csrf', + ], +]; diff --git a/user_guide_src/source/libraries/security/007.php b/user_guide_src/source/libraries/security/007.php new file mode 100644 index 000000000000..d647d1b8c120 --- /dev/null +++ b/user_guide_src/source/libraries/security/007.php @@ -0,0 +1,7 @@ + [ + 'csrf' => ['except' => ['api/record/save']], + ], +]; diff --git a/user_guide_src/source/libraries/security/008.php b/user_guide_src/source/libraries/security/008.php new file mode 100644 index 000000000000..c78d18937b08 --- /dev/null +++ b/user_guide_src/source/libraries/security/008.php @@ -0,0 +1,7 @@ + [ + 'csrf' => ['except' => ['api/record/[0-9]+']], + ], +]; diff --git a/user_guide_src/source/libraries/security/009.php b/user_guide_src/source/libraries/security/009.php new file mode 100644 index 000000000000..e2b03e79ba25 --- /dev/null +++ b/user_guide_src/source/libraries/security/009.php @@ -0,0 +1,6 @@ + ['csrf'], + 'post' => ['csrf'], +]; diff --git a/user_guide_src/source/libraries/security/010.php b/user_guide_src/source/libraries/security/010.php new file mode 100644 index 000000000000..228df8107fda --- /dev/null +++ b/user_guide_src/source/libraries/security/010.php @@ -0,0 +1,3 @@ +sanitizeFilename($request->getVar('filepath')); diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index cb6e78c25330..889ad559d8bb 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -21,24 +21,26 @@ Initializing a Session Sessions will typically run globally with each page load, so the Session class should be magically initialized. -To access and initialize the session:: +To access and initialize the session: - $session = \Config\Services::session($config); +.. literalinclude:: sessions/001.php + :lines: 2- The ``$config`` parameter is optional - your application configuration. If not provided, the services register will instantiate your default one. -Once loaded, the Sessions library object will be available using:: +Once loaded, the Sessions library object will be available using: - $session +.. literalinclude:: sessions/002.php + :lines: 2- Alternatively, you can use the helper function that will use the default configuration options. This version is a little friendlier to read, but does not take any configuration options. -:: - $session = session(); +.. literalinclude:: sessions/003.php + :lines: 2- How do Sessions work? ===================== @@ -89,9 +91,9 @@ Locking is not the issue, it is a solution. Your issue is that you still have the session open, while you've already processed it and therefore no longer need it. So, what you need is to close the session for the current request after you no longer need it. -:: - session_write_close(); +.. literalinclude:: sessions/004.php + :lines: 2- What is Session Data? ===================== @@ -115,47 +117,41 @@ Retrieving Session Data ======================= Any piece of information from the session array is available through the -``$_SESSION`` superglobal:: +``$_SESSION`` superglobal: - $_SESSION['item'] +.. literalinclude:: sessions/005.php + :lines: 2- -Or through the conventional accessor method:: +Or through the conventional accessor method: - $session->get('item'); +.. literalinclude:: sessions/006.php + :lines: 2- -Or through the magic getter:: +Or through the magic getter: - $session->item +.. literalinclude:: sessions/007.php + :lines: 2- -Or even through the session helper method:: +Or even through the session helper method: - session('item'); +.. literalinclude:: sessions/008.php + :lines: 2- Where ``item`` is the array key corresponding to the item you wish to fetch. For example, to assign a previously stored 'name' item to the ``$name`` -variable, you will do this:: - - $name = $_SESSION['name']; - - // or: - - $name = $session->name +variable, you will do this: - // or: - - $name = $session->get('name'); +.. literalinclude:: sessions/009.php + :lines: 2- .. note:: The ``get()`` method returns null if the item you are trying to access does not exist. If you want to retrieve all of the existing userdata, you can simply -omit the item key (magic getter only works for single property values):: - - $_SESSION +omit the item key (magic getter only works for single property values): - // or: - - $session->get(); +.. literalinclude:: sessions/010.php + :lines: 2- Adding Session Data =================== @@ -170,71 +166,64 @@ variable. Or as a property of ``$session``. The former userdata method is deprecated, but you can pass an array containing your new session data to the -``set()`` method:: +``set()`` method: - $session->set($array); +.. literalinclude:: sessions/011.php + :lines: 2- Where ``$array`` is an associative array containing your new data. Here's -an example:: - - $newdata = [ - 'username' => 'johndoe', - 'email' => 'johndoe@some-site.com', - 'logged_in' => true, - ]; +an example: - $session->set($newdata); +.. literalinclude:: sessions/012.php + :lines: 2- If you want to add session data one value at a time, ``set()`` also -supports this syntax:: +supports this syntax: - $session->set('some_name', 'some_value'); +.. literalinclude:: sessions/013.php + :lines: 2- If you want to verify that a session value exists, simply check with -``isset()``:: +``isset()``: - // returns false if the 'some_name' item doesn't exist or is null, - // true otherwise: - isset($_SESSION['some_name']) +.. literalinclude:: sessions/014.php + :lines: 2- -Or you can call ``has()``:: +Or you can call ``has()``: - $session->has('some_name'); +.. literalinclude:: sessions/015.php + :lines: 2- Pushing new value to session data ================================= The push method is used to push a new value onto a session value that is an array. -For instance, if the 'hobbies' key contains an array of hobbies, you can add a new value onto the array like so:: +For instance, if the 'hobbies' key contains an array of hobbies, you can add a new value onto the array like so: -$session->push('hobbies', ['sport'=>'tennis']); +.. literalinclude:: sessions/016.php + :lines: 2- Removing Session Data ===================== Just as with any other variable, unsetting a value in ``$_SESSION`` can be -done through ``unset()``:: +done through ``unset()``: - unset($_SESSION['some_name']); - - // or multiple values: - - unset( - $_SESSION['some_name'], - $_SESSION['another_name'] - ); +.. literalinclude:: sessions/017.php + :lines: 2- Also, just as ``set()`` can be used to add information to a session, ``remove()`` can be used to remove it, by passing the session key. For example, if you wanted to remove 'some_name' from your -session data array:: +session data array: - $session->remove('some_name'); +.. literalinclude:: sessions/018.php + :lines: 2- -This method also accepts an array of item keys to unset:: +This method also accepts an array of item keys to unset: - $array_items = ['username', 'email']; - $session->remove($array_items); +.. literalinclude:: sessions/019.php + :lines: 2- Flashdata ========= @@ -248,44 +237,50 @@ status messages (for example: "Record 2 deleted"). It should be noted that flashdata variables are regular session variables, managed inside the CodeIgniter session handler. -To mark an existing item as "flashdata":: +To mark an existing item as "flashdata": - $session->markAsFlashdata('item'); +.. literalinclude:: sessions/020.php + :lines: 2- If you want to mark multiple items as flashdata, simply pass the keys as an -array:: +array: - $session->markAsFlashdata(['item', 'item2']); +.. literalinclude:: sessions/021.php + :lines: 2- -To add flashdata:: +To add flashdata: - $_SESSION['item'] = 'value'; - $session->markAsFlashdata('item'); +.. literalinclude:: sessions/022.php + :lines: 2- -Or alternatively, using the ``setFlashdata()`` method:: +Or alternatively, using the ``setFlashdata()`` method: - $session->setFlashdata('item', 'value'); +.. literalinclude:: sessions/023.php + :lines: 2- You can also pass an array to ``setFlashdata()``, in the same manner as ``set()``. Reading flashdata variables is the same as reading regular session data -through ``$_SESSION``:: +through ``$_SESSION``: - $_SESSION['item'] +.. literalinclude:: sessions/005.php + :lines: 2- .. important:: The ``get()`` method WILL return flashdata items when retrieving a single item by key. It will not return flashdata when grabbing all userdata from the session, however. However, if you want to be sure that you're reading "flashdata" (and not -any other kind), you can also use the ``getFlashdata()`` method:: +any other kind), you can also use the ``getFlashdata()`` method: - $session->getFlashdata('item'); +.. literalinclude:: sessions/025.php + :lines: 2- -Or to get an array with all flashdata, simply omit the key parameter:: +Or to get an array with all flashdata, simply omit the key parameter: - $session->getFlashdata(); +.. literalinclude:: sessions/026.php + :lines: 2- .. note:: The ``getFlashdata()`` method returns null if the item cannot be found. @@ -294,10 +289,8 @@ If you find that you need to preserve a flashdata variable through an additional request, you can do so using the ``keepFlashdata()`` method. You can either pass a single item or an array of flashdata items to keep. -:: - - $session->keepFlashdata('item'); - $session->keepFlashdata(['item1', 'item2', 'item3']); +.. literalinclude:: sessions/027.php + :lines: 2- Tempdata ======== @@ -310,73 +303,72 @@ Similarly to flashdata, tempdata variables are managed internally by the CodeIgniter session handler. To mark an existing item as "tempdata", simply pass its key and expiry time -(in seconds!) to the ``markAsTempdata()`` method:: +(in seconds!) to the ``markAsTempdata()`` method: - // 'item' will be erased after 300 seconds - $session->markAsTempdata('item', 300); +.. literalinclude:: sessions/028.php + :lines: 2- You can mark multiple items as tempdata in two ways, depending on whether -you want them all to have the same expiry time or not:: +you want them all to have the same expiry time or not: - // Both 'item' and 'item2' will expire after 300 seconds - $session->markAsTempdata(['item', 'item2'], 300); +.. literalinclude:: sessions/029.php + :lines: 2- - // 'item' will be erased after 300 seconds, while 'item2' - // will do so after only 240 seconds - $session->markAsTempdata([ - 'item' => 300, - 'item2' => 240, - ]); +To add tempdata: -To add tempdata:: +.. literalinclude:: sessions/030.php + :lines: 2- - $_SESSION['item'] = 'value'; - $session->markAsTempdata('item', 300); // Expire in 5 minutes +Or alternatively, using the ``setTempdata()`` method: -Or alternatively, using the ``setTempdata()`` method:: +.. literalinclude:: sessions/031.php + :lines: 2- - $session->setTempdata('item', 'value', 300); +You can also pass an array to ``setTempdata()``: -You can also pass an array to ``setTempdata()``:: - - $tempdata = ['newuser' => true, 'message' => 'Thanks for joining!']; - $session->setTempdata($tempdata, null, $expire); +.. literalinclude:: sessions/032.php + :lines: 2- .. note:: If the expiration is omitted or set to 0, the default time-to-live value of 300 seconds (or 5 minutes) will be used. To read a tempdata variable, again you can just access it through the -``$_SESSION`` superglobal array:: +``$_SESSION`` superglobal array: - $_SESSION['item'] +.. literalinclude:: sessions/005.php + :lines: 2- .. important:: The ``get()`` method WILL return tempdata items when retrieving a single item by key. It will not return tempdata when grabbing all userdata from the session, however. Or if you want to be sure that you're reading "tempdata" (and not any -other kind), you can also use the ``getTempdata()`` method:: +other kind), you can also use the ``getTempdata()`` method: - $session->getTempdata('item'); +.. literalinclude:: sessions/034.php + :lines: 2- -And of course, if you want to retrieve all existing tempdata:: +And of course, if you want to retrieve all existing tempdata: - $session->getTempdata(); +.. literalinclude:: sessions/035.php + :lines: 2- .. note:: The ``getTempdata()`` method returns null if the item cannot be found. If you need to remove a tempdata value before it expires, you can directly -unset it from the ``$_SESSION`` array:: +unset it from the ``$_SESSION`` array: - unset($_SESSION['item']); +.. literalinclude:: sessions/036.php + :lines: 2- However, this won't remove the marker that makes this specific item to be tempdata (it will be invalidated on the next HTTP request), so if you intend to reuse that same key in the same request, you'd want to use -``removeTempdata()``:: +``removeTempdata()``: - $session->removeTempdata('item'); +.. literalinclude:: sessions/037.php + :lines: 2- Destroying a Session ==================== @@ -384,13 +376,10 @@ Destroying a Session To clear the current session (for example, during a logout), you may simply use either PHP's `session_destroy() `_ function, or the library's ``destroy()`` method. Both will work in exactly the -same way:: - - session_destroy(); +same way: - // or - - $session->destroy(); +.. literalinclude:: sessions/038.php + :lines: 2- .. note:: This must be the last session-related operation that you do during the same request. All session data (including flashdata and @@ -399,9 +388,10 @@ same way:: You may also use the ``stop()`` method to completely kill the session by removing the old session_id, destroying all data, and destroying -the cookie that contained the session id:: +the cookie that contained the session id: - $session->stop(); +.. literalinclude:: sessions/039.php + :lines: 2- Accessing session metadata ========================== @@ -463,7 +453,6 @@ Preference Default Opti (often the default value of ``1440``). This needs to be changed in ``php.ini`` or via ``ini_set()`` as needed. - In addition to the values above, the cookie and native drivers apply the following configuration values shared by the :doc:`IncomingRequest ` and :doc:`Security ` classes: @@ -575,10 +564,10 @@ In order to use the 'DatabaseHandler' session driver, you must also create this table that we already mentioned and then set it as your ``$sessionSavePath`` value. For example, if you would like to use 'ci_sessions' as your table name, -you would do this:: +you would do this: - public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; - public $sessionSavePath = 'ci_sessions'; +.. literalinclude:: sessions/040.php + :lines: 2- And then of course, create the database table ... @@ -616,9 +605,10 @@ setting**. The examples below work both on MySQL and PostgreSQL:: ALTER TABLE ci_sessions DROP PRIMARY KEY; You can choose the Database group to use by adding a new line to the -**app/Config/App.php** file with the name of the group to use:: +**app/Config/App.php** file with the name of the group to use: - public $sessionDBGroup = 'groupName'; +.. literalinclude:: sessions/041.php + :lines: 2- If you'd rather not do all of this by hand, you can use the ``session:migration`` command from the cli to generate a migration file for you:: @@ -669,10 +659,10 @@ link you to it: the link above. For the most common case however, a simple ``host:port`` pair should be -sufficient:: +sufficient: - public $sessionDiver = 'CodeIgniter\Session\Handlers\RedisHandler'; - public $sessionSavePath = 'tcp://localhost:6379'; +.. literalinclude:: sessions/042.php + :lines: 2- MemcachedHandler Driver ======================= @@ -697,10 +687,10 @@ expire earlier than that time). This happens very rarely, but should be considered as it may result in loss of sessions. The ``$sessionSavePath`` format is fairly straightforward here, -being just a ``host:port`` pair:: +being just a ``host:port`` pair: - public $sessionDriver = 'CodeIgniter\Session\Handlers\MemcachedHandler'; - public $sessionSavePath = 'localhost:11211'; +.. literalinclude:: sessions/043.php + :lines: 2- Bonus Tip --------- @@ -710,8 +700,7 @@ third colon-separated (``:weight``) value is also supported, but we have to note that we haven't tested if that is reliable. If you want to experiment with this feature (on your own risk), simply -separate the multiple server paths with commas:: +separate the multiple server paths with commas: - // localhost will be given higher priority (5) here, - // compared to 192.0.2.1 with a weight of 1. - public $sessionSavePath = 'localhost:11211:5,192.0.2.1:11211:1'; +.. literalinclude:: sessions/044.php + :lines: 2- diff --git a/user_guide_src/source/libraries/sessions/001.php b/user_guide_src/source/libraries/sessions/001.php new file mode 100644 index 000000000000..b1fa9aac3530 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/001.php @@ -0,0 +1,3 @@ +get('item'); diff --git a/user_guide_src/source/libraries/sessions/007.php b/user_guide_src/source/libraries/sessions/007.php new file mode 100644 index 000000000000..d3d4aaf2aaf8 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/007.php @@ -0,0 +1,3 @@ +item diff --git a/user_guide_src/source/libraries/sessions/008.php b/user_guide_src/source/libraries/sessions/008.php new file mode 100644 index 000000000000..ebe59d510994 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/008.php @@ -0,0 +1,3 @@ +name + +// or: + +$name = $session->get('name'); diff --git a/user_guide_src/source/libraries/sessions/010.php b/user_guide_src/source/libraries/sessions/010.php new file mode 100644 index 000000000000..e723f1b13ddd --- /dev/null +++ b/user_guide_src/source/libraries/sessions/010.php @@ -0,0 +1,7 @@ +get(); diff --git a/user_guide_src/source/libraries/sessions/011.php b/user_guide_src/source/libraries/sessions/011.php new file mode 100644 index 000000000000..b8b949797d22 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/011.php @@ -0,0 +1,3 @@ +set($array); diff --git a/user_guide_src/source/libraries/sessions/012.php b/user_guide_src/source/libraries/sessions/012.php new file mode 100644 index 000000000000..01bbbe1670b0 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/012.php @@ -0,0 +1,9 @@ + 'johndoe', + 'email' => 'johndoe@some-site.com', + 'logged_in' => true, +]; + +$session->set($newdata); diff --git a/user_guide_src/source/libraries/sessions/013.php b/user_guide_src/source/libraries/sessions/013.php new file mode 100644 index 000000000000..0d9c4699281a --- /dev/null +++ b/user_guide_src/source/libraries/sessions/013.php @@ -0,0 +1,3 @@ +set('some_name', 'some_value'); diff --git a/user_guide_src/source/libraries/sessions/014.php b/user_guide_src/source/libraries/sessions/014.php new file mode 100644 index 000000000000..4cab41e404aa --- /dev/null +++ b/user_guide_src/source/libraries/sessions/014.php @@ -0,0 +1,5 @@ +has('some_name'); diff --git a/user_guide_src/source/libraries/sessions/016.php b/user_guide_src/source/libraries/sessions/016.php new file mode 100644 index 000000000000..ef48af6552cc --- /dev/null +++ b/user_guide_src/source/libraries/sessions/016.php @@ -0,0 +1,3 @@ +push('hobbies', ['sport'=>'tennis']); diff --git a/user_guide_src/source/libraries/sessions/017.php b/user_guide_src/source/libraries/sessions/017.php new file mode 100644 index 000000000000..66a5f8662b39 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/017.php @@ -0,0 +1,10 @@ +remove('some_name'); diff --git a/user_guide_src/source/libraries/sessions/019.php b/user_guide_src/source/libraries/sessions/019.php new file mode 100644 index 000000000000..2ebd4f8a4e5f --- /dev/null +++ b/user_guide_src/source/libraries/sessions/019.php @@ -0,0 +1,4 @@ +remove($array_items); diff --git a/user_guide_src/source/libraries/sessions/020.php b/user_guide_src/source/libraries/sessions/020.php new file mode 100644 index 000000000000..471c5c5fef96 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/020.php @@ -0,0 +1,3 @@ +markAsFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/021.php b/user_guide_src/source/libraries/sessions/021.php new file mode 100644 index 000000000000..4be42e7f3a62 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/021.php @@ -0,0 +1,3 @@ +markAsFlashdata(['item', 'item2']); diff --git a/user_guide_src/source/libraries/sessions/022.php b/user_guide_src/source/libraries/sessions/022.php new file mode 100644 index 000000000000..d87dd8763d34 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/022.php @@ -0,0 +1,4 @@ +markAsFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/023.php b/user_guide_src/source/libraries/sessions/023.php new file mode 100644 index 000000000000..f22af522ab61 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/023.php @@ -0,0 +1,3 @@ +setFlashdata('item', 'value'); diff --git a/user_guide_src/source/libraries/sessions/024.php b/user_guide_src/source/libraries/sessions/024.php new file mode 100644 index 000000000000..4f09358d5fc8 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/024.php @@ -0,0 +1,3 @@ +getFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/026.php b/user_guide_src/source/libraries/sessions/026.php new file mode 100644 index 000000000000..7c387b5a4fa2 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/026.php @@ -0,0 +1,3 @@ +getFlashdata(); diff --git a/user_guide_src/source/libraries/sessions/027.php b/user_guide_src/source/libraries/sessions/027.php new file mode 100644 index 000000000000..94a299006a5d --- /dev/null +++ b/user_guide_src/source/libraries/sessions/027.php @@ -0,0 +1,4 @@ +keepFlashdata('item'); +$session->keepFlashdata(['item1', 'item2', 'item3']); diff --git a/user_guide_src/source/libraries/sessions/028.php b/user_guide_src/source/libraries/sessions/028.php new file mode 100644 index 000000000000..d2ed461826c0 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/028.php @@ -0,0 +1,4 @@ +markAsTempdata('item', 300); diff --git a/user_guide_src/source/libraries/sessions/029.php b/user_guide_src/source/libraries/sessions/029.php new file mode 100644 index 000000000000..978341190b52 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/029.php @@ -0,0 +1,11 @@ +markAsTempdata(['item', 'item2'], 300); + +// 'item' will be erased after 300 seconds, while 'item2' +// will do so after only 240 seconds +$session->markAsTempdata([ + 'item' => 300, + 'item2' => 240, +]); diff --git a/user_guide_src/source/libraries/sessions/030.php b/user_guide_src/source/libraries/sessions/030.php new file mode 100644 index 000000000000..d4e8941b5d34 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/030.php @@ -0,0 +1,4 @@ +markAsTempdata('item', 300); // Expire in 5 minutes diff --git a/user_guide_src/source/libraries/sessions/031.php b/user_guide_src/source/libraries/sessions/031.php new file mode 100644 index 000000000000..444c045adae9 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/031.php @@ -0,0 +1,3 @@ +setTempdata('item', 'value', 300); diff --git a/user_guide_src/source/libraries/sessions/032.php b/user_guide_src/source/libraries/sessions/032.php new file mode 100644 index 000000000000..f7099d76289a --- /dev/null +++ b/user_guide_src/source/libraries/sessions/032.php @@ -0,0 +1,4 @@ + true, 'message' => 'Thanks for joining!']; +$session->setTempdata($tempdata, null, $expire); diff --git a/user_guide_src/source/libraries/sessions/033.php b/user_guide_src/source/libraries/sessions/033.php new file mode 100644 index 000000000000..4f09358d5fc8 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/033.php @@ -0,0 +1,3 @@ +getTempdata('item'); diff --git a/user_guide_src/source/libraries/sessions/035.php b/user_guide_src/source/libraries/sessions/035.php new file mode 100644 index 000000000000..f44b959eee81 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/035.php @@ -0,0 +1,3 @@ +getTempdata(); diff --git a/user_guide_src/source/libraries/sessions/036.php b/user_guide_src/source/libraries/sessions/036.php new file mode 100644 index 000000000000..f063fa2907f4 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/036.php @@ -0,0 +1,3 @@ +removeTempdata('item'); diff --git a/user_guide_src/source/libraries/sessions/038.php b/user_guide_src/source/libraries/sessions/038.php new file mode 100644 index 000000000000..72c7d5d07602 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/038.php @@ -0,0 +1,7 @@ +destroy(); diff --git a/user_guide_src/source/libraries/sessions/039.php b/user_guide_src/source/libraries/sessions/039.php new file mode 100644 index 000000000000..7b43795e71e4 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/039.php @@ -0,0 +1,3 @@ +stop(); diff --git a/user_guide_src/source/libraries/sessions/040.php b/user_guide_src/source/libraries/sessions/040.php new file mode 100644 index 000000000000..a3724620886d --- /dev/null +++ b/user_guide_src/source/libraries/sessions/040.php @@ -0,0 +1,4 @@ +check($name, 60, MINUTE); +.. literalinclude:: throttler/001.php + :lines: 2- Here we're using one of the :doc:`global constants ` for the time, to make it a little more readable. This says that the bucket allows 60 actions every minute, or 1 action every second. @@ -50,50 +50,9 @@ The Code ======== You could make your own Throttler filter, at **app/Filters/Throttle.php**, -along the lines of:: - - check(md5($request->getIPAddress()), 60, MINUTE) === false) { - return Services::response()->setStatusCode(429); - } - } - - /** - * We don't have anything to do here. - * - * @param array|null $arguments - * - * @return mixed - */ - public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) - { - // ... - } - } +along the lines of: + +.. literalinclude:: throttler/002.php When run, this method first grabs an instance of the throttler. Next, it uses the IP address as the bucket name, and sets things to limit them to one request per second. If the throttler rejects the check, returning false, @@ -107,18 +66,15 @@ Applying the Filter We don't necessarily need to throttle every page on the site. For many web applications, this makes the most sense to apply only to POST requests, though API's might want to limit every request made by a user. In order to apply this to incoming requests, you need to edit **/app/Config/Filters.php** and first add an alias to the -filter:: +filter: - public $aliases = [ - ... - 'throttle' => \App\Filters\Throttle::class, - ]; +.. literalinclude:: throttler/003.php + :lines: 2- -Next, we assign it to all POST requests made on the site:: +Next, we assign it to all POST requests made on the site: - public $methods = [ - 'post' => ['throttle'], - ]; +.. literalinclude:: throttler/004.php + :lines: 2- .. Warning:: If you use ``$methods`` filters, you should :ref:`disable auto-routing ` because auto-routing permits any HTTP method to access a controller. diff --git a/user_guide_src/source/libraries/throttler/001.php b/user_guide_src/source/libraries/throttler/001.php new file mode 100644 index 000000000000..20086d3fc60a --- /dev/null +++ b/user_guide_src/source/libraries/throttler/001.php @@ -0,0 +1,4 @@ +check($name, 60, MINUTE); diff --git a/user_guide_src/source/libraries/throttler/002.php b/user_guide_src/source/libraries/throttler/002.php new file mode 100644 index 000000000000..91c89ca83d97 --- /dev/null +++ b/user_guide_src/source/libraries/throttler/002.php @@ -0,0 +1,42 @@ +check(md5($request->getIPAddress()), 60, MINUTE) === false) { + return Services::response()->setStatusCode(429); + } + } + + /** + * We don't have anything to do here. + * + * @param array|null $arguments + * + * @return mixed + */ + public function after(RequestInterface $request, ResponseInterface $response, $arguments = null) + { + // ... + } +} diff --git a/user_guide_src/source/libraries/throttler/003.php b/user_guide_src/source/libraries/throttler/003.php new file mode 100644 index 000000000000..af756092e30d --- /dev/null +++ b/user_guide_src/source/libraries/throttler/003.php @@ -0,0 +1,6 @@ + \App\Filters\Throttle::class, +]; diff --git a/user_guide_src/source/libraries/throttler/004.php b/user_guide_src/source/libraries/throttler/004.php new file mode 100644 index 000000000000..455874cd5730 --- /dev/null +++ b/user_guide_src/source/libraries/throttler/004.php @@ -0,0 +1,5 @@ + ['throttle'], +]; diff --git a/user_guide_src/source/libraries/time.rst b/user_guide_src/source/libraries/time.rst index 6e55cf87aed3..b8788eee17b7 100644 --- a/user_guide_src/source/libraries/time.rst +++ b/user_guide_src/source/libraries/time.rst @@ -19,21 +19,18 @@ 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 -be any string that PHP's strtotime function can parse:: +be any string that PHP's strtotime function can parse: - use CodeIgniter\I18n\Time; - - $myTime = new Time('+3 week'); - $myTime = new Time('now'); +.. literalinclude:: time/001.php + :lines: 2- You can pass in strings representing the timezone and the locale in the second and parameters, respectively. Timezones can be any supported by PHP's `DateTimeZone `__ class. The locale can be any supported by PHP's `Locale `__ class. If no locale or timezone is provided, the application defaults will be used. -:: - - $myTime = new Time('now', 'America/Chicago', 'en_US'); +.. literalinclude:: time/002.php + :lines: 2- now() ----- @@ -42,106 +39,111 @@ The Time class has several helper methods to instantiate the class. The first of that returns a new instance set to the current time. You can pass in strings representing the timezone and the locale in the second and parameters, respectively. If no locale or timezone is provided, the application defaults will be used. -:: - - $myTime = Time::now('America/Chicago', 'en_US'); +.. literalinclude:: time/003.php + :lines: 2- 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.:: +constructor as the first parameter, a timezone as the second parameter, and the locale as the third parameter.: - $myTime = Time::parse('next Tuesday', 'America/Chicago', 'en_US'); +.. literalinclude:: time/004.php + :lines: 2- 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:: +for the timezone and locale in the first and second parameters: - $myTime = Time::today('America/Chicago', 'en_US'); +.. literalinclude:: time/005.php + :lines: 2- 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:: +for the timezone and locale in the first and second parameters: - $myTime = Time::yesterday('America/Chicago', 'en_US'); +.. literalinclude:: time/006.php + :lines: 2- 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:: +for the timezone and locale in the first and second parameters: - $myTime = Time::tomorrow('America/Chicago', 'en_US'); +.. literalinclude:: time/007.php + :lines: 2- 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 -fourth and fifth parameters:: +fourth and fifth parameters: - $today = Time::createFromDate(); // Uses current year, month, and day - $anniversary = Time::createFromDate(2018); // Uses current month and day - $date = Time::createFromDate(2018, 3, 15, 'America/Chicago', 'en_US'); +.. literalinclude:: time/008.php + :lines: 2- 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 -fourth and fifth parameters:: +fourth and fifth parameters: - $lunch = Time::createFromTime(11, 30); // 11:30 am today - $dinner = Time::createFromTime(18, 00, 00); // 6:00 pm today - $time = Time::createFromTime($hour, $minutes, $seconds, $timezone, $locale); +.. literalinclude:: time/009.php + :lines: 2- 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 -timezone and locale in the fourth and fifth parameters:: +timezone and locale in the fourth and fifth parameters: - $time = Time::create($year, $month, $day, $hour, $minutes, $seconds, $timezone, $locale); +.. literalinclude:: time/010.php + :lines: 2- 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:: +and returns a ``Time`` instance, instead of DateTime: - $time = Time::createFromFormat('j-M-Y', '15-Feb-2009', 'America/Chicago'); +.. literalinclude:: time/011.php + :lines: 2- createFromTimestamp() --------------------- -This method takes a UNIX timestamp and, optionally, the timezone and locale, to create a new Time instance:: +This method takes a UNIX timestamp and, optionally, the timezone and locale, to create a new Time instance: - $time = Time::createFromTimestamp(1501821586, 'America/Chicago', 'en_US'); +.. literalinclude:: time/012.php + :lines: 2- 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 -instance passed in:: +instance passed in: - $dt = new DateTime('now'); - $time = Time::createFromInstance($dt, 'en_US'); +.. literalinclude:: time/013.php + :lines: 2- 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 -not aware of locales:: +not aware of locales: - $datetime = Time::toDateTime(); +.. literalinclude:: time/014.php + :lines: 2- ==================== Displaying the Value @@ -157,47 +159,44 @@ 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. A full listing of values can be found `here `__. -:: - $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toLocalizedString('MMM d, yyyy'); // March 9, 2016 +.. literalinclude:: time/015.php + :lines: 2- toDateTimeString() ------------------ This is the first of three helper methods to work with the IntlDateFormatter without having to remember their values. -This will return a string formatted as you would commonly use for datetime columns in a database (Y-m-d H:i:s):: +This will return a string formatted as you would commonly use for datetime columns in a database (Y-m-d H:i:s): - $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toDateTimeString(); // 2016-03-09 12:00:00 +.. literalinclude:: time/016.php + :lines: 2- toDateString() -------------- -Displays just the date portion of the Time:: +Displays just the date portion of the Time: - $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toDateString(); // 2016-03-09 +.. literalinclude:: time/017.php + :lines: 2- toTimeString() -------------- -Displays just the time portion of the value:: +Displays just the time portion of the value: - $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - echo $time->toTimeString(); // 12:00:00 +.. literalinclude:: time/018.php + :lines: 2- humanize() ---------- This methods returns a string that displays the difference between the current date/time and the instance in a human readable format that is geared towards being easily understood. It can create strings like '3 hours ago', -'in 1 month', etc:: - - // Assume current time is: March 10, 2017 (America/Chicago) - $time = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); +'in 1 month', etc: - echo $time->humanize(); // 1 year ago +.. literalinclude:: time/019.php + :lines: 2- The exact time displayed is determined in the following manner: @@ -230,96 +229,65 @@ like ``getYear()`` can also be accessed through ``$time->year``, and so on. Getters ------- -The following basic getters exist:: - - $time = Time::parse('August 12, 2016 4:15:23pm'); - - echo $time->getYear(); // 2016 - echo $time->getMonth(); // 8 - echo $time->getDay(); // 12 - echo $time->getHour(); // 16 - echo $time->getMinute(); // 15 - echo $time->getSecond(); // 23 - - echo $time->year; // 2016 - echo $time->month; // 8 - echo $time->day; // 12 - echo $time->hour; // 16 - echo $time->minute; // 15 - echo $time->second; // 23 +The following basic getters exist: -In addition to these, a number of methods exist to provide additional information about the date:: +.. literalinclude:: time/020.php + :lines: 2- - $time = Time::parse('August 12, 2016 4:15:23pm'); +In addition to these, a number of methods exist to provide additional information about the date: - echo $time->getDayOfWeek(); // 6 - but may vary based on locale's starting day of the week - echo $time->getDayOfYear(); // 225 - echo $time->getWeekOfMonth(); // 2 - echo $time->getWeekOfYear(); // 33 - echo $time->getTimestamp(); // 1471018523 - UNIX timestamp - echo $time->getQuarter(); // 3 - - echo $time->dayOfWeek; // 6 - echo $time->dayOfYear; // 225 - echo $time->weekOfMonth; // 2 - echo $time->weekOfYear; // 33 - echo $time->timestamp; // 1471018523 - echo $time->quarter; // 3 +.. literalinclude:: time/021.php + :lines: 2- getAge() -------- Returns the age, in years, of between the Time's instance and the current time. Perfect for checking -the age of someone based on their birthday:: - - $time = Time::parse('5 years ago'); +the age of someone based on their birthday: - echo $time->getAge(); // 5 - echo $time->age; // 5 +.. literalinclude:: time/022.php + :lines: 2- getDST() -------- -Returns boolean true/false based on whether the Time instance is currently observing Daylight Savings Time:: +Returns boolean true/false based on whether the Time instance is currently observing Daylight Savings Time: - echo Time::createFromDate(2012, 1, 1)->getDst(); // false - echo Time::createFromDate(2012, 9, 1)->dst; // true +.. literalinclude:: time/023.php + :lines: 2- getLocal() ---------- -Returns boolean true if the Time instance is in the same timezone as the application is currently running in:: +Returns boolean true if the Time instance is in the same timezone as the application is currently running in: - echo Time::now()->getLocal(); // true - echo Time::now('Europe/London'); // false +.. literalinclude:: time/024.php + :lines: 2- getUtc() -------- -Returns boolean true if the Time instance is in UTC time:: +Returns boolean true if the Time instance is in UTC time: - echo Time::now('America/Chicago')->getUtc(); // false - echo Time::now('UTC')->utc; // true +.. literalinclude:: time/025.php + :lines: 2- getTimezone() ------------- Returns a new `DateTimeZone `__ object set the timezone of the Time -instance:: - - $tz = Time::now()->getTimezone(); - $tz = Time::now()->timezone; +instance: - echo $tz->getName(); - echo $tz->getOffset(); +.. literalinclude:: time/026.php + :lines: 2- getTimezoneName() ----------------- -Returns the full `timezone string `__ of the Time instance:: +Returns the full `timezone string `__ of the Time instance: - echo Time::now('America/Chicago')->getTimezoneName(); // America/Chicago - echo Time::now('Europe/London')->timezoneName; // Europe/London +.. literalinclude:: time/027.php + :lines: 2- Setters ======= @@ -331,41 +299,24 @@ thrown. .. note:: All setters will throw an InvalidArgumentException if the value is out of range. -:: - - $time = $time->setYear(2017); - $time = $time->setMonth(4); // April - $time = $time->setMonth('April'); - $time = $time->setMonth('Feb'); // February - $time = $time->setDay(25); - $time = $time->setHour(14); // 2:00 pm - $time = $time->setMinute(30); - $time = $time->setSecond(54); +.. literalinclude:: time/028.php + :lines: 2- setTimezone() ------------- -Converts the time from it's current timezone into the new one:: - - $time = Time::parse('13 May 2020 10:00', 'America/Chicago'); - $time2 = $time->setTimezone('Europe/London'); // Returns new instance converted to new timezone - - echo $time->getTimezoneName(); // American/Chicago - echo $time2->getTimezoneName(); // Europe/London +Converts the time from it's current timezone into the new one: - echo $time->toDateTimeString(); // 2020-05-13 10:00:00 - echo $time2->toDateTimeString(); // 2020-05-13 18:00:00 +.. literalinclude:: time/029.php + :lines: 2- setTimestamp() -------------- -Returns a new instance with the date set to the new timestamp:: +Returns a new instance with the date set to the new timestamp: - $time = Time::parse('May 10, 2017', 'America/Chicago'); - $time2 = $time->setTimestamp(strtotime('April 1, 2017')); - - echo $time->toDateTimeString(); // 2017-05-10 00:00:00 - echo $time2->toDateTimeString(); // 2017-04-01 00:00:00 +.. literalinclude:: time/030.php + :lines: 2- Modifying the Value =================== @@ -373,21 +324,8 @@ Modifying the Value The following methods allow you to modify the date by adding or subtracting values to the current Time. This will not modify the existing Time instance, but will return a new instance. -:: - - $time = $time->addSeconds(23); - $time = $time->addMinutes(15); - $time = $time->addHours(12); - $time = $time->addDays(21); - $time = $time->addMonths(14); - $time = $time->addYears(5); - - $time = $time->subSeconds(23); - $time = $time->subMinutes(15); - $time = $time->subHours(12); - $time = $time->subDays(21); - $time = $time->subMonths(14); - $time = $time->subYears(5); +.. literalinclude:: time/031.php + :lines: 2- Comparing Two Times =================== @@ -400,113 +338,82 @@ equals() Determines if the datetime passed in is equal to the current instance. Equal in this case means that they represent the same moment in time, and are not required to be in the same timezone, as both times are converted to UTC and compared -that way:: +that way: - $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); - $time2 = Time::parse('January 11, 2017 03:50:00', 'Europe/London'); - - $time1->equals($time2); // true +.. literalinclude:: time/032.php + :lines: 2- The value being tested against can be a Time instance, a DateTime instance, or a string with the full date time in a manner that a new DateTime instance can understand. When passing a string as the first parameter, you can pass -a timezone string in as the second parameter. If no timezone is given, the system default will be used:: +a timezone string in as the second parameter. If no timezone is given, the system default will be used: - $time1->equals('January 11, 2017 03:50:00', 'Europe/London'); // true +.. literalinclude:: time/033.php + :lines: 2- sameAs() -------- This is identical to the ``equals()`` method, except that it only returns true when the date, time, AND timezone are -all identical:: - - $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); - $time2 = Time::parse('January 11, 2017 03:50:00', 'Europe/London'); +all identical: - $time1->sameAs($time2); // false - $time2->sameAs('January 10, 2017 21:50:00', 'America/Chicago'); // true +.. literalinclude:: time/034.php + :lines: 2- isBefore() ---------- Checks if the passed in time is before the current instance. The comparison is done against the UTC versions of -both times:: - - $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); - $time2 = Time::parse('January 11, 2017 03:50:00', 'America/Chicago'); +both times: - $time1->isBefore($time2); // true - $time2->isBefore($time1); // false +.. literalinclude:: time/035.php + :lines: 2- The value being tested against can be a Time instance, a DateTime instance, or a string with the full date time in a manner that a new DateTime instance can understand. When passing a string as the first parameter, you can pass -a timezone string in as the second parameter. If no timezone is given, the system default will be used:: +a timezone string in as the second parameter. If no timezone is given, the system default will be used: - $time1->isBefore('March 15, 2013', 'America/Chicago'); // false +.. literalinclude:: time/036.php + :lines: 2- isAfter() --------- -Works exactly the same as ``isBefore()`` except checks if the time is after the time passed in:: +Works exactly the same as ``isBefore()`` except checks if the time is after the time passed in: - $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago'); - $time2 = Time::parse('January 11, 2017 03:50:00', 'America/Chicago'); - - $time1->isAfter($time2); // false - $time2->isAfter($time1); // true +.. literalinclude:: time/037.php + :lines: 2- Viewing Differences =================== To compare two Times directly, you would use the ``difference()`` method, which returns a ``CodeIgniter\I18n\TimeDifference`` instance. The first parameter is either a Time instance, a DateTime instance, or a string with the date/time. If -a string is passed in the first parameter, the second parameter can be a timezone string:: - - $time = Time::parse('March 10, 2017', 'America/Chicago'); +a string is passed in the first parameter, the second parameter can be a timezone string: - $diff = $time->difference(Time::now()); - $diff = $time->difference(new DateTime('July 4, 1975', 'America/Chicago'); - $diff = $time->difference('July 4, 1975 13:32:05', 'America/Chicago'); +.. literalinclude:: time/038.php + :lines: 2- Once you have the TimeDifference instance, you have several methods you can use to find information about the difference between the two times. The value returned will be negative if it was in the past, or positive if in the future from -the original time:: - - $current = Time::parse('March 10, 2017', 'America/Chicago'); - $test = Time::parse('March 10, 2010', 'America/Chicago'); +the original time: - $diff = $current->difference($test); +.. literalinclude:: time/039.php + :lines: 2- - echo $diff->getYears(); // -7 - echo $diff->getMonths(); // -84 - echo $diff->getWeeks(); // -365 - echo $diff->getDays(); // -2557 - echo $diff->getHours(); // -61368 - echo $diff->getMinutes(); // -3682080 - echo $diff->getSeconds(); // -220924800 +You can use either ``getX()`` methods, or access the calculate values as if they were properties: -You can use either ``getX()`` methods, or access the calculate values as if they were properties:: - - echo $diff->years; // -7 - echo $diff->months; // -84 - echo $diff->weeks; // -365 - echo $diff->days; // -2557 - echo $diff->hours; // -61368 - echo $diff->minutes; // -3682080 - echo $diff->seconds; // -220924800 +.. literalinclude:: time/040.php + :lines: 2- humanize() ---------- Much like Time's ``humanize()`` method, this returns a string that displays the difference between the times in a human readable format that is geared towards being easily understood. It can create strings like '3 hours ago', -'in 1 month', etc. The biggest differences are in how very recent dates are handled:: - - $current = Time::parse('March 10, 2017', 'America/Chicago') - $test = Time::parse('March 9, 2016 12:00:00', 'America/Chicago'); - - $diff = $current->difference($test) +'in 1 month', etc. The biggest differences are in how very recent dates are handled: - echo $diff->humanize(); // 1 year ago +.. literalinclude:: time/041.php + :lines: 2- The exact time displayed is determined in the following manner: diff --git a/user_guide_src/source/libraries/time/001.php b/user_guide_src/source/libraries/time/001.php new file mode 100644 index 000000000000..ba7e4d3b36bc --- /dev/null +++ b/user_guide_src/source/libraries/time/001.php @@ -0,0 +1,6 @@ +toLocalizedString('MMM d, yyyy'); // March 9, 2016 diff --git a/user_guide_src/source/libraries/time/016.php b/user_guide_src/source/libraries/time/016.php new file mode 100644 index 000000000000..32fa8a8fe83f --- /dev/null +++ b/user_guide_src/source/libraries/time/016.php @@ -0,0 +1,4 @@ +toDateTimeString(); // 2016-03-09 12:00:00 diff --git a/user_guide_src/source/libraries/time/017.php b/user_guide_src/source/libraries/time/017.php new file mode 100644 index 000000000000..5ff0734c8add --- /dev/null +++ b/user_guide_src/source/libraries/time/017.php @@ -0,0 +1,4 @@ +toDateString(); // 2016-03-09 diff --git a/user_guide_src/source/libraries/time/018.php b/user_guide_src/source/libraries/time/018.php new file mode 100644 index 000000000000..4d0fcaf8c216 --- /dev/null +++ b/user_guide_src/source/libraries/time/018.php @@ -0,0 +1,4 @@ +toTimeString(); // 12:00:00 diff --git a/user_guide_src/source/libraries/time/019.php b/user_guide_src/source/libraries/time/019.php new file mode 100644 index 000000000000..50088537061c --- /dev/null +++ b/user_guide_src/source/libraries/time/019.php @@ -0,0 +1,6 @@ +humanize(); // 1 year ago diff --git a/user_guide_src/source/libraries/time/020.php b/user_guide_src/source/libraries/time/020.php new file mode 100644 index 000000000000..8d83bcaf5747 --- /dev/null +++ b/user_guide_src/source/libraries/time/020.php @@ -0,0 +1,17 @@ +getYear(); // 2016 +echo $time->getMonth(); // 8 +echo $time->getDay(); // 12 +echo $time->getHour(); // 16 +echo $time->getMinute(); // 15 +echo $time->getSecond(); // 23 + +echo $time->year; // 2016 +echo $time->month; // 8 +echo $time->day; // 12 +echo $time->hour; // 16 +echo $time->minute; // 15 +echo $time->second; // 23 diff --git a/user_guide_src/source/libraries/time/021.php b/user_guide_src/source/libraries/time/021.php new file mode 100644 index 000000000000..a3e0f128c5d7 --- /dev/null +++ b/user_guide_src/source/libraries/time/021.php @@ -0,0 +1,17 @@ +getDayOfWeek(); // 6 - but may vary based on locale's starting day of the week +echo $time->getDayOfYear(); // 225 +echo $time->getWeekOfMonth(); // 2 +echo $time->getWeekOfYear(); // 33 +echo $time->getTimestamp(); // 1471018523 - UNIX timestamp +echo $time->getQuarter(); // 3 + +echo $time->dayOfWeek; // 6 +echo $time->dayOfYear; // 225 +echo $time->weekOfMonth; // 2 +echo $time->weekOfYear; // 33 +echo $time->timestamp; // 1471018523 +echo $time->quarter; // 3 diff --git a/user_guide_src/source/libraries/time/022.php b/user_guide_src/source/libraries/time/022.php new file mode 100644 index 000000000000..facfdc5a9d02 --- /dev/null +++ b/user_guide_src/source/libraries/time/022.php @@ -0,0 +1,6 @@ +getAge(); // 5 +echo $time->age; // 5 diff --git a/user_guide_src/source/libraries/time/023.php b/user_guide_src/source/libraries/time/023.php new file mode 100644 index 000000000000..970aaad45d76 --- /dev/null +++ b/user_guide_src/source/libraries/time/023.php @@ -0,0 +1,4 @@ +getDst(); // false +echo Time::createFromDate(2012, 9, 1)->dst; // true diff --git a/user_guide_src/source/libraries/time/024.php b/user_guide_src/source/libraries/time/024.php new file mode 100644 index 000000000000..1919e1d097cf --- /dev/null +++ b/user_guide_src/source/libraries/time/024.php @@ -0,0 +1,4 @@ +getLocal(); // true +echo Time::now('Europe/London'); // false diff --git a/user_guide_src/source/libraries/time/025.php b/user_guide_src/source/libraries/time/025.php new file mode 100644 index 000000000000..b25d5de4aef9 --- /dev/null +++ b/user_guide_src/source/libraries/time/025.php @@ -0,0 +1,4 @@ +getUtc(); // false +echo Time::now('UTC')->utc; // true diff --git a/user_guide_src/source/libraries/time/026.php b/user_guide_src/source/libraries/time/026.php new file mode 100644 index 000000000000..030102f72d70 --- /dev/null +++ b/user_guide_src/source/libraries/time/026.php @@ -0,0 +1,7 @@ +getTimezone(); +$tz = Time::now()->timezone; + +echo $tz->getName(); +echo $tz->getOffset(); diff --git a/user_guide_src/source/libraries/time/027.php b/user_guide_src/source/libraries/time/027.php new file mode 100644 index 000000000000..dde3a39bec92 --- /dev/null +++ b/user_guide_src/source/libraries/time/027.php @@ -0,0 +1,4 @@ +getTimezoneName(); // America/Chicago +echo Time::now('Europe/London')->timezoneName; // Europe/London diff --git a/user_guide_src/source/libraries/time/028.php b/user_guide_src/source/libraries/time/028.php new file mode 100644 index 000000000000..97a3c26764d3 --- /dev/null +++ b/user_guide_src/source/libraries/time/028.php @@ -0,0 +1,10 @@ +setYear(2017); +$time = $time->setMonth(4); // April +$time = $time->setMonth('April'); +$time = $time->setMonth('Feb'); // February +$time = $time->setDay(25); +$time = $time->setHour(14); // 2:00 pm +$time = $time->setMinute(30); +$time = $time->setSecond(54); diff --git a/user_guide_src/source/libraries/time/029.php b/user_guide_src/source/libraries/time/029.php new file mode 100644 index 000000000000..d65f408fe05d --- /dev/null +++ b/user_guide_src/source/libraries/time/029.php @@ -0,0 +1,10 @@ +setTimezone('Europe/London'); // Returns new instance converted to new timezone + +echo $time->getTimezoneName(); // American/Chicago +echo $time2->getTimezoneName(); // Europe/London + +echo $time->toDateTimeString(); // 2020-05-13 10:00:00 +echo $time2->toDateTimeString(); // 2020-05-13 18:00:00 diff --git a/user_guide_src/source/libraries/time/030.php b/user_guide_src/source/libraries/time/030.php new file mode 100644 index 000000000000..929a9f272e28 --- /dev/null +++ b/user_guide_src/source/libraries/time/030.php @@ -0,0 +1,7 @@ +setTimestamp(strtotime('April 1, 2017')); + +echo $time->toDateTimeString(); // 2017-05-10 00:00:00 +echo $time2->toDateTimeString(); // 2017-04-01 00:00:00 diff --git a/user_guide_src/source/libraries/time/031.php b/user_guide_src/source/libraries/time/031.php new file mode 100644 index 000000000000..3737ae67a3c1 --- /dev/null +++ b/user_guide_src/source/libraries/time/031.php @@ -0,0 +1,15 @@ +addSeconds(23); +$time = $time->addMinutes(15); +$time = $time->addHours(12); +$time = $time->addDays(21); +$time = $time->addMonths(14); +$time = $time->addYears(5); + +$time = $time->subSeconds(23); +$time = $time->subMinutes(15); +$time = $time->subHours(12); +$time = $time->subDays(21); +$time = $time->subMonths(14); +$time = $time->subYears(5); diff --git a/user_guide_src/source/libraries/time/032.php b/user_guide_src/source/libraries/time/032.php new file mode 100644 index 000000000000..9207945c5242 --- /dev/null +++ b/user_guide_src/source/libraries/time/032.php @@ -0,0 +1,6 @@ +equals($time2); // true diff --git a/user_guide_src/source/libraries/time/033.php b/user_guide_src/source/libraries/time/033.php new file mode 100644 index 000000000000..73962921a299 --- /dev/null +++ b/user_guide_src/source/libraries/time/033.php @@ -0,0 +1,3 @@ +equals('January 11, 2017 03:50:00', 'Europe/London'); // true diff --git a/user_guide_src/source/libraries/time/034.php b/user_guide_src/source/libraries/time/034.php new file mode 100644 index 000000000000..229dfe82c094 --- /dev/null +++ b/user_guide_src/source/libraries/time/034.php @@ -0,0 +1,7 @@ +sameAs($time2); // false +$time2->sameAs('January 10, 2017 21:50:00', 'America/Chicago'); // true diff --git a/user_guide_src/source/libraries/time/035.php b/user_guide_src/source/libraries/time/035.php new file mode 100644 index 000000000000..e21714c2f2ef --- /dev/null +++ b/user_guide_src/source/libraries/time/035.php @@ -0,0 +1,7 @@ +isBefore($time2); // true +$time2->isBefore($time1); // false diff --git a/user_guide_src/source/libraries/time/036.php b/user_guide_src/source/libraries/time/036.php new file mode 100644 index 000000000000..817f31e4dce8 --- /dev/null +++ b/user_guide_src/source/libraries/time/036.php @@ -0,0 +1,3 @@ +isBefore('March 15, 2013', 'America/Chicago'); // false diff --git a/user_guide_src/source/libraries/time/037.php b/user_guide_src/source/libraries/time/037.php new file mode 100644 index 000000000000..103d228e1bc3 --- /dev/null +++ b/user_guide_src/source/libraries/time/037.php @@ -0,0 +1,7 @@ +isAfter($time2); // false +$time2->isAfter($time1); // true diff --git a/user_guide_src/source/libraries/time/038.php b/user_guide_src/source/libraries/time/038.php new file mode 100644 index 000000000000..5284ee5d5828 --- /dev/null +++ b/user_guide_src/source/libraries/time/038.php @@ -0,0 +1,7 @@ +difference(Time::now()); +$diff = $time->difference(new DateTime('July 4, 1975', 'America/Chicago'); +$diff = $time->difference('July 4, 1975 13:32:05', 'America/Chicago'); diff --git a/user_guide_src/source/libraries/time/039.php b/user_guide_src/source/libraries/time/039.php new file mode 100644 index 000000000000..12cc3d638f2c --- /dev/null +++ b/user_guide_src/source/libraries/time/039.php @@ -0,0 +1,14 @@ +difference($test); + +echo $diff->getYears(); // -7 +echo $diff->getMonths(); // -84 +echo $diff->getWeeks(); // -365 +echo $diff->getDays(); // -2557 +echo $diff->getHours(); // -61368 +echo $diff->getMinutes(); // -3682080 +echo $diff->getSeconds(); // -220924800 diff --git a/user_guide_src/source/libraries/time/040.php b/user_guide_src/source/libraries/time/040.php new file mode 100644 index 000000000000..1af52b88fd75 --- /dev/null +++ b/user_guide_src/source/libraries/time/040.php @@ -0,0 +1,9 @@ +years; // -7 +echo $diff->months; // -84 +echo $diff->weeks; // -365 +echo $diff->days; // -2557 +echo $diff->hours; // -61368 +echo $diff->minutes; // -3682080 +echo $diff->seconds; // -220924800 diff --git a/user_guide_src/source/libraries/time/041.php b/user_guide_src/source/libraries/time/041.php new file mode 100644 index 000000000000..98a67ecf7998 --- /dev/null +++ b/user_guide_src/source/libraries/time/041.php @@ -0,0 +1,8 @@ +difference($test) + +echo $diff->humanize(); // 1 year ago diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst index 0a4ded63a898..adbb868ae902 100644 --- a/user_guide_src/source/libraries/typography.rst +++ b/user_guide_src/source/libraries/typography.rst @@ -14,9 +14,10 @@ Loading the Library ******************* Like all services in CodeIgniter, it can be loaded via ``Config\Services``, though you usually will not need -to load it manually:: +to load it manually: - $typography = \Config\Services::typography(); +.. literalinclude:: typography/001.php + :lines: 2- ************************** Available static functions @@ -34,9 +35,10 @@ The following functions are available: Formats text so that it is semantically and typographically correct HTML. - Usage example:: + Usage example: - $string = $typography->autoTypography($string); + .. literalinclude:: typography/002.php + :lines: 2- .. note:: Typographic formatting can be processor intensive, particularly if you have a lot of content being formatted. If you choose to use this @@ -53,9 +55,10 @@ The following functions are available: to curly entities, but it also converts em-dashes, double spaces, and ampersands. - Usage example:: + Usage example: - $string = $typography->formatCharacters($string); + .. literalinclude:: typography/003.php + :lines: 2- .. php:function:: nl2brExceptPre($str) @@ -67,6 +70,7 @@ The following functions are available: This function is identical to the native PHP ``nl2br()`` function, except that it ignores ``
    `` tags.
     
    -    Usage example::
    +    Usage example:
     
    -        $string = $typography->nl2brExceptPre($string);
    +    .. literalinclude:: typography/004.php
    +       :lines: 2-
    diff --git a/user_guide_src/source/libraries/typography/001.php b/user_guide_src/source/libraries/typography/001.php
    new file mode 100644
    index 000000000000..0c82ed0e95fa
    --- /dev/null
    +++ b/user_guide_src/source/libraries/typography/001.php
    @@ -0,0 +1,3 @@
    +autoTypography($string);
    diff --git a/user_guide_src/source/libraries/typography/003.php b/user_guide_src/source/libraries/typography/003.php
    new file mode 100644
    index 000000000000..1c2d51a9afdd
    --- /dev/null
    +++ b/user_guide_src/source/libraries/typography/003.php
    @@ -0,0 +1,3 @@
    +formatCharacters($string);
    diff --git a/user_guide_src/source/libraries/typography/004.php b/user_guide_src/source/libraries/typography/004.php
    new file mode 100644
    index 000000000000..3d5b4347aafc
    --- /dev/null
    +++ b/user_guide_src/source/libraries/typography/004.php
    @@ -0,0 +1,3 @@
    +nl2brExceptPre($string);
    diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst
    index 9640809ba99b..b2117f37c37a 100644
    --- a/user_guide_src/source/libraries/uploaded_files.rst
    +++ b/user_guide_src/source/libraries/uploaded_files.rst
    @@ -33,31 +33,9 @@ Creating the Upload Form
     ========================
     
     Using a text editor, create a form called upload_form.php. In it, place
    -this code and save it to your **app/Views/** directory::
    +this code and save it to your **app/Views/** directory:
     
    -    
    -    
    -    
    -        Upload Form
    -    
    -    
    -
    -    
    -        
  • - - - - - - -

    - - - - - - - +.. literalinclude:: uploaded_files/000.php You'll notice we are using a form helper to create the opening form tag. File uploads require a multipart form, so the helper creates the proper @@ -95,56 +73,9 @@ The Controller ============== Using a text editor, create a controller called Upload.php. In it, place -this code and save it to your **app/Controllers/** directory:: - - []]); - } - - public function upload() - { - $validationRule = [ - 'userfile' => [ - 'label' => 'Image File', - 'rules' => 'uploaded[userfile]' - . '|is_image[userfile]' - . '|mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]' - . '|max_size[userfile,100]' - . '|max_dims[userfile,1024,768]', - ], - ]; - if (! $this->validate($validationRule)) { - $data = ['errors' => $this->validator->getErrors()]; +this code and save it to your **app/Controllers/** directory: - return view('upload_form', $data); - } - - $img = $this->request->getFile('userfile'); - - if (! $img->hasMoved()) { - $filepath = WRITEPATH . 'uploads/' . $img->store(); - - $data = ['uploaded_flleinfo' => new File($filepath)]; - - return view('upload_success', $data); - } else { - $data = ['errors' => 'The file has already been moved.']; - - return view('upload_form', $data); - } - } - } +.. literalinclude:: uploaded_files/001.php .. note:: Since the value of a file upload HTML field doesn't exist, and is stored in the ``$_FILES`` global, only :ref:`rules-for-file-uploads` can be used to validate upload file with :doc:`validation`. @@ -181,20 +112,20 @@ are not aware of. CodeIgniter helps with both of these situations by standardizi common interface. Files are accessed through the current ``IncomingRequest`` instance. To retrieve all files that were uploaded with this -request, use ``getFiles()``. This will return an array of files represented by instances of ``CodeIgniter\HTTP\Files\UploadedFile``:: +request, use ``getFiles()``. This will return an array of files represented by instances of ``CodeIgniter\HTTP\Files\UploadedFile``: - $files = $this->request->getFiles(); +.. literalinclude:: uploaded_files/002.php + :lines: 2- Of course, there are multiple ways to name the file input, and anything but the simplest can create strange results. The array returns in a manner that you would expect. With the simplest usage, a single file might be submitted like:: -Which would return a simple array like:: +Which would return a simple array like: - [ - 'avatar' => // UploadedFile instance - ] +.. literalinclude:: uploaded_files/003.php + :lines: 2- .. note:: The UploadedFile instance corresponds to ``$_FILES``. Even if a user just clicks the submit button and does not upload any file, the instance will still exist. You can check that the file was actually uploaded by the ``isValid()`` method in UploadedFile. See :ref:`verify-a-file`. @@ -202,32 +133,20 @@ If you used an array notation for the name, the input would look something like: -The array returned by ``getFiles()`` would look more like this:: +The array returned by ``getFiles()`` would look more like this: - [ - 'my-form' => [ - 'details' => [ - 'avatar' => // UploadedFile instance - ] - ] - ] +.. literalinclude:: uploaded_files/004.php + :lines: 2- In some cases, you may specify an array of files to upload:: Upload an avatar: Upload an avatar: -In this case, the returned array of files would be more like:: +In this case, the returned array of files would be more like: - [ - 'my-form' => [ - 'details' => [ - 'avatar' => [ - 0 => /* UploadedFile instance */, - 1 => /* UploadedFile instance */ - ] - ] - ] +.. literalinclude:: uploaded_files/005.php + :lines: 2- Single File =========== @@ -241,9 +160,10 @@ With the simplest usage, a single file might be submitted like:: -Which would return a simple file instance like:: +Which would return a simple file instance like: - $file = $this->request->getFile('userfile'); +.. literalinclude:: uploaded_files/006.php + :lines: 2- Array notation -------------- @@ -252,9 +172,10 @@ If you used an array notation for the name, the input would look something like: -For get the file instance:: +For get the file instance: - $file = $this->request->getFile('my-form.details.avatar'); +.. literalinclude:: uploaded_files/007.php + :lines: 2- Multiple files ============== @@ -263,40 +184,34 @@ Multiple files -In controller:: +In controller: - if ($imagefile = $this->request->getFiles()) { - foreach($imagefile['images'] as $img) { - if ($img->isValid() && ! $img->hasMoved()) { - $newName = $img->getRandomName(); - $img->move(WRITEPATH . 'uploads', $newName); - } - } - } +.. literalinclude:: uploaded_files/008.php + :lines: 2- where the ``images`` is a loop from the form field name. If there are multiple files with the same name you can use ``getFile()`` to retrieve every file individually. -In controller:: - - $file1 = $this->request->getFile('images.0'); - $file2 = $this->request->getFile('images.1'); +In controller: -You might find it easier to use ``getFileMultiple()``, to get an array of uploaded files with the same name:: +.. literalinclude:: uploaded_files/009.php + :lines: 2- - $files = $this->request->getFileMultiple('images'); +You might find it easier to use ``getFileMultiple()``, to get an array of uploaded files with the same name: +.. literalinclude:: uploaded_files/010.php + :lines: 2- Another example:: Upload an avatar: Upload an avatar: -In controller:: +In controller: - $file1 = $this->request->getFile('my-form.details.avatars.0'); - $file2 = $this->request->getFile('my-form.details.avatars.1'); +.. literalinclude:: uploaded_files/011.php + :lines: 2- .. note:: Using ``getFiles()`` is more appropriate. @@ -312,11 +227,10 @@ move the file to a new location. Verify a File ============= -You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method:: +You can check that a file was actually uploaded via HTTP with no errors by calling the ``isValid()`` method: - if (! $file->isValid()) { - throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); - } +.. literalinclude:: uploaded_files/012.php + :lines: 2- As seen in this example, if a file had an upload error, you can retrieve the error code (an integer) and the error message with the ``getError()`` and ``getErrorString()`` methods. The following errors can be discovered through @@ -337,61 +251,64 @@ File Names You can retrieve the original filename provided by the client with the ``getName()`` method. This will typically be the filename sent by the client, and should not be trusted. If the file has been moved, this will return the final name of -the moved file:: +the moved file: - $name = $file->getName(); +.. literalinclude:: uploaded_files/013.php + :lines: 2- **getClientName()** -Always returns the original name of the uploaded file as sent by the client, even if the file has been moved:: +Always returns the original name of the uploaded file as sent by the client, even if the file has been moved: - $originalName = $file->getClientName(); +.. literalinclude:: uploaded_files/014.php + :lines: 2- **getTempName()** -To get the full path of the temp file that was created during the upload, you can use the ``getTempName()`` method:: +To get the full path of the temp file that was created during the upload, you can use the ``getTempName()`` method: - $tempfile = $file->getTempName(); +.. literalinclude:: uploaded_files/015.php + :lines: 2- Other File Info =============== **getClientExtension()** -Returns the original file extension, based on the file name that was uploaded:: +Returns the original file extension, based on the file name that was uploaded: - $ext = $file->getClientExtension(); +.. literalinclude:: uploaded_files/016.php + :lines: 2- .. warning:: This is NOT a trusted source. For a trusted version, use ``guessExtension()`` instead. **getClientMimeType()** Returns the mime type (mime type) of the file as provided by the client. This is NOT a trusted value. For a trusted -version, use ``getMimeType()`` instead:: - - $type = $file->getClientMimeType(); +version, use ``getMimeType()`` instead: - echo $type; // image/png +.. literalinclude:: uploaded_files/017.php + :lines: 2- Moving Files ============ Each file can be moved to its new location with the aptly named ``move()`` method. This takes the directory to move -the file to as the first parameter:: +the file to as the first parameter: - $file->move(WRITEPATH . 'uploads'); +.. literalinclude:: uploaded_files/018.php + :lines: 2- -By default, the original filename was used. You can specify a new filename by passing it as the second parameter:: +By default, the original filename was used. You can specify a new filename by passing it as the second parameter: - $newName = $file->getRandomName(); - $file->move(WRITEPATH . 'uploads', $newName); +.. literalinclude:: uploaded_files/019.php + :lines: 2- Once the file has been removed the temporary file is deleted. You can check if a file has been moved already with -the ``hasMoved()`` method, which returns a boolean:: +the ``hasMoved()`` method, which returns a boolean: - if ($file->isValid() && ! $file->hasMoved()) { - $file->move($path); - } +.. literalinclude:: uploaded_files/020.php + :lines: 2- Moving an uploaded file can fail, with an HTTPException, under several circumstances: @@ -409,14 +326,16 @@ With the simplest usage, a single file might be submitted like:: By default, upload files are saved in **writable/uploads** directory. The **YYYYMMDD** folder -and random file name will be created. Returns a file path:: +and random file name will be created. Returns a file path: - $path = $this->request->getFile('userfile')->store(); +.. literalinclude:: uploaded_files/021.php + :lines: 2- You can specify a directory to move the file to as the first parameter. A new filename by -passing it as the second parameter:: +passing it as the second parameter: - $path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg'); +.. literalinclude:: uploaded_files/022.php + :lines: 2- Moving an uploaded file can fail, with an ``HTTPException``, under several circumstances: diff --git a/user_guide_src/source/libraries/uploaded_files/000.php b/user_guide_src/source/libraries/uploaded_files/000.php new file mode 100644 index 000000000000..d58b7664d28b --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/000.php @@ -0,0 +1,23 @@ + + + + Upload Form + + + + +
  • + + + + + + +

    + + + + + + + diff --git a/user_guide_src/source/libraries/uploaded_files/001.php b/user_guide_src/source/libraries/uploaded_files/001.php new file mode 100644 index 000000000000..f186d517fd96 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/001.php @@ -0,0 +1,48 @@ + []]); + } + + public function upload() + { + $validationRule = [ + 'userfile' => [ + 'label' => 'Image File', + 'rules' => 'uploaded[userfile]' + . '|is_image[userfile]' + . '|mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]' + . '|max_size[userfile,100]' + . '|max_dims[userfile,1024,768]', + ], + ]; + if (! $this->validate($validationRule)) { + $data = ['errors' => $this->validator->getErrors()]; + + return view('upload_form', $data); + } + + $img = $this->request->getFile('userfile'); + + if (! $img->hasMoved()) { + $filepath = WRITEPATH . 'uploads/' . $img->store(); + + $data = ['uploaded_flleinfo' => new File($filepath)]; + + return view('upload_success', $data); + } else { + $data = ['errors' => 'The file has already been moved.']; + + return view('upload_form', $data); + } + } +} diff --git a/user_guide_src/source/libraries/uploaded_files/002.php b/user_guide_src/source/libraries/uploaded_files/002.php new file mode 100644 index 000000000000..17141efbdde8 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/002.php @@ -0,0 +1,3 @@ +request->getFiles(); diff --git a/user_guide_src/source/libraries/uploaded_files/003.php b/user_guide_src/source/libraries/uploaded_files/003.php new file mode 100644 index 000000000000..368facf4f7ab --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/003.php @@ -0,0 +1,5 @@ + // UploadedFile instance +] diff --git a/user_guide_src/source/libraries/uploaded_files/004.php b/user_guide_src/source/libraries/uploaded_files/004.php new file mode 100644 index 000000000000..bf31373e57bd --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/004.php @@ -0,0 +1,9 @@ + [ + 'details' => [ + 'avatar' => // UploadedFile instance + ] + ] +] diff --git a/user_guide_src/source/libraries/uploaded_files/005.php b/user_guide_src/source/libraries/uploaded_files/005.php new file mode 100644 index 000000000000..c53d82a298fc --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/005.php @@ -0,0 +1,11 @@ + [ + 'details' => [ + 'avatar' => [ + 0 => /* UploadedFile instance */, + 1 => /* UploadedFile instance */ + ] + ] +] diff --git a/user_guide_src/source/libraries/uploaded_files/006.php b/user_guide_src/source/libraries/uploaded_files/006.php new file mode 100644 index 000000000000..e5f6440d96fb --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/006.php @@ -0,0 +1,3 @@ +request->getFile('userfile'); diff --git a/user_guide_src/source/libraries/uploaded_files/007.php b/user_guide_src/source/libraries/uploaded_files/007.php new file mode 100644 index 000000000000..ad71bd5575fb --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/007.php @@ -0,0 +1,3 @@ +request->getFile('my-form.details.avatar'); diff --git a/user_guide_src/source/libraries/uploaded_files/008.php b/user_guide_src/source/libraries/uploaded_files/008.php new file mode 100644 index 000000000000..f37491c04821 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/008.php @@ -0,0 +1,10 @@ +request->getFiles()) { + foreach($imagefile['images'] as $img) { + if ($img->isValid() && ! $img->hasMoved()) { + $newName = $img->getRandomName(); + $img->move(WRITEPATH . 'uploads', $newName); + } + } +} diff --git a/user_guide_src/source/libraries/uploaded_files/009.php b/user_guide_src/source/libraries/uploaded_files/009.php new file mode 100644 index 000000000000..da51d17dbd15 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/009.php @@ -0,0 +1,4 @@ +request->getFile('images.0'); +$file2 = $this->request->getFile('images.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/010.php b/user_guide_src/source/libraries/uploaded_files/010.php new file mode 100644 index 000000000000..646e6bb0b8b9 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/010.php @@ -0,0 +1,3 @@ +request->getFileMultiple('images'); diff --git a/user_guide_src/source/libraries/uploaded_files/011.php b/user_guide_src/source/libraries/uploaded_files/011.php new file mode 100644 index 000000000000..d18a755ba234 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/011.php @@ -0,0 +1,4 @@ +request->getFile('my-form.details.avatars.0'); +$file2 = $this->request->getFile('my-form.details.avatars.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/012.php b/user_guide_src/source/libraries/uploaded_files/012.php new file mode 100644 index 000000000000..094ea73c1064 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/012.php @@ -0,0 +1,5 @@ +isValid()) { + throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); +} diff --git a/user_guide_src/source/libraries/uploaded_files/013.php b/user_guide_src/source/libraries/uploaded_files/013.php new file mode 100644 index 000000000000..057a56b3e9a0 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/013.php @@ -0,0 +1,3 @@ +getName(); diff --git a/user_guide_src/source/libraries/uploaded_files/014.php b/user_guide_src/source/libraries/uploaded_files/014.php new file mode 100644 index 000000000000..4fb0cae0ad12 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/014.php @@ -0,0 +1,3 @@ +getClientName(); diff --git a/user_guide_src/source/libraries/uploaded_files/015.php b/user_guide_src/source/libraries/uploaded_files/015.php new file mode 100644 index 000000000000..c9e4774a4bbf --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/015.php @@ -0,0 +1,3 @@ +getTempName(); diff --git a/user_guide_src/source/libraries/uploaded_files/016.php b/user_guide_src/source/libraries/uploaded_files/016.php new file mode 100644 index 000000000000..867877238c76 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/016.php @@ -0,0 +1,3 @@ +getClientExtension(); diff --git a/user_guide_src/source/libraries/uploaded_files/017.php b/user_guide_src/source/libraries/uploaded_files/017.php new file mode 100644 index 000000000000..dd1288e441c3 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/017.php @@ -0,0 +1,5 @@ +getClientMimeType(); + +echo $type; // image/png diff --git a/user_guide_src/source/libraries/uploaded_files/018.php b/user_guide_src/source/libraries/uploaded_files/018.php new file mode 100644 index 000000000000..12499a3ca1ba --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/018.php @@ -0,0 +1,3 @@ +move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/uploaded_files/019.php b/user_guide_src/source/libraries/uploaded_files/019.php new file mode 100644 index 000000000000..2e6b39645a4b --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/019.php @@ -0,0 +1,4 @@ +getRandomName(); +$file->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/uploaded_files/020.php b/user_guide_src/source/libraries/uploaded_files/020.php new file mode 100644 index 000000000000..7f49d1f5232e --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/020.php @@ -0,0 +1,5 @@ +isValid() && ! $file->hasMoved()) { + $file->move($path); +} diff --git a/user_guide_src/source/libraries/uploaded_files/021.php b/user_guide_src/source/libraries/uploaded_files/021.php new file mode 100644 index 000000000000..90f9495eaf7b --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/021.php @@ -0,0 +1,3 @@ +request->getFile('userfile')->store(); diff --git a/user_guide_src/source/libraries/uploaded_files/022.php b/user_guide_src/source/libraries/uploaded_files/022.php new file mode 100644 index 000000000000..0e552f417d52 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/022.php @@ -0,0 +1,3 @@ +request->getFile('userfile')->store('head_img/', 'user_name.jpg'); diff --git a/user_guide_src/source/libraries/uri.rst b/user_guide_src/source/libraries/uri.rst index 4f5e9dda6fb6..25e7c92566b0 100644 --- a/user_guide_src/source/libraries/uri.rst +++ b/user_guide_src/source/libraries/uri.rst @@ -14,58 +14,59 @@ relative URI to an existing one and have it resolved safely and correctly. Creating URI instances ====================== -Creating a URI instance is as simple as creating a new class instance:: +Creating a URI instance is as simple as creating a new class instance: - $uri = new \CodeIgniter\HTTP\URI(); +.. literalinclude:: uri/001.php + :lines: 2- -Alternatively, you can use the ``service()`` function to return an instance for you:: +Alternatively, you can use the ``service()`` function to return an instance for you: - $uri = service('uri'); +.. literalinclude:: uri/002.php + :lines: 2- When you create the new instance, you can pass a full or partial URL in the constructor and it will be parsed -into its appropriate sections:: +into its appropriate sections: - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com/some/path'); - $uri = service('uri', 'http://www.example.com/some/path'); +.. literalinclude:: uri/003.php + :lines: 2- The Current URI --------------- Many times, all you really want is an object representing the current URL of this request. -You can use one of the functions available in the **url_helper**:: +You can use one of the functions available in the **url_helper**: - $uri = current_url(true); +.. literalinclude:: uri/004.php + :lines: 2- You must pass ``true`` as the first parameter, otherwise, it will return the string representation of the current URL. This URI is based on the path (relative to your ``baseURL``) as determined by the current request object and your settings in ``Config\App`` (baseURL, indexPage, and forceGlobalSecureRequests). -Assuming that you're in a controller that extends ``CodeIgniter\Controller`` you can get this relative path:: +Assuming that you're in a controller that extends ``CodeIgniter\Controller`` you can get this relative path: - $path = $this->request->getPath(); +.. literalinclude:: uri/005.php + :lines: 2- =========== URI Strings =========== Many times, all you really want is to get a string representation of a URI. This is easy to do by simply casting -the URI as a string:: +the URI as a string: - $uri = current_url(true); - echo (string) $uri; // http://example.com/index.php +.. literalinclude:: uri/006.php + :lines: 2- If you know the pieces of the URI and just want to ensure it's all formatted correctly, you can generate a string -using the URI class' static ``createURIString()`` method:: +using the URI class' static ``createURIString()`` method: - $uriString = URI::createURIString($scheme, $authority, $path, $query, $fragment); - - // Creates: http://exmample.com/some/path?foo=bar#first-heading - echo URI::createURIString('http', 'example.com', 'some/path', 'foo=bar', 'first-heading'); +.. literalinclude:: uri/007.php + :lines: 2- .. important:: When ``URI`` is cast to a string, it will attempt to adjust project URLs to the settings defined in ``Config\App``. If you need the exact, unaltered string representation then use ``URI::createURIString()`` instead. - ============= The URI Parts ============= @@ -77,12 +78,9 @@ Scheme ------ The scheme is frequently 'http' or 'https', but any scheme is supported, including 'file', 'mailto', etc. -:: - - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com/some/path'); - echo $uri->getScheme(); // 'http' - $uri->setScheme('https'); +.. literalinclude:: uri/008.php + :lines: 2- Authority --------- @@ -90,25 +88,21 @@ Authority Many URIs contain several elements that are collectively known as the 'authority'. This includes any user info, the host and the port number. You can retrieve all of these pieces as one single string with the ``getAuthority()`` method, or you can manipulate the individual parts. -:: - $uri = new \CodeIgniter\HTTP\URI('ftp://user:password@example.com:21/some/path'); - - echo $uri->getAuthority(); // user@example.com:21 +.. literalinclude:: uri/009.php + :lines: 2- By default, this will not display the password portion since you wouldn't want to show that to anyone. If you want to show the password, you can use the ``showPassword()`` method. This URI instance will continue to show that password -until you turn it off again, so always make sure that you turn it off as soon as you are finished with it:: - - echo $uri->getAuthority(); // user@example.com:21 - echo $uri->showPassword()->getAuthority(); // user:password@example.com:21 +until you turn it off again, so always make sure that you turn it off as soon as you are finished with it: - // Turn password display off again. - $uri->showPassword(false); +.. literalinclude:: uri/010.php + :lines: 2- -If you do not want to display the port, pass in ``true`` as the only parameter:: +If you do not want to display the port, pass in ``true`` as the only parameter: - echo $uri->getAuthority(true); // user@example.com +.. literalinclude:: uri/011.php + :lines: 2- .. note:: If the current port is the default port for the scheme it will never be displayed. @@ -116,36 +110,32 @@ Userinfo -------- The userinfo section is simply the username and password that you might see with an FTP URI. While you can get -this as part of the Authority, you can also retrieve it yourself:: +this as part of the Authority, you can also retrieve it yourself: - echo $uri->getUserInfo(); // user +.. literalinclude:: uri/012.php + :lines: 2- -By default, it will not display the password, but you can override that with the ``showPassword()`` method:: +By default, it will not display the password, but you can override that with the ``showPassword()`` method: - echo $uri->showPassword()->getUserInfo(); // user:password - $uri->showPassword(false); +.. literalinclude:: uri/013.php + :lines: 2- Host ---- The host portion of the URI is typically the domain name of the URL. This can be easily set and retrieved with the -``getHost()`` and ``setHost()`` methods:: +``getHost()`` and ``setHost()`` methods: - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com/some/path'); - - echo $uri->getHost(); // www.example.com - echo $uri->setHost('anotherexample.com')->getHost(); // anotherexample.com +.. literalinclude:: uri/014.php + :lines: 2- Port ---- The port is an integer number between 0 and 65535. Each sheme has a default value associated with it. -:: - - $uri = new \CodeIgniter\HTTP\URI('ftp://user:password@example.com:21/some/path'); - echo $uri->getPort(); // 21 - echo $uri->setPort(2201)->getPort(); // 2201 +.. literalinclude:: uri/015.php + :lines: 2- When using the ``setPort()`` method, the port will be checked that it is within the valid range and assigned. @@ -153,12 +143,10 @@ Path ---- The path are all of the segments within the site itself. As expected, the ``getPath()`` and ``setPath()`` methods -can be used to manipulate it:: +can be used to manipulate it: - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com/some/path'); - - echo $uri->getPath(); // 'some/path' - echo $uri->setPath('another/path')->getPath(); // 'another/path' +.. literalinclude:: uri/016.php + :lines: 2- .. note:: When setting the path this way, or any other way the class allows, it is sanitized to encode any dangerous characters, and remove dot segments for safety. @@ -168,48 +156,37 @@ Query The query variables can be manipulated through the class using simple string representations. Query values can only be set as a string currently. -:: - - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com?foo=bar'); - echo $uri->getQuery(); // 'foo=bar' - $uri->setQuery('foo=bar&bar=baz'); +.. literalinclude:: uri/017.php + :lines: 2- .. note:: Query values cannot contain fragments. An InvalidArgumentException will be thrown if it does. -You can set query values using an array:: +You can set query values using an array: - $uri->setQueryArray(['foo' => 'bar', 'bar' => 'baz']); +.. literalinclude:: uri/018.php + :lines: 2- The ``setQuery()`` and ``setQueryArray()`` methods overwrite any existing query variables. You can add a value to the query variables collection without destroying the existing query variables with the ``addQuery()`` method. The first -parameter is the name of the variable, and the second parameter is the value:: +parameter is the name of the variable, and the second parameter is the value: - $uri->addQuery('foo', 'bar'); +.. literalinclude:: uri/019.php + :lines: 2- **Filtering Query Values** You can filter the query values returned by passing an options array to the ``getQuery()`` method, with either an -*only* or an *except* key:: +*only* or an *except* key: - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com?foo=bar&bar=baz&baz=foz'); - - // Returns 'foo=bar' - echo $uri->getQuery(['only' => ['foo']); - - // Returns 'foo=bar&baz=foz' - echo $uri->getQuery(['except' => ['bar']]); +.. literalinclude:: uri/020.php + :lines: 2- This only changes the values returned during this one call. If you need to modify the URI's query values more permanently, -you can use the ``stripQuery()`` and ``keepQuery()`` methods to change the actual object's query variable collection:: - - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com?foo=bar&bar=baz&baz=foz'); +you can use the ``stripQuery()`` and ``keepQuery()`` methods to change the actual object's query variable collection: - // Leaves just the 'baz' variable - $uri->stripQuery('foo', 'bar'); - - // Leaves just the 'foo' variable - $uri->keepQuery('foo'); +.. literalinclude:: uri/021.php + :lines: 2- .. note:: By default ``setQuery()`` and ``setQueryArray()`` methods uses native ``parse_str()`` function to prepare data. If you want to use more liberal rules (which allow key names to contain dots), you can use a special method @@ -220,12 +197,9 @@ Fragment Fragments are the portion at the end of the URL, preceded by the pound-sign (#). In HTML URL's these are links to an on-page anchor. Media URI's can make use of them in various other ways. -:: - - $uri = new \CodeIgniter\HTTP\URI('http://www.example.com/some/path#first-heading'); - echo $uri->getFragment(); // 'first-heading' - echo $uri->setFragment('second-heading')->getFragment(); // 'second-heading' +.. literalinclude:: uri/022.php + :lines: 2- ============ URI Segments @@ -233,45 +207,24 @@ URI Segments Each section of the path between the slashes is a single segment. The URI class provides a simple way to determine what the values of the segments are. The segments start at 1 being the furthest left of the path. -:: - // URI = http://example.com/users/15/profile - - // Prints '15' - if ($uri->getSegment(1) == 'users') { - echo $uri->getSegment(2); - } +.. literalinclude:: uri/023.php + :lines: 2- You can also set a different default value for a particular segment by using the second parameter of the ``getSegment()`` method. The default is empty string. -:: - - // URI = http://example.com/users/15/profile - // will print 'profile' - echo $uri->getSegment(3, 'foo'); - // will print 'bar' - echo $uri->getSegment(4, 'bar'); - // will throw an exception - echo $uri->getSegment(5, 'baz'); - // will print 'baz' - echo $uri->setSilent()->getSegment(5, 'baz'); - // will print '' (empty string) - echo $uri->setSilent()->getSegment(5); +.. literalinclude:: uri/024.php + :lines: 2- -You can get a count of the total segments:: +You can get a count of the total segments: - $total = $uri->getTotalSegments(); // 3 +.. literalinclude:: uri/025.php + :lines: 2- -Finally, you can retrieve an array of all of the segments:: +Finally, you can retrieve an array of all of the segments: - $segments = $uri->getSegments(); - - // $segments = - [ - 0 => 'users', - 1 => '15', - 2 => 'profile' - ] +.. literalinclude:: uri/026.php + :lines: 2- =========================== Disable Throwing Exceptions @@ -279,10 +232,6 @@ Disable Throwing Exceptions By default, some methods of this class may throw an exception. If you want to disable it, you can set a special flag that will prevent throwing exceptions. -:: - - // Disable throwing exceptions - $uri->setSilent(); - // Enable throwing exceptions (default) - $uri->setSilent(false); +.. literalinclude:: uri/027.php + :lines: 2- diff --git a/user_guide_src/source/libraries/uri/001.php b/user_guide_src/source/libraries/uri/001.php new file mode 100644 index 000000000000..524e67669110 --- /dev/null +++ b/user_guide_src/source/libraries/uri/001.php @@ -0,0 +1,3 @@ +request->getPath(); diff --git a/user_guide_src/source/libraries/uri/006.php b/user_guide_src/source/libraries/uri/006.php new file mode 100644 index 000000000000..3cdabe4db4e8 --- /dev/null +++ b/user_guide_src/source/libraries/uri/006.php @@ -0,0 +1,4 @@ +getScheme(); // 'http' +$uri->setScheme('https'); diff --git a/user_guide_src/source/libraries/uri/009.php b/user_guide_src/source/libraries/uri/009.php new file mode 100644 index 000000000000..44043fbe63d0 --- /dev/null +++ b/user_guide_src/source/libraries/uri/009.php @@ -0,0 +1,5 @@ +getAuthority(); // user@example.com:21 diff --git a/user_guide_src/source/libraries/uri/010.php b/user_guide_src/source/libraries/uri/010.php new file mode 100644 index 000000000000..7b723837fd7f --- /dev/null +++ b/user_guide_src/source/libraries/uri/010.php @@ -0,0 +1,7 @@ +getAuthority(); // user@example.com:21 +echo $uri->showPassword()->getAuthority(); // user:password@example.com:21 + +// Turn password display off again. +$uri->showPassword(false); diff --git a/user_guide_src/source/libraries/uri/011.php b/user_guide_src/source/libraries/uri/011.php new file mode 100644 index 000000000000..ac1297380583 --- /dev/null +++ b/user_guide_src/source/libraries/uri/011.php @@ -0,0 +1,3 @@ +getAuthority(true); // user@example.com diff --git a/user_guide_src/source/libraries/uri/012.php b/user_guide_src/source/libraries/uri/012.php new file mode 100644 index 000000000000..0f733222f408 --- /dev/null +++ b/user_guide_src/source/libraries/uri/012.php @@ -0,0 +1,3 @@ +getUserInfo(); // user diff --git a/user_guide_src/source/libraries/uri/013.php b/user_guide_src/source/libraries/uri/013.php new file mode 100644 index 000000000000..65836aa97865 --- /dev/null +++ b/user_guide_src/source/libraries/uri/013.php @@ -0,0 +1,4 @@ +showPassword()->getUserInfo(); // user:password +$uri->showPassword(false); diff --git a/user_guide_src/source/libraries/uri/014.php b/user_guide_src/source/libraries/uri/014.php new file mode 100644 index 000000000000..79192a56955d --- /dev/null +++ b/user_guide_src/source/libraries/uri/014.php @@ -0,0 +1,6 @@ +getHost(); // www.example.com +echo $uri->setHost('anotherexample.com')->getHost(); // anotherexample.com diff --git a/user_guide_src/source/libraries/uri/015.php b/user_guide_src/source/libraries/uri/015.php new file mode 100644 index 000000000000..f5b43c3a65d0 --- /dev/null +++ b/user_guide_src/source/libraries/uri/015.php @@ -0,0 +1,6 @@ +getPort(); // 21 +echo $uri->setPort(2201)->getPort(); // 2201 diff --git a/user_guide_src/source/libraries/uri/016.php b/user_guide_src/source/libraries/uri/016.php new file mode 100644 index 000000000000..a9e680ac38de --- /dev/null +++ b/user_guide_src/source/libraries/uri/016.php @@ -0,0 +1,6 @@ +getPath(); // 'some/path' +echo $uri->setPath('another/path')->getPath(); // 'another/path' diff --git a/user_guide_src/source/libraries/uri/017.php b/user_guide_src/source/libraries/uri/017.php new file mode 100644 index 000000000000..dd45fb157f4b --- /dev/null +++ b/user_guide_src/source/libraries/uri/017.php @@ -0,0 +1,6 @@ +getQuery(); // 'foo=bar' +$uri->setQuery('foo=bar&bar=baz'); diff --git a/user_guide_src/source/libraries/uri/018.php b/user_guide_src/source/libraries/uri/018.php new file mode 100644 index 000000000000..64d5ab6f359c --- /dev/null +++ b/user_guide_src/source/libraries/uri/018.php @@ -0,0 +1,3 @@ +setQueryArray(['foo' => 'bar', 'bar' => 'baz']); diff --git a/user_guide_src/source/libraries/uri/019.php b/user_guide_src/source/libraries/uri/019.php new file mode 100644 index 000000000000..076fbf4652c1 --- /dev/null +++ b/user_guide_src/source/libraries/uri/019.php @@ -0,0 +1,3 @@ +addQuery('foo', 'bar'); diff --git a/user_guide_src/source/libraries/uri/020.php b/user_guide_src/source/libraries/uri/020.php new file mode 100644 index 000000000000..ab991a826cff --- /dev/null +++ b/user_guide_src/source/libraries/uri/020.php @@ -0,0 +1,9 @@ +getQuery(['only' => ['foo']); + +// Returns 'foo=bar&baz=foz' +echo $uri->getQuery(['except' => ['bar']]); diff --git a/user_guide_src/source/libraries/uri/021.php b/user_guide_src/source/libraries/uri/021.php new file mode 100644 index 000000000000..ed2976e6e1d3 --- /dev/null +++ b/user_guide_src/source/libraries/uri/021.php @@ -0,0 +1,9 @@ +stripQuery('foo', 'bar'); + +// Leaves just the 'foo' variable +$uri->keepQuery('foo'); diff --git a/user_guide_src/source/libraries/uri/022.php b/user_guide_src/source/libraries/uri/022.php new file mode 100644 index 000000000000..e2df019dcb87 --- /dev/null +++ b/user_guide_src/source/libraries/uri/022.php @@ -0,0 +1,6 @@ +getFragment(); // 'first-heading' +echo $uri->setFragment('second-heading')->getFragment(); // 'second-heading' diff --git a/user_guide_src/source/libraries/uri/023.php b/user_guide_src/source/libraries/uri/023.php new file mode 100644 index 000000000000..8c611f066c28 --- /dev/null +++ b/user_guide_src/source/libraries/uri/023.php @@ -0,0 +1,8 @@ +getSegment(1) == 'users') { + echo $uri->getSegment(2); +} diff --git a/user_guide_src/source/libraries/uri/024.php b/user_guide_src/source/libraries/uri/024.php new file mode 100644 index 000000000000..61a951db93c3 --- /dev/null +++ b/user_guide_src/source/libraries/uri/024.php @@ -0,0 +1,14 @@ +getSegment(3, 'foo'); +// will print 'bar' +echo $uri->getSegment(4, 'bar'); +// will throw an exception +echo $uri->getSegment(5, 'baz'); +// will print 'baz' +echo $uri->setSilent()->getSegment(5, 'baz'); +// will print '' (empty string) +echo $uri->setSilent()->getSegment(5); diff --git a/user_guide_src/source/libraries/uri/025.php b/user_guide_src/source/libraries/uri/025.php new file mode 100644 index 000000000000..ce130a2c6f8b --- /dev/null +++ b/user_guide_src/source/libraries/uri/025.php @@ -0,0 +1,3 @@ +getTotalSegments(); // 3 diff --git a/user_guide_src/source/libraries/uri/026.php b/user_guide_src/source/libraries/uri/026.php new file mode 100644 index 000000000000..c5be0f68c2ff --- /dev/null +++ b/user_guide_src/source/libraries/uri/026.php @@ -0,0 +1,10 @@ +getSegments(); + +// $segments = +[ + 0 => 'users', + 1 => '15', + 2 => 'profile' +] diff --git a/user_guide_src/source/libraries/uri/027.php b/user_guide_src/source/libraries/uri/027.php new file mode 100644 index 000000000000..8ad2f883ffe4 --- /dev/null +++ b/user_guide_src/source/libraries/uri/027.php @@ -0,0 +1,7 @@ +setSilent(); + +// Enable throwing exceptions (default) +$uri->setSilent(false); diff --git a/user_guide_src/source/libraries/user_agent.rst b/user_guide_src/source/libraries/user_agent.rst index 576798bf4b2a..fad24a91d403 100644 --- a/user_guide_src/source/libraries/user_agent.rst +++ b/user_guide_src/source/libraries/user_agent.rst @@ -18,9 +18,10 @@ Initializing the Class The User Agent class is always available directly from the current :doc:`IncomingRequest ` instance. By default, you will have a request instance in your controller that you can retrieve the -User Agent class from:: +User Agent class from: - $agent = $this->request->getUserAgent(); +.. literalinclude:: user_agent/001.php + :lines: 2- User Agent Definitions ====================== @@ -35,23 +36,10 @@ Example When the User Agent class is initialized it will attempt to determine whether the user agent browsing your site is a web browser, a mobile device, or a robot. It will also gather the platform information if it -is available:: +is available: - $agent = $this->request->getUserAgent(); - - if ($agent->isBrowser()) { - $currentAgent = $agent->getBrowser() . ' ' . $agent->getVersion(); - } elseif ($agent->isRobot()) { - $currentAgent = $agent->getRobot(); - } elseif ($agent->isMobile()) { - $currentAgent = $agent->getMobile(); - } else { - $currentAgent = 'Unidentified User Agent'; - } - - echo $currentAgent; - - echo $agent->getPlatform(); // Platform info (Windows, Linux, Mac, etc.) +.. literalinclude:: user_agent/002.php + :lines: 2- *************** Class Reference @@ -66,13 +54,9 @@ Class Reference :rtype: bool Returns true/false (boolean) if the user agent is a known web browser. - :: - if ($agent->isBrowser('Safari')) { - echo 'You are using Safari.'; - } elseif ($agent->isBrowser()) { - echo 'You are using a browser.'; - } + .. literalinclude:: user_agent/003.php + :lines: 2- .. note:: The string "Safari" in this example is an array key in the list of browser definitions. You can find this list in **app/Config/UserAgents.php** if you want to add new @@ -85,15 +69,9 @@ Class Reference :rtype: bool Returns true/false (boolean) if the user agent is a known mobile device. - :: - if ($agent->isMobile('iphone')) { - echo view('iphone/home'); - } elseif ($agent->isMobile()) { - echo view('mobile/home'); - } else { - echo view('web/home'); - } + .. literalinclude:: user_agent/004.php + :lines: 2- .. php:method:: isRobot([$key = null]) @@ -155,11 +133,10 @@ Class Reference :returns: Detected referrer or an empty string :rtype: string - The referrer, if the user agent was referred from another site. Typically you'll test for this as follows:: + The referrer, if the user agent was referred from another site. Typically you'll test for this as follows: - if ($agent->isReferral()) { - echo $agent->referrer(); - } + .. literalinclude:: user_agent/005.php + :lines: 2- .. php:method:: getAgentString() diff --git a/user_guide_src/source/libraries/user_agent/001.php b/user_guide_src/source/libraries/user_agent/001.php new file mode 100644 index 000000000000..f8af7f7cfaee --- /dev/null +++ b/user_guide_src/source/libraries/user_agent/001.php @@ -0,0 +1,3 @@ +request->getUserAgent(); diff --git a/user_guide_src/source/libraries/user_agent/002.php b/user_guide_src/source/libraries/user_agent/002.php new file mode 100644 index 000000000000..0a92a06bc2f7 --- /dev/null +++ b/user_guide_src/source/libraries/user_agent/002.php @@ -0,0 +1,17 @@ +request->getUserAgent(); + +if ($agent->isBrowser()) { + $currentAgent = $agent->getBrowser() . ' ' . $agent->getVersion(); +} elseif ($agent->isRobot()) { + $currentAgent = $agent->getRobot(); +} elseif ($agent->isMobile()) { + $currentAgent = $agent->getMobile(); +} else { + $currentAgent = 'Unidentified User Agent'; +} + +echo $currentAgent; + +echo $agent->getPlatform(); // Platform info (Windows, Linux, Mac, etc.) diff --git a/user_guide_src/source/libraries/user_agent/003.php b/user_guide_src/source/libraries/user_agent/003.php new file mode 100644 index 000000000000..0abfbf22d7d8 --- /dev/null +++ b/user_guide_src/source/libraries/user_agent/003.php @@ -0,0 +1,7 @@ +isBrowser('Safari')) { + echo 'You are using Safari.'; +} elseif ($agent->isBrowser()) { + echo 'You are using a browser.'; +} diff --git a/user_guide_src/source/libraries/user_agent/004.php b/user_guide_src/source/libraries/user_agent/004.php new file mode 100644 index 000000000000..80405bff519d --- /dev/null +++ b/user_guide_src/source/libraries/user_agent/004.php @@ -0,0 +1,9 @@ +isMobile('iphone')) { + echo view('iphone/home'); +} elseif ($agent->isMobile()) { + echo view('mobile/home'); +} else { + echo view('web/home'); +} diff --git a/user_guide_src/source/libraries/user_agent/005.php b/user_guide_src/source/libraries/user_agent/005.php new file mode 100644 index 000000000000..944c70975971 --- /dev/null +++ b/user_guide_src/source/libraries/user_agent/005.php @@ -0,0 +1,5 @@ +isReferral()) { + echo $agent->referrer(); +} diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 89eb4740179d..0f43f911a506 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -117,29 +117,9 @@ The Controller ================================================ Using a text editor, create a controller called **Form.php**. In it, place -this code and save it to your **app/Controllers/** folder:: +this code and save it to your **app/Controllers/** folder: - validate([])) { - echo view('Signup', [ - 'validation' => $this->validator, - ]); - } else { - echo view('Success'); - } - } - } +.. literalinclude:: validation/001.php Try it! ================================================ @@ -188,16 +168,10 @@ form or the success page. Add Validation Rules ================================================ -Then add validation rules in the controller (**Form.php**):: +Then add validation rules in the controller (**Form.php**): - if (! $this->validate([ - 'username' => 'required', - 'password' => 'required|min_length[10]', - 'passconf' => 'required|matches[password]', - 'email' => 'required|valid_email', - ])) { - ... - } +.. literalinclude:: validation/002.php + :lines: 2- If you submit the form you should see the success page or the form with error messages. @@ -228,21 +202,18 @@ The **Strict Rules** don't use implicit type conversion. Using Strict Rules ------------------ -If you want to use these rules, you need to change the rule classes in **app/Config/Validation.php**:: +If you want to use these rules, you need to change the rule classes in **app/Config/Validation.php**: - public $ruleSets = [ - \CodeIgniter\Validation\StrictRules\CreditCardRules::class, - \CodeIgniter\Validation\StrictRules\FileRules::class, - \CodeIgniter\Validation\StrictRules\FormatRules::class, - \CodeIgniter\Validation\StrictRules\Rules::class, - ]; +.. literalinclude:: validation/003.php + :lines: 2- Loading the Library ************************************************ -The library is loaded as a service named **validation**:: +The library is loaded as a service named **validation**: - $validation = \Config\Services::validation(); +.. literalinclude:: validation/004.php + :lines: 2- This automatically loads the ``Config\Validation`` file which contains settings for including multiple Rulesets, and collections of rules that can be easily reused. @@ -265,10 +236,10 @@ This method sets a single rule. It has the method signature:: setRule(string $field, ?string $label, array|string $rules[, array $errors = []]) -The ``$rules`` either takes in a pipe-delimited list of rules or an array collection of rules:: +The ``$rules`` either takes in a pipe-delimited list of rules or an array collection of rules: - $validation->setRule('username', 'Username', 'required|min_length[3]'); - $validation->setRule('password', 'Password', ['required', 'min_length[8]', 'alpha_numeric_punct']); +.. literalinclude:: validation/005.php + :lines: 2- The value you pass to ``$field`` must match the key of any data array that is sent in. If the data is taken directly from ``$_POST``, then it must be an exact match for @@ -282,19 +253,15 @@ the form input name. setRules() ========== -Like ``setRule()``, but accepts an array of field names and their rules:: +Like ``setRule()``, but accepts an array of field names and their rules: - $validation->setRules([ - 'username' => 'required', - 'password' => 'required|min_length[10]', - ]); +.. literalinclude:: validation/006.php + :lines: 2- -To give a labeled error message you can set up as:: +To give a labeled error message you can set up as: - $validation->setRules([ - 'username' => ['label' => 'Username', 'rules' => 'required'], - 'password' => ['label' => 'Password', 'rules' => 'required|min_length[10]'], - ]); +.. literalinclude:: validation/007.php + :lines: 2- withRequest() ============= @@ -302,9 +269,10 @@ withRequest() One of the most common times you will use the validation library is when validating data that was input from an HTTP Request. If desired, you can pass an instance of the current Request object and it will take all of the input data and set it as the -data to be validated:: +data to be validated: - $validation->withRequest($this->request)->run(); +.. literalinclude:: validation/008.php + :lines: 2- Working with Validation ************************************************ @@ -313,58 +281,29 @@ Validating Keys that are Arrays ================================================ If your data is in a nested associative array, you can use "dot array syntax" to -easily validate your data:: +easily validate your data: - // The data to test: - 'contacts' => [ - 'name' => 'Joe Smith', - 'friends' => [ - [ - 'name' => 'Fred Flinstone', - ], - [ - 'name' => 'Wilma', - ], - ] - ] +.. literalinclude:: validation/009.php + :lines: 2- - // Joe Smith - $validation->setRules([ - 'contacts.name' => 'required', - ]); - - // Fred Flintsone & Wilma - $validation->setRules([ - 'contacts.friends.name' => 'required', - ]); +You can use the '*' wildcard symbol to match any one level of the array: -You can use the '*' wildcard symbol to match any one level of the array:: - - // Fred Flintsone & Wilma - $validation->setRules([ - 'contacts.*.name' => 'required', - ]); +.. literalinclude:: validation/010.php + :lines: 2- "dot array syntax" can also be useful when you have single dimension array data. -For example, data returned by multi select dropdown:: +For example, data returned by multi select dropdown: - // The data to test: - 'user_ids' => [ - 1, - 2, - 3, - ] - // Rule - $validation->setRules([ - 'user_ids.*' => 'required', - ]); +.. literalinclude:: validation/011.php + :lines: 2- Validate 1 Value ================================================ -Validate one value against a rule:: +Validate one value against a rule: - $validation->check($value, 'required'); +.. literalinclude:: validation/012.php + :lines: 2- Saving Sets of Validation Rules to the Config File ======================================================= @@ -381,64 +320,27 @@ How to save your rules To store your validation rules, simply create a new public property in the ``Config\Validation`` class with the name of your group. This element will hold an array with your validation -rules. As shown earlier, the validation array will have this prototype:: +rules. As shown earlier, the validation array will have this prototype: - class Validation - { - public $signup = [ - 'username' => 'required', - 'password' => 'required', - 'pass_confirm' => 'required|matches[password]', - 'email' => 'required|valid_email', - ]; - } +.. literalinclude:: validation/013.php + :lines: 2- -You can specify the group to use when you call the ``run()`` method:: +You can specify the group to use when you call the ``run()`` method: - $validation->run($data, 'signup'); +.. literalinclude:: validation/014.php + :lines: 2- You can also store custom error messages in this configuration file by naming the property the same as the group, and appended with ``_errors``. These will automatically -be used for any errors when this group is used:: - - class Validation - { - public $signup = [ - 'username' => 'required', - 'password' => 'required', - 'pass_confirm' => 'required|matches[password]', - 'email' => 'required|valid_email', - ]; - - public $signup_errors = [ - 'username' => [ - 'required' => 'You must choose a username.', - ], - 'email' => [ - 'valid_email' => 'Please check the Email field. It does not appear to be valid.', - ], - ]; - } - -Or pass all settings in an array:: - - class Validation - { - public $signup = [ - 'username' => [ - 'rules' => 'required', - 'errors' => [ - 'required' => 'You must choose a Username.', - ], - ], - 'email' => [ - 'rules' => 'required|valid_email', - 'errors' => [ - 'valid_email' => 'Please check the Email field. It does not appear to be valid.', - ], - ], - ]; - } +be used for any errors when this group is used: + +.. literalinclude:: validation/015.php + :lines: 2- + +Or pass all settings in an array: + +.. literalinclude:: validation/016.php + :lines: 2- See below for details on the formatting of the array. @@ -447,15 +349,17 @@ Getting & Setting Rule Groups **Get Rule Group** -This method gets a rule group from the validation configuration:: +This method gets a rule group from the validation configuration: - $validation->getRuleGroup('signup'); +.. literalinclude:: validation/017.php + :lines: 2- **Set Rule Group** -This method sets a rule group from the validation configuration to the validation service:: +This method sets a rule group from the validation configuration to the validation service: - $validation->setRuleGroup('signup'); +.. literalinclude:: validation/018.php + :lines: 2- Running Multiple Validations ======================================================= @@ -467,16 +371,10 @@ Running Multiple Validations If you intend to run multiple validations, for instance on different data sets or with different rules after one another, you might need to call ``$validation->reset()`` before each run to get rid of errors from previous run. Be aware that ``reset()`` will invalidate any data, rule or custom error -you previously set, so ``setRules()``, ``setRuleGroup()`` etc. need to be repeated:: +you previously set, so ``setRules()``, ``setRuleGroup()`` etc. need to be repeated: - foreach ($userAccounts as $user) { - $validation->reset(); - $validation->setRules($userAccountRules); - - if (! $validation->run($user)) { - // handle validation errors - } - } +.. literalinclude:: validation/019.php + :lines: 2- Validation Placeholders ======================================================= @@ -484,25 +382,21 @@ Validation Placeholders The Validation class provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply the name of the field (or array key) that was passed in as ``$data`` surrounded by curly brackets. It will be -replaced by the **value** of the matched incoming field. An example should clarify this:: +replaced by the **value** of the matched incoming field. An example should clarify this: - $validation->setRules([ - 'email' => 'required|valid_email|is_unique[users.email,id,{id}]', - ]); +.. literalinclude:: validation/020.php + :lines: 2- In this set of rules, it states that the email address should be unique in the database, except for the row -that has an id matching the placeholder's value. Assuming that the form POST data had the following:: +that has an id matching the placeholder's value. Assuming that the form POST data had the following: - $_POST = [ - 'id' => 4, - 'email' => 'foo@example.com', - ]; +.. literalinclude:: validation/021.php + :lines: 2- -then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule:: +then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule: - $validation->setRules([ - 'email' => 'required|valid_email|is_unique[users.email,id,4]', - ]); +.. literalinclude:: validation/022.php + :lines: 2- So it will ignore the row in the database that has ``id=4`` when it verifies the email is unique. @@ -530,46 +424,21 @@ instance. If not custom error message is provided, the default value will be use These are two ways to provide custom error messages. -As the last parameter:: +As the last parameter: - $validation->setRules([ - 'username' => 'required|is_unique[users.username]', - 'password' => 'required|min_length[10]' - ], - [ // Errors - 'username' => [ - 'required' => 'All accounts must have usernames provided', - ], - 'password' => [ - 'min_length' => 'Your password is too short. You want to get hacked?', - ], - ] - ); +.. literalinclude:: validation/023.php + :lines: 2- -Or as a labeled style:: +Or as a labeled style: - $validation->setRules([ - 'username' => [ - 'label' => 'Username', - 'rules' => 'required|is_unique[users.username]', - 'errors' => [ - 'required' => 'All accounts must have {field} provided', - ], - ], - 'password' => [ - 'label' => 'Password', - 'rules' => 'required|min_length[10]', - 'errors' => [ - 'min_length' => 'Your {field} is too short. You want to get hacked?', - ], - ] - ] - ); +.. literalinclude:: validation/024.php + :lines: 2- If you’d like to include a field’s “human” name, or the optional parameter some rules allow for (such as max_length), -or the value that was validated you can add the ``{field}``, ``{param}`` and ``{value}`` tags to your message, respectively:: +or the value that was validated you can add the ``{field}``, ``{param}`` and ``{value}`` tags to your message, respectively: - 'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.' +.. literalinclude:: validation/025.php + :lines: 2- On a field with the human name Username and a rule of ``min_length[6]`` with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must have at least 6 characters.” @@ -583,40 +452,20 @@ Translation Of Messages And Validation Labels To use translated strings from language files, we can simply use the dot syntax. Let's say we have a file with translations located here: ``app/Languages/en/Rules.php``. -We can simply use the language lines defined in this file, like this:: - - $validation->setRules([ - 'username' => [ - 'label' => 'Rules.username', - 'rules' => 'required|is_unique[users.username]', - 'errors' => [ - 'required' => 'Rules.username.required', - ], - ], - 'password' => [ - 'label' => 'Rules.password', - 'rules' => 'required|min_length[10]', - 'errors' => [ - 'min_length' => 'Rules.password.min_length', - ], - ], - ] - ); +We can simply use the language lines defined in this file, like this: + +.. literalinclude:: validation/026.php + :lines: 2- .. _validation-getting-all-errors: Getting All Errors ================== -If you need to retrieve all error messages for failed fields, you can use the ``getErrors()`` method:: - - $errors = $validation->getErrors(); +If you need to retrieve all error messages for failed fields, you can use the ``getErrors()`` method: - // Returns: - [ - 'field1' => 'error message', - 'field2' => 'error message', - ] +.. literalinclude:: validation/027.php + :lines: 2- If no errors exist, an empty array will be returned. @@ -644,9 +493,10 @@ Getting a Single Error ====================== You can retrieve the error for a single field with the ``getError()`` method. The only parameter is the field -name:: +name: - $error = $validation->getError('username'); +.. literalinclude:: validation/028.php + :lines: 2- If no error exists, an empty string will be returned. @@ -655,11 +505,10 @@ If no error exists, an empty string will be returned. Check If Error Exists ===================== -You can check to see if an error exists with the ``hasError()`` method. The only parameter is the field name:: +You can check to see if an error exists with the ``hasError()`` method. The only parameter is the field name: - if ($validation->hasError('username')) { - echo $validation->getError('username'); - } +.. literalinclude:: validation/029.php + :lines: 2- When specifying a field with a wildcard, all errors matching the mask will be checked.:: @@ -683,23 +532,15 @@ Creating the Views The first step is to create custom views. These can be placed anywhere that the ``view()`` method can locate them, which means the standard View directory, or any namespaced View folder will work. For example, you could create -a new view at **/app/Views/_errors_list.php**:: +a new view at **/app/Views/_errors_list.php**: - +.. literalinclude:: validation/029-2.php An array named ``$errors`` is available within the view that contains a list of the errors, where the key is -the name of the field that had the error, and the value is the error message, like this:: +the name of the field that had the error, and the value is the error message, like this: - $errors = [ - 'username' => 'The username field must be unique.', - 'email' => 'You must provide a valid email address.' - ]; +.. literalinclude:: validation/030.php + :lines: 2- There are actually two types of views that you can create. The first has an array of all of the errors, and is what we just looked at. The other type is simpler, and only contains a single variable, ``$error`` that contains the @@ -712,13 +553,10 @@ Configuration Once you have your views created, you need to let the Validation library know about them. Open ``Config/Validation.php``. Inside, you'll find the ``$templates`` property where you can list as many custom views as you want, and provide an -short alias they can be referenced by. If we were to add our example file from above, it would look something like:: +short alias they can be referenced by. If we were to add our example file from above, it would look something like: - public $templates = [ - 'list' => 'CodeIgniter\Validation\Views\list', - 'single' => 'CodeIgniter\Validation\Views\single', - 'my_list' => '_errors_list', - ]; +.. literalinclude:: validation/031.php + :lines: 2- Specifying the Template ======================= @@ -737,94 +575,41 @@ Creating Custom Rules Rules are stored within simple, namespaced classes. They can be stored any location you would like, as long as the autoloader can find it. These files are called RuleSets. To add a new RuleSet, edit **Config/Validation.php** and -add the new file to the ``$ruleSets`` array:: - - use CodeIgniter\Validation\CreditCardRules; - use CodeIgniter\Validation\FileRules; - use CodeIgniter\Validation\FormatRules; - use CodeIgniter\Validation\Rules; +add the new file to the ``$ruleSets`` array: - public $ruleSets = [ - Rules::class, - FormatRules::class, - FileRules::class, - CreditCardRules::class, - ]; +.. literalinclude:: validation/032.php + :lines: 2- You can add it as either a simple string with the fully qualified class name, or using the ``::class`` suffix as shown above. The primary benefit here is that it provides some extra navigation capabilities in more advanced IDEs. Within the file itself, each method is a rule and must accept a string as the first parameter, and must return -a boolean true or false value signifying true if it passed the test or false if it did not:: +a boolean true or false value signifying true if it passed the test or false if it did not: - class MyRules - { - public function even(string $str): bool - { - return (int) $str % 2 == 0; - } - } +.. literalinclude:: validation/033.php + :lines: 2- By default, the system will look within ``CodeIgniter\Language\en\Validation.php`` for the language strings used within errors. In custom rules, you may provide error messages by accepting a ``$error`` variable by reference in the -second parameter:: +second parameter: - public function even(string $str, string &$error = null): bool - { - if ((int) $str % 2 !== 0) { - $error = lang('myerrors.evenError'); +.. literalinclude:: validation/034.php + :lines: 2- - return false; - } +Your new custom rule could now be used just like any other rule: - return true; - } - -Your new custom rule could now be used just like any other rule:: - - $this->validate($request, [ - 'foo' => 'required|even', - ]); +.. literalinclude:: validation/035.php + :lines: 2- Allowing Parameters =================== If your method needs to work with parameters, the function will need a minimum of three parameters: the string to validate, the parameter string, and an array with all of the data that was submitted the form. The ``$data`` array is especially handy -for rules like ``require_with`` that needs to check the value of another submitted field to base its result on:: - - public function required_with($str, string $fields, array $data): bool - { - $fields = explode(',', $fields); - - // If the field is present we can safely assume that - // the field is here, no matter whether the corresponding - // search field is present or not. - $present = $this->required($str ?? ''); +for rules like ``require_with`` that needs to check the value of another submitted field to base its result on: - if ($present) { - return true; - } - - // Still here? Then we fail this test if - // any of the fields are present in $data - // as $fields is the lis - $requiredFields = []; - - foreach ($fields as $field) { - if (array_key_exists($field, $data)) { - $requiredFields[] = $field; - } - } - - // Remove any keys with empty values since, that means they - // weren't truly there, as far as this is concerned. - $requiredFields = array_filter($requiredFields, function ($item) use ($data) { - return ! empty($data[$item]); - }); - - return empty($requiredFields); - } +.. literalinclude:: validation/036.php + :lines: 2- Custom errors can be returned as the fourth parameter, just as described above. @@ -836,16 +621,8 @@ The following is a list of all the native rules that are available to use: .. note:: Rule is a string; there must be **no spaces** between the parameters, especially the ``is_unique`` rule. There can be no spaces before and after ``ignore_value``. -:: - - // is_unique[table.field,ignore_field,ignore_value] - - $validation->setRules([ - 'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok - 'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok - 'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok - 'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders" - ]); +.. literalinclude:: validation/037.php + :lines: 2- ======================= ========== ============================================= =================================================== Rule Parameter Description Example diff --git a/user_guide_src/source/libraries/validation/001.php b/user_guide_src/source/libraries/validation/001.php new file mode 100644 index 000000000000..e52362c46cea --- /dev/null +++ b/user_guide_src/source/libraries/validation/001.php @@ -0,0 +1,21 @@ +validate([])) { + echo view('Signup', [ + 'validation' => $this->validator, + ]); + } else { + echo view('Success'); + } + } +} diff --git a/user_guide_src/source/libraries/validation/002.php b/user_guide_src/source/libraries/validation/002.php new file mode 100644 index 000000000000..46322fe586bd --- /dev/null +++ b/user_guide_src/source/libraries/validation/002.php @@ -0,0 +1,10 @@ +validate([ + 'username' => 'required', + 'password' => 'required|min_length[10]', + 'passconf' => 'required|matches[password]', + 'email' => 'required|valid_email', +])) { + ... +} diff --git a/user_guide_src/source/libraries/validation/003.php b/user_guide_src/source/libraries/validation/003.php new file mode 100644 index 000000000000..a6ae3a4a6fff --- /dev/null +++ b/user_guide_src/source/libraries/validation/003.php @@ -0,0 +1,8 @@ +setRule('username', 'Username', 'required|min_length[3]'); +$validation->setRule('password', 'Password', ['required', 'min_length[8]', 'alpha_numeric_punct']); diff --git a/user_guide_src/source/libraries/validation/006.php b/user_guide_src/source/libraries/validation/006.php new file mode 100644 index 000000000000..24a771f70e31 --- /dev/null +++ b/user_guide_src/source/libraries/validation/006.php @@ -0,0 +1,6 @@ +setRules([ + 'username' => 'required', + 'password' => 'required|min_length[10]', +]); diff --git a/user_guide_src/source/libraries/validation/007.php b/user_guide_src/source/libraries/validation/007.php new file mode 100644 index 000000000000..b211d9c1cec5 --- /dev/null +++ b/user_guide_src/source/libraries/validation/007.php @@ -0,0 +1,6 @@ +setRules([ + 'username' => ['label' => 'Username', 'rules' => 'required'], + 'password' => ['label' => 'Password', 'rules' => 'required|min_length[10]'], +]); diff --git a/user_guide_src/source/libraries/validation/008.php b/user_guide_src/source/libraries/validation/008.php new file mode 100644 index 000000000000..1b570f1aad82 --- /dev/null +++ b/user_guide_src/source/libraries/validation/008.php @@ -0,0 +1,3 @@ +withRequest($this->request)->run(); diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php new file mode 100644 index 000000000000..1678d5530f27 --- /dev/null +++ b/user_guide_src/source/libraries/validation/009.php @@ -0,0 +1,24 @@ + [ + 'name' => 'Joe Smith', + 'friends' => [ + [ + 'name' => 'Fred Flinstone', + ], + [ + 'name' => 'Wilma', + ], + ] +] + +// Joe Smith +$validation->setRules([ + 'contacts.name' => 'required', +]); + +// Fred Flintsone & Wilma +$validation->setRules([ + 'contacts.friends.name' => 'required', +]); diff --git a/user_guide_src/source/libraries/validation/010.php b/user_guide_src/source/libraries/validation/010.php new file mode 100644 index 000000000000..94c6919311d5 --- /dev/null +++ b/user_guide_src/source/libraries/validation/010.php @@ -0,0 +1,6 @@ +setRules([ + 'contacts.*.name' => 'required', +]); diff --git a/user_guide_src/source/libraries/validation/011.php b/user_guide_src/source/libraries/validation/011.php new file mode 100644 index 000000000000..023712f4315e --- /dev/null +++ b/user_guide_src/source/libraries/validation/011.php @@ -0,0 +1,12 @@ + [ + 1, + 2, + 3, +] +// Rule +$validation->setRules([ + 'user_ids.*' => 'required', +]); diff --git a/user_guide_src/source/libraries/validation/012.php b/user_guide_src/source/libraries/validation/012.php new file mode 100644 index 000000000000..a43f9ab1a498 --- /dev/null +++ b/user_guide_src/source/libraries/validation/012.php @@ -0,0 +1,3 @@ +check($value, 'required'); diff --git a/user_guide_src/source/libraries/validation/013.php b/user_guide_src/source/libraries/validation/013.php new file mode 100644 index 000000000000..f90dfc0ba5fc --- /dev/null +++ b/user_guide_src/source/libraries/validation/013.php @@ -0,0 +1,11 @@ + 'required', + 'password' => 'required', + 'pass_confirm' => 'required|matches[password]', + 'email' => 'required|valid_email', + ]; +} diff --git a/user_guide_src/source/libraries/validation/014.php b/user_guide_src/source/libraries/validation/014.php new file mode 100644 index 000000000000..1aa5b7f521c0 --- /dev/null +++ b/user_guide_src/source/libraries/validation/014.php @@ -0,0 +1,3 @@ +run($data, 'signup'); diff --git a/user_guide_src/source/libraries/validation/015.php b/user_guide_src/source/libraries/validation/015.php new file mode 100644 index 000000000000..31cf681b92a7 --- /dev/null +++ b/user_guide_src/source/libraries/validation/015.php @@ -0,0 +1,20 @@ + 'required', + 'password' => 'required', + 'pass_confirm' => 'required|matches[password]', + 'email' => 'required|valid_email', + ]; + + public $signup_errors = [ + 'username' => [ + 'required' => 'You must choose a username.', + ], + 'email' => [ + 'valid_email' => 'Please check the Email field. It does not appear to be valid.', + ], + ]; +} diff --git a/user_guide_src/source/libraries/validation/016.php b/user_guide_src/source/libraries/validation/016.php new file mode 100644 index 000000000000..55d9f6985cf9 --- /dev/null +++ b/user_guide_src/source/libraries/validation/016.php @@ -0,0 +1,19 @@ + [ + 'rules' => 'required', + 'errors' => [ + 'required' => 'You must choose a Username.', + ], + ], + 'email' => [ + 'rules' => 'required|valid_email', + 'errors' => [ + 'valid_email' => 'Please check the Email field. It does not appear to be valid.', + ], + ], + ]; +} diff --git a/user_guide_src/source/libraries/validation/017.php b/user_guide_src/source/libraries/validation/017.php new file mode 100644 index 000000000000..f84561eb5375 --- /dev/null +++ b/user_guide_src/source/libraries/validation/017.php @@ -0,0 +1,3 @@ +getRuleGroup('signup'); diff --git a/user_guide_src/source/libraries/validation/018.php b/user_guide_src/source/libraries/validation/018.php new file mode 100644 index 000000000000..245c4b6932cf --- /dev/null +++ b/user_guide_src/source/libraries/validation/018.php @@ -0,0 +1,3 @@ +setRuleGroup('signup'); diff --git a/user_guide_src/source/libraries/validation/019.php b/user_guide_src/source/libraries/validation/019.php new file mode 100644 index 000000000000..bf158323f638 --- /dev/null +++ b/user_guide_src/source/libraries/validation/019.php @@ -0,0 +1,10 @@ +reset(); + $validation->setRules($userAccountRules); + + if (! $validation->run($user)) { + // handle validation errors + } +} diff --git a/user_guide_src/source/libraries/validation/020.php b/user_guide_src/source/libraries/validation/020.php new file mode 100644 index 000000000000..d9ab8f75fcdc --- /dev/null +++ b/user_guide_src/source/libraries/validation/020.php @@ -0,0 +1,5 @@ +setRules([ + 'email' => 'required|valid_email|is_unique[users.email,id,{id}]', +]); diff --git a/user_guide_src/source/libraries/validation/021.php b/user_guide_src/source/libraries/validation/021.php new file mode 100644 index 000000000000..ab70fa937a5d --- /dev/null +++ b/user_guide_src/source/libraries/validation/021.php @@ -0,0 +1,6 @@ + 4, + 'email' => 'foo@example.com', +]; diff --git a/user_guide_src/source/libraries/validation/022.php b/user_guide_src/source/libraries/validation/022.php new file mode 100644 index 000000000000..9c0f3ab7410d --- /dev/null +++ b/user_guide_src/source/libraries/validation/022.php @@ -0,0 +1,5 @@ +setRules([ + 'email' => 'required|valid_email|is_unique[users.email,id,4]', +]); diff --git a/user_guide_src/source/libraries/validation/023.php b/user_guide_src/source/libraries/validation/023.php new file mode 100644 index 000000000000..5d0618b338ee --- /dev/null +++ b/user_guide_src/source/libraries/validation/023.php @@ -0,0 +1,15 @@ +setRules([ + 'username' => 'required|is_unique[users.username]', + 'password' => 'required|min_length[10]' + ], + [ // Errors + 'username' => [ + 'required' => 'All accounts must have usernames provided', + ], + 'password' => [ + 'min_length' => 'Your password is too short. You want to get hacked?', + ], + ] +); diff --git a/user_guide_src/source/libraries/validation/024.php b/user_guide_src/source/libraries/validation/024.php new file mode 100644 index 000000000000..b6b7c7464a5d --- /dev/null +++ b/user_guide_src/source/libraries/validation/024.php @@ -0,0 +1,19 @@ +setRules([ + 'username' => [ + 'label' => 'Username', + 'rules' => 'required|is_unique[users.username]', + 'errors' => [ + 'required' => 'All accounts must have {field} provided', + ], + ], + 'password' => [ + 'label' => 'Password', + 'rules' => 'required|min_length[10]', + 'errors' => [ + 'min_length' => 'Your {field} is too short. You want to get hacked?', + ], + ] + ] +); diff --git a/user_guide_src/source/libraries/validation/025.php b/user_guide_src/source/libraries/validation/025.php new file mode 100644 index 000000000000..0531b84be47c --- /dev/null +++ b/user_guide_src/source/libraries/validation/025.php @@ -0,0 +1,3 @@ + 'Supplied value ({value}) for {field} must have at least {param} characters.' diff --git a/user_guide_src/source/libraries/validation/026.php b/user_guide_src/source/libraries/validation/026.php new file mode 100644 index 000000000000..50bd0147aaf2 --- /dev/null +++ b/user_guide_src/source/libraries/validation/026.php @@ -0,0 +1,19 @@ +setRules([ + 'username' => [ + 'label' => 'Rules.username', + 'rules' => 'required|is_unique[users.username]', + 'errors' => [ + 'required' => 'Rules.username.required', + ], + ], + 'password' => [ + 'label' => 'Rules.password', + 'rules' => 'required|min_length[10]', + 'errors' => [ + 'min_length' => 'Rules.password.min_length', + ], + ], + ] +); diff --git a/user_guide_src/source/libraries/validation/027.php b/user_guide_src/source/libraries/validation/027.php new file mode 100644 index 000000000000..57aa5a31cb84 --- /dev/null +++ b/user_guide_src/source/libraries/validation/027.php @@ -0,0 +1,9 @@ +getErrors(); + +// Returns: +[ + 'field1' => 'error message', + 'field2' => 'error message', +] diff --git a/user_guide_src/source/libraries/validation/028.php b/user_guide_src/source/libraries/validation/028.php new file mode 100644 index 000000000000..2a3cffba88fc --- /dev/null +++ b/user_guide_src/source/libraries/validation/028.php @@ -0,0 +1,3 @@ +getError('username'); diff --git a/user_guide_src/source/libraries/validation/029-2.php b/user_guide_src/source/libraries/validation/029-2.php new file mode 100644 index 000000000000..f7c69eb42e99 --- /dev/null +++ b/user_guide_src/source/libraries/validation/029-2.php @@ -0,0 +1,7 @@ + diff --git a/user_guide_src/source/libraries/validation/029.php b/user_guide_src/source/libraries/validation/029.php new file mode 100644 index 000000000000..2334c3c00f50 --- /dev/null +++ b/user_guide_src/source/libraries/validation/029.php @@ -0,0 +1,5 @@ +hasError('username')) { + echo $validation->getError('username'); +} diff --git a/user_guide_src/source/libraries/validation/030.php b/user_guide_src/source/libraries/validation/030.php new file mode 100644 index 000000000000..0da86ca2d054 --- /dev/null +++ b/user_guide_src/source/libraries/validation/030.php @@ -0,0 +1,6 @@ + 'The username field must be unique.', + 'email' => 'You must provide a valid email address.' +]; diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php new file mode 100644 index 000000000000..110b159a41cc --- /dev/null +++ b/user_guide_src/source/libraries/validation/031.php @@ -0,0 +1,7 @@ + 'CodeIgniter\Validation\Views\list', + 'single' => 'CodeIgniter\Validation\Views\single', + 'my_list' => '_errors_list', +]; diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php new file mode 100644 index 000000000000..ccee27b08ad7 --- /dev/null +++ b/user_guide_src/source/libraries/validation/032.php @@ -0,0 +1,13 @@ +validate($request, [ + 'foo' => 'required|even', +]); diff --git a/user_guide_src/source/libraries/validation/036.php b/user_guide_src/source/libraries/validation/036.php new file mode 100644 index 000000000000..9511380c04f5 --- /dev/null +++ b/user_guide_src/source/libraries/validation/036.php @@ -0,0 +1,34 @@ +required($str ?? ''); + + if ($present) { + return true; + } + + // Still here? Then we fail this test if + // any of the fields are present in $data + // as $fields is the lis + $requiredFields = []; + + foreach ($fields as $field) { + if (array_key_exists($field, $data)) { + $requiredFields[] = $field; + } + } + + // Remove any keys with empty values since, that means they + // weren't truly there, as far as this is concerned. + $requiredFields = array_filter($requiredFields, function ($item) use ($data) { + return ! empty($data[$item]); + }); + + return empty($requiredFields); +} diff --git a/user_guide_src/source/libraries/validation/037.php b/user_guide_src/source/libraries/validation/037.php new file mode 100644 index 000000000000..089b0eeaf465 --- /dev/null +++ b/user_guide_src/source/libraries/validation/037.php @@ -0,0 +1,10 @@ +setRules([ + 'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok + 'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok + 'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok + 'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders" +]); diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index dda716209451..3a9d9b705bc2 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -38,41 +38,16 @@ Now create a new Entity class. Since there's no default location to store these in with the existing directory structure, create a new directory at **app/Entities**. Create the Entity itself at **app/Entities/User.php**. -:: - - find($id); - - // Display - echo $user->username; - echo $user->email; +Now that all of the pieces are in place, you would work with the Entity class as you would any other class: - // Updating - unset($user->username); - - if (! isset($user->username) { - $user->username = 'something new'; - } - - $userModel->save($user); - - // Create - $user = new \App\Entities\User(); - $user->username = 'foo'; - $user->email = 'foo@example.com'; - $userModel->save($user); +.. literalinclude:: entities/003.php + :lines: 2- You may have noticed that the ``User`` class has not set any properties for the columns, but you can still access them as if they were public properties. The base class, ``CodeIgniter\Entity\Entity``, takes care of this for you, as @@ -128,22 +85,13 @@ and populate the class properties. Any property in the array will be set on the the model, only the fields in ``$allowedFields`` will actually be saved to the database, so you can store additional data on your entities without worrying much about stray fields getting saved incorrectly. -:: - - $data = $this->request->getPost(); - - $user = new \App\Entities\User(); - $user->fill($data); - $userModel->save($user); +.. literalinclude:: entities/004.php + :lines: 2- You can also pass the data in the constructor and the data will be passed through the ``fill()`` method during instantiation. -:: - - $data = $this->request->getPost(); - - $user = new \App\Entities\User($data); - $userModel->save($user); +.. literalinclude:: entities/005.php + :lines: 2- Bulk Accessing Properties ------------------------- @@ -160,43 +108,9 @@ While the examples above are convenient, they don't help enforce any business lo some smart ``__get()`` and ``__set()`` methods that will check for special methods and use those instead of using the attributes directly, allowing you to enforce any business logic or data conversion that you need. -Here's an updated User entity to provide some examples of how this could be used:: - - attributes['password'] = password_hash($pass, PASSWORD_BCRYPT); - - return $this; - } - - public function setCreatedAt(string $dateString) - { - $this->attributes['created_at'] = new Time($dateString, 'UTC'); - - return $this; - } - - public function getCreatedAt(string $format = 'Y-m-d H:i:s') - { - // Convert to CodeIgniter\I18n\Time object - $this->attributes['created_at'] = $this->mutateDate($this->attributes['created_at']); - - $timezone = $this->timezone ?? app_timezone(); - - $this->attributes['created_at']->setTimezone($timezone); - - return $this->attributes['created_at']->format($format); - } - } +.. literalinclude:: entities/006.php The first thing to notice is the name of the methods we've added. For each one, the class expects the snake_case column name to be converted into PascalCase, and prefixed with either ``set`` or ``get``. These methods will then @@ -216,11 +130,8 @@ a formatted string in the application's current timezone. While fairly simple, these examples show that using Entity classes can provide a very flexible way to enforce business logic and create objects that are pleasant to use. -:: - - // Auto-hash the password - both do the same thing - $user->password = 'my great password'; - $user->setPassword('my great password'); +.. literalinclude:: entities/007.php + :lines: 2- Data Mapping ============ @@ -230,25 +141,9 @@ original column names in the database no longer make sense. Or you find that you class properties, but your database schema required snake_case names. These situations can be easily handled with the Entity class' data mapping features. -As an example, imagine you have the simplified User Entity that is used throughout your application:: - - null, - 'name' => null, // Represents a username - 'email' => null, - 'password' => null, - 'created_at' => null, - 'updated_at' => null, - ]; - } +.. literalinclude:: entities/008.php Your boss comes to you and says that no one uses usernames anymore, so you're switching to just use emails for login. But they do want to personalize the application a bit, so they want you to change the name field to represent a user's @@ -257,29 +152,9 @@ in the database you whip up a migration to rename the `name` field to `full_name Ignoring how contrived this example is, we now have two choices on how to fix the User class. We could modify the class property from ``$name`` to ``$full_name``, but that would require changes throughout the application. Instead, we can -simply map the ``full_name`` column in the database to the ``$name`` property, and be done with the Entity changes:: - - null, - 'full_name' => null, // In the $attributes, the key is the column name - 'email' => null, - 'password' => null, - 'created_at' => null, - 'updated_at' => null, - ]; +simply map the ``full_name`` column in the database to the ``$name`` property, and be done with the Entity changes: - protected $datamap = [ - 'name' => 'full_name', - ]; - } +.. literalinclude:: entities/009.php By adding our new database name to the ``$datamap`` array, we can tell the class what class property the database column should be accessible through. The key of the array is class property to map it to, where the value in the array is the @@ -301,30 +176,15 @@ By default, the Entity class will convert fields named `created_at`, `updated_at :doc:`Time ` instances whenever they are set or retrieved. The Time class provides a large number of helpful methods in an immutable, localized way. -You can define which properties are automatically converted by adding the name to the ``$dates`` property:: +You can define which properties are automatically converted by adding the name to the ``$dates`` property: - created_at = 'April 15, 2017 10:30:00'; +current timezone, as set in **app/Config/App.php**: - // Can now use any Time methods: - echo $user->created_at->humanize(); - echo $user->created_at->setTimezone('Europe/London')->toDateString(); +.. literalinclude:: entities/011.php + :lines: 2- Property Casting ---------------- @@ -336,21 +196,9 @@ either the entity or the database. Properties can be cast to any of the followin **integer**, **float**, **double**, **string**, **boolean**, **object**, **array**, **datetime**, **timestamp**, and **uri**. Add a question mark at the beginning of type to mark property as nullable, i.e., **?string**, **?integer**. -For example, if you had a User entity with an ``is_banned`` property, you can cast it as a boolean:: +For example, if you had a User entity with an ``is_banned`` property, you can cast it as a boolean: - 'boolean', - 'is_banned_nullable' => '?boolean', - ]; - } +.. literalinclude:: entities/012.php Array/Json Casting ------------------ @@ -367,32 +215,12 @@ Unlike the rest of the data types that you can cast properties into, the: * **array** cast type will serialize, * **json** and **json-array** cast will use json_encode function on -the value whenever the property is set:: - - 'array', - 'options_object' => 'json', - 'options_array' => 'json-array', - ]; - } - -:: - - $user = $userModel->find(15); - $options = $user->options; - - $options['foo'] = 'bar'; - - $user->options = $options; - $userModel->save($user); +.. literalinclude:: entities/014.php + :lines: 2- CSV Casting ----------- @@ -400,24 +228,14 @@ CSV Casting If you know you have a flat array of simple values, encoding them as a serialized or JSON string may be more complex than the original structure. Casting as Comma-Separated Values (CSV) is a simpler alternative will result in a string that uses less space and is more easily read -by humans:: - - 'csv', - ]; - } +.. literalinclude:: entities/015.php -Stored in the database as "red,yellow,green":: +Stored in the database as "red,yellow,green": - $widget->colors = ['red', 'yellow', 'green']; +.. literalinclude:: entities/016.php + :lines: 2- .. note:: Casting as CSV uses PHP's internal ``implode`` and ``explode`` methods and assumes all values are string-safe and free of commas. For more complex data casts try ``array`` or ``json``. @@ -427,67 +245,18 @@ Custom casting You can define your own conversion types for getting and setting data. At first you need to create a handler class for your type. -Let's say the class will be located in the **app/Entities/Cast** directory:: +Let's say the class will be located in the **app/Entities/Cast** directory: - 'base64', - ]; - - // Bind the type to the handler - protected $castHandlers = [ - 'base64' => \App\Entities\Cast\CastBase64::class, - ]; - } - - // ... - - $entity->key = 'test'; // dGVzdA== - echo $entity->key; // test - - -If you don't need to change values when getting or setting a value. Then just don't implement the appropriate method:: - - use CodeIgniter\Entity\Cast\BaseCast; - - class CastBase64 extends BaseCast - { - public static function get($value, array $params = []) - { - return base64_decode($value); - } - } +If you don't need to change values when getting or setting a value. Then just don't implement the appropriate method: +.. literalinclude:: entities/019.php + :lines: 2- **Parameters** @@ -496,55 +265,26 @@ Additional parameters are indicated in square brackets and listed with a comma. **type[param1, param2]** -:: - - // Defining a type with parameters - protected $casts = [ - 'some_attribute' => 'class[App\SomeClass, param2, param3]', - ]; - - // Bind the type to the handler - protected $castHandlers = [ - 'class' => 'SomeHandler', - ]; - -:: - - use CodeIgniter\Entity\Cast\BaseCast; - - class SomeHandler extends BaseCast - { - public static function get($value, array $params = []) - { - var_dump($params); - // array(3) { - // [0]=> - // string(13) "App\SomeClass" - // [1]=> - // string(6) "param2" - // [2]=> - // string(6) "param3" - // } - } - } +.. literalinclude:: entities/020.php + :lines: 2- + +.. literalinclude:: entities/021.php + :lines: 2- .. note:: If the casting type is marked as nullable ``?bool`` and the passed value is not null, then the parameter with the value ``nullable`` will be passed to the casting type handler. If casting type has predefined parameters, then ``nullable`` will be added to the end of the list. - Checking for Changed Attributes =============================== You can check if an Entity attribute has changed since it was created. The only parameter is the name of the -attribute to check:: - - $user = new \App\Entities\User(); - $user->hasChanged('name'); // false +attribute to check: - $user->name = 'Fred'; - $user->hasChanged('name'); // true +.. literalinclude:: entities/022.php + :lines: 2- -Or to check the whole entity for changed values omit the parameter:: +Or to check the whole entity for changed values omit the parameter: - $user->hasChanged(); // true +.. literalinclude:: entities/023.php + :lines: 2- diff --git a/user_guide_src/source/models/entities/001.php b/user_guide_src/source/models/entities/001.php new file mode 100644 index 000000000000..2da022b25edd --- /dev/null +++ b/user_guide_src/source/models/entities/001.php @@ -0,0 +1,10 @@ +find($id); + +// Display +echo $user->username; +echo $user->email; + +// Updating +unset($user->username); + +if (! isset($user->username) { + $user->username = 'something new'; +} + +$userModel->save($user); + +// Create +$user = new \App\Entities\User(); +$user->username = 'foo'; +$user->email = 'foo@example.com'; +$userModel->save($user); diff --git a/user_guide_src/source/models/entities/004.php b/user_guide_src/source/models/entities/004.php new file mode 100644 index 000000000000..e5307d38b1a2 --- /dev/null +++ b/user_guide_src/source/models/entities/004.php @@ -0,0 +1,7 @@ +request->getPost(); + +$user = new \App\Entities\User(); +$user->fill($data); +$userModel->save($user); diff --git a/user_guide_src/source/models/entities/005.php b/user_guide_src/source/models/entities/005.php new file mode 100644 index 000000000000..5dd5d47af1f5 --- /dev/null +++ b/user_guide_src/source/models/entities/005.php @@ -0,0 +1,6 @@ +request->getPost(); + +$user = new \App\Entities\User($data); +$userModel->save($user); diff --git a/user_guide_src/source/models/entities/006.php b/user_guide_src/source/models/entities/006.php new file mode 100644 index 000000000000..0a271a37a73d --- /dev/null +++ b/user_guide_src/source/models/entities/006.php @@ -0,0 +1,35 @@ +attributes['password'] = password_hash($pass, PASSWORD_BCRYPT); + + return $this; + } + + public function setCreatedAt(string $dateString) + { + $this->attributes['created_at'] = new Time($dateString, 'UTC'); + + return $this; + } + + public function getCreatedAt(string $format = 'Y-m-d H:i:s') + { + // Convert to CodeIgniter\I18n\Time object + $this->attributes['created_at'] = $this->mutateDate($this->attributes['created_at']); + + $timezone = $this->timezone ?? app_timezone(); + + $this->attributes['created_at']->setTimezone($timezone); + + return $this->attributes['created_at']->format($format); + } +} diff --git a/user_guide_src/source/models/entities/007.php b/user_guide_src/source/models/entities/007.php new file mode 100644 index 000000000000..36a39a017e43 --- /dev/null +++ b/user_guide_src/source/models/entities/007.php @@ -0,0 +1,5 @@ +password = 'my great password'; +$user->setPassword('my great password'); diff --git a/user_guide_src/source/models/entities/008.php b/user_guide_src/source/models/entities/008.php new file mode 100644 index 000000000000..f0612ce0e4b9 --- /dev/null +++ b/user_guide_src/source/models/entities/008.php @@ -0,0 +1,17 @@ + null, + 'name' => null, // Represents a username + 'email' => null, + 'password' => null, + 'created_at' => null, + 'updated_at' => null, + ]; +} diff --git a/user_guide_src/source/models/entities/009.php b/user_guide_src/source/models/entities/009.php new file mode 100644 index 000000000000..411961833749 --- /dev/null +++ b/user_guide_src/source/models/entities/009.php @@ -0,0 +1,21 @@ + null, + 'full_name' => null, // In the $attributes, the key is the column name + 'email' => null, + 'password' => null, + 'created_at' => null, + 'updated_at' => null, + ]; + + protected $datamap = [ + 'name' => 'full_name', + ]; +} diff --git a/user_guide_src/source/models/entities/010.php b/user_guide_src/source/models/entities/010.php new file mode 100644 index 000000000000..e8636fa0fbcc --- /dev/null +++ b/user_guide_src/source/models/entities/010.php @@ -0,0 +1,10 @@ +created_at = 'April 15, 2017 10:30:00'; + +// Can now use any Time methods: +echo $user->created_at->humanize(); +echo $user->created_at->setTimezone('Europe/London')->toDateString(); diff --git a/user_guide_src/source/models/entities/012.php b/user_guide_src/source/models/entities/012.php new file mode 100644 index 000000000000..0c14d2f822c6 --- /dev/null +++ b/user_guide_src/source/models/entities/012.php @@ -0,0 +1,13 @@ + 'boolean', + 'is_banned_nullable' => '?boolean', + ]; +} diff --git a/user_guide_src/source/models/entities/013.php b/user_guide_src/source/models/entities/013.php new file mode 100644 index 000000000000..460f42435304 --- /dev/null +++ b/user_guide_src/source/models/entities/013.php @@ -0,0 +1,14 @@ + 'array', + 'options_object' => 'json', + 'options_array' => 'json-array', + ]; +} diff --git a/user_guide_src/source/models/entities/014.php b/user_guide_src/source/models/entities/014.php new file mode 100644 index 000000000000..0a6523818e5c --- /dev/null +++ b/user_guide_src/source/models/entities/014.php @@ -0,0 +1,9 @@ +find(15); +$options = $user->options; + +$options['foo'] = 'bar'; + +$user->options = $options; +$userModel->save($user); diff --git a/user_guide_src/source/models/entities/015.php b/user_guide_src/source/models/entities/015.php new file mode 100644 index 000000000000..079797096bec --- /dev/null +++ b/user_guide_src/source/models/entities/015.php @@ -0,0 +1,12 @@ + 'csv', + ]; +} diff --git a/user_guide_src/source/models/entities/016.php b/user_guide_src/source/models/entities/016.php new file mode 100644 index 000000000000..739ab9f3237a --- /dev/null +++ b/user_guide_src/source/models/entities/016.php @@ -0,0 +1,3 @@ +colors = ['red', 'yellow', 'green']; diff --git a/user_guide_src/source/models/entities/017.php b/user_guide_src/source/models/entities/017.php new file mode 100644 index 000000000000..422a28cd1c37 --- /dev/null +++ b/user_guide_src/source/models/entities/017.php @@ -0,0 +1,19 @@ + 'base64', + ]; + + // Bind the type to the handler + protected $castHandlers = [ + 'base64' => \App\Entities\Cast\CastBase64::class, + ]; +} + +// ... + +$entity->key = 'test'; // dGVzdA== +echo $entity->key; // test diff --git a/user_guide_src/source/models/entities/019.php b/user_guide_src/source/models/entities/019.php new file mode 100644 index 000000000000..7d3744cc037c --- /dev/null +++ b/user_guide_src/source/models/entities/019.php @@ -0,0 +1,11 @@ + 'class[App\SomeClass, param2, param3]', +]; + +// Bind the type to the handler +protected $castHandlers = [ + 'class' => 'SomeHandler', +]; diff --git a/user_guide_src/source/models/entities/021.php b/user_guide_src/source/models/entities/021.php new file mode 100644 index 000000000000..12a805850827 --- /dev/null +++ b/user_guide_src/source/models/entities/021.php @@ -0,0 +1,19 @@ + + // string(13) "App\SomeClass" + // [1]=> + // string(6) "param2" + // [2]=> + // string(6) "param3" + // } + } +} diff --git a/user_guide_src/source/models/entities/022.php b/user_guide_src/source/models/entities/022.php new file mode 100644 index 000000000000..07dc560038a3 --- /dev/null +++ b/user_guide_src/source/models/entities/022.php @@ -0,0 +1,7 @@ +hasChanged('name'); // false + +$user->name = 'Fred'; +$user->hasChanged('name'); // true diff --git a/user_guide_src/source/models/entities/023.php b/user_guide_src/source/models/entities/023.php new file mode 100644 index 000000000000..1e336bcf9d3c --- /dev/null +++ b/user_guide_src/source/models/entities/023.php @@ -0,0 +1,3 @@ +hasChanged(); // true diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 707491b2cb37..abf096b90857 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -24,23 +24,8 @@ location within the directory, like ``namespace App\Models``. You can access models within your classes by creating a new instance or using the ``model()`` helper function. -:: - - // Create a new class manually - $userModel = new \App\Models\UserModel(); - - // Create a new class with the model function - $userModel = model('App\Models\UserModel', false); - - // Create a shared instance of the model - $userModel = model('App\Models\UserModel'); - - // Create shared instance with a supplied database connection - // When no namespace is given, it will search through all namespaces - // the system knows about and attempt to located the UserModel class. - $db = db_connect('custom'); - $userModel = model('UserModel', true, $db); - +.. literalinclude:: model/001.php + :lines: 2- CodeIgniter's Model =================== @@ -60,43 +45,18 @@ Creating Your Model =================== To take advantage of CodeIgniter's model, you would simply create a new model class -that extends ``CodeIgniter\Model``:: - - allowedFields[] = 'middlename'; - } - } +.. literalinclude:: model/003.php Connecting to the Database -------------------------- @@ -106,18 +66,8 @@ it will automatically connect to the default database group, as set in the confi modify which group is used on a per-model basis by adding the ``$DBGroup`` property to your class. This ensures that within the model any references to ``$this->db`` are made through the appropriate connection. -:: - - find($user_id); +.. literalinclude:: model/006.php + :lines: 2- The value is returned in the format specified in ``$returnType``. You can specify more than one row to return by passing an array of primaryKey values instead -of just one:: +of just one: - $users = $userModel->find([1,2,3]); +.. literalinclude:: model/007.php + :lines: 2- If no parameters are passed in, will return all rows in that model's table, effectively acting like ``findAll()``, though less explicit. **findColumn()** -Returns null or an indexed array of column values:: +Returns null or an indexed array of column values: - $user = $userModel->findColumn($column_name); +.. literalinclude:: model/008.php + :lines: 2- ``$column_name`` should be a name of single column else you will get the DataException. **findAll()** -Returns all results:: +Returns all results: - $users = $userModel->findAll(); +.. literalinclude:: model/009.php + :lines: 2- -This query may be modified by interjecting Query Builder commands as needed prior to calling this method:: +This query may be modified by interjecting Query Builder commands as needed prior to calling this method: - $users = $userModel->where('active', 1) - ->findAll(); +.. literalinclude:: model/010.php + :lines: 2- You can pass in a limit and offset values as the first and second -parameters, respectively:: +parameters, respectively: - $users = $userModel->findAll($limit, $offset); +.. literalinclude:: model/011.php + :lines: 2- **first()** Returns the first row in the result set. This is best used in combination with the query builder. -:: - $user = $userModel->where('deleted', 0) - ->first(); +.. literalinclude:: model/012.php + :lines: 2- **withDeleted()** If ``$useSoftDeletes`` is true, then the **find*()** methods will not return any rows where 'deleted_at IS NOT NULL'. To temporarily override this, you can use the ``withDeleted()`` method prior to calling the **find*()** method. -:: - - // Only gets non-deleted rows (deleted = 0) - $activeUsers = $userModel->findAll(); - // Gets all rows - $allUsers = $userModel->withDeleted()->findAll(); +.. literalinclude:: model/013.php + :lines: 2- **onlyDeleted()** Whereas ``withDeleted()`` will return both deleted and not-deleted rows, this method modifies -the next **find*()** methods to return only soft deleted rows:: +the next **find*()** methods to return only soft deleted rows: - $deletedUsers = $userModel->onlyDeleted()->findAll(); +.. literalinclude:: model/014.php + :lines: 2- Saving Data ----------- @@ -348,67 +273,38 @@ Saving Data An associative array of data is passed into this method as the only parameter to create a new row of data in the database. The array's keys must match the name of the columns in a ``$table``, while -the array's values are the values to save for that key:: - - $data = [ - 'username' => 'darth', - 'email' => 'd.vader@theempire.com', - ]; +the array's values are the values to save for that key: - $userModel->insert($data); +.. literalinclude:: model/015.php + :lines: 2- **update()** Updates an existing record in the database. The first parameter is the ``$primaryKey`` of the record to update. An associative array of data is passed into this method as the second parameter. The array's keys must match the name -of the columns in a ``$table``, while the array's values are the values to save for that key:: +of the columns in a ``$table``, while the array's values are the values to save for that key: - $data = [ - 'username' => 'darth', - 'email' => 'd.vader@theempire.com', - ]; +.. literalinclude:: model/016.php + :lines: 2- - $userModel->update($id, $data); +Multiple records may be updated with a single call by passing an array of primary keys as the first parameter: -Multiple records may be updated with a single call by passing an array of primary keys as the first parameter:: - - $data = [ - 'active' => 1, - ]; - - $userModel->update([1, 2, 3], $data); +.. literalinclude:: model/017.php + :lines: 2- When you need a more flexible solution, you can leave the parameters empty and it functions like the Query Builder's -update command, with the added benefit of validation, events, etc:: +update command, with the added benefit of validation, events, etc: - $userModel - ->whereIn('id', [1,2,3]) - ->set(['active' => 1]) - ->update(); +.. literalinclude:: model/018.php + :lines: 2- **save()** This is a wrapper around the ``insert()`` and ``update()`` methods that handle inserting or updating the record -automatically, based on whether it finds an array key matching the **primary key** value:: - - // Defined as a model property - $primaryKey = 'id'; +automatically, based on whether it finds an array key matching the **primary key** value: - // Does an insert() - $data = [ - 'username' => 'darth', - 'email' => 'd.vader@theempire.com', - ]; - - $userModel->save($data); - - // Performs an update, since the primary key, 'id', is found. - $data = [ - 'id' => 3, - 'username' => 'darth', - 'email' => 'd.vader@theempire.com', - ]; - $userModel->save($data); +.. literalinclude:: model/019.php + :lines: 2- The save method also can make working with custom class result objects much simpler by recognizing a non-simple object and grabbing its public and protected values into an array, which is then passed to the appropriate @@ -416,56 +312,22 @@ insert or update method. This allows you to work with Entity classes in a very c simple classes that represent a single instance of an object type, like a user, a blog post, job, etc. This class is responsible for maintaining the business logic surrounding the object itself, like formatting elements in a certain way, etc. They shouldn't have any idea about how they are saved to the database. At their -simplest, they might look like this:: - - namespace App\Entities; - - class Job - { - protected $id; - protected $name; - protected $description; - - public function __get($key) - { - if (property_exists($this, $key)) { - return $this->$key; - } - } - - public function __set($key, $value) - { - if (property_exists($this, $key)) { - $this->$key = $value; - } - } - } - -A very simple model to work with this might look like:: - - use CodeIgniter\Model; - - class JobModel extends Model - { - protected $table = 'jobs'; - protected $returnType = '\App\Entities\Job'; - protected $allowedFields = [ - 'name', 'description' - ]; - } +simplest, they might look like this: -This model works with data from the ``jobs`` table, and returns all results as an instance of ``App\Entities\Job``. -When you need to persist that record to the database, you will need to either write custom methods, or use the -model's ``save()`` method to inspect the class, grab any public and private properties, and save them to the database:: +.. literalinclude:: model/020.php + :lines: 2- + +A very simple model to work with this might look like: - // Retrieve a Job instance - $job = $model->find(15); +.. literalinclude:: model/021.php + :lines: 2- - // Make some changes - $job->name = "Foobar"; +This model works with data from the ``jobs`` table, and returns all results as an instance of ``App\Entities\Job``. +When you need to persist that record to the database, you will need to either write custom methods, or use the +model's ``save()`` method to inspect the class, grab any public and private properties, and save them to the database: - // Save the changes - $model->save($job); +.. literalinclude:: model/022.php + :lines: 2- .. note:: If you find yourself working with Entities a lot, CodeIgniter provides a built-in :doc:`Entity class ` that provides several handy features that make developing Entities simpler. @@ -475,27 +337,31 @@ Deleting Data **delete()** -Takes a primary key value as the first parameter and deletes the matching record from the model's table:: +Takes a primary key value as the first parameter and deletes the matching record from the model's table: - $userModel->delete(12); +.. literalinclude:: model/023.php + :lines: 2- If the model's ``$useSoftDeletes`` value is true, this will update the row to set ``deleted_at`` to the current date and time. You can force a permanent delete by setting the second parameter as true. -An array of primary keys can be passed in as the first parameter to delete multiple records at once:: +An array of primary keys can be passed in as the first parameter to delete multiple records at once: - $userModel->delete([1,2,3]); +.. literalinclude:: model/024.php + :lines: 2- If no parameters are passed in, will act like the Query Builder's delete method, requiring a where call -previously:: +previously: - $userModel->where('id', 12)->delete(); +.. literalinclude:: model/025.php + :lines: 2- **purgeDeleted()** -Cleans out the database table by permanently removing all rows that have 'deleted_at IS NOT NULL'. :: +Cleans out the database table by permanently removing all rows that have 'deleted_at IS NOT NULL'. - $userModel->purgeDeleted(); +.. literalinclude:: model/026.php + :lines: 2- Validating Data --------------- @@ -505,23 +371,10 @@ standard, without duplicating code. The Model class provides a way to automatica prior to saving to the database with the ``insert()``, ``update()``, or ``save()`` methods. The first step is to fill out the ``$validationRules`` class property with the fields and rules that should -be applied. If you have custom error message that you want to use, place them in the ``$validationMessages`` array:: - - class UserModel extends Model - { - protected $validationRules = [ - 'username' => 'required|alpha_numeric_space|min_length[3]', - 'email' => 'required|valid_email|is_unique[users.email]', - 'password' => 'required|min_length[8]', - 'pass_confirm' => 'required_with[password]|matches[password]', - ]; - - protected $validationMessages = [ - 'email' => [ - 'is_unique' => 'Sorry. That email has already been taken. Please choose another.', - ], - ]; - } +be applied. If you have custom error message that you want to use, place them in the ``$validationMessages`` array: + +.. literalinclude:: model/027.php + :lines: 2- The other way to set the validation rules to fields by functions, @@ -532,12 +385,10 @@ The other way to set the validation rules to fields by functions, This function will set the field validation rules. - Usage example:: - - $fieldName = 'username'; - $fieldRules = 'required|alpha_numeric_space|min_length[3]'; + Usage example: - $model->setValidationRule($fieldName, $fieldRules); + .. literalinclude:: model/028.php + :lines: 2- .. php:function:: setValidationRules($validationRules) @@ -545,18 +396,10 @@ The other way to set the validation rules to fields by functions, This function will set the validation rules. - Usage example:: + Usage example: - $validationRules = [ - 'username' => 'required|alpha_numeric_space|min_length[3]', - 'email' => [ - 'rules' => 'required|valid_email|is_unique[users.email]', - 'errors' => [ - 'required' => 'We really need your email.', - ], - ], - ]; - $model->setValidationRules($validationRules); + .. literalinclude:: model/029.php + :lines: 2- The other way to set the validation message to fields by functions, @@ -567,13 +410,10 @@ The other way to set the validation message to fields by functions, This function will set the field wise error messages. - Usage example:: + Usage example: - $fieldName = 'name'; - $fieldValidationMessage = [ - 'required' => 'Your name is required here', - ]; - $model->setValidationMessage($fieldName, $fieldValidationMessage); + .. literalinclude:: model/030.php + :lines: 2- .. php:function:: setValidationMessages($fieldMessages) @@ -581,63 +421,49 @@ The other way to set the validation message to fields by functions, This function will set the field messages. - Usage example:: + Usage example: - $fieldValidationMessage = [ - 'name' => [ - 'required' => 'Your baby name is missing.', - 'min_length' => 'Too short, man!', - ], - ]; - $model->setValidationMessages($fieldValidationMessage); + .. literalinclude:: model/031.php + :lines: 2- Now, whenever you call the ``insert()``, ``update()``, or ``save()`` methods, the data will be validated. If it fails, -the model will return boolean **false**. You can use the ``errors()`` method to retrieve the validation errors:: +the model will return boolean **false**. You can use the ``errors()`` method to retrieve the validation errors: - if ($model->save($data) === false) { - return view('updateUser', ['errors' => $model->errors()]); - } +.. literalinclude:: model/032.php + :lines: 2- This returns an array with the field names and their associated errors that can be used to either show all of the -errors at the top of the form, or to display them individually:: +errors at the top of the form, or to display them individually: - -
    - $error): ?> -

    - -
    - +.. literalinclude:: model/033.php If you'd rather organize your rules and error messages within the Validation configuration file, you can do that -and simply set ``$validationRules`` to the name of the validation rule group you created:: +and simply set ``$validationRules`` to the name of the validation rule group you created: - class UserModel extends Model - { - protected $validationRules = 'users'; - } +.. literalinclude:: model/034.php + :lines: 2- Retrieving Validation Rules --------------------------- You can retrieve a model's validation rules by accessing its ``validationRules`` -property:: +property: - $rules = $model->validationRules; +.. literalinclude:: model/035.php + :lines: 2- You can also retrieve just a subset of those rules by calling the accessor -method directly, with options:: +method directly, with options: - $rules = $model->getValidationRules($options); +.. literalinclude:: model/036.php + :lines: 2- The ``$options`` parameter is an associative array with one element, whose key is either ``'except'`` or ``'only'``, and which has as its -value an array of fieldnames of interest.:: +value an array of fieldnames of interest.: - // get the rules for all but the "username" field - $rules = $model->getValidationRules(['except' => ['username']]); - // get the rules for only the "city" and "state" fields - $rules = $model->getValidationRules(['only' => ['city', 'state']]); +.. literalinclude:: model/037.php + :lines: 2- Validation Placeholders ----------------------- @@ -645,25 +471,21 @@ Validation Placeholders The model provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply the name of the field (or array key) that was passed in as ``$data`` surrounded by curly brackets. It will be -replaced by the **value** of the matched incoming field. An example should clarify this:: +replaced by the **value** of the matched incoming field. An example should clarify this: - protected $validationRules = [ - 'email' => 'required|valid_email|is_unique[users.email,id,{id}]' - ]; +.. literalinclude:: model/038.php + :lines: 2- In this set of rules, it states that the email address should be unique in the database, except for the row -that has an id matching the placeholder's value. Assuming that the form POST data had the following:: +that has an id matching the placeholder's value. Assuming that the form POST data had the following: - $_POST = [ - 'id' => 4, - 'email' => 'foo@example.com' - ]; +.. literalinclude:: model/039.php + :lines: 2- -then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule:: +then the ``{id}`` placeholder would be replaced with the number **4**, giving this revised rule: - protected $validationRules = [ - 'email' => 'required|valid_email|is_unique[users.email,id,4]' - ]; +.. literalinclude:: model/040.php + :lines: 2- So it will ignore the row in the database that has ``id=4`` when it verifies the email is unique. @@ -677,45 +499,46 @@ To help protect against Mass Assignment Attacks, the Model class **requires** th that can be changed during inserts and updates in the ``$allowedFields`` class property. Any data provided in addition to these will be removed prior to hitting the database. This is great for ensuring that timestamps, or primary keys do not get changed. -:: - protected $allowedFields = ['name', 'email', 'address']; +.. literalinclude:: model/041.php + :lines: 2- Occasionally, you will find times where you need to be able to change these elements. This is often during -testing, migrations, or seeds. In these cases, you can turn the protection on or off:: +testing, migrations, or seeds. In these cases, you can turn the protection on or off: - $model->protect(false) - ->insert($data) - ->protect(true); +.. literalinclude:: model/042.php + :lines: 2- Working With Query Builder -------------------------- You can get access to a shared instance of the Query Builder for that model's database connection any time you -need it:: +need it: - $builder = $userModel->builder(); +.. literalinclude:: model/043.php + :lines: 2- This builder is already set up with the model's ``$table``. If you need access to another table -you can pass it in as a parameter, but be aware that this will not return a shared instance:: +you can pass it in as a parameter, but be aware that this will not return a shared instance: - $groupBuilder = $userModel->builder('groups'); +.. literalinclude:: model/044.php + :lines: 2- You can also use Query Builder methods and the Model's CRUD methods in the same chained call, allowing for -very elegant use:: +very elegant use: - $users = $userModel->where('status', 'active') - ->orderBy('last_login', 'asc') - ->findAll(); +.. literalinclude:: model/045.php + :lines: 2- .. important:: The Model does not provide a perfect interface to the Query Builder. The Model and the Query Builder are separate classes with different purposes. They should not be expected to return the same data. For example, if you need to get the compiledInsert you should do so directly on the builder instance. -.. note:: You can also access the model's database connection seamlessly:: +.. note:: You can also access the model's database connection seamlessly: - $user_name = $userModel->escape($name); + .. literalinclude:: model/046.php + :lines: 2- Runtime Return Type Changes ---------------------------- @@ -729,19 +552,17 @@ provides methods that allow you to do just that. **asArray()** -Returns data from the next **find*()** method as associative arrays:: +Returns data from the next **find*()** method as associative arrays: - $users = $userModel->asArray()->where('status', 'active')->findAll(); +.. literalinclude:: model/047.php + :lines: 2- **asObject()** -Returns data from the next **find*()** method as standard objects or custom class intances:: +Returns data from the next **find*()** method as standard objects or custom class intances: - // Return as standard objects - $users = $userModel->asObject()->where('status', 'active')->findAll(); - - // Return as custom class instances - $users = $userModel->asObject('User')->where('status', 'active')->findAll(); +.. literalinclude:: model/048.php + :lines: 2- Processing Large Amounts of Data -------------------------------- @@ -752,12 +573,9 @@ do your work on. The first parameter is the number of rows to retrieve in a sing parameter is a Closure that will be called for each row of data. This is best used during cronjobs, data exports, or other large tasks. -:: - $userModel->chunk(100, function ($data) { - // do something. - // $data is a single row of data. - }); +.. literalinclude:: model/049.php + :lines: 2- Model Events ============ @@ -777,38 +595,28 @@ of the insert* or update* methods, that will be the key/value pairs that are bei main array will also contain the other values passed to the method, and be detailed later. The callback method must return the original $data array so other callbacks have the full information. -:: - - protected function hashPassword(array $data) - { - if (! isset($data['data']['password'])) { - return $data; - } - - $data['data']['password_hash'] = password_hash($data['data']['password'], PASSWORD_DEFAULT); - unset($data['data']['password']); - - return $data; - } +.. literalinclude:: model/050.php + :lines: 2- Specifying Callbacks To Run --------------------------- You specify when to run the callbacks by adding the method name to the appropriate class property (``$beforeInsert``, ``$afterUpdate``, etc). Multiple callbacks can be added to a single event and they will be processed one after the other. You can -use the same callback in multiple events:: +use the same callback in multiple events: - protected $beforeInsert = ['hashPassword']; - protected $beforeUpdate = ['hashPassword']; +.. literalinclude:: model/051.php + :lines: 2- -Additionally, each model may allow (default) or deny callbacks class-wide by setting its ``$allowCallbacks`` property:: +Additionally, each model may allow (default) or deny callbacks class-wide by setting its ``$allowCallbacks`` property: - protected $allowCallbacks = false; +.. literalinclude:: model/052.php + :lines: 2- -You may also change this setting temporarily for a single model call sing the ``allowCallbacks()`` method:: +You may also change this setting temporarily for a single model call sing the ``allowCallbacks()`` method: - $model->allowCallbacks(false)->find(1); // No callbacks triggered - $model->find(1); // Callbacks subject to original property value +.. literalinclude:: model/053.php + :lines: 2- Event Parameters ---------------- @@ -851,22 +659,10 @@ Modifying Find* Data The ``beforeFind`` and ``afterFind`` methods can both return a modified set of data to override the normal response from the model. For ``afterFind`` any changes made to ``data`` in the return array will automatically be passed back to the calling context. In order for ``beforeFind`` to intercept the find workflow it must also return an additional -boolean, ``returnData``:: - - protected $beforeFind = ['checkCache']; - // ... - protected function checkCache(array $data) - { - // Check if the requested item is already in our cache - if (isset($data['id']) && $item = $this->getCachedItem($data['id']])) { - $data['data'] = $item; - $data['returnData'] = true; - - return $data; - } +boolean, ``returnData``: - // ... - } +.. literalinclude:: model/054.php + :lines: 2- Manual Model Creation ===================== @@ -875,20 +671,4 @@ You do not need to extend any special class to create a model for your applicati instance of the database connection and you're good to go. This allows you to bypass the features CodeIgniter's Model gives you out of the box, and create a fully custom experience. -:: - - db = &$db; - } - } +.. literalinclude:: model/055.php diff --git a/user_guide_src/source/models/model/001.php b/user_guide_src/source/models/model/001.php new file mode 100644 index 000000000000..ac8ede5c3dec --- /dev/null +++ b/user_guide_src/source/models/model/001.php @@ -0,0 +1,16 @@ +allowedFields[] = 'middlename'; + } +} diff --git a/user_guide_src/source/models/model/004.php b/user_guide_src/source/models/model/004.php new file mode 100644 index 000000000000..1ae028acbf7a --- /dev/null +++ b/user_guide_src/source/models/model/004.php @@ -0,0 +1,10 @@ +find($user_id); diff --git a/user_guide_src/source/models/model/007.php b/user_guide_src/source/models/model/007.php new file mode 100644 index 000000000000..1c5d65b7d93e --- /dev/null +++ b/user_guide_src/source/models/model/007.php @@ -0,0 +1,3 @@ +find([1,2,3]); diff --git a/user_guide_src/source/models/model/008.php b/user_guide_src/source/models/model/008.php new file mode 100644 index 000000000000..981f887120e3 --- /dev/null +++ b/user_guide_src/source/models/model/008.php @@ -0,0 +1,3 @@ +findColumn($column_name); diff --git a/user_guide_src/source/models/model/009.php b/user_guide_src/source/models/model/009.php new file mode 100644 index 000000000000..881962a52c3b --- /dev/null +++ b/user_guide_src/source/models/model/009.php @@ -0,0 +1,3 @@ +findAll(); diff --git a/user_guide_src/source/models/model/010.php b/user_guide_src/source/models/model/010.php new file mode 100644 index 000000000000..bc654f2703c9 --- /dev/null +++ b/user_guide_src/source/models/model/010.php @@ -0,0 +1,4 @@ +where('active', 1) + ->findAll(); diff --git a/user_guide_src/source/models/model/011.php b/user_guide_src/source/models/model/011.php new file mode 100644 index 000000000000..a906bda6142e --- /dev/null +++ b/user_guide_src/source/models/model/011.php @@ -0,0 +1,3 @@ +findAll($limit, $offset); diff --git a/user_guide_src/source/models/model/012.php b/user_guide_src/source/models/model/012.php new file mode 100644 index 000000000000..117771f78ca8 --- /dev/null +++ b/user_guide_src/source/models/model/012.php @@ -0,0 +1,4 @@ +where('deleted', 0) + ->first(); diff --git a/user_guide_src/source/models/model/013.php b/user_guide_src/source/models/model/013.php new file mode 100644 index 000000000000..1abc1e3be49b --- /dev/null +++ b/user_guide_src/source/models/model/013.php @@ -0,0 +1,7 @@ +findAll(); + +// Gets all rows +$allUsers = $userModel->withDeleted()->findAll(); diff --git a/user_guide_src/source/models/model/014.php b/user_guide_src/source/models/model/014.php new file mode 100644 index 000000000000..f12fc5e0cb6a --- /dev/null +++ b/user_guide_src/source/models/model/014.php @@ -0,0 +1,3 @@ +onlyDeleted()->findAll(); diff --git a/user_guide_src/source/models/model/015.php b/user_guide_src/source/models/model/015.php new file mode 100644 index 000000000000..23414a8c9a01 --- /dev/null +++ b/user_guide_src/source/models/model/015.php @@ -0,0 +1,8 @@ + 'darth', + 'email' => 'd.vader@theempire.com', +]; + +$userModel->insert($data); diff --git a/user_guide_src/source/models/model/016.php b/user_guide_src/source/models/model/016.php new file mode 100644 index 000000000000..efecefe6ba81 --- /dev/null +++ b/user_guide_src/source/models/model/016.php @@ -0,0 +1,8 @@ + 'darth', + 'email' => 'd.vader@theempire.com', +]; + +$userModel->update($id, $data); diff --git a/user_guide_src/source/models/model/017.php b/user_guide_src/source/models/model/017.php new file mode 100644 index 000000000000..5032c34a4613 --- /dev/null +++ b/user_guide_src/source/models/model/017.php @@ -0,0 +1,7 @@ + 1, +]; + +$userModel->update([1, 2, 3], $data); diff --git a/user_guide_src/source/models/model/018.php b/user_guide_src/source/models/model/018.php new file mode 100644 index 000000000000..8c13a5a85e2a --- /dev/null +++ b/user_guide_src/source/models/model/018.php @@ -0,0 +1,6 @@ +whereIn('id', [1,2,3]) + ->set(['active' => 1]) + ->update(); diff --git a/user_guide_src/source/models/model/019.php b/user_guide_src/source/models/model/019.php new file mode 100644 index 000000000000..789218001968 --- /dev/null +++ b/user_guide_src/source/models/model/019.php @@ -0,0 +1,20 @@ + 'darth', + 'email' => 'd.vader@theempire.com', +]; + +$userModel->save($data); + +// Performs an update, since the primary key, 'id', is found. +$data = [ + 'id' => 3, + 'username' => 'darth', + 'email' => 'd.vader@theempire.com', +]; +$userModel->save($data); diff --git a/user_guide_src/source/models/model/020.php b/user_guide_src/source/models/model/020.php new file mode 100644 index 000000000000..ebc37ee608c1 --- /dev/null +++ b/user_guide_src/source/models/model/020.php @@ -0,0 +1,24 @@ +$key; + } + } + + public function __set($key, $value) + { + if (property_exists($this, $key)) { + $this->$key = $value; + } + } +} diff --git a/user_guide_src/source/models/model/021.php b/user_guide_src/source/models/model/021.php new file mode 100644 index 000000000000..a49cfe210163 --- /dev/null +++ b/user_guide_src/source/models/model/021.php @@ -0,0 +1,12 @@ +find(15); + +// Make some changes +$job->name = "Foobar"; + +// Save the changes +$model->save($job); diff --git a/user_guide_src/source/models/model/023.php b/user_guide_src/source/models/model/023.php new file mode 100644 index 000000000000..c1045eecbbb2 --- /dev/null +++ b/user_guide_src/source/models/model/023.php @@ -0,0 +1,3 @@ +delete(12); diff --git a/user_guide_src/source/models/model/024.php b/user_guide_src/source/models/model/024.php new file mode 100644 index 000000000000..f6769f061142 --- /dev/null +++ b/user_guide_src/source/models/model/024.php @@ -0,0 +1,3 @@ +delete([1,2,3]); diff --git a/user_guide_src/source/models/model/025.php b/user_guide_src/source/models/model/025.php new file mode 100644 index 000000000000..dc520c882d8e --- /dev/null +++ b/user_guide_src/source/models/model/025.php @@ -0,0 +1,3 @@ +where('id', 12)->delete(); diff --git a/user_guide_src/source/models/model/026.php b/user_guide_src/source/models/model/026.php new file mode 100644 index 000000000000..c06642313a0c --- /dev/null +++ b/user_guide_src/source/models/model/026.php @@ -0,0 +1,3 @@ +purgeDeleted(); diff --git a/user_guide_src/source/models/model/027.php b/user_guide_src/source/models/model/027.php new file mode 100644 index 000000000000..b0d19738c5c0 --- /dev/null +++ b/user_guide_src/source/models/model/027.php @@ -0,0 +1,17 @@ + 'required|alpha_numeric_space|min_length[3]', + 'email' => 'required|valid_email|is_unique[users.email]', + 'password' => 'required|min_length[8]', + 'pass_confirm' => 'required_with[password]|matches[password]', + ]; + + protected $validationMessages = [ + 'email' => [ + 'is_unique' => 'Sorry. That email has already been taken. Please choose another.', + ], + ]; +} diff --git a/user_guide_src/source/models/model/028.php b/user_guide_src/source/models/model/028.php new file mode 100644 index 000000000000..c9bea660de81 --- /dev/null +++ b/user_guide_src/source/models/model/028.php @@ -0,0 +1,6 @@ +setValidationRule($fieldName, $fieldRules); diff --git a/user_guide_src/source/models/model/029.php b/user_guide_src/source/models/model/029.php new file mode 100644 index 000000000000..15221f2505a6 --- /dev/null +++ b/user_guide_src/source/models/model/029.php @@ -0,0 +1,12 @@ + 'required|alpha_numeric_space|min_length[3]', + 'email' => [ + 'rules' => 'required|valid_email|is_unique[users.email]', + 'errors' => [ + 'required' => 'We really need your email.', + ], + ], +]; +$model->setValidationRules($validationRules); diff --git a/user_guide_src/source/models/model/030.php b/user_guide_src/source/models/model/030.php new file mode 100644 index 000000000000..deca0d44f722 --- /dev/null +++ b/user_guide_src/source/models/model/030.php @@ -0,0 +1,7 @@ + 'Your name is required here', +]; +$model->setValidationMessage($fieldName, $fieldValidationMessage); diff --git a/user_guide_src/source/models/model/031.php b/user_guide_src/source/models/model/031.php new file mode 100644 index 000000000000..902cea408f1f --- /dev/null +++ b/user_guide_src/source/models/model/031.php @@ -0,0 +1,9 @@ + [ + 'required' => 'Your baby name is missing.', + 'min_length' => 'Too short, man!', + ], +]; +$model->setValidationMessages($fieldValidationMessage); diff --git a/user_guide_src/source/models/model/032.php b/user_guide_src/source/models/model/032.php new file mode 100644 index 000000000000..0e93993557b4 --- /dev/null +++ b/user_guide_src/source/models/model/032.php @@ -0,0 +1,5 @@ +save($data) === false) { + return view('updateUser', ['errors' => $model->errors()]); +} diff --git a/user_guide_src/source/models/model/033.php b/user_guide_src/source/models/model/033.php new file mode 100644 index 000000000000..32005c35b635 --- /dev/null +++ b/user_guide_src/source/models/model/033.php @@ -0,0 +1,7 @@ + +
    + $error): ?> +

    + +
    + diff --git a/user_guide_src/source/models/model/034.php b/user_guide_src/source/models/model/034.php new file mode 100644 index 000000000000..8de746bec4cd --- /dev/null +++ b/user_guide_src/source/models/model/034.php @@ -0,0 +1,6 @@ +validationRules; diff --git a/user_guide_src/source/models/model/036.php b/user_guide_src/source/models/model/036.php new file mode 100644 index 000000000000..af5a3eef010e --- /dev/null +++ b/user_guide_src/source/models/model/036.php @@ -0,0 +1,3 @@ +getValidationRules($options); diff --git a/user_guide_src/source/models/model/037.php b/user_guide_src/source/models/model/037.php new file mode 100644 index 000000000000..ff15de70d9c5 --- /dev/null +++ b/user_guide_src/source/models/model/037.php @@ -0,0 +1,6 @@ +getValidationRules(['except' => ['username']]); +// get the rules for only the "city" and "state" fields +$rules = $model->getValidationRules(['only' => ['city', 'state']]); diff --git a/user_guide_src/source/models/model/038.php b/user_guide_src/source/models/model/038.php new file mode 100644 index 000000000000..0a0dffd7dba5 --- /dev/null +++ b/user_guide_src/source/models/model/038.php @@ -0,0 +1,5 @@ + 'required|valid_email|is_unique[users.email,id,{id}]' +]; diff --git a/user_guide_src/source/models/model/039.php b/user_guide_src/source/models/model/039.php new file mode 100644 index 000000000000..00ab7df2a766 --- /dev/null +++ b/user_guide_src/source/models/model/039.php @@ -0,0 +1,6 @@ + 4, + 'email' => 'foo@example.com' +]; diff --git a/user_guide_src/source/models/model/040.php b/user_guide_src/source/models/model/040.php new file mode 100644 index 000000000000..68f9c5c13143 --- /dev/null +++ b/user_guide_src/source/models/model/040.php @@ -0,0 +1,5 @@ + 'required|valid_email|is_unique[users.email,id,4]' +]; diff --git a/user_guide_src/source/models/model/041.php b/user_guide_src/source/models/model/041.php new file mode 100644 index 000000000000..8aaa151c61a1 --- /dev/null +++ b/user_guide_src/source/models/model/041.php @@ -0,0 +1,3 @@ +protect(false) + ->insert($data) + ->protect(true); diff --git a/user_guide_src/source/models/model/043.php b/user_guide_src/source/models/model/043.php new file mode 100644 index 000000000000..44a962a082f8 --- /dev/null +++ b/user_guide_src/source/models/model/043.php @@ -0,0 +1,3 @@ +builder(); diff --git a/user_guide_src/source/models/model/044.php b/user_guide_src/source/models/model/044.php new file mode 100644 index 000000000000..229af898adcb --- /dev/null +++ b/user_guide_src/source/models/model/044.php @@ -0,0 +1,3 @@ +builder('groups'); diff --git a/user_guide_src/source/models/model/045.php b/user_guide_src/source/models/model/045.php new file mode 100644 index 000000000000..9b064dd4fbff --- /dev/null +++ b/user_guide_src/source/models/model/045.php @@ -0,0 +1,5 @@ +where('status', 'active') + ->orderBy('last_login', 'asc') + ->findAll(); diff --git a/user_guide_src/source/models/model/046.php b/user_guide_src/source/models/model/046.php new file mode 100644 index 000000000000..13b84dc5d71c --- /dev/null +++ b/user_guide_src/source/models/model/046.php @@ -0,0 +1,3 @@ +escape($name); diff --git a/user_guide_src/source/models/model/047.php b/user_guide_src/source/models/model/047.php new file mode 100644 index 000000000000..ab2dfdecc85b --- /dev/null +++ b/user_guide_src/source/models/model/047.php @@ -0,0 +1,3 @@ +asArray()->where('status', 'active')->findAll(); diff --git a/user_guide_src/source/models/model/048.php b/user_guide_src/source/models/model/048.php new file mode 100644 index 000000000000..799e88726d93 --- /dev/null +++ b/user_guide_src/source/models/model/048.php @@ -0,0 +1,7 @@ +asObject()->where('status', 'active')->findAll(); + +// Return as custom class instances +$users = $userModel->asObject('User')->where('status', 'active')->findAll(); diff --git a/user_guide_src/source/models/model/049.php b/user_guide_src/source/models/model/049.php new file mode 100644 index 000000000000..0aace6d0fc28 --- /dev/null +++ b/user_guide_src/source/models/model/049.php @@ -0,0 +1,6 @@ +chunk(100, function ($data) { + // do something. + // $data is a single row of data. +}); diff --git a/user_guide_src/source/models/model/050.php b/user_guide_src/source/models/model/050.php new file mode 100644 index 000000000000..a933f49d5f3e --- /dev/null +++ b/user_guide_src/source/models/model/050.php @@ -0,0 +1,13 @@ +allowCallbacks(false)->find(1); // No callbacks triggered +$model->find(1); // Callbacks subject to original property value diff --git a/user_guide_src/source/models/model/054.php b/user_guide_src/source/models/model/054.php new file mode 100644 index 000000000000..dd8bb573b5dd --- /dev/null +++ b/user_guide_src/source/models/model/054.php @@ -0,0 +1,16 @@ +getCachedItem($data['id']])) { + $data['data'] = $item; + $data['returnData'] = true; + + return $data; + } + + // ... +} diff --git a/user_guide_src/source/models/model/055.php b/user_guide_src/source/models/model/055.php new file mode 100644 index 000000000000..1d62c54ba058 --- /dev/null +++ b/user_guide_src/source/models/model/055.php @@ -0,0 +1,15 @@ +db = &$db; + } +} diff --git a/user_guide_src/source/outgoing/alternative_php.rst b/user_guide_src/source/outgoing/alternative_php.rst index 369808874413..b4a2b10257e5 100644 --- a/user_guide_src/source/outgoing/alternative_php.rst +++ b/user_guide_src/source/outgoing/alternative_php.rst @@ -25,17 +25,9 @@ Alternative Control Structures ============================== Controls structures, like if, for, foreach, and while can be written in -a simplified format as well. Here is an example using ``foreach``:: +a simplified format as well. Here is an example using ``foreach``: -
      - - - -
    • - - - -
    +.. literalinclude:: alternative_php/001.php Notice that there are no braces. Instead, the end brace is replaced with ``endforeach``. Each of the control structures listed above has a similar @@ -44,18 +36,6 @@ closing syntax: ``endif``, ``endfor``, ``endforeach``, and ``endwhile`` Also notice that instead of using a semicolon after each structure (except the last one), there is a colon. This is important! -Here is another example, using ``if``/``elseif``/``else``. Notice the colons:: - - - -

    Hi Sally

    - - - -

    Hi Joe

    - - - -

    Hi unknown user

    +Here is another example, using ``if``/``elseif``/``else``. Notice the colons: - +.. literalinclude:: alternative_php/002.php diff --git a/user_guide_src/source/outgoing/alternative_php/001.php b/user_guide_src/source/outgoing/alternative_php/001.php new file mode 100644 index 000000000000..9158fe27dccc --- /dev/null +++ b/user_guide_src/source/outgoing/alternative_php/001.php @@ -0,0 +1,9 @@ +
      + + + +
    • + + + +
    diff --git a/user_guide_src/source/outgoing/alternative_php/002.php b/user_guide_src/source/outgoing/alternative_php/002.php new file mode 100644 index 000000000000..47c5afcfb95a --- /dev/null +++ b/user_guide_src/source/outgoing/alternative_php/002.php @@ -0,0 +1,13 @@ + + +

    Hi Sally

    + + + +

    Hi Joe

    + + + +

    Hi unknown user

    + + diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index 92eaa066f36f..1e6e2bba735f 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -17,66 +17,13 @@ Example Usage The following example shows a common usage pattern within your controllers. -:: - - save($this->request->getPost()); - - // Respond with 201 status code - return $this->respondCreated(); - } - } +.. literalinclude:: api_responses/001.php In this example, an HTTP status code of 201 is returned, with the generic status message, 'Created'. Methods -exist for the most common use cases:: - - // Generic response method - $this->respond($data, 200); - - // Generic failure response - $this->fail($errors, 400); - - // Item created response - $this->respondCreated($data); - - // Item successfully deleted - $this->respondDeleted($data); - - // Command executed by no response required - $this->respondNoContent($message); - - // Client isn't authorized - $this->failUnauthorized($description); - - // Forbidden action - $this->failForbidden($description); - - // Resource Not Found - $this->failNotFound($description); - - // Data did not validate - $this->failValidationError($description); +exist for the most common use cases: - // Resource already exists - $this->failResourceExists($description); - - // Resource previously deleted - $this->failResourceGone($description); - - // Client made too many requests - $this->failTooManyRequests($description); +.. literalinclude:: api_responses/002.php + :lines: 2- *********************** Handling Response Types @@ -92,12 +39,10 @@ the following criteria: To define the formatter that is used, edit **Config/Format.php**. The ``$supportedResponseFormats`` contains a list of mime types that your application can automatically format the response for. By default, the system knows how to -format both XML and JSON responses:: +format both XML and JSON responses: - public $supportedResponseFormats = [ - 'application/json', - 'application/xml', - ]; +.. literalinclude:: api_responses/003.php + :lines: 2- This is the array that is used during :doc:`Content Negotiation ` to determine which type of response to return. If no matches are found between what the client requested and what you support, the first @@ -105,12 +50,10 @@ format in this array is what will be returned. Next, you need to define the class that is used to format the array of data. This must be a fully qualified class name, and the class must implement ``CodeIgniter\Format\FormatterInterface``. Formatters come out of the box that -support both JSON and XML:: +support both JSON and XML: - public $formatters = [ - 'application/json' => \CodeIgniter\Format\JSONFormatter::class, - 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, - ]; +.. literalinclude:: api_responses/004.php + :lines: 2- So, if your request asks for JSON formatted data in an **Accept** header, the data array you pass any of the ``respond*`` or ``fail*`` methods will be formatted by the ``CodeIgniter\Format\JSONFormatter`` class. The resulting @@ -125,10 +68,8 @@ Class Reference This defines the format to be used when formatting arrays in responses. If you provide a ``null`` value for ``$format``, it will be automatically determined through content negotiation. -:: - - return $this->setResponseFormat('json')->respond(['error' => false]); - +.. literalinclude:: api_responses/005.php + :lines: 2- .. php:method:: respond($data[, $statusCode = 200[, $message = '']]) @@ -171,16 +112,10 @@ Class Reference that match the status code. The response is an array with two elements: ``error`` and ``messages``. The ``error`` element contains the status - code of the error. The ``messages`` element contains an array of error messages. It would look something like:: + code of the error. The ``messages`` element contains an array of error messages. It would look something like: - $response = [ - 'status' => 400, - 'code' => '321a', - 'messages' => [ - 'Error message 1', - 'Error message 2', - ], - ]; + .. literalinclude:: api_responses/006.php + :lines: 2- .. php:method:: respondCreated($data = null[, string $message = '']) @@ -188,10 +123,10 @@ Class Reference :param string $message: A custom "reason" message to return. :returns: The value of the Response object's send() method. - Sets the appropriate status code to use when a new resource was created, typically 201.:: + Sets the appropriate status code to use when a new resource was created, typically 201.: - $user = $userModel->insert($data); - return $this->respondCreated($user); + .. literalinclude:: api_responses/007.php + :lines: 2- .. php:method:: respondDeleted($data = null[, string $message = '']) @@ -201,10 +136,8 @@ Class Reference Sets the appropriate status code to use when a new resource was deleted as the result of this API call, typically 200. - :: - - $user = $userModel->delete($id); - return $this->respondDeleted(['id' => $id]); + .. literalinclude:: api_responses/008.php + :lines: 2- .. php:method:: respondNoContent(string $message = 'No Content') @@ -214,10 +147,8 @@ Class Reference Sets the appropriate status code to use when a command was successfully executed by the server but there is no meaningful reply to send back to the client, typically 204. - :: - - sleep(1); - return $this->respondNoContent(); + .. literalinclude:: api_responses/009.php + :lines: 2- .. php:method:: failUnauthorized(string $description = 'Unauthorized'[, string $code = null[, string $message = '']]) @@ -229,9 +160,8 @@ Class Reference Sets the appropriate status code to use when the user either has not been authorized, or has incorrect authorization. Status code is 401. - :: - - return $this->failUnauthorized('Invalid Auth token'); + .. literalinclude:: api_responses/010.php + :lines: 2- .. php:method:: failForbidden(string $description = 'Forbidden'[, string $code=null[, string $message = '']]) @@ -244,9 +174,8 @@ Class Reference Unauthorized implies the client is encouraged to try again with different credentials. Forbidden means the client should not try again because it won't help. Status code is 403. - :: - - return $this->failForbidden('Invalid API endpoint.'); + .. literalinclude:: api_responses/011.php + :lines: 2- .. php:method:: failNotFound(string $description = 'Not Found'[, string $code=null[, string $message = '']]) @@ -257,9 +186,8 @@ Class Reference Sets the appropriate status code to use when the requested resource cannot be found. Status code is 404. - :: - - return $this->failNotFound('User 13 cannot be found.'); + .. literalinclude:: api_responses/012.php + :lines: 2- .. php:method:: failValidationErrors($errors[, string $code=null[, string $message = '']]) @@ -270,9 +198,8 @@ Class Reference Sets the appropriate status code to use when data the client sent did not pass validation rules. Status code is typically 400. - :: - - return $this->failValidationErrors($validation->getErrors()); + .. literalinclude:: api_responses/013.php + :lines: 2- .. php:method:: failResourceExists(string $description = 'Conflict'[, string $code=null[, string $message = '']]) @@ -284,9 +211,8 @@ Class Reference Sets the appropriate status code to use when the resource the client is trying to create already exists. Status code is typically 409. - :: - - return $this->failResourceExists('A user already exists with that email.'); + .. literalinclude:: api_responses/014.php + :lines: 2- .. php:method:: failResourceGone(string $description = 'Gone'[, string $code=null[, string $message = '']]) @@ -298,9 +224,8 @@ Class Reference Sets the appropriate status code to use when the requested resource was previously deleted and is no longer available. Status code is typically 410. - :: - - return $this->failResourceGone('That user has been previously deleted.'); + .. literalinclude:: api_responses/015.php + :lines: 2- .. php:method:: failTooManyRequests(string $description = 'Too Many Requests'[, string $code=null[, string $message = '']]) @@ -312,9 +237,8 @@ Class Reference Sets the appropriate status code to use when the client has called an API endpoint too many times. This might be due to some form of throttling or rate limiting. Status code is typically 400. - :: - - return $this->failTooManyRequests('You must wait 15 seconds before making another request.'); + .. literalinclude:: api_responses/016.php + :lines: 2- .. php:method:: failServerError(string $description = 'Internal Server Error'[, string $code = null[, string $message = '']]) @@ -325,6 +249,5 @@ Class Reference Sets the appropriate status code to use when there is a server error. - :: - - return $this->failServerError('Server error.'); + .. literalinclude:: api_responses/017.php + :lines: 2- diff --git a/user_guide_src/source/outgoing/api_responses/001.php b/user_guide_src/source/outgoing/api_responses/001.php new file mode 100644 index 000000000000..c2a196482b58 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/001.php @@ -0,0 +1,19 @@ +save($this->request->getPost()); + + // Respond with 201 status code + return $this->respondCreated(); + } +} diff --git a/user_guide_src/source/outgoing/api_responses/002.php b/user_guide_src/source/outgoing/api_responses/002.php new file mode 100644 index 000000000000..e383ddc3c09f --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/002.php @@ -0,0 +1,37 @@ +respond($data, 200); + +// Generic failure response +$this->fail($errors, 400); + +// Item created response +$this->respondCreated($data); + +// Item successfully deleted +$this->respondDeleted($data); + +// Command executed by no response required +$this->respondNoContent($message); + +// Client isn't authorized +$this->failUnauthorized($description); + +// Forbidden action +$this->failForbidden($description); + +// Resource Not Found +$this->failNotFound($description); + +// Data did not validate +$this->failValidationError($description); + +// Resource already exists +$this->failResourceExists($description); + +// Resource previously deleted +$this->failResourceGone($description); + +// Client made too many requests +$this->failTooManyRequests($description); diff --git a/user_guide_src/source/outgoing/api_responses/003.php b/user_guide_src/source/outgoing/api_responses/003.php new file mode 100644 index 000000000000..ab1db7ccdc45 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/003.php @@ -0,0 +1,6 @@ + \CodeIgniter\Format\JSONFormatter::class, + 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, +]; diff --git a/user_guide_src/source/outgoing/api_responses/005.php b/user_guide_src/source/outgoing/api_responses/005.php new file mode 100644 index 000000000000..dbe887df0b63 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/005.php @@ -0,0 +1,3 @@ +setResponseFormat('json')->respond(['error' => false]); diff --git a/user_guide_src/source/outgoing/api_responses/006.php b/user_guide_src/source/outgoing/api_responses/006.php new file mode 100644 index 000000000000..3c910d6566b5 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/006.php @@ -0,0 +1,10 @@ + 400, + 'code' => '321a', + 'messages' => [ + 'Error message 1', + 'Error message 2', + ], +]; diff --git a/user_guide_src/source/outgoing/api_responses/007.php b/user_guide_src/source/outgoing/api_responses/007.php new file mode 100644 index 000000000000..568075938d3a --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/007.php @@ -0,0 +1,4 @@ +insert($data); +return $this->respondCreated($user); diff --git a/user_guide_src/source/outgoing/api_responses/008.php b/user_guide_src/source/outgoing/api_responses/008.php new file mode 100644 index 000000000000..5c1fe47efb65 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/008.php @@ -0,0 +1,4 @@ +delete($id); +return $this->respondDeleted(['id' => $id]); diff --git a/user_guide_src/source/outgoing/api_responses/009.php b/user_guide_src/source/outgoing/api_responses/009.php new file mode 100644 index 000000000000..e7672d94a610 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/009.php @@ -0,0 +1,4 @@ +respondNoContent(); diff --git a/user_guide_src/source/outgoing/api_responses/010.php b/user_guide_src/source/outgoing/api_responses/010.php new file mode 100644 index 000000000000..3de055d94cba --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/010.php @@ -0,0 +1,3 @@ +failUnauthorized('Invalid Auth token'); diff --git a/user_guide_src/source/outgoing/api_responses/011.php b/user_guide_src/source/outgoing/api_responses/011.php new file mode 100644 index 000000000000..44f3c4eeb23e --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/011.php @@ -0,0 +1,3 @@ +failForbidden('Invalid API endpoint.'); diff --git a/user_guide_src/source/outgoing/api_responses/012.php b/user_guide_src/source/outgoing/api_responses/012.php new file mode 100644 index 000000000000..2c8d8b29175a --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/012.php @@ -0,0 +1,3 @@ +failNotFound('User 13 cannot be found.'); diff --git a/user_guide_src/source/outgoing/api_responses/013.php b/user_guide_src/source/outgoing/api_responses/013.php new file mode 100644 index 000000000000..d470b1079d3b --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/013.php @@ -0,0 +1,3 @@ +failValidationErrors($validation->getErrors()); diff --git a/user_guide_src/source/outgoing/api_responses/014.php b/user_guide_src/source/outgoing/api_responses/014.php new file mode 100644 index 000000000000..d0772239c43e --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/014.php @@ -0,0 +1,3 @@ +failResourceExists('A user already exists with that email.'); diff --git a/user_guide_src/source/outgoing/api_responses/015.php b/user_guide_src/source/outgoing/api_responses/015.php new file mode 100644 index 000000000000..a8ce10dc9ff6 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/015.php @@ -0,0 +1,3 @@ +failResourceGone('That user has been previously deleted.'); diff --git a/user_guide_src/source/outgoing/api_responses/016.php b/user_guide_src/source/outgoing/api_responses/016.php new file mode 100644 index 000000000000..197376fe271f --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/016.php @@ -0,0 +1,3 @@ +failTooManyRequests('You must wait 15 seconds before making another request.'); diff --git a/user_guide_src/source/outgoing/api_responses/017.php b/user_guide_src/source/outgoing/api_responses/017.php new file mode 100644 index 000000000000..5bb665f3dd60 --- /dev/null +++ b/user_guide_src/source/outgoing/api_responses/017.php @@ -0,0 +1,3 @@ +failServerError('Server error.'); diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 58b24c48524f..cb87e8717f1a 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -30,9 +30,10 @@ supported language:: Configuring the Locale ====================== -Every site will have a default language/locale they operate in. This can be set in **Config/App.php**:: +Every site will have a default language/locale they operate in. This can be set in **Config/App.php**: - public $defaultLocale = 'en'; +.. literalinclude:: localization/001.php + :lines: 2- The value can be any string that your application uses to manage text strings and other formats. It is recommended that a `BCP 47 `_ language code is used. This results in @@ -58,25 +59,28 @@ Content Negotiation ------------------- You can set up content negotiation to happen automatically by setting two additional settings in Config/App. -The first value tells the Request class that we do want to negotiate a locale, so simply set it to true:: +The first value tells the Request class that we do want to negotiate a locale, so simply set it to true: - public $negotiateLocale = true; +.. literalinclude:: localization/002.php + :lines: 2- Once this is enabled, the system will automatically negotiate the correct language based upon an array of locales that you have defined in ``$supportLocales``. If no match is found between the languages that you support, and the requested language, the first item in $supportedLocales will be used. In -the following example, the **en** locale would be used if no match is found:: +the following example, the **en** locale would be used if no match is found: - public $supportedLocales = ['en', 'es', 'fr-FR']; +.. literalinclude:: localization/003.php + :lines: 2- In Routes --------- The second method uses a custom placeholder to detect the desired locale and set it on the Request. The placeholder ``{locale}`` can be placed as a segment in your route. If present, the contents of the matching -segment will be your locale:: +segment will be your locale: - $routes->get('{locale}/books', 'App\Books::index'); +.. literalinclude:: localization/004.php + :lines: 2- In this example, if the user tried to visit ``http://example.com/fr/books``, then the locale would be set to ``fr``, assuming it was configured as a valid locale. @@ -88,23 +92,14 @@ Retrieving the Current Locale ============================= The current locale can always be retrieved from the IncomingRequest object, through the ``getLocale()`` method. -If your controller is extending ``CodeIgniter\Controller``, this will be available through ``$this->request``:: +If your controller is extending ``CodeIgniter\Controller``, this will be available through ``$this->request``: - ` to retrieve the current request: - class UserController extends \CodeIgniter\Controller - { - public function index() - { - $locale = $this->request->getLocale(); - } - } - -Alternatively, you can use the :doc:`Services class ` to retrieve the current request:: - - $locale = service('request')->getLocale(); +.. literalinclude:: localization/006.php + :lines: 2- ********************* Language Localization @@ -117,43 +112,33 @@ Languages do not have any specific naming convention that are required. The file describe the type of content it holds. For example, let's say you want to create a file containing error messages. You might name it simply: **Errors.php**. -Within the file, you would return an array, where each element in the array has a language key and can have string to return:: +Within the file, you would return an array, where each element in the array has a language key and can have string to return: - 'languageKey' => 'The actual message to be shown.' +.. literalinclude:: localization/007.php + :lines: 2- -It also support nested definition:: +It also support nested definition: - 'languageKey' => [ - 'nested' => [ - 'key' => 'The actual message to be shown.', - ], - ], +.. literalinclude:: localization/008.php + :lines: 2- -:: - - return [ - 'errorEmailMissing' => 'You must submit an email address', - 'errorURLMissing' => 'You must submit a URL', - 'errorUsernameMissing' => 'You must submit a username', - 'nested' => [ - 'error' => [ - 'message' => 'A specific error message', - ], - ], - ]; +.. literalinclude:: localization/009.php + :lines: 2- Basic Usage =========== You can use the ``lang()`` helper function to retrieve text from any of the language files, by passing the filename and the language key as the first parameter, separated by a period (.). For example, to load the -``errorEmailMissing`` string from the ``Errors`` language file, you would do the following:: +``errorEmailMissing`` string from the ``Errors`` language file, you would do the following: - echo lang('Errors.errorEmailMissing'); +.. literalinclude:: localization/010.php + :lines: 2- -For nested definition, you would do the following:: +For nested definition, you would do the following: - echo lang('Errors.nested.error.message'); +.. literalinclude:: localization/011.php + :lines: 2- If the requested language key doesn't exist in the file for the current locale, the string will be passed back, unchanged. In this example, it would return 'Errors.errorEmailMissing' or 'Errors.nested.error.message' if it didn't exist. @@ -166,27 +151,20 @@ Replacing Parameters A great overview can be found over at `Sitepoint `_. You can pass an array of values to replace placeholders in the language string as the second parameter to the -``lang()`` function. This allows for very simple number translations and formatting:: - - // The language file, Tests.php: - return [ - 'apples' => 'I have {0, number} apples.', - 'men' => 'The top {1, number} men out-performed the remaining {0, number}', - 'namedApples' => 'I have {number_apples, number, integer} apples.', - ]; +``lang()`` function. This allows for very simple number translations and formatting: - // Displays "I have 3 apples." - echo lang('Tests.apples', [ 3 ]); +.. literalinclude:: localization/012.php + :lines: 2- -The first item in the placeholder corresponds to the index of the item in the array, if it's numerical:: +The first item in the placeholder corresponds to the index of the item in the array, if it's numerical: - // Displays "The top 23 men out-performed the remaining 20" - echo lang('Tests.men', [20, 23]); +.. literalinclude:: localization/013.php + :lines: 2- -You can also use named keys to make it easier to keep things straight, if you'd like:: +You can also use named keys to make it easier to keep things straight, if you'd like: - // Displays "I have 3 apples." - echo lang('Tests.namedApples', ['number_apples' => 3]); +.. literalinclude:: localization/014.php + :lines: 2- Obviously, you can do more than just number replacement. According to the `official ICU docs `_ for the underlying @@ -199,46 +177,10 @@ library, the following types of data can be replaced: * ordinal * duration -Here are a few examples:: - - // The language file, Tests.php - return [ - 'shortTime' => 'The time is now {0, time, short}.', - 'mediumTime' => 'The time is now {0, time, medium}.', - 'longTime' => 'The time is now {0, time, long}.', - 'fullTime' => 'The time is now {0, time, full}.', - 'shortDate' => 'The date is now {0, date, short}.', - 'mediumDate' => 'The date is now {0, date, medium}.', - 'longDate' => 'The date is now {0, date, long}.', - 'fullDate' => 'The date is now {0, date, full}.', - 'spelledOut' => '34 is {0, spellout}', - 'ordinal' => 'The ordinal is {0, ordinal}', - 'duration' => 'It has been {0, duration}', - ]; - - // Displays "The time is now 11:18 PM" - echo lang('Tests.shortTime', [time()]); - // Displays "The time is now 11:18:50 PM" - echo lang('Tests.mediumTime', [time()]); - // Displays "The time is now 11:19:09 PM CDT" - echo lang('Tests.longTime', [time()]); - // Displays "The time is now 11:19:26 PM Central Daylight Time" - echo lang('Tests.fullTime', [time()]); - - // Displays "The date is now 8/14/16" - echo lang('Tests.shortDate', [time()]); - // Displays "The date is now Aug 14, 2016" - echo lang('Tests.mediumDate', [time()]); - // Displays "The date is now August 14, 2016" - echo lang('Tests.longDate', [time()]); - // Displays "The date is now Sunday, August 14, 2016" - echo lang('Tests.fullDate', [time()]); - - // Displays "34 is thirty-four" - echo lang('Tests.spelledOut', [34]); - - // Displays "It has been 408,676:24:35" - echo lang('Tests.ordinal', [time()]); +Here are a few examples: + +.. literalinclude:: localization/015.php + :lines: 2- You should be sure to read up on the MessageFormatter class and the underlying ICU formatting to get a better idea on what capabilities it has, like performing the conditional replacement, pluralization, and more. Both of the links provided @@ -249,37 +191,17 @@ Specifying Locale To specify a different locale to be used when replacing parameters, you can pass the locale in as the third parameter to the ``lang()`` method. -:: - - // Displays "The time is now 23:21:28 GMT-5" - echo lang('Test.longTime', [time()], 'ru-RU'); - // Displays "£7.41" - echo lang('{price, number, currency}', ['price' => 7.41], 'en-GB'); - // Displays "$7.41" - echo lang('{price, number, currency}', ['price' => 7.41], 'en-US'); +.. literalinclude:: localization/016.php + :lines: 2- Nested Arrays ------------- Language files also allow nested arrays to make working with lists, etc... easier. -:: - - // Language/en/Fruit.php - - return [ - 'list' => [ - 'Apples', - 'Bananas', - 'Grapes', - 'Lemons', - 'Oranges', - 'Strawberries', - ], - ]; - - // Displays "Apples, Bananas, Grapes, Lemons, Oranges, Strawberries" - echo implode(', ', lang('Fruit.list')); + +.. literalinclude:: localization/017.php + :lines: 2- Language Fallback ================= diff --git a/user_guide_src/source/outgoing/localization/001.php b/user_guide_src/source/outgoing/localization/001.php new file mode 100644 index 000000000000..c3b3de65be20 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/001.php @@ -0,0 +1,3 @@ +get('{locale}/books', 'App\Books::index'); diff --git a/user_guide_src/source/outgoing/localization/005.php b/user_guide_src/source/outgoing/localization/005.php new file mode 100644 index 000000000000..09d2d5cae03d --- /dev/null +++ b/user_guide_src/source/outgoing/localization/005.php @@ -0,0 +1,11 @@ +request->getLocale(); + } +} diff --git a/user_guide_src/source/outgoing/localization/006.php b/user_guide_src/source/outgoing/localization/006.php new file mode 100644 index 000000000000..06eee03102b5 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/006.php @@ -0,0 +1,3 @@ +getLocale(); diff --git a/user_guide_src/source/outgoing/localization/007.php b/user_guide_src/source/outgoing/localization/007.php new file mode 100644 index 000000000000..48dc3e455282 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/007.php @@ -0,0 +1,3 @@ + 'The actual message to be shown.' diff --git a/user_guide_src/source/outgoing/localization/008.php b/user_guide_src/source/outgoing/localization/008.php new file mode 100644 index 000000000000..b8975a521320 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/008.php @@ -0,0 +1,7 @@ + [ + 'nested' => [ + 'key' => 'The actual message to be shown.', + ], +], diff --git a/user_guide_src/source/outgoing/localization/009.php b/user_guide_src/source/outgoing/localization/009.php new file mode 100644 index 000000000000..07e6924dcdab --- /dev/null +++ b/user_guide_src/source/outgoing/localization/009.php @@ -0,0 +1,12 @@ + 'You must submit an email address', + 'errorURLMissing' => 'You must submit a URL', + 'errorUsernameMissing' => 'You must submit a username', + 'nested' => [ + 'error' => [ + 'message' => 'A specific error message', + ], + ], +]; diff --git a/user_guide_src/source/outgoing/localization/010.php b/user_guide_src/source/outgoing/localization/010.php new file mode 100644 index 000000000000..7631da71f069 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/010.php @@ -0,0 +1,3 @@ + 'I have {0, number} apples.', + 'men' => 'The top {1, number} men out-performed the remaining {0, number}', + 'namedApples' => 'I have {number_apples, number, integer} apples.', +]; + +// Displays "I have 3 apples." +echo lang('Tests.apples', [ 3 ]); diff --git a/user_guide_src/source/outgoing/localization/013.php b/user_guide_src/source/outgoing/localization/013.php new file mode 100644 index 000000000000..c74a8f868f6e --- /dev/null +++ b/user_guide_src/source/outgoing/localization/013.php @@ -0,0 +1,4 @@ + 3]); diff --git a/user_guide_src/source/outgoing/localization/015.php b/user_guide_src/source/outgoing/localization/015.php new file mode 100644 index 000000000000..04e15f558f69 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/015.php @@ -0,0 +1,40 @@ + 'The time is now {0, time, short}.', + 'mediumTime' => 'The time is now {0, time, medium}.', + 'longTime' => 'The time is now {0, time, long}.', + 'fullTime' => 'The time is now {0, time, full}.', + 'shortDate' => 'The date is now {0, date, short}.', + 'mediumDate' => 'The date is now {0, date, medium}.', + 'longDate' => 'The date is now {0, date, long}.', + 'fullDate' => 'The date is now {0, date, full}.', + 'spelledOut' => '34 is {0, spellout}', + 'ordinal' => 'The ordinal is {0, ordinal}', + 'duration' => 'It has been {0, duration}', +]; + +// Displays "The time is now 11:18 PM" +echo lang('Tests.shortTime', [time()]); +// Displays "The time is now 11:18:50 PM" +echo lang('Tests.mediumTime', [time()]); +// Displays "The time is now 11:19:09 PM CDT" +echo lang('Tests.longTime', [time()]); +// Displays "The time is now 11:19:26 PM Central Daylight Time" +echo lang('Tests.fullTime', [time()]); + +// Displays "The date is now 8/14/16" +echo lang('Tests.shortDate', [time()]); +// Displays "The date is now Aug 14, 2016" +echo lang('Tests.mediumDate', [time()]); +// Displays "The date is now August 14, 2016" +echo lang('Tests.longDate', [time()]); +// Displays "The date is now Sunday, August 14, 2016" +echo lang('Tests.fullDate', [time()]); + +// Displays "34 is thirty-four" +echo lang('Tests.spelledOut', [34]); + +// Displays "It has been 408,676:24:35" +echo lang('Tests.ordinal', [time()]); diff --git a/user_guide_src/source/outgoing/localization/016.php b/user_guide_src/source/outgoing/localization/016.php new file mode 100644 index 000000000000..93b709a73e99 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/016.php @@ -0,0 +1,9 @@ + 7.41], 'en-GB'); +// Displays "$7.41" +echo lang('{price, number, currency}', ['price' => 7.41], 'en-US'); diff --git a/user_guide_src/source/outgoing/localization/017.php b/user_guide_src/source/outgoing/localization/017.php new file mode 100644 index 000000000000..bd6218e927b5 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/017.php @@ -0,0 +1,17 @@ + [ + 'Apples', + 'Bananas', + 'Grapes', + 'Lemons', + 'Oranges', + 'Strawberries', + ], +]; + +// Displays "Apples, Bananas, Grapes, Lemons, Oranges, Strawberries" +echo implode(', ', lang('Fruit.list')); diff --git a/user_guide_src/source/outgoing/response.rst b/user_guide_src/source/outgoing/response.rst index a573710ad8c8..6a1fcd81b85c 100644 --- a/user_guide_src/source/outgoing/response.rst +++ b/user_guide_src/source/outgoing/response.rst @@ -23,26 +23,22 @@ Setting the Output When you need to set the output of the script directly, and not rely on CodeIgniter to automatically get it, you do it manually with the ``setBody`` method. This is usually used in conjunction with setting the status code of -the response:: +the response: - $this->response->setStatusCode(404)->setBody($body); +.. literalinclude:: response/001.php + :lines: 2- The reason phrase ('OK', 'Created', 'Moved Permanently') will be automatically added, but you can add custom reasons -as the second parameter of the ``setStatusCode()`` method:: +as the second parameter of the ``setStatusCode()`` method: - $this->response->setStatusCode(404, 'Nope. Not here.'); +.. literalinclude:: response/002.php + :lines: 2- You can set format an array into either JSON or XML and set the content type header to the appropriate mime with the -``setJSON`` and ``setXML`` methods. Typically, you will send an array of data to be converted:: +``setJSON`` and ``setXML`` methods. Typically, you will send an array of data to be converted: - $data = [ - 'success' => true, - 'id' => 123, - ]; - - return $this->response->setJSON($data); - // or - return $this->response->setXML($data); +.. literalinclude:: response/003.php + :lines: 2- Setting Headers --------------- @@ -52,24 +48,22 @@ with the ``setHeader()`` method. The first parameter is the name of the header. which can be either a string or an array of values that will be combined correctly when sent to the client. Using these functions instead of using the native PHP functions allows you to ensure that no headers are sent prematurely, causing errors, and makes testing possible. -:: - $response->setHeader('Location', 'http://example.com') - ->setHeader('WWW-Authenticate', 'Negotiate'); +.. literalinclude:: response/004.php + :lines: 2- If the header exists and can have more than one value, you may use the ``appendHeader()`` and ``prependHeader()`` methods to add the value to the end or beginning of the values list, respectively. The first parameter is the name of the header, while the second is the value to append or prepend. -:: - $response->setHeader('Cache-Control', 'no-cache') - ->appendHeader('Cache-Control', 'must-revalidate'); +.. literalinclude:: response/005.php + :lines: 2- Headers can be removed from the response with the ``removeHeader()`` method, which takes the header name as the only parameter. This is not case-sensitive. -:: - $response->removeHeader('Location'); +.. literalinclude:: response/006.php + :lines: 2- Force File Download =================== @@ -87,21 +81,21 @@ If you set the third parameter to boolean true, then the actual file MIME type (based on the filename extension) will be sent, so that if your browser has a handler for that type - it can use it. -Example:: +Example: - $data = 'Here is some text!'; - $name = 'mytext.txt'; - return $response->download($name, $data); +.. literalinclude:: response/007.php + :lines: 2- If you want to download an existing file from your server you'll need to -pass ``null`` explicitly for the second parameter:: +pass ``null`` explicitly for the second parameter: - // Contents of photo.jpg will be automatically read - return $response->download('/path/to/photo.jpg', null); +.. literalinclude:: response/008.php + :lines: 2- -Use the optional ``setFileName()`` method to change the filename as it is sent to the client's browser:: +Use the optional ``setFileName()`` method to change the filename as it is sent to the client's browser: - return $response->download('awkwardEncryptedFileName.fakeExt', null)->setFileName('expenses.csv'); +.. literalinclude:: response/009.php + :lines: 2- .. note:: The response object MUST be returned for the download to be sent to the client. This allows the response to be passed through all **after** filters before being sent to the client. @@ -119,14 +113,10 @@ introduction to all of the cache headers power, but you can get a good understan By default, all response objects sent through CodeIgniter have HTTP caching turned off. The options and exact circumstances are too varied for us to be able to create a good default other than turning it off. It's simple -to set the Cache values to what you need, through the ``setCache()`` method:: +to set the Cache values to what you need, through the ``setCache()`` method: - $options = [ - 'max-age' => 300, - 's-maxage' => 900, - 'etag' => 'abcde' - ]; - $this->response->setCache($options); +.. literalinclude:: response/010.php + :lines: 2- The ``$options`` array simply takes an array of key/value pairs that are, with a couple of exceptions, assigned to the ``Cache-Control`` header. You are free to set all of the options exactly as you need for your specific @@ -159,9 +149,10 @@ Turning CSP On -------------- By default, support for this is off. To enable support in your application, edit the ``CSPEnabled`` value in -**app/Config/App.php**:: +**app/Config/App.php**: - public $CSPEnabled = true; +.. literalinclude:: response/011.php + :lines: 2- When enabled, the response object will contain an instance of ``CodeIgniter\HTTP\ContentSecurityPolicy``. The values set in **app/Config/ContentSecurityPolicy.php** are applied to that instance, and if no changes are @@ -184,48 +175,20 @@ Runtime Configuration If your application needs to make changes at run-time, you can access the instance at ``$response->CSP``. The class holds a number of methods that map pretty clearly to the appropriate header value that you need to set. Examples are shown below, with different combinations of parameters, though all accept either a directive -name or an array of them.:: - - // specify the default directive treatment - $response->CSP->reportOnly(false); - - // specify the origin to use if none provided for a directive - $response->CSP->setDefaultSrc('cdn.example.com'); - - // specify the URL that "report-only" reports get sent to - $response->CSP->setReportURI('http://example.com/csp/reports'); - - // specify that HTTP requests be upgraded to HTTPS - $response->CSP->upgradeInsecureRequests(true); - - // add types or origins to CSP directives - // assuming that the default treatment is to block rather than just report - $response->CSP->addBaseURI('example.com', true); // report only - $response->CSP->addChildSrc('https://youtube.com'); // blocked - $response->CSP->addConnectSrc('https://*.facebook.com', false); // blocked - $response->CSP->addFontSrc('fonts.example.com'); - $response->CSP->addFormAction('self'); - $response->CSP->addFrameAncestor('none', true); // report this one - $response->CSP->addImageSrc('cdn.example.com'); - $response->CSP->addMediaSrc('cdn.example.com'); - $response->CSP->addManifestSrc('cdn.example.com'); - $response->CSP->addObjectSrc('cdn.example.com', false); // reject from here - $response->CSP->addPluginType('application/pdf', false); // reject this media type - $response->CSP->addScriptSrc('scripts.example.com', true); // allow but report requests from here - $response->CSP->addStyleSrc('css.example.com'); - $response->CSP->addSandbox(['allow-forms', 'allow-scripts']); +name or an array of them.: + +.. literalinclude:: response/012.php + :lines: 2- The first parameter to each of the "add" methods is an appropriate string value, or an array of them. The ``reportOnly`` method allows you to specify the default reporting treatment for subsequent sources, unless over-ridden. For instance, you could specify -that youtube.com was allowed, and then provide several allowed but reported sources:: +that youtube.com was allowed, and then provide several allowed but reported sources: - $response->addChildSrc('https://youtube.com'); // allowed - $response->reportOnly(true); - $response->addChildSrc('https://metube.com'); // allowed but reported - $response->addChildSrc('https://ourtube.com',false); // allowed +.. literalinclude:: response/013.php + :lines: 2- Inline Content -------------- @@ -305,9 +268,10 @@ The methods provided by the parent class that are available are: :rtype: int Returns the currently status code for this response. If no status code has been set, a BadMethodCallException - will be thrown:: + will be thrown: - echo $response->getStatusCode(); + .. literalinclude:: response/014.php + :lines: 2- .. php:method:: setStatusCode($code[, $reason='']) @@ -316,23 +280,26 @@ The methods provided by the parent class that are available are: :returns: The current Response instance :rtype: ``CodeIgniter\HTTP\Response`` - Sets the HTTP status code that should be sent with this response:: + Sets the HTTP status code that should be sent with this response: - $response->setStatusCode(404); + .. literalinclude:: response/015.php + :lines: 2- The reason phrase will be automatically generated based upon the official lists. If you need to set your own - for a custom status code, you can pass the reason phrase as the second parameter:: + for a custom status code, you can pass the reason phrase as the second parameter: - $response->setStatusCode(230, "Tardis initiated"); + .. literalinclude:: response/016.php + :lines: 2- .. php:method:: getReasonPhrase() :returns: The current reason phrase. :rtype: string - Returns the current status code for this response. If not status has been set, will return an empty string:: + Returns the current status code for this response. If not status has been set, will return an empty string: - echo $response->getReasonPhrase(); + .. literalinclude:: response/017.php + :lines: 2- .. php:method:: setDate($date) @@ -340,10 +307,10 @@ The methods provided by the parent class that are available are: :returns: The current response instance. :rtype: ``CodeIgniter\HTTP\Response`` - Sets the date used for this response. The ``$date`` argument must be an instance of ``DateTime``:: + Sets the date used for this response. The ``$date`` argument must be an instance of ``DateTime``: - $date = DateTime::createFromFormat('j-M-Y', '15-Feb-2016'); - $response->setDate($date); + .. literalinclude:: response/018.php + :lines: 2- .. php:method:: setContentType($mime[, $charset='UTF-8']) @@ -352,16 +319,16 @@ The methods provided by the parent class that are available are: :returns: The current response instance. :rtype: ``CodeIgniter\HTTP\Response`` - Sets the content type this response represents:: + Sets the content type this response represents: - $response->setContentType('text/plain'); - $response->setContentType('text/html'); - $response->setContentType('application/json'); + .. literalinclude:: response/019.php + :lines: 2- By default, the method sets the character set to ``UTF-8``. If you need to change this, you can - pass the character set as the second parameter:: + pass the character set as the second parameter: - $response->setContentType('text/plain', 'x-pig-latin'); + .. literalinclude:: response/020.php + :lines: 2- .. php:method:: noCache() @@ -369,12 +336,10 @@ The methods provided by the parent class that are available are: :rtype: ``CodeIgniter\HTTP\Response`` Sets the ``Cache-Control`` header to turn off all HTTP caching. This is the default setting - of all response messages:: + of all response messages: - $response->noCache(); - - // Sets the following header: - Cache-Control: no-store, max-age=0, no-cache + .. literalinclude:: response/021.php + :lines: 2- .. php:method:: setCache($options) @@ -403,10 +368,10 @@ The methods provided by the parent class that are available are: :rtype: ``CodeIgniter\HTTP\Response`` Sets the ``Last-Modified`` header. The ``$date`` object can be either a string or a ``DateTime`` - instance:: + instance: - $response->setLastModified(date('D, d M Y H:i:s')); - $response->setLastModified(DateTime::createFromFormat('u', $time)); + .. literalinclude:: response/022.php + :lines: 2- .. php:method:: send(): Response @@ -437,21 +402,10 @@ The methods provided by the parent class that are available are: **Array Method** Using this method, an associative array is passed as the first - parameter:: - - $cookie = [ - 'name' => 'The Cookie Name', - 'value' => 'The Value', - 'expire' => '86500', - 'domain' => '.some-domain.com', - 'path' => '/', - 'prefix' => 'myprefix_', - 'secure' => true, - 'httponly' => false, - 'samesite' => 'Lax' - ]; - - $response->setCookie($cookie); + parameter: + + .. literalinclude:: response/023.php + :lines: 2- **Notes** @@ -482,9 +436,10 @@ The methods provided by the parent class that are available are: **Discrete Parameters** If you prefer, you can set the cookie by passing data using individual - parameters:: + parameters: - $response->setCookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly, $samesite); + .. literalinclude:: response/024.php + :lines: 2- .. php:method:: deleteCookie($name = ''[, $domain = ''[, $path = '/'[, $prefix = '']]]) @@ -510,9 +465,10 @@ The methods provided by the parent class that are available are: If any of the optional parameters are empty, then the same-named cookie will be deleted across all that apply. - Example:: + Example: - $response->deleteCookie($name); + .. literalinclude:: response/025.php + :lines: 2- .. php:method:: hasCookie($name = ''[, $value = null[, $prefix = '']]) @@ -531,9 +487,10 @@ The methods provided by the parent class that are available are: If a value is given, then the method checks that the cookie exists, and that it has the prescribed value. - Example:: + Example: - if ($response->hasCookie($name)) ... + .. literalinclude:: response/026.php + :lines: 2- .. php:method:: getCookie($name = ''[, $prefix = '']) @@ -544,9 +501,10 @@ The methods provided by the parent class that are available are: Returns the named cookie, if found, or ``null``. If no name is given, returns the array of ``Cookie`` objects. - Example:: + Example: - $cookie = $response->getCookie($name); + .. literalinclude:: response/027.php + :lines: 2- .. php:method:: getCookies() diff --git a/user_guide_src/source/outgoing/response/001.php b/user_guide_src/source/outgoing/response/001.php new file mode 100644 index 000000000000..9815f6f1475d --- /dev/null +++ b/user_guide_src/source/outgoing/response/001.php @@ -0,0 +1,3 @@ +response->setStatusCode(404)->setBody($body); diff --git a/user_guide_src/source/outgoing/response/002.php b/user_guide_src/source/outgoing/response/002.php new file mode 100644 index 000000000000..d5ed0fd87d96 --- /dev/null +++ b/user_guide_src/source/outgoing/response/002.php @@ -0,0 +1,3 @@ +response->setStatusCode(404, 'Nope. Not here.'); diff --git a/user_guide_src/source/outgoing/response/003.php b/user_guide_src/source/outgoing/response/003.php new file mode 100644 index 000000000000..e8d671f81739 --- /dev/null +++ b/user_guide_src/source/outgoing/response/003.php @@ -0,0 +1,10 @@ + true, + 'id' => 123, +]; + +return $this->response->setJSON($data); +// or +return $this->response->setXML($data); diff --git a/user_guide_src/source/outgoing/response/004.php b/user_guide_src/source/outgoing/response/004.php new file mode 100644 index 000000000000..2777aea2795b --- /dev/null +++ b/user_guide_src/source/outgoing/response/004.php @@ -0,0 +1,4 @@ +setHeader('Location', 'http://example.com') + ->setHeader('WWW-Authenticate', 'Negotiate'); diff --git a/user_guide_src/source/outgoing/response/005.php b/user_guide_src/source/outgoing/response/005.php new file mode 100644 index 000000000000..acc3254fa49a --- /dev/null +++ b/user_guide_src/source/outgoing/response/005.php @@ -0,0 +1,4 @@ +setHeader('Cache-Control', 'no-cache') + ->appendHeader('Cache-Control', 'must-revalidate'); diff --git a/user_guide_src/source/outgoing/response/006.php b/user_guide_src/source/outgoing/response/006.php new file mode 100644 index 000000000000..a2fdee1e9ed5 --- /dev/null +++ b/user_guide_src/source/outgoing/response/006.php @@ -0,0 +1,3 @@ +removeHeader('Location'); diff --git a/user_guide_src/source/outgoing/response/007.php b/user_guide_src/source/outgoing/response/007.php new file mode 100644 index 000000000000..c8e545831e00 --- /dev/null +++ b/user_guide_src/source/outgoing/response/007.php @@ -0,0 +1,5 @@ +download($name, $data); diff --git a/user_guide_src/source/outgoing/response/008.php b/user_guide_src/source/outgoing/response/008.php new file mode 100644 index 000000000000..832d75fc0616 --- /dev/null +++ b/user_guide_src/source/outgoing/response/008.php @@ -0,0 +1,4 @@ +download('/path/to/photo.jpg', null); diff --git a/user_guide_src/source/outgoing/response/009.php b/user_guide_src/source/outgoing/response/009.php new file mode 100644 index 000000000000..e75c386647cb --- /dev/null +++ b/user_guide_src/source/outgoing/response/009.php @@ -0,0 +1,3 @@ +download('awkwardEncryptedFileName.fakeExt', null)->setFileName('expenses.csv'); diff --git a/user_guide_src/source/outgoing/response/010.php b/user_guide_src/source/outgoing/response/010.php new file mode 100644 index 000000000000..724c1fb213a1 --- /dev/null +++ b/user_guide_src/source/outgoing/response/010.php @@ -0,0 +1,8 @@ + 300, + 's-maxage' => 900, + 'etag' => 'abcde' +]; +$this->response->setCache($options); diff --git a/user_guide_src/source/outgoing/response/011.php b/user_guide_src/source/outgoing/response/011.php new file mode 100644 index 000000000000..37d2234a5527 --- /dev/null +++ b/user_guide_src/source/outgoing/response/011.php @@ -0,0 +1,3 @@ +CSP->reportOnly(false); + +// specify the origin to use if none provided for a directive +$response->CSP->setDefaultSrc('cdn.example.com'); + +// specify the URL that "report-only" reports get sent to +$response->CSP->setReportURI('http://example.com/csp/reports'); + +// specify that HTTP requests be upgraded to HTTPS +$response->CSP->upgradeInsecureRequests(true); + +// add types or origins to CSP directives +// assuming that the default treatment is to block rather than just report +$response->CSP->addBaseURI('example.com', true); // report only +$response->CSP->addChildSrc('https://youtube.com'); // blocked +$response->CSP->addConnectSrc('https://*.facebook.com', false); // blocked +$response->CSP->addFontSrc('fonts.example.com'); +$response->CSP->addFormAction('self'); +$response->CSP->addFrameAncestor('none', true); // report this one +$response->CSP->addImageSrc('cdn.example.com'); +$response->CSP->addMediaSrc('cdn.example.com'); +$response->CSP->addManifestSrc('cdn.example.com'); +$response->CSP->addObjectSrc('cdn.example.com', false); // reject from here +$response->CSP->addPluginType('application/pdf', false); // reject this media type +$response->CSP->addScriptSrc('scripts.example.com', true); // allow but report requests from here +$response->CSP->addStyleSrc('css.example.com'); +$response->CSP->addSandbox(['allow-forms', 'allow-scripts']); diff --git a/user_guide_src/source/outgoing/response/013.php b/user_guide_src/source/outgoing/response/013.php new file mode 100644 index 000000000000..8cebd2451096 --- /dev/null +++ b/user_guide_src/source/outgoing/response/013.php @@ -0,0 +1,6 @@ +addChildSrc('https://youtube.com'); // allowed +$response->reportOnly(true); +$response->addChildSrc('https://metube.com'); // allowed but reported +$response->addChildSrc('https://ourtube.com',false); // allowed diff --git a/user_guide_src/source/outgoing/response/014.php b/user_guide_src/source/outgoing/response/014.php new file mode 100644 index 000000000000..c05ef6fbe606 --- /dev/null +++ b/user_guide_src/source/outgoing/response/014.php @@ -0,0 +1,3 @@ +getStatusCode(); diff --git a/user_guide_src/source/outgoing/response/015.php b/user_guide_src/source/outgoing/response/015.php new file mode 100644 index 000000000000..3fbc71bc6371 --- /dev/null +++ b/user_guide_src/source/outgoing/response/015.php @@ -0,0 +1,3 @@ +setStatusCode(404); diff --git a/user_guide_src/source/outgoing/response/016.php b/user_guide_src/source/outgoing/response/016.php new file mode 100644 index 000000000000..38d6a8e3b690 --- /dev/null +++ b/user_guide_src/source/outgoing/response/016.php @@ -0,0 +1,3 @@ +setStatusCode(230, "Tardis initiated"); diff --git a/user_guide_src/source/outgoing/response/017.php b/user_guide_src/source/outgoing/response/017.php new file mode 100644 index 000000000000..78ce30be95bb --- /dev/null +++ b/user_guide_src/source/outgoing/response/017.php @@ -0,0 +1,3 @@ +getReasonPhrase(); diff --git a/user_guide_src/source/outgoing/response/018.php b/user_guide_src/source/outgoing/response/018.php new file mode 100644 index 000000000000..606424af8f79 --- /dev/null +++ b/user_guide_src/source/outgoing/response/018.php @@ -0,0 +1,4 @@ +setDate($date); diff --git a/user_guide_src/source/outgoing/response/019.php b/user_guide_src/source/outgoing/response/019.php new file mode 100644 index 000000000000..f74953ae772d --- /dev/null +++ b/user_guide_src/source/outgoing/response/019.php @@ -0,0 +1,5 @@ +setContentType('text/plain'); +$response->setContentType('text/html'); +$response->setContentType('application/json'); diff --git a/user_guide_src/source/outgoing/response/020.php b/user_guide_src/source/outgoing/response/020.php new file mode 100644 index 000000000000..fdbc546b6fad --- /dev/null +++ b/user_guide_src/source/outgoing/response/020.php @@ -0,0 +1,3 @@ +setContentType('text/plain', 'x-pig-latin'); diff --git a/user_guide_src/source/outgoing/response/021.php b/user_guide_src/source/outgoing/response/021.php new file mode 100644 index 000000000000..41745631aaac --- /dev/null +++ b/user_guide_src/source/outgoing/response/021.php @@ -0,0 +1,6 @@ +noCache(); + +// Sets the following header: +Cache-Control: no-store, max-age=0, no-cache diff --git a/user_guide_src/source/outgoing/response/022.php b/user_guide_src/source/outgoing/response/022.php new file mode 100644 index 000000000000..5a841f28d2ce --- /dev/null +++ b/user_guide_src/source/outgoing/response/022.php @@ -0,0 +1,4 @@ +setLastModified(date('D, d M Y H:i:s')); +$response->setLastModified(DateTime::createFromFormat('u', $time)); diff --git a/user_guide_src/source/outgoing/response/023.php b/user_guide_src/source/outgoing/response/023.php new file mode 100644 index 000000000000..35d072f354d9 --- /dev/null +++ b/user_guide_src/source/outgoing/response/023.php @@ -0,0 +1,15 @@ + 'The Cookie Name', + 'value' => 'The Value', + 'expire' => '86500', + 'domain' => '.some-domain.com', + 'path' => '/', + 'prefix' => 'myprefix_', + 'secure' => true, + 'httponly' => false, + 'samesite' => 'Lax' +]; + +$response->setCookie($cookie); diff --git a/user_guide_src/source/outgoing/response/024.php b/user_guide_src/source/outgoing/response/024.php new file mode 100644 index 000000000000..3b75c4004362 --- /dev/null +++ b/user_guide_src/source/outgoing/response/024.php @@ -0,0 +1,3 @@ +setCookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly, $samesite); diff --git a/user_guide_src/source/outgoing/response/025.php b/user_guide_src/source/outgoing/response/025.php new file mode 100644 index 000000000000..a2343928babe --- /dev/null +++ b/user_guide_src/source/outgoing/response/025.php @@ -0,0 +1,3 @@ +deleteCookie($name); diff --git a/user_guide_src/source/outgoing/response/026.php b/user_guide_src/source/outgoing/response/026.php new file mode 100644 index 000000000000..55149496da87 --- /dev/null +++ b/user_guide_src/source/outgoing/response/026.php @@ -0,0 +1,3 @@ +hasCookie($name)) ... diff --git a/user_guide_src/source/outgoing/response/027.php b/user_guide_src/source/outgoing/response/027.php new file mode 100644 index 000000000000..1d76679940c8 --- /dev/null +++ b/user_guide_src/source/outgoing/response/027.php @@ -0,0 +1,3 @@ +getCookie($name); diff --git a/user_guide_src/source/outgoing/table.rst b/user_guide_src/source/outgoing/table.rst index 01b7dabe5cef..9890a18acbe4 100644 --- a/user_guide_src/source/outgoing/table.rst +++ b/user_guide_src/source/outgoing/table.rst @@ -17,9 +17,10 @@ Initializing the Class ====================== The Table class is not provided as a service, and should be instantiated -"normally", for instance:: +"normally", for instance: - $table = new \CodeIgniter\View\Table(); +.. literalinclude:: table/001.php + :lines: 2- Examples ======== @@ -29,100 +30,37 @@ multi-dimensional array. Note that the first array index will become the table heading (or you can set your own headings using the ``setHeading()`` method described in the function reference below). -:: - - $table = new \CodeIgniter\View\Table(); - - $data = [ - ['Name', 'Color', 'Size'], - ['Fred', 'Blue', 'Small'], - ['Mary', 'Red', 'Large'], - ['John', 'Green', 'Medium'], - ]; - - echo $table->generate($data); +.. literalinclude:: table/002.php + :lines: 2- Here is an example of a table created from a database query result. The table class will automatically generate the headings based on the table names (or you can set your own headings using the ``setHeading()`` method described in the class reference below). -:: - - $table = new \CodeIgniter\View\Table(); - - $query = $db->query('SELECT * FROM my_table'); - - echo $table->generate($query); +.. literalinclude:: table/003.php + :lines: 2- Here is an example showing how you might create a table using discrete -parameters:: +parameters: - $table = new \CodeIgniter\View\Table(); - - $table->setHeading('Name', 'Color', 'Size'); - - $table->addRow('Fred', 'Blue', 'Small'); - $table->addRow('Mary', 'Red', 'Large'); - $table->addRow('John', 'Green', 'Medium'); - - echo $table->generate(); +.. literalinclude:: table/004.php + :lines: 2- Here is the same example, except instead of individual parameters, -arrays are used:: - - $table = new \CodeIgniter\View\Table(); - - $table->setHeading(array('Name', 'Color', 'Size')); +arrays are used: - $table->addRow(['Fred', 'Blue', 'Small']); - $table->addRow(['Mary', 'Red', 'Large']); - $table->addRow(['John', 'Green', 'Medium']); - - echo $table->generate(); +.. literalinclude:: table/005.php + :lines: 2- Changing the Look of Your Table =============================== The Table Class permits you to set a table template with which you can -specify the design of your layout. Here is the template prototype:: - - $template = [ - 'table_open' => '
    {duration} {! sql !}
    ' . ($hasChildren ? '' : '') . $row['name'] . '' . (($hasChildren || $isQuery) ? '' : '') . $row['name'] . '' . $row['component'] . '' . number_format($row['duration'] * 1000, 2) . ' ms"; @@ -211,12 +213,22 @@ protected function renderTimelineRecursive(array $rows, float $startTime, int $s $styleCount++; // Add children if any - if ($hasChildren) { + if ($hasChildren || $isQuery) { $output .= '
    '; $output .= ''; $output .= ''; - $output .= $this->renderTimelineRecursive($row['children'], $startTime, $segmentCount, $segmentDuration, $styles, $styleCount, $level + 1, true); + + if ($isQuery) { + // Output query string if query + $output .= ''; + $output .= ''; + $output .= ''; + } else { + // Recursively render children + $output .= $this->renderTimelineRecursive($row['children'], $startTime, $segmentCount, $segmentDuration, $styles, $styleCount, $level + 1, true); + } + $output .= ''; $output .= '
    ' . $row['query'] . '
    '; $output .= '
    ' . (($hasChildren || $isQuery) ? '' : '') . $row['name'] . '' . ($hasChildren || $isQuery ? '' : '') . $row['name'] . '' . $row['component'] . '' . number_format($row['duration'] * 1000, 2) . ' ms"; From e393aac29dec267f11a454a2ef93f226f35f0db2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Oct 2021 14:30:16 +0900 Subject: [PATCH 0457/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/helpers/form_helper.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/helpers/form_helper.rst b/user_guide_src/source/helpers/form_helper.rst index f4e5b09c1af1..e8788de0a499 100644 --- a/user_guide_src/source/helpers/form_helper.rst +++ b/user_guide_src/source/helpers/form_helper.rst @@ -105,7 +105,7 @@ The following functions are available: - .. note:: To use auto generation of CSRF field, you need to turn CSRF filter on to the form page. In most cases it is requested using the `GET` method. + .. note:: To use auto-generation of CSRF field, you need to turn CSRF filter on to the form page. In most cases it is requested using the ``GET`` method. **Adding Hidden Input Fields** From 105253c076a2da292d5bda59b69b36635a6ee018 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Oct 2021 14:31:42 +0900 Subject: [PATCH 0458/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/installation/upgrade_security.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 61cf699658b2..5f2d8ecfdb66 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -30,8 +30,8 @@ Upgrade Guide ] ]; -2. Within your html forms you have to remove the csrf input which looks similar to ````. -3. Now within your html forms you have to add ```` somewhere in the form body, unless you are using ``form_open()``. +2. Within your HTML forms you have to remove the CSRF input field which looks similar to ````. +3. Now, within your HTML forms you have to add ```` somewhere in the form body, unless you are using ``form_open()``. Code Example ============ From a790f87b1d6c2c38b904a18c130124da0d3342f2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Oct 2021 14:31:50 +0900 Subject: [PATCH 0459/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/libraries/security.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 758d16b54173..3e173aa4bc45 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -61,8 +61,8 @@ If you use the :doc:`form helper <../helpers/form_helper>`, then :func:`form_open()` will automatically insert a hidden csrf field in your forms. -.. note:: To use auto generation of CSRF field, you need to turn CSRF filter on to the form page. - In most cases it is requested using the `GET` method. +.. note:: To use auto-generation of CSRF field, you need to turn CSRF filter on to the form page. + In most cases it is requested using the ``GET`` method. If not, then you can use the always available ``csrf_token()`` and ``csrf_hash()`` functions From b3cda21155714546e64da3045003a95a57d96226 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Oct 2021 14:34:12 +0900 Subject: [PATCH 0460/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/libraries/security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 3e173aa4bc45..3c2ad833f1d8 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -93,7 +93,7 @@ The order of checking the availability of the CSRF token is as follows: 1. ``$_POST`` array 2. HTTP header -3. ``php://input`` (JSON request) - bare in mind that this approach is the slowest one since we have to decode JSON and then encode it again +3. ``php://input`` (JSON request) - bear in mind that this approach is the slowest one since we have to decode JSON and then re-encode it Tokens Regeneration =================== From 51c070fe496e891763cfc1025f8395ecc09a0c75 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Oct 2021 14:34:20 +0900 Subject: [PATCH 0461/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/libraries/security.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 3c2ad833f1d8..9497723c4b46 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -95,7 +95,7 @@ The order of checking the availability of the CSRF token is as follows: 2. HTTP header 3. ``php://input`` (JSON request) - bear in mind that this approach is the slowest one since we have to decode JSON and then re-encode it -Tokens Regeneration +Token Regeneration =================== Tokens may be either regenerated on every submission (default) or From 125052ade293f46a30b7cc4d5363caf7709c1d9e Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 14 Oct 2021 02:11:05 +0900 Subject: [PATCH 0462/2325] docs: Github -> GitHub --- README.md | 4 ++-- admin/css/debug-toolbar/_settings.scss | 2 +- admin/framework/README.md | 2 +- admin/starter/README.md | 2 +- tests/_support/Config/Registrar.php | 2 +- user_guide_src/ghpages.rst | 2 +- user_guide_src/source/installation/repositories.rst | 6 +++--- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1bcfdfcb922d..fa5194457cbc 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,7 @@ CodeIgniter is developed completely on a volunteer basis. As such, please give u for your issues to be reviewed. If you haven't heard from one of the team in that time period, feel free to leave a comment on the issue so that it gets brought back to our attention. -We use Github issues to track **BUGS** and to track approved **DEVELOPMENT** work packages. +We use GitHub issues to track **BUGS** and to track approved **DEVELOPMENT** work packages. We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss FEATURE REQUESTS. @@ -54,7 +54,7 @@ If you raise an issue here that pertains to support or a feature request, it wil be closed! If you are not sure if you have found a bug, raise a thread on the forum first - someone else may have encountered the same thing. -Before raising a new Github issue, please check that your bug hasn't already +Before raising a new GitHub issue, please check that your bug hasn't already been reported or fixed. We use pull requests (PRs) for CONTRIBUTIONS to the repository. diff --git a/admin/css/debug-toolbar/_settings.scss b/admin/css/debug-toolbar/_settings.scss index 06a51de634bb..1bb1386a46a0 100644 --- a/admin/css/debug-toolbar/_settings.scss +++ b/admin/css/debug-toolbar/_settings.scss @@ -1,7 +1,7 @@ // FONT // ========================================================================== */ -// Standard "sans-serif" font stack used by Github +// Standard "sans-serif" font stack used by GitHub $base-font: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; // Default size, all other styles are based on this size diff --git a/admin/framework/README.md b/admin/framework/README.md index 1f95a415d37a..6b7c6673e33a 100644 --- a/admin/framework/README.md +++ b/admin/framework/README.md @@ -28,7 +28,7 @@ framework are exposed. ## Repository Management -We use Github issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. +We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss FEATURE REQUESTS. diff --git a/admin/starter/README.md b/admin/starter/README.md index 41ce92110d7a..363e7c89f304 100644 --- a/admin/starter/README.md +++ b/admin/starter/README.md @@ -41,7 +41,7 @@ framework are exposed. ## Repository Management -We use Github issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. +We use GitHub issues, in our main repository, to track **BUGS** and to track approved **DEVELOPMENT** work packages. We use our [forum](http://forum.codeigniter.com) to provide SUPPORT and to discuss FEATURE REQUESTS. diff --git a/tests/_support/Config/Registrar.php b/tests/_support/Config/Registrar.php index 15e8f54ff92d..989b406655b1 100644 --- a/tests/_support/Config/Registrar.php +++ b/tests/_support/Config/Registrar.php @@ -111,7 +111,7 @@ public static function Database() { $config = []; - // Under Github Actions, we can set an ENV var named 'DB' + // Under GitHub Actions, we can set an ENV var named 'DB' // so that we can test against multiple databases. if ($group = getenv('DB')) { if (! empty(self::$dbConfig[$group])) { diff --git a/user_guide_src/ghpages.rst b/user_guide_src/ghpages.rst index 4699d38f978d..15619a060e0d 100644 --- a/user_guide_src/ghpages.rst +++ b/user_guide_src/ghpages.rst @@ -6,7 +6,7 @@ The intent is, eventually, for the in-progress user guide to be automatically generated as part of a PR merge. This writeup explains how it can be done manually in the meantime. -The user guide takes advantage of Github pages, where the "gh-pages" branch of +The user guide takes advantage of GitHub pages, where the "gh-pages" branch of a repo, containing HTML only, is accessible through `github.io `_. diff --git a/user_guide_src/source/installation/repositories.rst b/user_guide_src/source/installation/repositories.rst index b585ca8e8f6b..9e4e0abc9db9 100644 --- a/user_guide_src/source/installation/repositories.rst +++ b/user_guide_src/source/installation/repositories.rst @@ -2,7 +2,7 @@ CodeIgniter Repositories ######################## The CodeIgniter 4 open source project has its own -`Github organization `_. +`GitHub organization `_. There are several development repositories, of interest to potential contributors: @@ -33,7 +33,7 @@ are not directly contributed to. In all the above, the latest version of a repository can be downloaded by selecting the "releases" link in the secondary navbar inside -the "Code" tab of its Github repository page. The current (in development) version of each can +the "Code" tab of its GitHub repository page. The current (in development) version of each can be cloned or downloaded by selecting the "Clone or download" dropdown button on the right-hand side if the repository homepage. @@ -54,7 +54,7 @@ CodeIgniter 4 Projects ====================== We maintain a `codeigniter4projects `_ organization -on Github as well, with projects that are not part of the framework, +on GitHub as well, with projects that are not part of the framework, but which showcase it or make it easier to work with! +------------------+--------------+-----------------------------------------------------------------+ From 101db1523eedcaa01c7580403b0b321becaac3ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Oct 2021 01:11:54 +0800 Subject: [PATCH 0463/2325] chore(deps-dev): update rector/rector requirement Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.11.57...0.11.58) --- updated-dependencies: - dependency-name: rector/rector dependency-type: direct:development ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index fd8b7198f11e..8a8fdaf00aa2 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.57", + "rector/rector": "0.11.58", "symplify/package-builder": "^9.3" }, "suggest": { From 00b6e325f63623b7ea1d21c7dce2f1987f063cd5 Mon Sep 17 00:00:00 2001 From: ytetsuro Date: Fri, 15 Oct 2021 16:23:48 +0900 Subject: [PATCH 0464/2325] docs: add escape for identifiers. --- user_guide_src/source/dbmgmt/forge.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index d7b3c4546825..66d7ebd75e09 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -312,7 +312,7 @@ Execute a DROP KEY. :: - // Produces: DROP INDEX users_index ON tablename + // Produces: DROP INDEX `users_index` ON `tablename` $forge->dropKey('tablename','users_index'); Renaming a table From 22a4c24798b7549ca9bc1c070039fbd03aa6c78d Mon Sep 17 00:00:00 2001 From: ytetsuro Date: Fri, 15 Oct 2021 16:29:55 +0900 Subject: [PATCH 0465/2325] docs: add escape for identifiers. --- user_guide_src/source/dbmgmt/forge.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/dbmgmt/forge.rst b/user_guide_src/source/dbmgmt/forge.rst index a0c677d3162b..6fedb1608af5 100644 --- a/user_guide_src/source/dbmgmt/forge.rst +++ b/user_guide_src/source/dbmgmt/forge.rst @@ -46,7 +46,7 @@ or will check if a database exists before create it (depending on DBMS). :: $forge->createDatabase('my_db', true); - // gives CREATE DATABASE IF NOT EXISTS my_db + // gives CREATE DATABASE IF NOT EXISTS `my_db` // or will check if a database exists **$forge->dropDatabase('db_name')** @@ -182,7 +182,7 @@ Primary Key. :: $forge->addField('id'); - // gives id INT(9) NOT NULL AUTO_INCREMENT + // gives `id` INT(9) NOT NULL AUTO_INCREMENT Adding Keys =========== @@ -280,10 +280,10 @@ Execute a DROP TABLE statement and optionally add an IF EXISTS clause. :: - // Produces: DROP TABLE table_name + // Produces: DROP TABLE `table_name` $forge->dropTable('table_name'); - // Produces: DROP TABLE IF EXISTS table_name + // Produces: DROP TABLE IF EXISTS `table_name` $forge->dropTable('table_name', true); A third parameter can be passed to add a "CASCADE" option, which might be required for some @@ -291,7 +291,7 @@ drivers to handle removal of tables with foreign keys. :: - // Produces: DROP TABLE table_name CASCADE + // Produces: DROP TABLE `table_name` CASCADE $forge->dropTable('table_name', false, true); Dropping a Foreign Key @@ -301,7 +301,7 @@ Execute a DROP FOREIGN KEY. :: - // Produces: ALTER TABLE tablename DROP FOREIGN KEY users_foreign + // Produces: ALTER TABLE `tablename` DROP FOREIGN KEY `users_foreign` $forge->dropForeignKey('tablename','users_foreign'); Renaming a table @@ -312,7 +312,7 @@ Executes a TABLE rename :: $forge->renameTable('old_table_name', 'new_table_name'); - // gives ALTER TABLE old_table_name RENAME TO new_table_name + // gives ALTER TABLE `old_table_name` RENAME TO `new_table_name` **************** Modifying Tables @@ -333,7 +333,7 @@ number of additional fields. 'preferences' => ['type' => 'TEXT'] ]; $forge->addColumn('table_name', $fields); - // Executes: ALTER TABLE table_name ADD preferences TEXT + // Executes: ALTER TABLE `table_name` ADD `preferences` TEXT If you are using MySQL or CUBIRD, then you can take advantage of their AFTER and FIRST clauses to position the new column. @@ -386,7 +386,7 @@ change the name, you can add a "name" key into the field defining array. ], ]; $forge->modifyColumn('table_name', $fields); - // gives ALTER TABLE table_name CHANGE old_name new_name TEXT + // gives ALTER TABLE `table_name` CHANGE `old_name` `new_name` TEXT *************** Class Reference From 2007d6434d9fc1d5cf30271c82a4459e92b403e2 Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Sat, 16 Oct 2021 17:04:50 +0200 Subject: [PATCH 0466/2325] [Debug] Improve keyword highlighting and escaping of query strings * Sort highlighted keywords alphabetically. * Add new composite keywords. * Deconstruct composite keywords. * Add basic test for query highlighting in toolbar. * Ignore keywords in string values of queries. * Use generic table and column names for tests. * Add credits for regex pattern. * Escape HTML entities when formatting query string. * Use esc() for escaping query string. --- system/Database/Query.php | 53 ++++++++++++++----------- tests/system/Database/BaseQueryTest.php | 33 +++++++++++++++ 2 files changed, 63 insertions(+), 23 deletions(-) diff --git a/system/Database/Query.php b/system/Database/Query.php index 01d27d8bdfff..a4bb1b2b9de5 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -367,46 +367,53 @@ public function debugToolbarDisplay(): string { // Key words we want bolded static $highlight = [ - 'SELECT', - 'DISTINCT', - 'FROM', - 'WHERE', 'AND', - 'LEFT JOIN', - 'RIGHT JOIN', - 'JOIN', - 'ORDER BY', + 'AS', 'ASC', + 'AVG', + 'BY', + 'COUNT', 'DESC', - 'GROUP BY', - 'LIMIT', - 'INSERT', - 'INTO', - 'VALUES', - 'UPDATE', - 'OR', + 'DISTINCT', + 'FROM', + 'GROUP', 'HAVING', - 'OFFSET', - 'NOT IN', 'IN', + 'INNER', + 'INSERT', + 'INTO', + 'IS', + 'JOIN', + 'LEFT', 'LIKE', - 'NOT LIKE', - 'COUNT', + 'LIMIT', 'MAX', 'MIN', + 'NOT', + 'NULL', + 'OFFSET', 'ON', - 'AS', - 'AVG', + 'OR', + 'ORDER', + 'RIGHT', + 'SELECT', 'SUM', + 'UPDATE', + 'VALUES', + 'WHERE', ]; if (empty($this->finalQueryString)) { $this->compileBinds(); // @codeCoverageIgnore } - $sql = $this->finalQueryString; + $sql = esc($this->finalQueryString); - $search = '/\b(?:' . implode('|', $highlight) . ')\b/'; + /** + * @see https://stackoverflow.com/a/20767160 + * @see https://regex101.com/r/hUlrGN/4 + */ + $search = '/\b(?:' . implode('|', $highlight) . ')\b(?![^(')]*'(?:(?:[^(')]*'){2})*[^(')]*$)/'; return preg_replace_callback($search, static function ($matches) { return '' . str_replace(' ', ' ', $matches[0]) . ''; diff --git a/tests/system/Database/BaseQueryTest.php b/tests/system/Database/BaseQueryTest.php index deec43c4f5bb..fe942ffeb187 100644 --- a/tests/system/Database/BaseQueryTest.php +++ b/tests/system/Database/BaseQueryTest.php @@ -363,4 +363,37 @@ public function testSetQueryBinds() $this->assertSame($expected, $query->getQuery()); } + + public function queryKeywords() + { + return [ + 'highlightKeyWords' => [ + 'SELECT `a`.*, `b`.`id` AS `b_id` FROM `a` LEFT JOIN `b` ON `b`.`a_id` = `a`.`id` WHERE `b`.`id` IN ('1') AND `a`.`deleted_at` IS NOT NULL LIMIT 1', + 'SELECT `a`.*, `b`.`id` AS `b_id` FROM `a` LEFT JOIN `b` ON `b`.`a_id` = `a`.`id` WHERE `b`.`id` IN (\'1\') AND `a`.`deleted_at` IS NOT NULL LIMIT 1', + ], + 'ignoreKeyWordsInValues' => [ + 'SELECT * FROM `a` WHERE `a`.`col` = 'SELECT escaped keyword in value' LIMIT 1', + 'SELECT * FROM `a` WHERE `a`.`col` = \'SELECT escaped keyword in value\' LIMIT 1', + ], + 'escapeHtmlValues' => [ + 'SELECT '<s>' FROM dual', + 'SELECT \'\' FROM dual', + ], + ]; + } + + /** + * @dataProvider queryKeywords + * + * @param mixed $expected + * @param mixed $sql + */ + public function testHighlightQueryKeywords($expected, $sql) + { + $query = new Query($this->db); + $query->setQuery($sql); + $query->getQuery(); + + $this->assertSame($expected, $query->debugToolbarDisplay()); + } } From 26e0025df9c508972934fa64cbf1f3be728bc60a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 17 Oct 2021 00:11:01 +0900 Subject: [PATCH 0467/2325] Fix CSRF filter does not work when set it to only post * refactor: case the existence of config files with if statements To make it easier to know which parts to delete in the future. * docs: fix PHPDoc explanation * fix: bug that CSRF cookie is not sent just by calling csrf_hash() When the CSRF filter was set to POST method, it did not work. * refactor: replace deprecated method getHeader() * refactor: extract method * refactor: extract method * refactor: extract method * refactor: use $this->hash instead of $_COOKIE * test: fix the timing for setting superglobals * test: fix Cannot modify header information ErrorException: Cannot modify header information - headers already sent by ... * style: vendor/bin/rector process * refactor: ensure instance It becomes clear that it is `SecurityConfig`. Co-authored-by: Abdul Malik Ikhsan * refactor: ensure instance It becomes clear that it is `CookieConfig`. Co-authored-by: Abdul Malik Ikhsan * refactor: when $cookie is null, Cookie::setDefaults($cookie) does nothing * refactor: extract method * fix: make private extracted methods * fix: make private added property * fix: fallback to the local properties Takes care when a user removes properties in config classes. * refactor: use $request instead of $_POST Co-authored-by: Abdul Malik Ikhsan --- app/Config/Security.php | 2 +- system/Security/Security.php | 128 ++++++++++++++------ tests/system/CommonFunctionsTest.php | 3 + tests/system/CommonSingleServiceTest.php | 6 +- tests/system/Config/ServicesTest.php | 2 + tests/system/Helpers/SecurityHelperTest.php | 5 + tests/system/Security/SecurityTest.php | 48 +++++--- 7 files changed, 135 insertions(+), 59 deletions(-) diff --git a/app/Config/Security.php b/app/Config/Security.php index 82afb9396ec4..01000ff52088 100644 --- a/app/Config/Security.php +++ b/app/Config/Security.php @@ -57,7 +57,7 @@ class Security extends BaseConfig * CSRF Regenerate * -------------------------------------------------------------------------- * - * Regenerate CSRF Token on every request. + * Regenerate CSRF Token on every submission. * * @var bool */ diff --git a/system/Security/Security.php b/system/Security/Security.php index 0f508628e240..7bf3b6689095 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -17,6 +17,7 @@ use Config\App; use Config\Cookie as CookieConfig; use Config\Security as SecurityConfig; +use Config\Services; /** * Class Security @@ -77,8 +78,6 @@ class Security implements SecurityInterface * Defaults to two hours (in seconds). * * @var int - * - * @deprecated */ protected $expires = 7200; @@ -117,6 +116,18 @@ class Security implements SecurityInterface */ protected $samesite = Cookie::SAMESITE_LAX; + /** + * @var RequestInterface + */ + private $request; + + /** + * CSRF Cookie Name without Prefix + * + * @var string + */ + private $rawCookieName; + /** * Constructor. * @@ -125,27 +136,46 @@ class Security implements SecurityInterface */ public function __construct(App $config) { - /** @var SecurityConfig $security */ + /** @var SecurityConfig|null $security */ $security = config('Security'); // Store CSRF-related configurations - $this->tokenName = $security->tokenName ?? $config->CSRFTokenName ?? $this->tokenName; - $this->headerName = $security->headerName ?? $config->CSRFHeaderName ?? $this->headerName; - $this->regenerate = $security->regenerate ?? $config->CSRFRegenerate ?? $this->regenerate; - $rawCookieName = $security->cookieName ?? $config->CSRFCookieName ?? $this->cookieName; + if ($security instanceof SecurityConfig) { + $this->tokenName = $security->tokenName ?? $this->tokenName; + $this->headerName = $security->headerName ?? $this->headerName; + $this->regenerate = $security->regenerate ?? $this->regenerate; + $this->rawCookieName = $security->cookieName ?? $this->rawCookieName; + $this->expires = $security->expires ?? $this->expires; + } else { + // `Config/Security.php` is absence + $this->tokenName = $config->CSRFTokenName ?? $this->tokenName; + $this->headerName = $config->CSRFHeaderName ?? $this->headerName; + $this->regenerate = $config->CSRFRegenerate ?? $this->regenerate; + $this->rawCookieName = $config->CSRFCookieName ?? $this->rawCookieName; + $this->expires = $config->CSRFExpire ?? $this->expires; + } - /** @var CookieConfig $cookie */ - $cookie = config('Cookie'); + $this->configureCookie($config); - $cookiePrefix = $cookie->prefix ?? $config->cookiePrefix; - $this->cookieName = $cookiePrefix . $rawCookieName; + $this->request = Services::request(); - $expires = $security->expires ?? $config->CSRFExpire ?? 7200; + $this->generateHash(); + } + + private function configureCookie(App $config): void + { + /** @var CookieConfig|null $cookie */ + $cookie = config('Cookie'); - Cookie::setDefaults($cookie); - $this->cookie = new Cookie($rawCookieName, $this->generateHash(), [ - 'expires' => $expires === 0 ? 0 : time() + $expires, - ]); + if ($cookie instanceof CookieConfig) { + $cookiePrefix = $cookie->prefix; + $this->cookieName = $cookiePrefix . $this->rawCookieName; + Cookie::setDefaults($cookie); + } else { + // `Config/Cookie.php` is absence + $cookiePrefix = $config->cookiePrefix; + $this->cookieName = $cookiePrefix . $this->rawCookieName; + } } /** @@ -202,26 +232,15 @@ public function verify(RequestInterface $request) return $this->sendCookie($request); } - // Does the token exist in POST, HEADER or optionally php:://input - json data. - if ($request->hasHeader($this->headerName) && ! empty($request->getHeader($this->headerName)->getValue())) { - $tokenName = $request->getHeader($this->headerName)->getValue(); - } else { - $json = json_decode($request->getBody()); - - if (! empty($request->getBody()) && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { - $tokenName = $json->{$this->tokenName} ?? null; - } else { - $tokenName = null; - } - } - - $token = $_POST[$this->tokenName] ?? $tokenName; + $token = $this->getPostedToken($request); // Does the tokens exist in both the POST/POSTed JSON and COOKIE arrays and match? - if (! isset($token, $_COOKIE[$this->cookieName]) || ! hash_equals($token, $_COOKIE[$this->cookieName])) { + if (! isset($token, $this->hash) || ! hash_equals($this->hash, $token)) { throw SecurityException::forDisallowedAction(); } + $json = json_decode($request->getBody()); + if (isset($_POST[$this->tokenName])) { // We kill this since we're done and we don't want to pollute the POST array. unset($_POST[$this->tokenName]); @@ -237,14 +256,31 @@ public function verify(RequestInterface $request) unset($_COOKIE[$this->cookieName]); } - $this->cookie = $this->cookie->withValue($this->generateHash()); - $this->sendCookie($request); + $this->generateHash(); log_message('info', 'CSRF token verified.'); return $this; } + private function getPostedToken(RequestInterface $request): ?string + { + // Does the token exist in POST, HEADER or optionally php:://input - json data. + if ($request->hasHeader($this->headerName) && ! empty($request->header($this->headerName)->getValue())) { + $tokenName = $request->header($this->headerName)->getValue(); + } else { + $json = json_decode($request->getBody()); + + if (! empty($request->getBody()) && ! empty($json) && json_last_error() === JSON_ERROR_NONE) { + $tokenName = $json->{$this->tokenName} ?? null; + } else { + $tokenName = null; + } + } + + return $request->getPost($this->tokenName) ?? $tokenName; + } + /** * Returns the CSRF Hash. */ @@ -373,19 +409,37 @@ protected function generateHash(): string // We don't necessarily want to regenerate it with // each page load since a page could contain embedded // sub-pages causing this feature to fail - if (isset($_COOKIE[$this->cookieName]) - && is_string($_COOKIE[$this->cookieName]) - && preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->cookieName]) === 1 - ) { + if ($this->isHashInCookie()) { return $this->hash = $_COOKIE[$this->cookieName]; } $this->hash = bin2hex(random_bytes(16)); + + $this->saveHashInCookie(); } return $this->hash; } + private function isHashInCookie(): bool + { + return isset($_COOKIE[$this->cookieName]) + && is_string($_COOKIE[$this->cookieName]) + && preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->cookieName]) === 1; + } + + private function saveHashInCookie() + { + $this->cookie = new Cookie( + $this->rawCookieName, + $this->hash, + [ + 'expires' => $this->expires === 0 ? 0 : time() + $this->expires, + ] + ); + $this->sendCookie($this->request); + } + /** * CSRF Send Cookie * diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 1ce1e7ab61a2..ad5ae969b1bc 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -22,6 +22,7 @@ use CodeIgniter\Session\Session; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockIncomingRequest; +use CodeIgniter\Test\Mock\MockSecurity; use CodeIgniter\Test\Mock\MockSession; use CodeIgniter\Test\TestLogger; use Config\App; @@ -232,6 +233,8 @@ public function testAppTimezone() public function testCSRFToken() { + Services::injectMock('security', new MockSecurity(new App())); + $this->assertSame('csrf_test_name', csrf_token()); } diff --git a/tests/system/CommonSingleServiceTest.php b/tests/system/CommonSingleServiceTest.php index 1dca6f823ab8..ede9d9b0445e 100644 --- a/tests/system/CommonSingleServiceTest.php +++ b/tests/system/CommonSingleServiceTest.php @@ -13,6 +13,8 @@ use CodeIgniter\Config\Services; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\Mock\MockSecurity; +use Config\App; use ReflectionClass; use ReflectionMethod; @@ -26,6 +28,8 @@ final class CommonSingleServiceTest extends CIUnitTestCase */ public function testSingleServiceWithNoParamsSupplied(string $service): void { + Services::injectMock('security', new MockSecurity(new App())); + $service1 = single_service($service); $service2 = single_service($service); @@ -90,7 +94,7 @@ public static function serviceNamesProvider(): iterable continue; } - yield [$name]; + yield $name => [$name]; } } } diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php index 6733ee06fff6..2712bdce8dd5 100644 --- a/tests/system/Config/ServicesTest.php +++ b/tests/system/Config/ServicesTest.php @@ -397,6 +397,8 @@ public function testRouter() public function testSecurity() { + Services::injectMock('security', new MockSecurity(new App())); + $result = Services::security(); $this->assertInstanceOf(Security::class, $result); } diff --git a/tests/system/Helpers/SecurityHelperTest.php b/tests/system/Helpers/SecurityHelperTest.php index 3e1d8c332080..4d8169f6f712 100644 --- a/tests/system/Helpers/SecurityHelperTest.php +++ b/tests/system/Helpers/SecurityHelperTest.php @@ -12,6 +12,9 @@ namespace CodeIgniter\Helpers; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\Mock\MockSecurity; +use Config\App; +use Tests\Support\Config\Services as Services; /** * @internal @@ -27,6 +30,8 @@ protected function setUp(): void public function testSanitizeFilenameSimpleSuccess() { + Services::injectMock('security', new MockSecurity(new App())); + $this->assertSame('hello.doc', sanitize_filename('hello.doc')); } diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index aadb84aa775b..74e8621e3a34 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -41,7 +41,11 @@ protected function setUp(): void public function testBasicConfigIsSaved() { - $security = new Security(new MockAppConfig()); + $config = new MockAppConfig(); + $security = $this->getMockBuilder(Security::class) + ->setConstructorArgs([$config]) + ->onlyMethods(['doSendCookie']) + ->getMock(); $hash = $security->getHash(); @@ -53,7 +57,11 @@ public function testHashIsReadFromCookie() { $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $security = new Security(new MockAppConfig()); + $config = new MockAppConfig(); + $security = $this->getMockBuilder(Security::class) + ->setConstructorArgs([$config]) + ->onlyMethods(['doSendCookie']) + ->getMock(); $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); } @@ -84,14 +92,14 @@ public function testCSRFVerifyPostThrowsExceptionOnNoMatch() public function testCSRFVerifyPostReturnsSelfOnMatch() { - $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $security = new MockSecurity(new MockAppConfig()); + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -114,15 +122,15 @@ public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch() public function testCSRFVerifyHeaderReturnsSelfOnMatch() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['foo'] = 'bar'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $security = new MockSecurity(new MockAppConfig()); $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST['foo'] = 'bar'; - $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -145,14 +153,14 @@ public function testCSRFVerifyJsonThrowsExceptionOnNoMatch() public function testCSRFVerifyJsonReturnsSelfOnMatch() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $security = new MockSecurity(new MockAppConfig()); $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}'); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $this->assertInstanceOf(Security::class, $security->verify($request)); $this->assertLogged('info', 'CSRF token verified.'); @@ -170,6 +178,10 @@ public function testSanitizeFilename() public function testRegenerateWithFalseSecurityRegenerateProperty() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $config = new SecurityConfig(); $config->regenerate = false; Factories::injectMock('config', 'Security', $config); @@ -177,10 +189,6 @@ public function testRegenerateWithFalseSecurityRegenerateProperty() $security = new MockSecurity(new MockAppConfig()); $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $oldHash = $security->getHash(); $security->verify($request); $newHash = $security->getHash(); @@ -190,6 +198,10 @@ public function testRegenerateWithFalseSecurityRegenerateProperty() public function testRegenerateWithTrueSecurityRegenerateProperty() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + $config = new SecurityConfig(); $config->regenerate = true; Factories::injectMock('config', 'Security', $config); @@ -197,10 +209,6 @@ public function testRegenerateWithTrueSecurityRegenerateProperty() $security = new MockSecurity(new MockAppConfig()); $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; - $oldHash = $security->getHash(); $security->verify($request); $newHash = $security->getHash(); From f3424a5062eba1e05edbcb1f609756fdcfcb25f0 Mon Sep 17 00:00:00 2001 From: uraku Date: Sun, 17 Oct 2021 02:05:17 +0900 Subject: [PATCH 0468/2325] Fix GC issue when session lifetime is set to 0 * fix #4169 GC processing issues when session lifetime is 0 * Added description about the structure of the session library of the document. * Apply suggestions from code review Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- system/Session/Session.php | 2 +- user_guide_src/source/libraries/sessions.rst | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/system/Session/Session.php b/system/Session/Session.php index abeed407425b..ebfb6a94d082 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -306,7 +306,7 @@ protected function configure() if (! isset($this->sessionExpiration)) { $this->sessionExpiration = (int) ini_get('session.gc_maxlifetime'); - } else { + } elseif ($this->sessionExpiration > 0) { ini_set('session.gc_maxlifetime', (string) $this->sessionExpiration); } diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index b2efd60b7025..d38ec66e8994 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -458,6 +458,12 @@ Preference Default Opti unexpected results or be changed in the future. Please configure everything properly. +.. note:: If ``sessionExpiration`` is set to ``0``, the ``session.gc_maxlifetime`` + setting set by PHP in session management will be used as-is + (often the default value of ``1440``). This needs to be changed in + ``php.ini`` or via ``ini_set()`` as needed. + + In addition to the values above, the cookie and native drivers apply the following configuration values shared by the :doc:`IncomingRequest ` and :doc:`Security ` classes: From dfe4ad4c3d344fe272f214f771458e0895060986 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 17 Oct 2021 12:31:38 +0900 Subject: [PATCH 0469/2325] docs: small improvement in debugging --- user_guide_src/source/testing/debugging.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/testing/debugging.rst b/user_guide_src/source/testing/debugging.rst index 4f6ffdce9e3f..fbd0f8eed440 100644 --- a/user_guide_src/source/testing/debugging.rst +++ b/user_guide_src/source/testing/debugging.rst @@ -19,7 +19,7 @@ and much, much more. Enabling Kint ============= -By default, Kint is enabled in **development** and **testing** environments only. This can be altered by modifying +By default, Kint is enabled in **development** and **testing** :doc:`environments ` only. This can be altered by modifying the ``$useKint`` value in the environment configuration section of the main **index.php** file:: $useKint = true; @@ -59,7 +59,7 @@ to help you debug and optimize. Enabling the Toolbar ==================== -The toolbar is enabled by default in any environment *except* production. It will be shown whenever the +The toolbar is enabled by default in any :doc:`environment ` *except* **production**. It will be shown whenever the constant CI_DEBUG is defined and its value is truthy. This is defined in the boot files (e.g. **app/Config/Boot/development.php**) and can be modified there to determine what environment to show. From 59c79d9a1912c61cdc654bd63109e7c9bdbdc94c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 17 Oct 2021 17:59:56 +0900 Subject: [PATCH 0470/2325] fix: test failures on macOS `var` is a symlink to `private/var` on macOS --- system/Publisher/Publisher.php | 1 + tests/system/Publisher/PublisherSupportTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 38e990776ef3..7e47c136fd03 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -229,6 +229,7 @@ final public function getScratch(): string if ($this->scratch === null) { $this->scratch = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . DIRECTORY_SEPARATOR; mkdir($this->scratch, 0700); + $this->scratch = realpath($this->scratch) . DIRECTORY_SEPARATOR; } return $this->scratch; diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index 43be04406891..83a41b69e991 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -144,6 +144,7 @@ public function testWipe() { $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); mkdir($directory, 0700); + $directory = realpath($directory); $this->assertDirectoryExists($directory); config('Publisher')->restrictions[$directory] = ''; // Allow the directory From 59ae985f9db44d443b573db1183501d3e8e9caf1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 17 Oct 2021 22:55:21 +0900 Subject: [PATCH 0471/2325] Add `@group CacheLive` to tests * test: add `@group CacheLive` * docs: add about CacheLive --- tests/README.md | 4 ++-- tests/system/Cache/Handlers/MemcachedHandlerTest.php | 2 ++ tests/system/Cache/Handlers/PredisHandlerTest.php | 2 ++ tests/system/Cache/Handlers/RedisHandlerTest.php | 2 ++ 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/README.md b/tests/README.md index 0ae640f24844..438c2674f4bc 100644 --- a/tests/README.md +++ b/tests/README.md @@ -49,9 +49,9 @@ Individual tests can be run by including the relative path to the test file. > ./phpunit tests/system/HTTP/RequestTest.php -You can run the tests without running the live database tests. +You can run the tests without running the live database and the live cache tests. - > ./phpunit --exclude-group DatabaseLive + > ./phpunit --exclude-group DatabaseLive,CacheLive ## Generating Code Coverage diff --git a/tests/system/Cache/Handlers/MemcachedHandlerTest.php b/tests/system/Cache/Handlers/MemcachedHandlerTest.php index af2e0a77775c..240225fd8bc0 100644 --- a/tests/system/Cache/Handlers/MemcachedHandlerTest.php +++ b/tests/system/Cache/Handlers/MemcachedHandlerTest.php @@ -16,6 +16,8 @@ use Exception; /** + * @group CacheLive + * * @internal */ final class MemcachedHandlerTest extends AbstractHandlerTest diff --git a/tests/system/Cache/Handlers/PredisHandlerTest.php b/tests/system/Cache/Handlers/PredisHandlerTest.php index b91ecefa2e2b..9b762f9c27f1 100644 --- a/tests/system/Cache/Handlers/PredisHandlerTest.php +++ b/tests/system/Cache/Handlers/PredisHandlerTest.php @@ -15,6 +15,8 @@ use Config\Cache; /** + * @group CacheLive + * * @internal */ final class PredisHandlerTest extends AbstractHandlerTest diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php index 863d9efa3b59..32d0cdf8223e 100644 --- a/tests/system/Cache/Handlers/RedisHandlerTest.php +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php @@ -15,6 +15,8 @@ use Config\Cache; /** + * @group CacheLive + * * @internal */ final class RedisHandlerTest extends AbstractHandlerTest From d10a6029cd766f0a44e468d4f91899dcf99a522e Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Oct 2021 00:23:48 +0900 Subject: [PATCH 0472/2325] docs: hashed id (`encodeID()`) in CodeIgniter\Model has been removed https://github.com/codeigniter4/CodeIgniter4/commit/f87ffec26b0d3dca7544a6e76e9110f03671dc54 --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 4bc619f1449f..5740898dd6a6 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -68,7 +68,7 @@ Placeholders Description (:num) will match any integer. (:alpha) will match any string of alphabetic characters (:alphanum) will match any string of alphabetic characters or integers, or any combination of the two. -(:hash) is the same as **(:segment)**, but can be used to easily see which routes use hashed ids (see the :doc:`Model ` docs). +(:hash) is the same as **(:segment)**, but can be used to easily see which routes use hashed ids. ============ =========================================================================================================== .. note:: **{locale}** cannot be used as a placeholder or other part of the route, as it is reserved for use From 52af51d1ffa588fc47aa71f725507ade8726b7df Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Oct 2021 13:56:53 +0900 Subject: [PATCH 0473/2325] docs: unify the decoration of app/Config/*.php --- user_guide_src/cilexer/pycilexer.egg-info/top_level.txt | 1 + user_guide_src/source/concepts/structure.rst | 2 +- user_guide_src/source/general/logging.rst | 6 +++--- user_guide_src/source/general/modules.rst | 2 +- user_guide_src/source/helpers/cookie_helper.rst | 2 +- user_guide_src/source/helpers/text_helper.rst | 2 +- user_guide_src/source/incoming/controllers.rst | 2 +- user_guide_src/source/incoming/filters.rst | 2 +- user_guide_src/source/incoming/routing.rst | 8 ++++---- .../source/installation/installing_composer.rst | 2 +- user_guide_src/source/installation/troubleshooting.rst | 6 +++--- user_guide_src/source/libraries/cookies.rst | 2 +- user_guide_src/source/libraries/encryption.rst | 6 +++--- user_guide_src/source/libraries/honeypot.rst | 4 ++-- 14 files changed, 24 insertions(+), 23 deletions(-) create mode 100644 user_guide_src/cilexer/pycilexer.egg-info/top_level.txt diff --git a/user_guide_src/cilexer/pycilexer.egg-info/top_level.txt b/user_guide_src/cilexer/pycilexer.egg-info/top_level.txt new file mode 100644 index 000000000000..2f88e1d75272 --- /dev/null +++ b/user_guide_src/cilexer/pycilexer.egg-info/top_level.txt @@ -0,0 +1 @@ +cilexer diff --git a/user_guide_src/source/concepts/structure.rst b/user_guide_src/source/concepts/structure.rst index 40c5f868ee73..14bb3a59304b 100644 --- a/user_guide_src/source/concepts/structure.rst +++ b/user_guide_src/source/concepts/structure.rst @@ -84,6 +84,6 @@ Modifying Directory Locations ----------------------------- If you've relocated any of the main directories, you can change the configuration -settings inside ``app/Config/Paths``. +settings inside **app/Config/Paths.php**. Please read `Managing your Applications <../general/managing_apps.html>`_ diff --git a/user_guide_src/source/general/logging.rst b/user_guide_src/source/general/logging.rst index 6a6ca1e49e0e..7fa706ce6a86 100644 --- a/user_guide_src/source/general/logging.rst +++ b/user_guide_src/source/general/logging.rst @@ -38,7 +38,7 @@ Configuration ============= You can modify which levels are actually logged, as well as assign different Loggers to handle different levels, within -the ``/app/Config/Logger.php`` configuration file. +the **app/Config/Logger.php** configuration file. The ``threshold`` value of the config file determines which levels are logged across your application. If any levels are requested to be logged by the application, but the threshold doesn't allow them to log currently, they will be @@ -140,8 +140,8 @@ You can use any other logger that you might like as long as it extends from eith that you can easily drop in use for any PSR3-compatible logger, or create your own. You must ensure that the third-party logger can be found by the system, by adding it to either -the ``/app/Config/Autoload.php`` configuration file, or through another autoloader, -like Composer. Next, you should modify ``/app/Config/Services.php`` to point the ``logger`` +the **app/Config/Autoload.php** configuration file, or through another autoloader, +like Composer. Next, you should modify **app/Config/Services.php** to point the ``logger`` alias to your new class name. Now, any call that is done through the ``log_message()`` function will use your library instead. diff --git a/user_guide_src/source/general/modules.rst b/user_guide_src/source/general/modules.rst index b744f30c0441..6fc24ecad55d 100644 --- a/user_guide_src/source/general/modules.rst +++ b/user_guide_src/source/general/modules.rst @@ -73,7 +73,7 @@ would be used. Another approach provided by CodeIgniter is to autoload these *non-class* files like how you would autoload your classes. All we need to do is provide the list of paths to those files and include them in the -``$files`` property of your ``app/Config/Autoload.php`` file. +``$files`` property of your **app/Config/Autoload.php** file. :: diff --git a/user_guide_src/source/helpers/cookie_helper.rst b/user_guide_src/source/helpers/cookie_helper.rst index 2a7f0e6e6c43..c7df02f6461f 100755 --- a/user_guide_src/source/helpers/cookie_helper.rst +++ b/user_guide_src/source/helpers/cookie_helper.rst @@ -50,7 +50,7 @@ The following functions are available: detailed description of its use, as this function acts very similarly to ``IncomingRequest::getCookie()``, except it will also prepend the ``$cookiePrefix`` that you might've set in your - *app/Config/App.php* file. + **app/Config/App.php** file. .. php:function:: delete_cookie($name[, $domain = ''[, $path = '/'[, $prefix = '']]]) diff --git a/user_guide_src/source/helpers/text_helper.rst b/user_guide_src/source/helpers/text_helper.rst index 98a6f3b9e332..d83fb54835ae 100755 --- a/user_guide_src/source/helpers/text_helper.rst +++ b/user_guide_src/source/helpers/text_helper.rst @@ -257,7 +257,7 @@ The following functions are available: $string = convert_accented_characters($string); .. note:: This function uses a companion config file - `app/Config/ForeignCharacters.php` to define the to and + **app/Config/ForeignCharacters.php** to define the to and from array for transliteration. .. php:function:: word_censor($str, $censored[, $replacement = '']) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index dfca82fea06e..516028d8c04d 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -288,7 +288,7 @@ one and place your controller classes within them. Each of your sub-directories may contain a default controller which will be called if the URL contains *only* the sub-directory. Simply put a controller in there that matches the name of your 'default_controller' as specified in -your *app/Config/Routes.php* file. +your **app/Config/Routes.php** file. CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index a95333516503..259bb496e0b7 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -88,7 +88,7 @@ the final output, or even to filter the final output with a bad words filter. Configuring Filters ******************* -Once you've created your filters, you need to configure when they get run. This is done in ``app/Config/Filters.php``. +Once you've created your filters, you need to configure when they get run. This is done in **app/Config/Filters.php**. This file contains four properties that allow you to configure exactly when the filters run. $aliases diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 5740898dd6a6..7e0e6d462f9b 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -238,7 +238,7 @@ run the filter before or after the controller. This is especially handy during a $routes->resource('users'); }); -The value for the filter must match one of the aliases defined within ``app/Config/Filters.php``. +The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. It is possible to nest groups within groups for finer organization if you need it:: @@ -355,14 +355,14 @@ Applying Filters You can alter the behavior of specific routes by supplying filters to run before or after the controller. This is especially handy during authentication or api logging. The value for the filter can be a string or an array of strings: -* matching the aliases defined in ``app/Config/Filters.php``. +* matching the aliases defined in **app/Config/Filters.php**. * filter classnames See `Controller filters `_ for more information on setting up filters. **Alias filter** -You specify an alias defined in ``app/Config/Filters.php`` for the filter value:: +You specify an alias defined in **app/Config/Filters.php** for the filter value:: $routes->add('admin',' AdminController::index', ['filter' => 'admin-auth']); @@ -477,7 +477,7 @@ Routes Configuration Options ============================ The RoutesCollection class provides several options that affect all routes, and can be modified to meet your -application's needs. These options are available at the top of `/app/Config/Routes.php`. +application's needs. These options are available at the top of **app/Config/Routes.php**. Default Namespace ----------------- diff --git a/user_guide_src/source/installation/installing_composer.rst b/user_guide_src/source/installation/installing_composer.rst index 16e5d1b2015f..b63e34602425 100644 --- a/user_guide_src/source/installation/installing_composer.rst +++ b/user_guide_src/source/installation/installing_composer.rst @@ -140,7 +140,7 @@ Copy the ``env``, ``phpunit.xml.dist`` and ``spark`` files, from ``vendor/codeigniter4/framework`` to your project root You will have to adjust the system path to refer to the vendor one, e.g., ``ROOTPATH . '/vendor/codeigniter4/framework/system'``, -- the ``$systemDirectory`` variable in ``app/Config/Paths.php`` +- the ``$systemDirectory`` variable in **app/Config/Paths.php** Upgrading --------- diff --git a/user_guide_src/source/installation/troubleshooting.rst b/user_guide_src/source/installation/troubleshooting.rst index dc15798d9839..a0b1684fda9d 100644 --- a/user_guide_src/source/installation/troubleshooting.rst +++ b/user_guide_src/source/installation/troubleshooting.rst @@ -30,11 +30,11 @@ Only the default page loads If you find that no matter what you put in your URL only your default page is loading, it might be that your server does not support the REQUEST_URI variable needed to serve search-engine friendly URLs. As a -first step, open your *app/Config/App.php* file and look for +first step, open your **app/Config/App.php** file and look for the URI Protocol information. It will recommend that you try a couple of alternate settings. If it still doesn't work after you've tried this you'll need to force CodeIgniter to add a question mark to your URLs. To -do this open your *app/Config/App.php* file and change this:: +do this open your **app/Config/App.php** file and change this:: public $indexPage = 'index.php'; @@ -72,7 +72,7 @@ Don't forget to reset the environment to "production" once you fix the problem! CodeIgniter Error Logs ---------------------- -CodeIgniter logs error messages, according to the settings in `app/Config/Logger.php`. +CodeIgniter logs error messages, according to the settings in **app/Config/Logger.php**. You can adjust the error threshold to see more or fewer messages. diff --git a/user_guide_src/source/libraries/cookies.rst b/user_guide_src/source/libraries/cookies.rst index e935c56bb1e8..86d36dec9a25 100644 --- a/user_guide_src/source/libraries/cookies.rst +++ b/user_guide_src/source/libraries/cookies.rst @@ -431,7 +431,7 @@ Cookie Personalization Sane defaults are already in place inside the ``Cookie`` class to ensure the smooth creation of cookie objects. However, you may wish to define your own settings by changing the following settings in the -``Config\Cookie`` class in ``app/Config/Cookie.php`` file. +``Config\Cookie`` class in **app/Config/Cookie.php** file. ==================== ===================================== ========= ===================================================== Setting Options/ Types Default Description diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 54fb1fb333a7..2c8373743f35 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -62,7 +62,7 @@ You don't need to worry about it. Configuring the Library ======================= -The example above uses the configuration settings found in ``app/Config/Encryption.php``. +The example above uses the configuration settings found in **app/Config/Encryption.php**. ========== ==================================================== Option Possible values (default in parentheses) @@ -108,10 +108,10 @@ you can use the Encryption library's ``createKey()`` method. $key = sodium_crypto_secretbox_keygen(); $key = \CodeIgniter\Encryption\Encryption::createKey(SODIUM_CRYPTO_SECRETBOX_KEYBYTES); -The key can be stored in ``app/Config/Encryption.php``, or you can design +The key can be stored in **app/Config/Encryption.php**, or you can design a storage mechanism of your own and pass the key dynamically when encrypting/decrypting. -To save your key to your ``app/Config/Encryption.php``, open the file +To save your key to your **app/Config/Encryption.php**, open the file and set:: public $key = 'YOUR KEY'; diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index 959a2278178e..471c0d520003 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -14,7 +14,7 @@ assumed the request is coming from a Bot, and you can throw a ``HoneypotExceptio Enabling Honeypot ===================== -To enable a Honeypot, changes have to be made to the ``app/Config/Filters.php``. Just uncomment honeypot +To enable a Honeypot, changes have to be made to the **app/Config/Filters.php**. Just uncomment honeypot from the ``$globals`` array, like...:: public $globals = [ @@ -36,7 +36,7 @@ Customizing Honeypot ===================== Honeypot can be customized. The fields below can be set either in -``app/Config/Honeypot.php`` or in ``.env``. +**app/Config/Honeypot.php** or in ``.env``. * ``hidden`` - true|false to control visibility of the honeypot field; default is ``true`` * ``label`` - HTML label for the honeypot field, default is 'Fill This Field' From a2309e6c8b15840df432da8ed6a50e71eac15163 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Oct 2021 20:55:17 +0900 Subject: [PATCH 0474/2325] fix: add fallbacks for realpath() so VFS is supported --- system/Publisher/Publisher.php | 3 ++- tests/system/Publisher/PublisherSupportTest.php | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 7e47c136fd03..a492a03e02c3 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -229,7 +229,8 @@ final public function getScratch(): string if ($this->scratch === null) { $this->scratch = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . DIRECTORY_SEPARATOR; mkdir($this->scratch, 0700); - $this->scratch = realpath($this->scratch) . DIRECTORY_SEPARATOR; + $this->scratch = realpath($this->scratch) ? realpath($this->scratch) . DIRECTORY_SEPARATOR + : $this->scratch . DIRECTORY_SEPARATOR; } return $this->scratch; diff --git a/tests/system/Publisher/PublisherSupportTest.php b/tests/system/Publisher/PublisherSupportTest.php index 83a41b69e991..de1fb29fbd93 100644 --- a/tests/system/Publisher/PublisherSupportTest.php +++ b/tests/system/Publisher/PublisherSupportTest.php @@ -144,7 +144,7 @@ public function testWipe() { $directory = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)); mkdir($directory, 0700); - $directory = realpath($directory); + $directory = realpath($directory) ?: $directory; $this->assertDirectoryExists($directory); config('Publisher')->restrictions[$directory] = ''; // Allow the directory From 24196f93168af1d5306e0d9b83bddd83a6b1c61e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 19 Oct 2021 11:34:07 +0900 Subject: [PATCH 0475/2325] test: remove invalid @runTestsInSeparateProcesses It must be in the class PHPdoc. --- tests/system/Commands/MigrationIntegrationTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/system/Commands/MigrationIntegrationTest.php b/tests/system/Commands/MigrationIntegrationTest.php index f2fca3405354..7dab2f1f8ef1 100644 --- a/tests/system/Commands/MigrationIntegrationTest.php +++ b/tests/system/Commands/MigrationIntegrationTest.php @@ -58,9 +58,6 @@ protected function tearDown(): void stream_filter_remove($this->streamFilter); } - /** - * @runTestsInSeparateProcesses - */ public function testMigrationWithRollbackHasSameNameFormat(): void { command('migrate -n App'); From 34afde80f0435e5157db3d60600ee9d974d9f7ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 19 Oct 2021 15:03:11 +0000 Subject: [PATCH 0476/2325] chore(deps-dev): update rector/rector requirement Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.11.58...0.11.59) --- 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 8a8fdaf00aa2..bc5e2a6fcaf2 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.58", + "rector/rector": "0.11.59", "symplify/package-builder": "^9.3" }, "suggest": { From 9718fa0abb12c17cd4597f2edabd3cc4702cef34 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 20 Oct 2021 09:20:24 +0900 Subject: [PATCH 0477/2325] docs: improve tests/README.md --- tests/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/README.md b/tests/README.md index 438c2674f4bc..a67852b451bd 100644 --- a/tests/README.md +++ b/tests/README.md @@ -8,7 +8,7 @@ use to test your application. Those details can be found in the documentation. ## Requirements It is recommended to use the latest version of PHPUnit. At the time of this -writing we are running version 8.5.13. Support for this has been built into the +writing we are running version 9.5.10. Support for this has been built into the **composer.json** file that ships with CodeIgniter and can easily be installed via [Composer](https://getcomposer.org/) if you don't already have it installed globally. @@ -27,11 +27,11 @@ A number of the tests use a running database. In order to set up the database edit the details for the `tests` group in **app/Config/Database.php** or **phpunit.xml**. Make sure that you provide a database engine that is currently running on your machine. More details on a test database setup are in the -*Docs>>Testing>>Testing Your Database* section of the documentation. +[Testing Your Database](https://codeigniter.com/user_guide/testing/database.html) section of the documentation. If you want to run the tests without using live database you can -exclude @DatabaseLive group. Or make a copy of **phpunit.dist.xml** - -call it **phpunit.xml** - and comment out the named "database". This will make +exclude `@DatabaseLive` group. Or make a copy of **phpunit.dist.xml** - +call it **phpunit.xml** - and comment out the `` named `Database`. This will make the tests run quite a bit faster. ## Running the tests From 7a1cf38eeb04b4eec2ac760f561099823262f19d Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 20 Oct 2021 21:46:42 +0900 Subject: [PATCH 0478/2325] docs: change the version of PHPUnit to major version only Co-authored-by: MGatner --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index a67852b451bd..0df329864c6b 100644 --- a/tests/README.md +++ b/tests/README.md @@ -8,7 +8,7 @@ use to test your application. Those details can be found in the documentation. ## Requirements It is recommended to use the latest version of PHPUnit. At the time of this -writing we are running version 9.5.10. Support for this has been built into the +writing we are running version 9.x. Support for this has been built into the **composer.json** file that ships with CodeIgniter and can easily be installed via [Composer](https://getcomposer.org/) if you don't already have it installed globally. From ac7d3b6875a121d0626a04c0f59717045ea289b8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 00:32:45 +0900 Subject: [PATCH 0479/2325] docs: improve Form Validation Tutorial Fixes #3017 --- .../source/libraries/validation.rst | 41 ++++++++++++++----- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 940a95953819..d8df45d1c95c 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -150,9 +150,12 @@ To try your form, visit your site using a URL similar to this one:: example.com/index.php/form/ If you submit the form you should simply see the form reload. That's -because you haven't set up any validation rules yet. +because you haven't set up any validation rules in ``$this->validate()`` yet. -.. note:: Since you haven't told the **Validation class** to validate anything +The ``validate()`` method is a method in the Controller. It uses +the **Validation class** inside. See *Validating data* in :doc:`/incoming/controllers`. + +.. note:: Since you haven't told the ``validate()`` method to validate anything yet, it **returns false** (boolean false) **by default**. The ``validate()`` method only returns true if it has successfully applied your rules without any of them failing. @@ -162,9 +165,9 @@ Explanation You'll notice several things about the above pages: -The form (Signup.php) is a standard web form with a couple of exceptions: +The form (**Signup.php**) is a standard web form with a couple of exceptions: -#. It uses a form helper to create the form opening. Technically, this +#. It uses a :doc:`form helper ` to create the form opening. Technically, this isn't necessary. You could create the form using standard HTML. However, the benefit of using the helper is that it generates the action URL for you, based on the URL in your config file. This makes @@ -177,15 +180,31 @@ The form (Signup.php) is a standard web form with a couple of exceptions: This function will return any error messages sent back by the validator. If there are no messages it returns an empty string. -The controller (Form.php) has one method: ``index()``. This method -uses the Controller-provided validate method and loads the form helper and URL +The controller (**Form.php**) has one method: ``index()``. This method +uses the Controller-provided ``validate()`` method and loads the form helper and URL helper used by your view files. It also runs the validation routine. Based on whether the validation was successful it either presents the form or the success page. -Loading the Library +Add Validation Rules ================================================ +Then add validation rules in the controller (**Form.php**):: + + if (! $this->validate([ + 'username' => 'required', + 'password' => 'required|min_length[10]', + 'passconf' => 'required|matches[password]', + 'email' => 'required|valid_email', + ])) { + ... + } + +If you submit the form you should see the success page or the form with error messages. + +Loading the Library +************************************************ + The library is loaded as a service named **validation**:: $validation = \Config\Services::validation(); @@ -197,7 +216,7 @@ for including multiple Rulesets, and collections of rules that can be easily reu the :doc:`Model ` provide methods to make validation even easier. Setting Validation Rules -================================================ +************************************************ CodeIgniter lets you set as many validation rules as you need for a given field, cascading them in order. To set validation rules you @@ -205,7 +224,7 @@ will use the ``setRule()``, ``setRules()``, or ``withRequest()`` methods. setRule() ---------- +========= This method sets a single rule. It takes the name of the field as the first parameter, an optional label and a string with a pipe-delimited list of rules @@ -218,7 +237,7 @@ the data is taken directly from $_POST, then it must be an exact match for the form input name. setRules() ----------- +========== Like, ``setRule()``, but accepts an array of field names and their rules:: @@ -235,7 +254,7 @@ To give a labeled error message you can set up as:: ]); withRequest() -------------- +============= One of the most common times you will use the validation library is when validating data that was input from an HTTP Request. If desired, you can pass an instance of the From eb5d8c2ef8fdfacdc64c3a61a1469742d465e7b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 00:33:17 +0900 Subject: [PATCH 0480/2325] docs: improve contributing docs * docs: add link to tests/README.md * docs: remove unneeded line breaks and spaces --- contributing/pull_request.md | 3 ++- contributing/signing.md | 20 +++++++------------- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/contributing/pull_request.md b/contributing/pull_request.md index 95e31e676809..d08bbd2e035c 100644 --- a/contributing/pull_request.md +++ b/contributing/pull_request.md @@ -63,7 +63,8 @@ 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 the [PHPUnit website](https://phpunit.de/) for more information. +See [Running System Tests](../tests/README.md) +and the [PHPUnit website](https://phpunit.de/) for more information. ### Comments diff --git a/contributing/signing.md b/contributing/signing.md index 0755f6806ed2..ca84ef79a9a7 100644 --- a/contributing/signing.md +++ b/contributing/signing.md @@ -32,25 +32,19 @@ Read below to find out how to sign your commits :) To verify your commits, you will need to setup a GPG key, and attach it to your GitHub account. -See the [git -tools](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) page -for directions on doing this. The complete story is part of [GitHub -help](https://help.github.com/categories/gpg/). +See the [git tools](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) page +for directions on doing this. The complete story is part of [GitHub help](https://help.github.com/categories/gpg/). The basic steps are -- [generate your GPG - key](https://help.github.com/articles/generating-a-new-gpg-key/), +- [generate your GPG key](https://help.github.com/articles/generating-a-new-gpg-key/), and copy the ASCII representation of it. -- [Add your GPG key to your GitHub - account](https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/). -- [Tell - Git](https://help.github.com/articles/telling-git-about-your-gpg-key/) +- [Add your GPG key to your GitHub account](https://help.github.com/articles/adding-a-new-gpg-key-to-your-github-account/). +- [Tell Git](https://help.github.com/articles/telling-git-about-your-gpg-key/) about your GPG key. -- [Set default - signing](https://help.github.com/articles/signing-commits-using-gpg/) +- [Set default signing](https://help.github.com/articles/signing-commits-using-gpg/) to have all of your commits securely signed automatically. -- Provide your GPG key passphrase, as prompted, when you do a commit. +- Provide your GPG key passphrase, as prompted, when you do a commit. Depending on your IDE, you may have to do your Git commits from your Git bash shell to use the **-S** option to force the secure signing. From 5e03647d34f8f66c2cf7ae7886ca50a8c53f3846 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 00:35:05 +0900 Subject: [PATCH 0481/2325] test: fix @var classname typo --- tests/system/RESTful/ResourceControllerTest.php | 3 ++- tests/system/RESTful/ResourcePresenterTest.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index 5f2e58994d10..185088da1505 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -19,6 +19,7 @@ use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; +use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCodeIgniter; use CodeIgniter\Test\Mock\MockResourceController; @@ -45,7 +46,7 @@ final class ResourceControllerTest extends CIUnitTestCase protected $codeigniter; /** - * @var \CodeIgniter\Router\RoutesCollection + * @var RouteCollection */ protected $routes; diff --git a/tests/system/RESTful/ResourcePresenterTest.php b/tests/system/RESTful/ResourcePresenterTest.php index 2f0a332a57f9..e32ce9aba5d3 100644 --- a/tests/system/RESTful/ResourcePresenterTest.php +++ b/tests/system/RESTful/ResourcePresenterTest.php @@ -13,6 +13,7 @@ use CodeIgniter\CodeIgniter; use CodeIgniter\Config\Services; +use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCodeIgniter; use CodeIgniter\Test\Mock\MockResourcePresenter; @@ -39,7 +40,7 @@ final class ResourcePresenterTest extends CIUnitTestCase protected $codeigniter; /** - * @var \CodeIgniter\Router\RoutesCollection + * @var RouteCollection */ protected $routes; From 654c2b70770e2603d0c5d37014d5bfa7295d15af Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 00:35:37 +0900 Subject: [PATCH 0482/2325] docs: add warning about auto-routing and filters --- user_guide_src/source/incoming/routing.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 7e0e6d462f9b..4392ecdba5b1 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -360,6 +360,13 @@ The value for the filter can be a string or an array of strings: See `Controller filters `_ for more information on setting up filters. +.. Warning:: If you set filters to routes in **app/Config/Routes.php** + (not in **app/Config/Filters.php**), it is recommended to disable auto-routing. + When auto-routing is enabled, it may be possible that a controller can be accessed + via a different URL than the configured route, + in which case the filter you specified to the route will not be applied. + See :ref:`use-defined-routes-only` to disable auto-routing. + **Alias filter** You specify an alias defined in **app/Config/Filters.php** for the filter value:: @@ -540,6 +547,8 @@ dash isn’t a valid class or method name character and would cause a fatal erro $routes->setTranslateURIDashes(true); +.. _use-defined-routes-only: + Use Defined Routes Only ----------------------- From 3ea7c9506e19b0c928b51b944592789325104835 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 20 Oct 2021 15:44:27 +0000 Subject: [PATCH 0483/2325] chore(deps-dev): update rector/rector requirement (#5225) --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index bc5e2a6fcaf2..d914b452e528 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^0.12.91", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.11.59", + "rector/rector": "0.11.60", "symplify/package-builder": "^9.3" }, "suggest": { From 22634300ebcf39343c310d9288de536e060ba606 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 11:00:39 +0900 Subject: [PATCH 0484/2325] feat: add Session based CSRF protection --- app/Config/Security.php | 11 + env | 1 + system/Security/Security.php | 76 +++++- .../Security/SecurityCSRFSessionTest.php | 225 ++++++++++++++++++ 4 files changed, 303 insertions(+), 10 deletions(-) create mode 100644 tests/system/Security/SecurityCSRFSessionTest.php diff --git a/app/Config/Security.php b/app/Config/Security.php index 01000ff52088..563cf2f3a86e 100644 --- a/app/Config/Security.php +++ b/app/Config/Security.php @@ -6,6 +6,17 @@ class Security extends BaseConfig { + /** + * -------------------------------------------------------------------------- + * CSRF Protection Method + * -------------------------------------------------------------------------- + * + * Protection Method for Cross Site Request Forgery protection. + * + * @var string 'cookie' or 'session' + */ + public $csrfProtection = 'cookie'; + /** * -------------------------------------------------------------------------- * CSRF Token Name diff --git a/env b/env index 38eabf203988..0b6aa1720782 100644 --- a/env +++ b/env @@ -110,6 +110,7 @@ # SECURITY #-------------------------------------------------------------------- +# security.csrfProtection = 'cookie' # security.tokenName = 'csrf_token_name' # security.headerName = 'X-CSRF-TOKEN' # security.cookieName = 'csrf_cookie_name' diff --git a/system/Security/Security.php b/system/Security/Security.php index 7bf3b6689095..cf55c3aeda5f 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -14,6 +14,7 @@ use CodeIgniter\Cookie\Cookie; use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\Security\Exceptions\SecurityException; +use CodeIgniter\Session\Session; use Config\App; use Config\Cookie as CookieConfig; use Config\Security as SecurityConfig; @@ -27,6 +28,18 @@ */ class Security implements SecurityInterface { + public const CSRF_PROTECTION_COOKIE = 'cookie'; + public const CSRF_PROTECTION_SESSION = 'session'; + + /** + * CSRF Protection Method + * + * Protection Method for Cross Site Request Forgery protection. + * + * @var string 'cookie' or 'session' + */ + protected $csrfProtection = self::CSRF_PROTECTION_COOKIE; + /** * CSRF Hash * @@ -128,6 +141,13 @@ class Security implements SecurityInterface */ private $rawCookieName; + /** + * Session instance. + * + * @var Session + */ + private $session; + /** * Constructor. * @@ -141,11 +161,12 @@ public function __construct(App $config) // Store CSRF-related configurations if ($security instanceof SecurityConfig) { - $this->tokenName = $security->tokenName ?? $this->tokenName; - $this->headerName = $security->headerName ?? $this->headerName; - $this->regenerate = $security->regenerate ?? $this->regenerate; - $this->rawCookieName = $security->cookieName ?? $this->rawCookieName; - $this->expires = $security->expires ?? $this->expires; + $this->csrfProtection = $security->csrfProtection ?? $this->csrfProtection; + $this->tokenName = $security->tokenName ?? $this->tokenName; + $this->headerName = $security->headerName ?? $this->headerName; + $this->regenerate = $security->regenerate ?? $this->regenerate; + $this->rawCookieName = $security->cookieName ?? $this->rawCookieName; + $this->expires = $security->expires ?? $this->expires; } else { // `Config/Security.php` is absence $this->tokenName = $config->CSRFTokenName ?? $this->tokenName; @@ -155,13 +176,28 @@ public function __construct(App $config) $this->expires = $config->CSRFExpire ?? $this->expires; } - $this->configureCookie($config); + if ($this->isCSRFCookie()) { + $this->configureCookie($config); + } else { + // Session based CSRF protection + $this->configureSession(); + } $this->request = Services::request(); $this->generateHash(); } + private function isCSRFCookie(): bool + { + return $this->csrfProtection === self::CSRF_PROTECTION_COOKIE; + } + + private function configureSession(): void + { + $this->session = Services::session(); + } + private function configureCookie(App $config): void { /** @var CookieConfig|null $cookie */ @@ -253,7 +289,12 @@ public function verify(RequestInterface $request) if ($this->regenerate) { $this->hash = null; - unset($_COOKIE[$this->cookieName]); + if ($this->isCSRFCookie()) { + unset($_COOKIE[$this->cookieName]); + } else { + // Session based CSRF protection + $this->session->remove($this->tokenName); + } } $this->generateHash(); @@ -409,13 +450,23 @@ protected function generateHash(): string // We don't necessarily want to regenerate it with // each page load since a page could contain embedded // sub-pages causing this feature to fail - if ($this->isHashInCookie()) { - return $this->hash = $_COOKIE[$this->cookieName]; + if ($this->isCSRFCookie()) { + if ($this->isHashInCookie()) { + return $this->hash = $_COOKIE[$this->cookieName]; + } + } elseif ($this->session->has($this->tokenName)) { + // Session based CSRF protection + return $this->hash = $this->session->get($this->tokenName); } $this->hash = bin2hex(random_bytes(16)); - $this->saveHashInCookie(); + if ($this->isCSRFCookie()) { + $this->saveHashInCookie(); + } else { + // Session based CSRF protection + $this->saveHashInSession(); + } } return $this->hash; @@ -467,4 +518,9 @@ protected function doSendCookie(): void { cookies([$this->cookie], false)->dispatch(); } + + private function saveHashInSession(): void + { + $this->session->set($this->tokenName, $this->hash); + } } diff --git a/tests/system/Security/SecurityCSRFSessionTest.php b/tests/system/Security/SecurityCSRFSessionTest.php new file mode 100644 index 000000000000..040f253b9774 --- /dev/null +++ b/tests/system/Security/SecurityCSRFSessionTest.php @@ -0,0 +1,225 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Security; + +use CodeIgniter\Config\Factories; +use CodeIgniter\Config\Services; +use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\UserAgent; +use CodeIgniter\Security\Exceptions\SecurityException; +use CodeIgniter\Session\Handlers\ArrayHandler; +use CodeIgniter\Session\Session; +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\Mock\MockAppConfig; +use CodeIgniter\Test\Mock\MockSession; +use CodeIgniter\Test\TestLogger; +use Config\App as AppConfig; +use Config\Logger as LoggerConfig; +use Config\Security as SecurityConfig; + +/** + * @runTestsInSeparateProcesses + * @preserveGlobalState disabled + * + * @internal + */ +final class SecurityCSRFSessionTest extends CIUnitTestCase +{ + /** + * @var string CSRF protection hash + */ + private $hash = '8b9218a55906f9dcc1dc263dce7f005a'; + + protected function setUp(): void + { + parent::setUp(); + + $_SESSION = []; + Factories::reset(); + + $config = new SecurityConfig(); + $config->csrfProtection = Security::CSRF_PROTECTION_SESSION; + Factories::injectMock('config', 'Security', $config); + + $this->injectSession($this->hash); + } + + private function createSession($options = []): Session + { + $defaults = [ + 'sessionDriver' => 'CodeIgniter\Session\Handlers\FileHandler', + 'sessionCookieName' => 'ci_session', + 'sessionExpiration' => 7200, + 'sessionSavePath' => null, + 'sessionMatchIP' => false, + 'sessionTimeToUpdate' => 300, + 'sessionRegenerateDestroy' => false, + 'cookieDomain' => '', + 'cookiePrefix' => '', + 'cookiePath' => '/', + 'cookieSecure' => false, + 'cookieSameSite' => 'Lax', + ]; + + $config = array_merge($defaults, $options); + $appConfig = new AppConfig(); + + foreach ($config as $key => $c) { + $appConfig->{$key} = $c; + } + + $session = new MockSession(new ArrayHandler($appConfig, '127.0.0.1'), $appConfig); + $session->setLogger(new TestLogger(new LoggerConfig())); + + return $session; + } + + private function injectSession(string $hash): void + { + $session = $this->createSession(); + $session->set('csrf_test_name', $hash); + Services::injectMock('session', $session); + } + + public function testHashIsReadFromSession() + { + $security = new Security(new MockAppConfig()); + + $this->assertSame($this->hash, $security->getHash()); + } + + public function testCSRFVerifyPostThrowsExceptionOnNoMatch() + { + $this->expectException(SecurityException::class); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + + $security = new Security(new MockAppConfig()); + + $security->verify($request); + } + + public function testCSRFVerifyPostReturnsSelfOnMatch() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['foo'] = 'bar'; + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + + $security = new Security(new MockAppConfig()); + + $this->assertInstanceOf(Security::class, $security->verify($request)); + $this->assertLogged('info', 'CSRF token verified.'); + $this->assertTrue(count($_POST) === 1); + } + + public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); + + $security = new Security(new MockAppConfig()); + + $this->expectException(SecurityException::class); + $security->verify($request); + } + + public function testCSRFVerifyHeaderReturnsSelfOnMatch() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['foo'] = 'bar'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); + + $security = new Security(new MockAppConfig()); + + $this->assertInstanceOf(Security::class, $security->verify($request)); + $this->assertLogged('info', 'CSRF token verified.'); + $this->assertCount(1, $_POST); + } + + public function testCSRFVerifyJsonThrowsExceptionOnNoMatch() + { + $this->expectException(SecurityException::class); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005b"}'); + + $security = new Security(new MockAppConfig()); + + $security->verify($request); + } + + public function testCSRFVerifyJsonReturnsSelfOnMatch() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a","foo":"bar"}'); + + $security = new Security(new MockAppConfig()); + + $this->assertInstanceOf(Security::class, $security->verify($request)); + $this->assertLogged('info', 'CSRF token verified.'); + $this->assertTrue($request->getBody() === '{"foo":"bar"}'); + } + + public function testRegenerateWithFalseSecurityRegenerateProperty() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + + $config = Factories::config('Security'); + $config->regenerate = false; + Factories::injectMock('config', 'Security', $config); + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + + $security = new Security(new MockAppConfig()); + + $oldHash = $security->getHash(); + $security->verify($request); + $newHash = $security->getHash(); + + $this->assertSame($oldHash, $newHash); + } + + public function testRegenerateWithTrueSecurityRegenerateProperty() + { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + + $config = Factories::config('Security'); + $config->regenerate = true; + Factories::injectMock('config', 'Security', $config); + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + + $security = new Security(new MockAppConfig()); + + $oldHash = $security->getHash(); + $security->verify($request); + $newHash = $security->getHash(); + + $this->assertNotSame($oldHash, $newHash); + } +} From 991c412adc6a9ba733474b94059fa4c558ec28c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 11:01:48 +0900 Subject: [PATCH 0485/2325] refactor: add missing return type --- system/Security/Security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index cf55c3aeda5f..d6edbb23025a 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -479,7 +479,7 @@ private function isHashInCookie(): bool && preg_match('#^[0-9a-f]{32}$#iS', $_COOKIE[$this->cookieName]) === 1; } - private function saveHashInCookie() + private function saveHashInCookie(): void { $this->cookie = new Cookie( $this->rawCookieName, From 537867a1471a3b8a360662a4a6df13dffb2d0f84 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 13:04:26 +0900 Subject: [PATCH 0486/2325] docs: add Session based CSRF Protection --- user_guide_src/source/libraries/security.rst | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 9497723c4b46..3b48072fd84d 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -120,6 +120,22 @@ than simply crashing. This can be turned off by editing the following config par Even when the redirect value is **true**, AJAX calls will not redirect, but will throw an error. +======================= +CSRF Protection Methods +======================= + +By default, the Cookie based CSRF Protection is used. It is +`Double Submit Cookie `_ +on OWASP Cross-Site Request Forgery Prevention Cheat Sheet. + +You can also use Session based CSRF Protection. It is +`Synchronizer Token Pattern `_. + +You can set to use the Session based CSRF protection by editing the following config parameter value in +**app/Config/Security.php**:: + + public $csrfProtection = 'session'; + ********************* Other Helpful Methods ********************* From b2fb16a07e9f65f54139cfb36a9b7d59eb7bebff Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Oct 2021 14:12:11 +0900 Subject: [PATCH 0487/2325] docs: fix text decoration --- user_guide_src/source/libraries/security.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 3b48072fd84d..d788e2d2a808 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -118,7 +118,7 @@ than simply crashing. This can be turned off by editing the following config par public $redirect = false; -Even when the redirect value is **true**, AJAX calls will not redirect, but will throw an error. +Even when the redirect value is ``true``, AJAX calls will not redirect, but will throw an error. ======================= CSRF Protection Methods @@ -148,8 +148,8 @@ you might find helpful that are not related to the CSRF protection. Tries to sanitize filenames in order to prevent directory traversal attempts and other security threats, which is particularly useful for files that were supplied via user input. The first parameter is the path to sanitize. -If it is acceptable for the user input to include relative paths, e.g., file/in/some/approved/folder.txt, you can set -the second optional parameter, $relative_path to true. +If it is acceptable for the user input to include relative paths, e.g., **file/in/some/approved/folder.txt**, you can set +the second optional parameter, ``$relativePath`` to ``true``. :: $path = $security->sanitizeFilename($request->getVar('filepath')); From 985134458b6a9eaf68be3ae0da02bc30a998bec7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Oct 2021 09:36:51 +0900 Subject: [PATCH 0488/2325] chore: Security can depend on Session For Session based CSRF Protection --- depfile.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/depfile.yaml b/depfile.yaml index c1d8b87c3db2..2c87969f4fc4 100644 --- a/depfile.yaml +++ b/depfile.yaml @@ -193,6 +193,7 @@ ruleset: - HTTP Security: - Cookie + - Session - HTTP Session: - Cookie From 562c12ef84a5a29f8eac5ff5e086696d5a18d9f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 09:39:25 +0900 Subject: [PATCH 0489/2325] docs: update link for CSRF protection Now Security class provides it. --- user_guide_src/source/concepts/security.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/concepts/security.rst b/user_guide_src/source/concepts/security.rst index d13c47d73564..63581c9510dd 100644 --- a/user_guide_src/source/concepts/security.rst +++ b/user_guide_src/source/concepts/security.rst @@ -57,7 +57,7 @@ CodeIgniter provisions ---------------------- - `Session <../libraries/sessions.html>`_ library -- `HTTP library <../incoming/incomingrequest.html>`_ provides for CSRF validation +- :doc:`Security ` library provides for CSRF validation - Easy to add third party authentication ***************************** @@ -162,7 +162,7 @@ CodeIgniter provisions ---------------------- - Public folder, with application and system outside -- `HTTP library <../incoming/incomingrequest.html>`_ provides for CSRF validation +- :doc:`Security ` library provides for CSRF validation ************************************ A8 Cross Site Request Forgery (CSRF) @@ -181,7 +181,7 @@ OWASP recommendations CodeIgniter provisions ---------------------- -- `HTTP library <../incoming/incomingrequest.html>`_ provides for CSRF validation +- :doc:`Security ` library provides for CSRF validation ********************************************** A9 Using Components with Known Vulnerabilities From 010fa6880792c4cc9fe23544d9f4ed10fde62d18 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 09:42:54 +0900 Subject: [PATCH 0490/2325] docs: fix sample code The CSRF filter alias name is lower case. --- user_guide_src/source/libraries/throttler.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/throttler.rst b/user_guide_src/source/libraries/throttler.rst index f4fbc9a325f4..bc13c16fc321 100644 --- a/user_guide_src/source/libraries/throttler.rst +++ b/user_guide_src/source/libraries/throttler.rst @@ -117,7 +117,7 @@ filter:: Next, we assign it to all POST requests made on the site:: public $methods = [ - 'post' => ['throttle', 'CSRF'], + 'post' => ['throttle', 'csrf'], ]; And that's all there is to it. Now all POST requests made on the site will have to be rate limited. From 045c6ea0915b3724b25ff5b7125f8d978a0d47cd Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 09:59:15 +0900 Subject: [PATCH 0491/2325] docs: remove Config\App.CSRFProtection which does not exist --- user_guide_src/source/general/configuration.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index d5599e1a0f25..194079ef9995 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -165,7 +165,6 @@ the configuration class properties are left unchanged. In this usage, the prefix the full (case-sensitive) namespace of the class. :: - Config\App.CSRFProtection = true Config\App.CSRFCookieName = csrf_cookie Config\App.CSPEnabled = true @@ -177,7 +176,6 @@ the configuration class name. If the short prefix matches the class name, the value from **.env** replaces the configuration file value. :: - app.CSRFProtection = true app.CSRFCookieName = csrf_cookie app.CSPEnabled = true @@ -186,7 +184,6 @@ the value from **.env** replaces the configuration file value. Some environments do not permit variable name with dots. In such case, you could also use ``_`` as a seperator. :: - app_CSRFProtection = true app_CSRFCookieName = csrf_cookie app_CSPEnabled = true From 485a0c3694be1c9cb9951eca8aa5740644c27756 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 10:03:33 +0900 Subject: [PATCH 0492/2325] docs: replace deprecated Config\App.CSRFCookieName --- user_guide_src/source/general/configuration.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index 194079ef9995..8254b9fe44ea 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -165,7 +165,7 @@ the configuration class properties are left unchanged. In this usage, the prefix the full (case-sensitive) namespace of the class. :: - Config\App.CSRFCookieName = csrf_cookie + Config\App.forceGlobalSecureRequests = true Config\App.CSPEnabled = true @@ -176,7 +176,7 @@ the configuration class name. If the short prefix matches the class name, the value from **.env** replaces the configuration file value. :: - app.CSRFCookieName = csrf_cookie + app.forceGlobalSecureRequests = true app.CSPEnabled = true .. note:: When using the *short prefix* the property names must still exactly match the class defined name. @@ -184,7 +184,7 @@ the value from **.env** replaces the configuration file value. Some environments do not permit variable name with dots. In such case, you could also use ``_`` as a seperator. :: - app_CSRFCookieName = csrf_cookie + app_forceGlobalSecureRequests = true app_CSPEnabled = true Environment Variables as Replacements for Data From e3eea9470beaa459dbc949ce3530438bf97ca913 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 10:10:37 +0900 Subject: [PATCH 0493/2325] docs: make @deprecated IncomingRequest::$enableCSRF that is not used --- system/HTTP/IncomingRequest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/system/HTTP/IncomingRequest.php b/system/HTTP/IncomingRequest.php index 21894949cb29..128d6ee1c432 100755 --- a/system/HTTP/IncomingRequest.php +++ b/system/HTTP/IncomingRequest.php @@ -51,6 +51,8 @@ class IncomingRequest extends Request * Set automatically based on Config setting. * * @var bool + * + * @deprecated Not used */ protected $enableCSRF = false; From 5d8724903c3190db7402f44d18c268183f397e8f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 10:11:54 +0900 Subject: [PATCH 0494/2325] test: remove $CSRFProtection properties in Mock*Config.php It does not exist. --- system/Test/Mock/MockAppConfig.php | 1 - system/Test/Mock/MockCLIConfig.php | 1 - 2 files changed, 2 deletions(-) diff --git a/system/Test/Mock/MockAppConfig.php b/system/Test/Mock/MockAppConfig.php index fe51c4d3202f..15aff95809f0 100644 --- a/system/Test/Mock/MockAppConfig.php +++ b/system/Test/Mock/MockAppConfig.php @@ -24,7 +24,6 @@ class MockAppConfig extends App public $cookieHTTPOnly = false; public $cookieSameSite = 'Lax'; public $proxyIPs = ''; - public $CSRFProtection = false; public $CSRFTokenName = 'csrf_test_name'; public $CSRFHeaderName = 'X-CSRF-TOKEN'; public $CSRFCookieName = 'csrf_cookie_name'; diff --git a/system/Test/Mock/MockCLIConfig.php b/system/Test/Mock/MockCLIConfig.php index 0e5f9c8dd64e..6eb0dd70a8b8 100644 --- a/system/Test/Mock/MockCLIConfig.php +++ b/system/Test/Mock/MockCLIConfig.php @@ -24,7 +24,6 @@ class MockCLIConfig extends App public $cookieHTTPOnly = false; public $cookieSameSite = 'Lax'; public $proxyIPs = ''; - public $CSRFProtection = false; public $CSRFTokenName = 'csrf_test_name'; public $CSRFCookieName = 'csrf_cookie_name'; public $CSRFExpire = 7200; From 2a9ab6a94bdf481a073877f6236e7cefe51af0c2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 17:08:47 +0900 Subject: [PATCH 0495/2325] docs: remove inappropriate samples Validation library does not trim the data unlike CI3's. Generally, HTML encoding should be done in Views. --- user_guide_src/source/libraries/validation.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index d8df45d1c95c..60cbec369b26 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -33,8 +33,7 @@ On the receiving end, the script must: be someone else's existing username, or perhaps even a reserved word. Etc. #. Sanitize the data for security. -#. Pre-format the data if needed (Does the data need to be trimmed? HTML - encoded? Etc.) +#. Pre-format the data if needed. #. Prep the data for insertion in the database. Although there is nothing terribly complex about the above process, it From 02a747ff590c6ffe9aeed99725daee1ad261fb7b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 17:33:00 +0900 Subject: [PATCH 0496/2325] docs: decorate variables --- user_guide_src/source/libraries/validation.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 60cbec369b26..10aa4cbd1135 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -232,7 +232,7 @@ that should be applied:: $validation->setRule('username', 'Username', 'required'); The **field name** must match the key of any data array that is sent in. If -the data is taken directly from $_POST, then it must be an exact match for +the data is taken directly from ``$_POST``, then it must be an exact match for the form input name. setRules() @@ -439,7 +439,7 @@ Validation Placeholders The Validation class provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply -the name of the field (or array key) that was passed in as $data surrounded by curly brackets. It will be +the name of the field (or array key) that was passed in as ``$data`` surrounded by curly brackets. It will be replaced by the **value** of the matched incoming field. An example should clarify this:: $validation->setRules([ @@ -686,7 +686,7 @@ a boolean true or false value signifying true if it passed the test or false if } By default, the system will look within ``CodeIgniter\Language\en\Validation.php`` for the language strings used -within errors. In custom rules, you may provide error messages by accepting a $error variable by reference in the +within errors. In custom rules, you may provide error messages by accepting a ``$error`` variable by reference in the second parameter:: public function even(string $str, string &$error = null): bool @@ -710,7 +710,7 @@ Allowing Parameters =================== If your method needs to work with parameters, the function will need a minimum of three parameters: the string to validate, -the parameter string, and an array with all of the data that was submitted the form. The $data array is especially handy +the parameter string, and an array with all of the data that was submitted the form. The ``$data`` array is especially handy for rules like ``require_with`` that needs to check the value of another submitted field to base its result on:: public function required_with($str, string $fields, array $data): bool From 09612db82d36c5011172c04f695410668954f8b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 17:33:57 +0900 Subject: [PATCH 0497/2325] docs: fix descrition aboug PHP native functions When using native functions, it needs one or three params. $rule($value) or $rule($value, $param, $data). It seems there is no function to fit the API. CI3's validation alters data. CI4 does not. --- user_guide_src/source/libraries/validation.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 10aa4cbd1135..1779877c50b1 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -928,6 +928,6 @@ is_image Yes Fails if the file cannot be determined to be The file validation rules apply for both single and multiple file uploads. -.. note:: You can also use any native PHP functions that permit up - to two parameters, where at least one is required (to pass - the field data). +.. note:: You can also use any native PHP functions that return boolean and + permit at least one parameter, the field data to validate. + The Validation library **never alters the data** to validate. From fb30326e2a7c579fb7b9ff29557c4576e49e02c7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 15:09:09 +0900 Subject: [PATCH 0498/2325] docs: fix comment --- system/Security/Security.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index d6edbb23025a..fc472fec6e99 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -270,7 +270,7 @@ public function verify(RequestInterface $request) $token = $this->getPostedToken($request); - // Does the tokens exist in both the POST/POSTed JSON and COOKIE arrays and match? + // Do the tokens match? if (! isset($token, $this->hash) || ! hash_equals($this->hash, $token)) { throw SecurityException::forDisallowedAction(); } From d67de2017ea7d2e1f3590b7fae9651aaa85bf289 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 15:11:02 +0900 Subject: [PATCH 0499/2325] feat: protect CSRF for PUT/PATCH/DELETE Fixes #2913 --- system/Security/Security.php | 10 ++++--- .../Security/SecurityCSRFSessionTest.php | 30 +++++++++++++++++-- tests/system/Security/SecurityTest.php | 2 +- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/system/Security/Security.php b/system/Security/Security.php index fc472fec6e99..01dd92b33c19 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -259,13 +259,15 @@ public function getCSRFTokenName(): string * * @throws SecurityException * - * @return $this|false + * @return $this */ public function verify(RequestInterface $request) { - // If it's not a POST request we will set the CSRF cookie. - if (strtoupper($_SERVER['REQUEST_METHOD']) !== 'POST') { - return $this->sendCookie($request); + // Protects POST, PUT, DELETE, PATCH + $method = strtoupper($_SERVER['REQUEST_METHOD']); + $methodsToProtect = ['POST', 'PUT', 'DELETE', 'PATCH']; + if (! in_array($method, $methodsToProtect, true)) { + return $this; } $token = $this->getPostedToken($request); diff --git a/tests/system/Security/SecurityCSRFSessionTest.php b/tests/system/Security/SecurityCSRFSessionTest.php index 040f253b9774..c0ec2c066c40 100644 --- a/tests/system/Security/SecurityCSRFSessionTest.php +++ b/tests/system/Security/SecurityCSRFSessionTest.php @@ -127,7 +127,7 @@ public function testCSRFVerifyPostReturnsSelfOnMatch() $this->assertTrue(count($_POST) === 1); } - public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch() + public function testCSRFVerifyPOSTHeaderThrowsExceptionOnNoMatch() { $_SERVER['REQUEST_METHOD'] = 'POST'; @@ -140,7 +140,7 @@ public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch() $security->verify($request); } - public function testCSRFVerifyHeaderReturnsSelfOnMatch() + public function testCSRFVerifyPOSTHeaderReturnsSelfOnMatch() { $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['foo'] = 'bar'; @@ -155,6 +155,32 @@ public function testCSRFVerifyHeaderReturnsSelfOnMatch() $this->assertCount(1, $_POST); } + public function testCSRFVerifyPUTHeaderThrowsExceptionOnNoMatch() + { + $_SERVER['REQUEST_METHOD'] = 'PUT'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005b'); + + $security = new Security(new MockAppConfig()); + + $this->expectException(SecurityException::class); + $security->verify($request); + } + + public function testCSRFVerifyPUTHeaderReturnsSelfOnMatch() + { + $_SERVER['REQUEST_METHOD'] = 'PUT'; + + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); + + $security = new Security(new MockAppConfig()); + + $this->assertInstanceOf(Security::class, $security->verify($request)); + $this->assertLogged('info', 'CSRF token verified.'); + } + public function testCSRFVerifyJsonThrowsExceptionOnNoMatch() { $this->expectException(SecurityException::class); diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 74e8621e3a34..eadcf5ff6326 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -66,7 +66,7 @@ public function testHashIsReadFromCookie() $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); } - public function testCSRFVerifySetsCookieWhenNotPOST() + public function testGetHashSetsCookieWhenNotPOST() { $security = new MockSecurity(new MockAppConfig()); From adf02f0c2583139fee86869032485ef8e83251b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 16:22:10 +0900 Subject: [PATCH 0500/2325] fix: HTTP Method Spoofing does not work correctly for Config\Filter::$methods and CSRF protection --- system/Filters/Filters.php | 2 +- system/Security/Security.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Filters/Filters.php b/system/Filters/Filters.php index c81dadf3330f..70cf58986727 100644 --- a/system/Filters/Filters.php +++ b/system/Filters/Filters.php @@ -443,7 +443,7 @@ protected function processMethods() } // Request method won't be set for CLI-based requests - $method = strtolower($_SERVER['REQUEST_METHOD'] ?? 'cli'); + $method = strtolower($this->request->getMethod()) ?? 'cli'; if (array_key_exists($method, $this->config->methods)) { $this->filters['before'] = array_merge($this->filters['before'], $this->config->methods[$method]); diff --git a/system/Security/Security.php b/system/Security/Security.php index 01dd92b33c19..d9a44c4c9e6a 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -264,7 +264,7 @@ public function getCSRFTokenName(): string public function verify(RequestInterface $request) { // Protects POST, PUT, DELETE, PATCH - $method = strtoupper($_SERVER['REQUEST_METHOD']); + $method = strtoupper($request->getMethod()); $methodsToProtect = ['POST', 'PUT', 'DELETE', 'PATCH']; if (! in_array($method, $methodsToProtect, true)) { return $this; From f44ceba98c7586eb933abb20d079cd94f6435c6c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 18:17:38 +0900 Subject: [PATCH 0501/2325] test: fix test CLIRequest should be used when CLI testing --- tests/system/Filters/FiltersTest.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php index dbe88c4879c5..1b8b4b27d956 100644 --- a/tests/system/Filters/FiltersTest.php +++ b/tests/system/Filters/FiltersTest.php @@ -13,8 +13,10 @@ use CodeIgniter\Config\Services; use CodeIgniter\Filters\Exceptions\FilterException; +use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\Mock\MockAppConfig; require_once __DIR__ . '/fixtures/GoogleMe.php'; require_once __DIR__ . '/fixtures/GoogleYou.php'; @@ -60,7 +62,8 @@ public function testProcessMethodDetectsCLI() 'cli' => ['foo'], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); + $request = new CLIRequest(new MockAppConfig()); + $filters = new Filters((object) $config, $request, $this->response); $expected = [ 'before' => ['foo'], From fa78859639c6de7243db4975ea82deacb8b751db Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 18:19:31 +0900 Subject: [PATCH 0502/2325] test: fix tests Request object should be created after setting super globals. --- tests/system/Filters/FiltersTest.php | 174 +++++++++++++++------------ 1 file changed, 94 insertions(+), 80 deletions(-) diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php index 1b8b4b27d956..dae4074cd134 100644 --- a/tests/system/Filters/FiltersTest.php +++ b/tests/system/Filters/FiltersTest.php @@ -50,7 +50,6 @@ protected function setUp(): void Services::autoloader()->addNamespace($defaults); - $this->request = Services::request(); $this->response = Services::response(); } @@ -83,7 +82,8 @@ public function testProcessMethodDetectsGetRequests() 'get' => ['foo'], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $expected = [ 'before' => ['foo'], @@ -107,7 +107,8 @@ public function testProcessMethodRespectsMethod() 'get' => ['bar'], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $expected = [ 'before' => ['bar'], @@ -131,7 +132,8 @@ public function testProcessMethodIgnoresMethod() 'get' => ['bar'], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $expected = [ 'before' => [], @@ -161,8 +163,8 @@ public function testProcessMethodProcessGlobals() ], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $expected = [ 'before' => [ @@ -210,8 +212,9 @@ public function testProcessMethodProcessGlobalsWithExcept(array $except) ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -240,8 +243,9 @@ public function testProcessMethodProcessesFiltersBefore() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => ['foo'], @@ -268,8 +272,9 @@ public function testProcessMethodProcessesFiltersAfter() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'users/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'users/foo/bar'; $expected = [ 'before' => [], @@ -314,8 +319,9 @@ public function testProcessMethodProcessesCombined() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -355,8 +361,9 @@ public function testProcessMethodProcessesCombinedAfterForToolbar() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => ['bar'], @@ -381,8 +388,8 @@ public function testRunThrowsWithInvalidAlias() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $this->expectException(FilterException::class); $uri = 'admin/foo/bar'; @@ -401,9 +408,9 @@ public function testCustomFiltersLoad() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $request = $filters->run($uri, 'before'); @@ -421,8 +428,8 @@ public function testRunThrowsWithInvalidClassType() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $this->expectException(FilterException::class); $uri = 'admin/foo/bar'; @@ -441,9 +448,9 @@ public function testRunDoesBefore() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $request = $filters->run($uri, 'before'); @@ -461,9 +468,9 @@ public function testRunDoesAfter() 'after' => ['google'], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $response = $filters->run($uri, 'after'); @@ -481,9 +488,9 @@ public function testShortCircuit() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $response = $filters->run($uri, 'before'); $this->assertTrue($response instanceof ResponseInterface); @@ -507,9 +514,9 @@ public function testOtherResult() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $response = $filters->run($uri, 'before'); @@ -536,8 +543,9 @@ public function testBeforeExceptString() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -569,8 +577,9 @@ public function testBeforeExceptInapplicable() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -603,8 +612,9 @@ public function testAfterExceptString() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -636,8 +646,9 @@ public function testAfterExceptInapplicable() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -663,8 +674,8 @@ public function testAddFilter() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters = $filters->addFilter('Some\Class', 'some_alias'); @@ -679,9 +690,9 @@ public function testAddFilterSection() { $_SERVER['REQUEST_METHOD'] = 'GET'; - $config = []; - - $filters = new Filters((object) $config, $this->request, $this->response); + $config = []; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters = $filters ->addFilter('Some\OtherClass', 'another', 'before', 'globals') @@ -696,9 +707,9 @@ public function testInitializeTwice() { $_SERVER['REQUEST_METHOD'] = 'GET'; - $config = []; - - $filters = new Filters((object) $config, $this->request, $this->response); + $config = []; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters = $filters ->addFilter('Some\OtherClass', 'another', 'before', 'globals') @@ -721,8 +732,8 @@ public function testEnableFilter() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters = $filters->initialize('admin/foo/bar'); @@ -744,9 +755,9 @@ public function testEnableFilterWithArguments() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $filters = $filters->initialize('admin/foo/bar'); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $filters = $filters->initialize('admin/foo/bar'); $filters->enableFilter('role:admin , super', 'before'); $filters->enableFilter('role:admin , super', 'after'); @@ -775,8 +786,8 @@ public function testEnableFilterWithNoArguments() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters = $filters->initialize('admin/foo/bar'); @@ -807,8 +818,8 @@ public function testEnableNonFilter() 'after' => [], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters = $filters->initialize('admin/foo/bar'); @@ -846,8 +857,9 @@ public function testMatchesURICaseInsensitively() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $expected = [ 'before' => [ @@ -883,9 +895,9 @@ public function testFilterMatching() ], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin'; $expected = [ 'before' => [ @@ -922,9 +934,9 @@ public function testGlobalFilterMatching() ], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin'; $expected = [ 'before' => [ @@ -971,9 +983,9 @@ public function testCombinedFilterMatching() ], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin123'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin123'; $expected = [ 'before' => [ @@ -1017,9 +1029,9 @@ public function testSegmentedFilterMatching() ], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/123'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/123'; $expected = [ 'before' => [ @@ -1051,8 +1063,9 @@ public function testFilterAlitasMultiple() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin/foo/bar'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin/foo/bar'; $request = $filters->run($uri, 'before'); $this->assertSame('http://exampleMultipleURL.com', $request->url); @@ -1074,7 +1087,8 @@ public function testFilterClass() ], ], ]; - $filters = new Filters((object) $config, $this->request, $this->response); + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); $filters->run('admin/foo/bar', 'before'); $expected = [ @@ -1101,9 +1115,9 @@ public function testReset() ], ], ]; - - $filters = new Filters((object) $config, $this->request, $this->response); - $uri = 'admin'; + $this->request = Services::request(); + $filters = new Filters((object) $config, $this->request, $this->response); + $uri = 'admin'; $this->assertSame(['foo'], $filters->initialize($uri)->getFilters()['before']); $this->assertSame([], $filters->reset()->getFilters()['before']); From 11b5c265ae8e121fe8a2d6326ec742103422d8a6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Oct 2021 19:02:26 +0900 Subject: [PATCH 0503/2325] test: fix tests Security object should be created after setting super globals. --- tests/system/Security/SecurityTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index eadcf5ff6326..9f14e355b981 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -79,13 +79,13 @@ public function testGetHashSetsCookieWhenNotPOST() public function testCSRFVerifyPostThrowsExceptionOnNoMatch() { - $security = new MockSecurity(new MockAppConfig()); - $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); - $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST['csrf_test_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; + $security = new MockSecurity(new MockAppConfig()); + $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); + $this->expectException(SecurityException::class); $security->verify($request); } @@ -108,14 +108,14 @@ public function testCSRFVerifyPostReturnsSelfOnMatch() public function testCSRFVerifyHeaderThrowsExceptionOnNoMatch() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; + $security = new MockSecurity(new MockAppConfig()); $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); $request->setHeader('X-CSRF-TOKEN', '8b9218a55906f9dcc1dc263dce7f005a'); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; - $this->expectException(SecurityException::class); $security->verify($request); } @@ -139,14 +139,14 @@ public function testCSRFVerifyHeaderReturnsSelfOnMatch() public function testCSRFVerifyJsonThrowsExceptionOnNoMatch() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; + $security = new MockSecurity(new MockAppConfig()); $request = new IncomingRequest(new MockAppConfig(), new URI('http://badurl.com'), null, new UserAgent()); $request->setBody('{"csrf_test_name":"8b9218a55906f9dcc1dc263dce7f005a"}'); - $_SERVER['REQUEST_METHOD'] = 'POST'; - $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005b'; - $this->expectException(SecurityException::class); $security->verify($request); } From 070cdb458dbbd771a2a9175f04f97c64a0ae9cb3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 11:25:33 +0900 Subject: [PATCH 0504/2325] docs: update user guide --- user_guide_src/source/changelogs/v4.1.5.rst | 6 ++++++ .../source/installation/upgrade_415.rst | 17 +++++++++++++++++ user_guide_src/source/libraries/security.rst | 10 ++++++++++ 3 files changed, 33 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst index 328e45163cb3..3290763f0ed3 100644 --- a/user_guide_src/source/changelogs/v4.1.5.rst +++ b/user_guide_src/source/changelogs/v4.1.5.rst @@ -5,6 +5,12 @@ Release Date: Not released **4.1.5 release of CodeIgniter4** +BREAKING: + +Fixed `a bug `_ on CSRF protection. +Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied. +If you use such requests, you need to send CSRF token. + Enhancements: - Added Cache config for reserved characters diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst index b05d0d0030a6..c9a6eb07da6e 100644 --- a/user_guide_src/source/installation/upgrade_415.rst +++ b/user_guide_src/source/installation/upgrade_415.rst @@ -53,3 +53,20 @@ The following methods and a property have been deprecated: - ``CodeIgniter\Router\RouteCollection``'s property ``$filterInfo`` See *Applying Filters* in :doc:`Routing ` for the functionality. + +**CSRF Protection** + +Because of a bug fix, +now CSRF protection works on not only **POST** but also **PUT/PATCH/DELETE** requests when CSRF filter is applied. + +When you use **PUT/PATCH/DELETE** requests, you need to send CSRF token. Or remove the CSRF filter +for such requests if you don't need CSRF protection for them. + +If you want the same behavior as the previous version, set the CSRF filter like the following in **app/Config/Filters.php**:: + + public $methods = [ + 'get' => ['csrf'], + 'post' => ['csrf'], + ]; + +Protecting **GET** method needs only when you use ``form_open()`` auto-generation of CSRF field. diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index d788e2d2a808..48b97baf1f61 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -23,6 +23,9 @@ If you find a case where you do need direct access though, you may load it throu Cross-site request forgery (CSRF) ********************************* +.. warning:: The CSRF Protection is only available for **POST/PUT/PATCH/DELETE** requests. + Requests for other methods are not protected. + Enable CSRF Protection ====================== @@ -54,6 +57,13 @@ Regular expressions are also supported (case-insensitive):: ], ]; +It is also possible to enable the CSRF filter only for specific methods:: + + public $methods = [ + 'get' => ['csrf'], + 'post' => ['csrf'], + ]; + HTML Forms ========== From e19228acfbaac655256498ef746d16e47247bc6c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Oct 2021 10:38:44 +0900 Subject: [PATCH 0505/2325] docs: improve Upgrading 4.1.5 page format --- .../source/installation/upgrade_415.rst | 57 +++++++++++++------ 1 file changed, 40 insertions(+), 17 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst index c9a6eb07da6e..6c20797775af 100644 --- a/user_guide_src/source/installation/upgrade_415.rst +++ b/user_guide_src/source/installation/upgrade_415.rst @@ -2,7 +2,15 @@ Upgrading from 4.1.4 to 4.1.5 ############################# -**Changes for set() method in BaseBuilder and Model class** +.. contents:: + :local: + :depth: 1 + +Breaking Changes +================ + +Changes for set() method in BaseBuilder and Model class +------------------------------------------------------- The casting for the ``$value`` parameter has been removed to fix a bug where passing parameters as array and string to the ``set()`` method were handled differently. If you extended the ``BaseBuilder`` class or ``Model`` class yourself @@ -10,7 +18,8 @@ and modified the ``set()`` method, then you need to change its definition from ``public function set($key, ?string $value = '', ?bool $escape = null)`` to ``public function set($key, $value = '', ?bool $escape = null)``. -**Session DatabaseHandler's database table change** +Session DatabaseHandler's database table change +----------------------------------------------- The types of the following columns in the session table have been changed for optimization. @@ -26,7 +35,29 @@ Update the definition of the session table. See the :doc:`/libraries/sessions` f The change was introduced in v4.1.2. But due to `a bug `_, the DatabaseHandler Driver did not work properly. -**Multiple filters for a route** +CSRF Protection +--------------- + +Because of a bug fix, +now CSRF protection works on not only **POST** but also **PUT/PATCH/DELETE** requests when CSRF filter is applied. + +When you use **PUT/PATCH/DELETE** requests, you need to send CSRF token. Or remove the CSRF filter +for such requests if you don't need CSRF protection for them. + +If you want the same behavior as the previous version, set the CSRF filter like the following in **app/Config/Filters.php**:: + + public $methods = [ + 'get' => ['csrf'], + 'post' => ['csrf'], + ]; + +Protecting **GET** method needs only when you use ``form_open()`` auto-generation of CSRF field. + +Breaking Enhancements +===================== + +Multiple filters for a route +---------------------------- A new feature to set multiple filters for a route. @@ -54,19 +85,11 @@ The following methods and a property have been deprecated: See *Applying Filters* in :doc:`Routing ` for the functionality. -**CSRF Protection** - -Because of a bug fix, -now CSRF protection works on not only **POST** but also **PUT/PATCH/DELETE** requests when CSRF filter is applied. - -When you use **PUT/PATCH/DELETE** requests, you need to send CSRF token. Or remove the CSRF filter -for such requests if you don't need CSRF protection for them. - -If you want the same behavior as the previous version, set the CSRF filter like the following in **app/Config/Filters.php**:: +Project Files +============= - public $methods = [ - 'get' => ['csrf'], - 'post' => ['csrf'], - ]; +Content Changes +--------------- -Protecting **GET** method needs only when you use ``form_open()`` auto-generation of CSRF field. +All Changes +----------- From f98556127023f89354b3ec2276cd4757beadd577 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Sun, 24 Oct 2021 14:18:49 +0800 Subject: [PATCH 0506/2325] Rename toolbar loader to be a regular JS file * Rename toolbar loader to be a regular JS file * Use `str_replace` instead of `window.appUrl` --- system/Debug/Toolbar.php | 4 ++-- .../Views/{toolbarloader.js.php => toolbarloader.js} | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) rename system/Debug/Toolbar/Views/{toolbarloader.js.php => toolbarloader.js} (96%) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 2199559d362d..b951e2ed9658 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -435,9 +435,9 @@ public function respond() header('Content-Type: application/javascript'); ob_start(); - include $this->config->viewsPath . 'toolbarloader.js.php'; + include $this->config->viewsPath . 'toolbarloader.js'; $output = ob_get_clean(); - $output = substr($output, 8, -10); // trim the script tags + $output = str_replace('{url}', rtrim(site_url(), '/'), $output); echo $output; exit; diff --git a/system/Debug/Toolbar/Views/toolbarloader.js.php b/system/Debug/Toolbar/Views/toolbarloader.js similarity index 96% rename from system/Debug/Toolbar/Views/toolbarloader.js.php rename to system/Debug/Toolbar/Views/toolbarloader.js index add85b52acda..7e5914354481 100644 --- a/system/Debug/Toolbar/Views/toolbarloader.js.php +++ b/system/Debug/Toolbar/Views/toolbarloader.js @@ -1,7 +1,3 @@ - - From 4876b4855e1568e3aad66c1c89525034f0996986 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 24 Oct 2021 15:58:34 +0700 Subject: [PATCH 0507/2325] [HTTP] Update Http Status Description based on latest iana.org --- system/HTTP/Response.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/HTTP/Response.php b/system/HTTP/Response.php index 70f31bd35f72..4efc6e804d3f 100644 --- a/system/HTTP/Response.php +++ b/system/HTTP/Response.php @@ -79,15 +79,15 @@ class Response extends Message implements MessageInterface, ResponseInterface 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', + 413 => 'Content Too Large', // https://www.iana.org/assignments/http-status-codes/http-status-codes.xml + 414 => 'URI Too Long', // https://www.iana.org/assignments/http-status-codes/http-status-codes.xml 415 => 'Unsupported Media Type', 416 => 'Requested Range Not Satisfiable', 417 => 'Expectation Failed', 418 => "I'm a teapot", // April's Fools joke; http://www.ietf.org/rfc/rfc2324.txt // 419 (Authentication Timeout) is a non-standard status code with unknown origin 421 => 'Misdirected Request', // http://www.iana.org/go/rfc7540 Section 9.1.2 - 422 => 'Unprocessable Entity', // http://www.iana.org/go/rfc4918 + 422 => 'Unprocessable Content', // https://www.iana.org/assignments/http-status-codes/http-status-codes.xml 423 => 'Locked', // http://www.iana.org/go/rfc4918 424 => 'Failed Dependency', // http://www.iana.org/go/rfc4918 425 => 'Too Early', // https://datatracker.ietf.org/doc/draft-ietf-httpbis-replay/ From 1121abae4693ad3d36a85bc4a5edcce23709d43f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 25 Oct 2021 10:39:05 +0900 Subject: [PATCH 0508/2325] test: reduce the size of the method to be mocked --- system/Test/Mock/MockSecurity.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/system/Test/Mock/MockSecurity.php b/system/Test/Mock/MockSecurity.php index 3f802a7d79f6..e24221c17b47 100644 --- a/system/Test/Mock/MockSecurity.php +++ b/system/Test/Mock/MockSecurity.php @@ -11,15 +11,12 @@ namespace CodeIgniter\Test\Mock; -use CodeIgniter\HTTP\RequestInterface; use CodeIgniter\Security\Security; class MockSecurity extends Security { - protected function sendCookie(RequestInterface $request) + protected function doSendCookie(): void { $_COOKIE['csrf_cookie_name'] = $this->hash; - - return $this; } } From 6af9fc56ba06b42efe366bbde198c80cf5d6fabf Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 25 Oct 2021 10:41:16 +0900 Subject: [PATCH 0509/2325] test: add a test case --- tests/system/Security/SecurityTest.php | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/system/Security/SecurityTest.php b/tests/system/Security/SecurityTest.php index 9f14e355b981..ba6a4ada5024 100644 --- a/tests/system/Security/SecurityTest.php +++ b/tests/system/Security/SecurityTest.php @@ -66,7 +66,7 @@ public function testHashIsReadFromCookie() $this->assertSame('8b9218a55906f9dcc1dc263dce7f005a', $security->getHash()); } - public function testGetHashSetsCookieWhenNotPOST() + public function testGetHashSetsCookieWhenGETWithoutCSRFCookie() { $security = new MockSecurity(new MockAppConfig()); @@ -77,6 +77,18 @@ public function testGetHashSetsCookieWhenNotPOST() $this->assertSame($_COOKIE['csrf_cookie_name'], $security->getHash()); } + public function testGetHashReturnsCSRFCookieWhenGETWithCSRFCookie() + { + $_SERVER['REQUEST_METHOD'] = 'GET'; + $_COOKIE['csrf_cookie_name'] = '8b9218a55906f9dcc1dc263dce7f005a'; + + $security = new MockSecurity(new MockAppConfig()); + + $security->verify(new Request(new MockAppConfig())); + + $this->assertSame($_COOKIE['csrf_cookie_name'], $security->getHash()); + } + public function testCSRFVerifyPostThrowsExceptionOnNoMatch() { $_SERVER['REQUEST_METHOD'] = 'POST'; From 2a3767ad91c5387e67307d815264a99da8d18dc9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 25 Oct 2021 11:09:13 +0900 Subject: [PATCH 0510/2325] docs: fix format of testing/overview.rst --- user_guide_src/source/testing/overview.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index f237acc03412..0a16a07b34ac 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -80,7 +80,7 @@ To test a new library, **Foo**, you would create a new file at **tests/app/Libra } } -To test one of your models, you might end up with something like this in ``tests/app/Models/OneOfMyModelsTest.php``:: +To test one of your models, you might end up with something like this in **tests/app/Models/OneOfMyModelsTest.php**:: assertEventTriggered('foo'); -**assertHeaderEmitted($header, $ignoreCase=false)** +**assertHeaderEmitted($header, $ignoreCase = false)** Ensure that a header or cookie was actually emitted:: @@ -218,7 +218,7 @@ Ensure that a header or cookie was actually emitted:: Note: the test case with this should be `run as a separate process in PHPunit `_. -**assertHeaderNotEmitted($header, $ignoreCase=false)** +**assertHeaderNotEmitted($header, $ignoreCase = false)** Ensure that a header or cookie was not emitted:: @@ -233,7 +233,7 @@ Ensure that a header or cookie was not emitted:: Note: the test case with this should be `run as a separate process in PHPunit `_. -**assertCloseEnough($expected, $actual, $message='', $tolerance=1)** +**assertCloseEnough($expected, $actual, $message = '', $tolerance = 1)** For extended execution time testing, tests that the absolute difference between expected and actual time is within the prescribed tolerance.:: @@ -244,7 +244,7 @@ between expected and actual time is within the prescribed tolerance.:: The above test will allow the actual time to be either 660 or 661 seconds. -**assertCloseEnoughString($expected, $actual, $message='', $tolerance=1)** +**assertCloseEnoughString($expected, $actual, $message = '', $tolerance = 1)** For extended execution time testing, tests that the absolute difference between expected and actual time, formatted as strings, is within the prescribed tolerance.:: From e2f4e59e253363b6a191a80e9a208a09f1371997 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 25 Oct 2021 11:14:07 +0900 Subject: [PATCH 0511/2325] docs: Zip file does not contain the user guide --- user_guide_src/source/installation/upgrade_4xx.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index bfc38a852778..f28de5092e3d 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -30,7 +30,7 @@ General Adjustments **Downloads** -- CI4 is still available as a ready-to-run zip or tarball, which includes the user guide (though in the `docs` subfolder). +- CI4 is still available as a ready-to-run zip or tarball. - It can also be installed using Composer. **Namespaces** From 024df6cbedfacfe509999abf85bdaa0ef957dfcc Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 25 Oct 2021 11:32:34 +0900 Subject: [PATCH 0512/2325] fix: remove extra DIRECTORY_SEPARATOR Co-authored-by: MGatner --- system/Publisher/Publisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index a492a03e02c3..dac7aa898f1a 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -230,7 +230,7 @@ final public function getScratch(): string $this->scratch = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . bin2hex(random_bytes(6)) . DIRECTORY_SEPARATOR; mkdir($this->scratch, 0700); $this->scratch = realpath($this->scratch) ? realpath($this->scratch) . DIRECTORY_SEPARATOR - : $this->scratch . DIRECTORY_SEPARATOR; + : $this->scratch; } return $this->scratch; From 7634d3a7a7f9f3bd8848e956a5797f9c40e78f02 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 25 Oct 2021 14:35:29 +0700 Subject: [PATCH 0513/2325] [Rector] Using LevelSetList::UP_TO_PHP_73 --- rector.php | 20 +++++++++++++++++++- tests/system/Autoloader/FileLocatorTest.php | 2 +- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/rector.php b/rector.php index aa9546d37ca9..fdd78a85e86c 100644 --- a/rector.php +++ b/rector.php @@ -37,11 +37,16 @@ use Rector\EarlyReturn\Rector\If_\ChangeIfElseValueAssignToEarlyReturnRector; use Rector\EarlyReturn\Rector\If_\RemoveAlwaysElseRector; use Rector\EarlyReturn\Rector\Return_\PreparedValueToEarlyReturnRector; +use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; +use Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector; +use Rector\Php70\Rector\FuncCall\RandomFunctionRector; use Rector\Php70\Rector\Ternary\TernaryToNullCoalescingRector; +use Rector\Php71\Rector\FuncCall\CountOnNullRector; use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; use Rector\Php71\Rector\List_\ListToArrayDestructRector; use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; +use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Utils\Rector\PassStrictParameterToFunctionParameterRector; @@ -51,7 +56,7 @@ return static function (ContainerConfigurator $containerConfigurator): void { $containerConfigurator->import(SetList::DEAD_CODE); - $containerConfigurator->import(SetList::PHP_73); + $containerConfigurator->import(LevelSetList::UP_TO_PHP_73); $parameters = $containerConfigurator->parameters(); @@ -95,6 +100,19 @@ UnderscoreToCamelCaseVariableNameRector::class => [ __DIR__ . '/system/Session/Handlers', ], + + // may cause load view files directly when detecting class that + // make warning + StringClassNameToClassConstantRector::class, + + // sometime too detail + CountOnNullRector::class, + + // may not be unitialized on purpose + AddDefaultValueForUndefinedVariableRector::class, + + // use mt_rand instead of random_int on purpose on non-cryptographically random + RandomFunctionRector::class, ]); // auto import fully qualified class names diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 8a8b91aeea90..c85e4c215ba2 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -261,7 +261,7 @@ public function testFindQNameFromPathWithoutCorrespondingNamespace() public function testGetClassNameFromClassFile() { $this->assertSame( - __CLASS__, + self::class, $this->locator->getClassname(__FILE__) ); } From dd72eef46b63a7fb87ef38e0a0be971de8d68bf6 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 25 Oct 2021 14:42:42 +0700 Subject: [PATCH 0514/2325] clean up existing already in set list --- rector.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/rector.php b/rector.php index fdd78a85e86c..04e761cbf89e 100644 --- a/rector.php +++ b/rector.php @@ -40,10 +40,7 @@ use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector; use Rector\Php56\Rector\FunctionLike\AddDefaultValueForUndefinedVariableRector; use Rector\Php70\Rector\FuncCall\RandomFunctionRector; -use Rector\Php70\Rector\Ternary\TernaryToNullCoalescingRector; use Rector\Php71\Rector\FuncCall\CountOnNullRector; -use Rector\Php71\Rector\FuncCall\RemoveExtraParametersRector; -use Rector\Php71\Rector\List_\ListToArrayDestructRector; use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector; use Rector\Php73\Rector\FuncCall\StringifyStrNeedlesRector; use Rector\Set\ValueObject\LevelSetList; @@ -141,12 +138,9 @@ $services->set(ChangeArrayPushToArrayAssignRector::class); $services->set(UnnecessaryTernaryExpressionRector::class); $services->set(RemoveErrorSuppressInTryCatchStmtsRector::class); - $services->set(TernaryToNullCoalescingRector::class); - $services->set(ListToArrayDestructRector::class); $services->set(RemoveVarTagFromClassConstantRector::class); $services->set(AddPregQuoteDelimiterRector::class); $services->set(SimplifyRegexPatternRector::class); - $services->set(RemoveExtraParametersRector::class); $services->set(FuncGetArgsToVariadicParamRector::class); $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); $services->set(FixClassCaseSensitivityNameRector::class); From d1edaee437d256d9cc1e16c76c4fec2ba8de48c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 19 Oct 2021 21:57:21 +0900 Subject: [PATCH 0515/2325] fix: reset unneeded headers to prevent request error Fixes #4826 --- system/HTTP/CURLRequest.php | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 3be8214d42b4..3b4b3ef9a850 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -72,6 +72,16 @@ class CURLRequest extends Request */ protected $delay = 0.0; + /** + * Request headers that are not shared between requests. + * + * @var string[] + */ + private $unsharedHeaders = [ + 'Content-Length', + 'Content-Type', + ]; + /** * Takes an array of options to set the following possible class properties: * @@ -106,6 +116,11 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response */ public function request($method, string $url, array $options = []): ResponseInterface { + // Reset unshared headers + foreach ($this->unsharedHeaders as $header) { + $this->removeHeader($header); + } + $this->parseOptions($options); $url = $this->prepareURL($url); @@ -379,6 +394,29 @@ protected function applyRequestHeaders(array $curlOptions = []): array return $curlOptions; } + /** + * Override + */ + public function populateHeaders(): void + { + foreach (array_keys($_SERVER) as $key) { + if (sscanf($key, 'HTTP_%s', $header) === 1) { + // take SOME_HEADER and turn it into Some-Header + $header = str_replace('_', ' ', strtolower($header)); + $header = str_replace(' ', '-', ucwords($header)); + + if (in_array($header, $this->unsharedHeaders, true)) { + continue; + } + + $this->setHeader($header, $_SERVER[$key]); + + // Add us to the header map so we can find them case-insensitively + $this->headerMap[strtolower($header)] = $header; + } + } + } + /** * Apply method */ From 245dade5a52217c9eff313e6caa76c4c8531490e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 19 Oct 2021 21:58:32 +0900 Subject: [PATCH 0516/2325] fix: reset unneeded configs If you reset it at the beginning of the request(), you will not be able to use setForm(). --- system/HTTP/CURLRequest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 3b4b3ef9a850..2a305fa1c802 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -129,6 +129,9 @@ public function request($method, string $url, array $options = []): ResponseInte $this->send($method, $url); + // Reset unshared configs + unset($this->config['multipart'], $this->config['form_params']); + return $this->response; } From fa3620b24ae7bb15c00ca4fb49e56d36a8f4c510 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 19 Oct 2021 22:03:44 +0900 Subject: [PATCH 0517/2325] test: add test for CURLRequest unshared headers --- tests/system/HTTP/CURLRequestTest.php | 40 +++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index c1ac77765a44..56420caa863f 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -220,6 +220,46 @@ public function testOptionHeadersNotUsingPopulate() $this->assertSame('', $request->header('Accept-Encoding')->getValue()); } + public function testHeaderContentLengthNotSharedBetweenRequests() + { + $options = [ + 'base_uri' => 'http://www.foo.com/api/v1/', + ]; + $request = $this->getRequest($options); + + $request->post('example', [ + 'form_params' => [ + 'q' => 'keyword', + ], + ]); + $request->get('example'); + + $this->assertNull($request->header('Content-Length')); + } + + /** + * @backupGlobals enabled + */ + public function testHeaderContentLengthNotSharedBetweenClients() + { + $_SERVER['HTTP_CONTENT_LENGTH'] = '10'; + + $options = [ + 'base_uri' => 'http://www.foo.com/api/v1/', + ]; + $request = $this->getRequest($options); + $request->post('example', [ + 'form_params' => [ + 'q' => 'keyword', + ], + ]); + + $request = $this->getRequest($options); + $request->get('example'); + + $this->assertNull($request->header('Content-Length')); + } + public function testOptionsDelay() { $options = [ From 4b51e01b5b039d277b41930482220521f7af9970 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 19 Oct 2021 22:03:59 +0900 Subject: [PATCH 0518/2325] test: fix test method names --- tests/system/HTTP/CURLRequestTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 56420caa863f..b46cec5ce992 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -176,7 +176,7 @@ public function testOptionsHeaders() /** * @backupGlobals enabled */ - public function testOptionHeadersUsingPopulate() + public function testOptionsHeadersUsingPopulate() { $_SERVER['HTTP_HOST'] = 'site1.com'; $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US'; @@ -199,7 +199,7 @@ public function testOptionHeadersUsingPopulate() /** * @backupGlobals enabled */ - public function testOptionHeadersNotUsingPopulate() + public function testOptionsHeadersNotUsingPopulate() { $_SERVER['HTTP_HOST'] = 'site1.com'; $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US'; From c497b28998eff9a0c7786237b53f7391bb741c50 Mon Sep 17 00:00:00 2001 From: MGatner Date: Mon, 25 Oct 2021 11:21:40 -0400 Subject: [PATCH 0519/2325] Switch PHPCPD to tool --- .github/workflows/test-phpcpd.yml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index d78edbea1f0e..f4215df01c0e 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -34,10 +34,8 @@ jobs: uses: shivammathur/setup-php@v2 with: php-version: '8.0' - tools: phive - extensions: intl, json, mbstring, xml + tools: phpcpd + extensions: dom, mbstring - name: Detect code duplication - run: | - sudo phive --no-progress install --global --trust-gpg-keys 4AA394086372C20A phpcpd - phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php --exclude system/Database/SQLSRV/Forge.php app/ public/ system/ + run: phpcpd --exclude system/Test --exclude system/ThirdParty --exclude system/Database/SQLSRV/Builder.php --exclude system/Database/SQLSRV/Forge.php -- app/ public/ system/ From 0061d9d80cb404796e67ed25a7de55a695097a41 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 26 Oct 2021 12:56:03 +0900 Subject: [PATCH 0520/2325] docs: remove unnecessary headings --- user_guide_src/source/libraries/typography.rst | 6 ------ 1 file changed, 6 deletions(-) diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst index 24e52419df35..9b381a151cdc 100644 --- a/user_guide_src/source/libraries/typography.rst +++ b/user_guide_src/source/libraries/typography.rst @@ -24,8 +24,6 @@ Available static functions The following functions are available: -**autoTypography()** - .. php:function:: autoTypography($str[, $reduce_linebreaks = false]) :param string $str: Input string @@ -45,8 +43,6 @@ The following functions are available: function you may want to consider :doc:`caching <../general/caching>` your pages. -**formatCharacters()** - .. php:function:: formatCharacters($str) :param string $str: Input string @@ -61,8 +57,6 @@ The following functions are available: $string = $typography->formatCharacters($string); -**nl2brExceptPre()** - .. php:function:: nl2brExceptPre($str) :param string $str: Input string From 5a1c7808c94b73f096c606672d639545dee3f32e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 26 Oct 2021 12:56:57 +0900 Subject: [PATCH 0521/2325] docs: decorate HTML tags --- user_guide_src/source/libraries/typography.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/typography.rst b/user_guide_src/source/libraries/typography.rst index 9b381a151cdc..0a4ded63a898 100644 --- a/user_guide_src/source/libraries/typography.rst +++ b/user_guide_src/source/libraries/typography.rst @@ -63,9 +63,9 @@ The following functions are available: :returns: String with HTML-formatted line breaks :rtype: string - Converts newlines to
    tags unless they appear within
     tags.
    +    Converts newlines to ``
    `` tags unless they appear within ``
    `` tags.
         This function is identical to the native PHP ``nl2br()`` function,
    -    except that it ignores 
     tags.
    +    except that it ignores ``
    `` tags.
     
         Usage example::
     
    
    From 4de18315b909eb89e38c5539b8c157e2f7f883e0 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Wed, 27 Oct 2021 08:38:40 +0900
    Subject: [PATCH 0522/2325] test: fix failed test
    
    1) CodeIgniter\Commands\CreateDatabaseTest::testCreateDatabase
    Failed asserting that 'Database ".../CodeIgniter4/writable/foobar.db" already exists.\n
    \n
    ' contains "successfully created.".
    
    .../CodeIgniter4/tests/system/Commands/CreateDatabaseTest.php:68
    ---
     tests/system/Commands/CreateDatabaseTest.php | 15 +++++----------
     1 file changed, 5 insertions(+), 10 deletions(-)
    
    diff --git a/tests/system/Commands/CreateDatabaseTest.php b/tests/system/Commands/CreateDatabaseTest.php
    index aed4fd5c144e..3875a2f51e68 100644
    --- a/tests/system/Commands/CreateDatabaseTest.php
    +++ b/tests/system/Commands/CreateDatabaseTest.php
    @@ -38,22 +38,17 @@ protected function setUp(): void
             $this->connection   = Database::connect();
     
             parent::setUp();
    +
    +        $file = WRITEPATH . 'foobar.db';
    +        if (file_exists($file)) {
    +            unlink($file);
    +        }
         }
     
         protected function tearDown(): void
         {
             stream_filter_remove($this->streamFilter);
     
    -        if ($this->connection instanceof Connection) {
    -            $file = WRITEPATH . 'foobar.db';
    -
    -            if (file_exists($file)) {
    -                unlink($file);
    -            }
    -        } else {
    -            Database::forge()->dropDatabase('foobar');
    -        }
    -
             parent::tearDown();
         }
     
    
    From 0923134ec7b31604208e192f4d209d739096029f Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Wed, 27 Oct 2021 08:42:45 +0900
    Subject: [PATCH 0523/2325] test: fix failed test
    MIME-Version: 1.0
    Content-Type: text/plain; charset=UTF-8
    Content-Transfer-Encoding: 8bit
    
    2) CodeIgniter\I18n\TimeTest::testToFormattedDateString
    Failed asserting that two strings are identical.
    --- Expected
    +++ Actual
    @@ @@
    -'May 10, 2017'
    +'5月 10, 2017'
    
    .../CodeIgniter4/tests/system/I18n/TimeTest.php:643
    ---
     tests/system/I18n/TimeTest.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php
    index 2da8e5accbf3..da1ef5b3c5ef 100644
    --- a/tests/system/I18n/TimeTest.php
    +++ b/tests/system/I18n/TimeTest.php
    @@ -28,7 +28,7 @@ protected function setUp(): void
             parent::setUp();
     
             helper('date');
    -        Locale::setDefault('America/Chicago');
    +        Locale::setDefault('en_US');
         }
     
         public function testNewTimeNow()
    
    From f1a9f3bb1985350ed527a02e514b980dffc4b5d7 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Wed, 27 Oct 2021 11:28:12 +0900
    Subject: [PATCH 0524/2325] test: fix setUp()
    
    Drop database for non-SQLite connections.
    ---
     tests/system/Commands/CreateDatabaseTest.php | 16 ++++++++++------
     1 file changed, 10 insertions(+), 6 deletions(-)
    
    diff --git a/tests/system/Commands/CreateDatabaseTest.php b/tests/system/Commands/CreateDatabaseTest.php
    index 3875a2f51e68..1b6d28fdf0f8 100644
    --- a/tests/system/Commands/CreateDatabaseTest.php
    +++ b/tests/system/Commands/CreateDatabaseTest.php
    @@ -12,7 +12,7 @@
     namespace CodeIgniter\Commands;
     
     use CodeIgniter\Database\BaseConnection;
    -use CodeIgniter\Database\SQLite3\Connection;
    +use CodeIgniter\Database\SQLite3\Connection as SQLite3Connection;
     use CodeIgniter\Test\CIUnitTestCase;
     use CodeIgniter\Test\Filters\CITestStreamFilter;
     use Config\Database;
    @@ -39,9 +39,13 @@ protected function setUp(): void
     
             parent::setUp();
     
    -        $file = WRITEPATH . 'foobar.db';
    -        if (file_exists($file)) {
    -            unlink($file);
    +        if ($this->connection instanceof SQLite3Connection) {
    +            $file = WRITEPATH . 'foobar.db';
    +            if (file_exists($file)) {
    +                unlink($file);
    +            }
    +        } else {
    +            Database::forge()->dropDatabase('foobar');
             }
         }
     
    @@ -65,7 +69,7 @@ public function testCreateDatabase()
     
         public function testSqliteDatabaseDuplicated()
         {
    -        if (! $this->connection instanceof Connection) {
    +        if (! $this->connection instanceof SQLite3Connection) {
                 $this->markTestSkipped('Needs to run on SQLite3.');
             }
     
    @@ -78,7 +82,7 @@ public function testSqliteDatabaseDuplicated()
     
         public function testOtherDriverDuplicatedDatabase()
         {
    -        if ($this->connection instanceof Connection) {
    +        if ($this->connection instanceof SQLite3Connection) {
                 $this->markTestSkipped('Needs to run on non-SQLite3 drivers.');
             }
     
    
    From ee2b89481b7255bc64e0a409a164bdb7ba252755 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Wed, 27 Oct 2021 11:33:58 +0800
    Subject: [PATCH 0525/2325] Fix wrong helper path resolution
    
    ---
     system/Common.php                    |  16 +--
     tests/system/CommonFunctionsTest.php |  39 -------
     tests/system/CommonHelperTest.php    | 148 +++++++++++++++++++++++++++
     3 files changed, 153 insertions(+), 50 deletions(-)
     create mode 100644 tests/system/CommonHelperTest.php
    
    diff --git a/system/Common.php b/system/Common.php
    index 0750fe38764e..7c150a01c1d4 100644
    --- a/system/Common.php
    +++ b/system/Common.php
    @@ -560,7 +560,7 @@ function helper($filenames)
         {
             static $loaded = [];
     
    -        $loader = Services::locator(true);
    +        $loader = Services::locator();
     
             if (! is_array($filenames)) {
                 $filenames = [$filenames];
    @@ -596,18 +596,14 @@ function helper($filenames)
     
                     $includes[] = $path;
                     $loaded[]   = $filename;
    -            }
    -
    -            // No namespaces, so search in all available locations
    -            else {
    +            } else {
    +                // No namespaces, so search in all available locations
                     $paths = $loader->search('Helpers/' . $filename);
     
                     foreach ($paths as $path) {
    -                    if (strpos($path, APPPATH) === 0) {
    -                        // @codeCoverageIgnoreStart
    +                    if (strpos($path, APPPATH . 'Helpers' . DIRECTORY_SEPARATOR) === 0) {
                             $appHelper = $path;
    -                    // @codeCoverageIgnoreEnd
    -                    } elseif (strpos($path, SYSTEMPATH) === 0) {
    +                    } elseif (strpos($path, SYSTEMPATH . 'Helpers' . DIRECTORY_SEPARATOR) === 0) {
                             $systemHelper = $path;
                         } else {
                             $localIncludes[] = $path;
    @@ -617,10 +613,8 @@ function helper($filenames)
     
                     // App-level helpers should override all others
                     if (! empty($appHelper)) {
    -                    // @codeCoverageIgnoreStart
                         $includes[] = $appHelper;
                         $loaded[]   = $filename;
    -                    // @codeCoverageIgnoreEnd
                     }
     
                     // All namespaced files get added in next
    diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php
    index ad5ae969b1bc..ba4c1e7a4e07 100644
    --- a/tests/system/CommonFunctionsTest.php
    +++ b/tests/system/CommonFunctionsTest.php
    @@ -29,9 +29,7 @@
     use Config\Logger;
     use Config\Modules;
     use InvalidArgumentException;
    -use RuntimeException;
     use stdClass;
    -use Tests\Support\Autoloader\FatalLocator;
     use Tests\Support\Models\JobModel;
     
     /**
    @@ -479,43 +477,6 @@ public function dirtyPathsProvider()
             ];
         }
     
    -    public function testHelperWithFatalLocatorThrowsException()
    -    {
    -        // Replace the locator with one that will fail if it is called
    -        $locator = new FatalLocator(Services::autoloader());
    -        Services::injectMock('locator', $locator);
    -
    -        try {
    -            helper('baguette');
    -            $exception = false;
    -        } catch (RuntimeException $e) {
    -            $exception = true;
    -        }
    -
    -        $this->assertTrue($exception);
    -        Services::reset();
    -    }
    -
    -    public function testHelperLoadsOnce()
    -    {
    -        // Load it the first time
    -        helper('baguette');
    -
    -        // Replace the locator with one that will fail if it is called
    -        $locator = new FatalLocator(Services::autoloader());
    -        Services::injectMock('locator', $locator);
    -
    -        try {
    -            helper('baguette');
    -            $exception = false;
    -        } catch (RuntimeException $e) {
    -            $exception = true;
    -        }
    -
    -        $this->assertFalse($exception);
    -        Services::reset();
    -    }
    -
         public function testIsCli()
         {
             $this->assertIsBool(is_cli());
    diff --git a/tests/system/CommonHelperTest.php b/tests/system/CommonHelperTest.php
    new file mode 100644
    index 000000000000..55d626cf966c
    --- /dev/null
    +++ b/tests/system/CommonHelperTest.php
    @@ -0,0 +1,148 @@
    +
    + *
    + * For the full copyright and license information, please view
    + * the LICENSE file that was distributed with this source code.
    + */
    +
    +namespace CodeIgniter;
    +
    +use CodeIgniter\Autoloader\FileLocator;
    +use CodeIgniter\Test\CIUnitTestCase;
    +use Config\Services;
    +use PHPUnit\Framework\MockObject\MockObject;
    +use RuntimeException;
    +use Tests\Support\Autoloader\FatalLocator;
    +
    +/**
    + * @internal
    + *
    + * @covers ::helper
    + */
    +final class CommonHelperTest extends CIUnitTestCase
    +{
    +    private $dummyHelpers = [
    +        APPPATH . 'Helpers' . DIRECTORY_SEPARATOR . 'foobarbaz_helper.php',
    +        SYSTEMPATH . 'Helpers' . DIRECTORY_SEPARATOR . 'foobarbaz_helper.php',
    +    ];
    +
    +    protected function setUp(): void
    +    {
    +        parent::setUp();
    +        $this->cleanUpDummyHelpers();
    +    }
    +
    +    protected function tearDown(): void
    +    {
    +        parent::tearDown();
    +        $this->cleanUpDummyHelpers();
    +        Services::reset();
    +    }
    +
    +    private function createDummyHelpers(): void
    +    {
    +        $text = <<<'PHP'
    +            dummyHelpers as $helper) {
    +            file_put_contents($helper, $text);
    +        }
    +    }
    +
    +    private function cleanUpDummyHelpers(): void
    +    {
    +        foreach ($this->dummyHelpers as $helper) {
    +            if (is_file($helper)) {
    +                unlink($helper);
    +            }
    +        }
    +    }
    +
    +    /**
    +     * @return FileLocator&MockObject
    +     */
    +    private function getMockLocator()
    +    {
    +        return $this->getMockBuilder(FileLocator::class)
    +            ->setConstructorArgs([Services::autoloader()])
    +            ->onlyMethods(['search'])
    +            ->getMock();
    +    }
    +
    +    public function testHelperWithFatalLocatorThrowsException()
    +    {
    +        // Replace the locator with one that will fail if it is called
    +        $locator = new FatalLocator(Services::autoloader());
    +        Services::injectMock('locator', $locator);
    +
    +        try {
    +            helper('baguette');
    +            $exception = false;
    +        } catch (RuntimeException $e) {
    +            $exception = true;
    +        }
    +
    +        $this->assertTrue($exception);
    +        Services::reset();
    +    }
    +
    +    public function testHelperLoadsOnce()
    +    {
    +        // Load it the first time
    +        helper('baguette');
    +
    +        // Replace the locator with one that will fail if it is called
    +        $locator = new FatalLocator(Services::autoloader());
    +        Services::injectMock('locator', $locator);
    +
    +        try {
    +            helper('baguette');
    +            $exception = false;
    +        } catch (RuntimeException $e) {
    +            $exception = true;
    +        }
    +
    +        $this->assertFalse($exception);
    +        Services::reset();
    +    }
    +
    +    public function testHelperLoadsAppHelperFirst(): void
    +    {
    +        foreach ($this->dummyHelpers as $helper) {
    +            $this->assertFileDoesNotExist($helper, sprintf(
    +                'The dummy helper file "%s" should not be existing before it is tested.',
    +                $helper
    +            ));
    +        }
    +
    +        $this->createDummyHelpers();
    +        $locator = $this->getMockLocator();
    +        $locator->method('search')->with('Helpers/foobarbaz_helper')->willReturn($this->dummyHelpers);
    +        Services::injectMock('locator', $locator);
    +
    +        helper('foobarbaz');
    +
    +        // this chunk is not needed really; just added so that IDEs will be happy
    +        if (! function_exists('foo_bar_baz')) {
    +            function foo_bar_baz(): string
    +            {
    +                return __FILE__;
    +            }
    +        }
    +
    +        $this->assertSame($this->dummyHelpers[0], foo_bar_baz());
    +    }
    +}
    
    From d7c9ad2ce64f886ae7e50781daf9d679d5252380 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Wed, 27 Oct 2021 13:27:22 +0900
    Subject: [PATCH 0526/2325] test: fix setUp()
    
    Ensure the database exists.
    ---
     tests/system/Commands/CreateDatabaseTest.php | 7 ++++++-
     1 file changed, 6 insertions(+), 1 deletion(-)
    
    diff --git a/tests/system/Commands/CreateDatabaseTest.php b/tests/system/Commands/CreateDatabaseTest.php
    index 1b6d28fdf0f8..a00de5c437a1 100644
    --- a/tests/system/Commands/CreateDatabaseTest.php
    +++ b/tests/system/Commands/CreateDatabaseTest.php
    @@ -12,6 +12,7 @@
     namespace CodeIgniter\Commands;
     
     use CodeIgniter\Database\BaseConnection;
    +use CodeIgniter\Database\Database as DatabaseFactory;
     use CodeIgniter\Database\SQLite3\Connection as SQLite3Connection;
     use CodeIgniter\Test\CIUnitTestCase;
     use CodeIgniter\Test\Filters\CITestStreamFilter;
    @@ -45,7 +46,11 @@ protected function setUp(): void
                     unlink($file);
                 }
             } else {
    -            Database::forge()->dropDatabase('foobar');
    +            $util = (new DatabaseFactory())->loadUtils($this->connection);
    +
    +            if ($util->databaseExists('foobar')) {
    +                Database::forge()->dropDatabase('foobar');
    +            }
             }
         }
     
    
    From f758702531514468d247796b4bef4d1eb864d697 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Thu, 28 Oct 2021 10:51:13 +0800
    Subject: [PATCH 0527/2325] Apply suggestions from code review
    
    ---
     tests/system/CommonHelperTest.php | 2 --
     1 file changed, 2 deletions(-)
    
    diff --git a/tests/system/CommonHelperTest.php b/tests/system/CommonHelperTest.php
    index 55d626cf966c..72e6075f7d1f 100644
    --- a/tests/system/CommonHelperTest.php
    +++ b/tests/system/CommonHelperTest.php
    @@ -96,7 +96,6 @@ public function testHelperWithFatalLocatorThrowsException()
             }
     
             $this->assertTrue($exception);
    -        Services::reset();
         }
     
         public function testHelperLoadsOnce()
    @@ -116,7 +115,6 @@ public function testHelperLoadsOnce()
             }
     
             $this->assertFalse($exception);
    -        Services::reset();
         }
     
         public function testHelperLoadsAppHelperFirst(): void
    
    From 120a56a71826a7dbcef5ead218ac56ed292725e7 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Thu, 28 Oct 2021 10:52:58 +0800
    Subject: [PATCH 0528/2325] Update tests/system/CommonHelperTest.php
    
    ---
     tests/system/CommonHelperTest.php | 1 +
     1 file changed, 1 insertion(+)
    
    diff --git a/tests/system/CommonHelperTest.php b/tests/system/CommonHelperTest.php
    index 72e6075f7d1f..ed3d629266a4 100644
    --- a/tests/system/CommonHelperTest.php
    +++ b/tests/system/CommonHelperTest.php
    @@ -33,6 +33,7 @@ final class CommonHelperTest extends CIUnitTestCase
         protected function setUp(): void
         {
             parent::setUp();
    +        Services::reset();
             $this->cleanUpDummyHelpers();
         }
     
    
    From 568d8a98e4b94f7ab44a78cc6afcfd6144ddeea8 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 28 Oct 2021 11:53:57 +0900
    Subject: [PATCH 0529/2325] docs: decorate `.env` with `**`
    
    ---
     user_guide_src/source/database/configuration.rst       | 4 ++--
     user_guide_src/source/general/common_functions.rst     | 2 +-
     user_guide_src/source/general/configuration.rst        | 8 ++++----
     user_guide_src/source/general/errors.rst               | 2 +-
     user_guide_src/source/installation/running.rst         | 4 ++--
     user_guide_src/source/installation/troubleshooting.rst | 2 +-
     user_guide_src/source/libraries/encryption.rst         | 2 +-
     user_guide_src/source/libraries/honeypot.rst           | 2 +-
     8 files changed, 13 insertions(+), 13 deletions(-)
    
    diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst
    index 53b2c3f932b0..f1776d93151d 100644
    --- a/user_guide_src/source/database/configuration.rst
    +++ b/user_guide_src/source/database/configuration.rst
    @@ -9,7 +9,7 @@ Database Configuration
     CodeIgniter has a config file that lets you store your database
     connection values (username, password, database name, etc.). The config
     file is located at **app/Config/Database.php**. You can also set
    -database connection values in the .env file. See below for more details.
    +database connection values in the **.env** file. See below for more details.
     
     The config settings are stored in a class property that is an array with this
     prototype::
    @@ -162,7 +162,7 @@ within the class' constructor::
     Configuring With .env File
     --------------------------
     
    -You can also save your configuration values within a ``.env`` file with the current server's
    +You can also save your configuration values within a **.env** file with the current server's
     database settings. You only need to enter the values that change from what is in the
     default group's configuration settings. The values should be name following this format, where
     ``default`` is the group name::
    diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst
    index 8d006197bcfe..dd4c69a9915e 100755
    --- a/user_guide_src/source/general/common_functions.rst
    +++ b/user_guide_src/source/general/common_functions.rst
    @@ -63,7 +63,7 @@ Service Accessors
         or return a default value if it is not found. Will format boolean values
         to actual booleans instead of string representations.
     
    -    Especially useful when used in conjunction with .env files for setting
    +    Especially useful when used in conjunction with **.env** files for setting
         values that are specific to the environment itself, like database
         settings, API keys, etc.
     
    diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst
    index 8254b9fe44ea..ac31e6f3241a 100644
    --- a/user_guide_src/source/general/configuration.rst
    +++ b/user_guide_src/source/general/configuration.rst
    @@ -191,15 +191,15 @@ Environment Variables as Replacements for Data
     ==============================================
     
     It is very important to always remember that environment variables contained in your **.env** are
    -**only replacements for existing data**. This means that you cannot expect to fill your ``.env`` with all
    +**only replacements for existing data**. This means that you cannot expect to fill your **.env** with all
     the replacements for your configurations but have nothing to receive these replacements in the
     related configuration file(s).
     
    -The ``.env`` only serves to fill or replace the values in your configuration files. That said, your
    +The **.env** only serves to fill or replace the values in your configuration files. That said, your
     configuration files should have a container or receiving property for those. Adding so many variables in
    -your ``.env`` with nothing to contain them in the receiving end is useless.
    +your **.env** with nothing to contain them in the receiving end is useless.
     
    -Simply put, you cannot just put ``app.myNewConfig = foo`` in your ``.env`` and expect your ``Config\App``
    +Simply put, you cannot just put ``app.myNewConfig = foo`` in your **.env** and expect your ``Config\App``
     to magically have that property and value at run time.
     
     Treating Environment Variables as Arrays
    diff --git a/user_guide_src/source/general/errors.rst b/user_guide_src/source/general/errors.rst
    index 410e58236a8d..b7863b03010d 100644
    --- a/user_guide_src/source/general/errors.rst
    +++ b/user_guide_src/source/general/errors.rst
    @@ -55,7 +55,7 @@ Configuration
     
     By default, CodeIgniter will display all errors in the ``development`` and ``testing`` environments, and will not
     display any errors in the ``production`` environment. You can change this by setting the ``CI_ENVIRONMENT`` variable
    -in the ``.env`` file.
    +in the **.env** file.
     
     .. important:: Disabling error reporting DOES NOT stop logs from being written if there are errors.
     
    diff --git a/user_guide_src/source/installation/running.rst b/user_guide_src/source/installation/running.rst
    index 4d00260ffcea..bb4b99aa468f 100644
    --- a/user_guide_src/source/installation/running.rst
    +++ b/user_guide_src/source/installation/running.rst
    @@ -17,11 +17,11 @@ Initial Configuration & Set Up
     
     #. Open the **app/Config/App.php** file with a text editor and
        set your base URL. If you need more flexibility, the baseURL may
    -   be set within the ``.env`` file as **app.baseURL="http://example.com/"**.
    +   be set within the **.env** file as ``app.baseURL="http://example.com/"``.
        (Always use a trailing slash on your base URL!)
     #. If you intend to use a database, open the
        **app/Config/Database.php** file with a text editor and set your
    -   database settings. Alternately, these could be set in your ``.env`` file.
    +   database settings. Alternately, these could be set in your **.env** file.
     
     One additional measure to take in production environments is to disable
     PHP error reporting and any other development-only functionality. In
    diff --git a/user_guide_src/source/installation/troubleshooting.rst b/user_guide_src/source/installation/troubleshooting.rst
    index a0b1684fda9d..ff30759efcad 100644
    --- a/user_guide_src/source/installation/troubleshooting.rst
    +++ b/user_guide_src/source/installation/troubleshooting.rst
    @@ -65,7 +65,7 @@ unrecoverable error, which we don't want to show to the viewer of
     the webapp, for better security.
     
     You can see the error in the debug toolbar display by setting your environment to
    -"development" (in `.env`), and reloading the page.
    +"development" (in **.env**), and reloading the page.
     
     Don't forget to reset the environment to "production" once you fix the problem!
     
    diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst
    index 2c8373743f35..2c45e7ad79d9 100644
    --- a/user_guide_src/source/libraries/encryption.rst
    +++ b/user_guide_src/source/libraries/encryption.rst
    @@ -153,7 +153,7 @@ the library.
         // or
         public $key = 'base64:'
     
    -Similarly, you can use these prefixes in your ``.env`` file, too!
    +Similarly, you can use these prefixes in your **.env** file, too!
     ::
     
         // For hex2bin
    diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst
    index 471c0d520003..0b9114456cf0 100644
    --- a/user_guide_src/source/libraries/honeypot.rst
    +++ b/user_guide_src/source/libraries/honeypot.rst
    @@ -36,7 +36,7 @@ Customizing Honeypot
     =====================
     
     Honeypot can be customized. The fields below can be set either in
    -**app/Config/Honeypot.php** or in ``.env``.
    +**app/Config/Honeypot.php** or in **.env**.
     
     * ``hidden`` - true|false to control visibility of the honeypot field; default is ``true``
     * ``label`` - HTML label for the honeypot field, default is 'Fill This Field'
    
    From d263558af1dcc0148a58b3edb134df919e941b67 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Thu, 28 Oct 2021 12:16:52 +0800
    Subject: [PATCH 0530/2325] Update tests/system/CommonHelperTest.php
    
    ---
     tests/system/CommonHelperTest.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/tests/system/CommonHelperTest.php b/tests/system/CommonHelperTest.php
    index ed3d629266a4..18e0a1022f8d 100644
    --- a/tests/system/CommonHelperTest.php
    +++ b/tests/system/CommonHelperTest.php
    @@ -32,8 +32,8 @@ final class CommonHelperTest extends CIUnitTestCase
     
         protected function setUp(): void
         {
    -        parent::setUp();
             Services::reset();
    +        parent::setUp();
             $this->cleanUpDummyHelpers();
         }
     
    
    From e307ef566c6f5d1ddeb611275cbba66faa490b89 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 28 Oct 2021 13:29:33 +0900
    Subject: [PATCH 0531/2325] fix: remove populateHeaders() not to share request
     headers form browser between CURL requests
    
    ---
     system/HTTP/CURLRequest.php           | 37 ++-------------------------
     tests/system/HTTP/CURLRequestTest.php | 23 -----------------
     2 files changed, 2 insertions(+), 58 deletions(-)
    
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index 2a305fa1c802..0b6b1cfb9005 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -368,27 +368,17 @@ public function send(string $method, string $url)
         }
     
         /**
    -     * Takes all headers current part of this request and adds them
    -     * to the cURL request.
    +     * Adds $this->headers to the cURL request.
          */
         protected function applyRequestHeaders(array $curlOptions = []): array
         {
             if (empty($this->headers)) {
    -            $this->populateHeaders();
    -            // Otherwise, it will corrupt the request
    -            $this->removeHeader('Host');
    -            $this->removeHeader('Accept-Encoding');
    -        }
    -
    -        $headers = $this->headers();
    -
    -        if (empty($headers)) {
                 return $curlOptions;
             }
     
             $set = [];
     
    -        foreach (array_keys($headers) as $name) {
    +        foreach (array_keys($this->headers) as $name) {
                 $set[] = $name . ': ' . $this->getHeaderLine($name);
             }
     
    @@ -397,29 +387,6 @@ protected function applyRequestHeaders(array $curlOptions = []): array
             return $curlOptions;
         }
     
    -    /**
    -     * Override
    -     */
    -    public function populateHeaders(): void
    -    {
    -        foreach (array_keys($_SERVER) as $key) {
    -            if (sscanf($key, 'HTTP_%s', $header) === 1) {
    -                // take SOME_HEADER and turn it into Some-Header
    -                $header = str_replace('_', ' ', strtolower($header));
    -                $header = str_replace(' ', '-', ucwords($header));
    -
    -                if (in_array($header, $this->unsharedHeaders, true)) {
    -                    continue;
    -                }
    -
    -                $this->setHeader($header, $_SERVER[$key]);
    -
    -                // Add us to the header map so we can find them case-insensitively
    -                $this->headerMap[strtolower($header)] = $header;
    -            }
    -        }
    -    }
    -
         /**
          * Apply method
          */
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index b46cec5ce992..33fb4d2adfdb 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -173,29 +173,6 @@ public function testOptionsHeaders()
             $this->assertSame('apple', $request->header('fruit')->getValue());
         }
     
    -    /**
    -     * @backupGlobals enabled
    -     */
    -    public function testOptionsHeadersUsingPopulate()
    -    {
    -        $_SERVER['HTTP_HOST']            = 'site1.com';
    -        $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US';
    -        $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate, br';
    -
    -        $options = [
    -            'base_uri' => 'http://www.foo.com/api/v1/',
    -        ];
    -
    -        $request = $this->getRequest($options);
    -        $request->get('example');
    -        // we fill the Accept-Language header from _SERVER when no headers are defined for the request
    -        $this->assertSame('en-US', $request->header('Accept-Language')->getValue());
    -        // but we skip Host header - since it would corrupt the request
    -        $this->assertNull($request->header('Host'));
    -        // and Accept-Encoding
    -        $this->assertNull($request->header('Accept-Encoding'));
    -    }
    -
         /**
          * @backupGlobals enabled
          */
    
    From 0b18ab84474ef9733487fd3b48eea135b0cd4569 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 28 Oct 2021 17:10:54 +0900
    Subject: [PATCH 0532/2325] style: change global_namespace_import to true in
     php-cs-fixer
    
    https://github.com/FriendsOfPHP/PHP-CS-Fixer/blob/2.19/doc/rules/import/global_namespace_import.rst
    ---
     tests/_support/Commands/AppInfo.php        |  3 ++-
     tests/_support/Commands/InvalidCommand.php |  3 ++-
     tests/_support/Controllers/Popcorn.php     |  3 ++-
     tests/_support/Widgets/SomeWidget.php      |  4 +++-
     tests/system/I18n/TimeTest.php             | 20 ++++++++++----------
     5 files changed, 19 insertions(+), 14 deletions(-)
    
    diff --git a/tests/_support/Commands/AppInfo.php b/tests/_support/Commands/AppInfo.php
    index 562cc9dd3847..e7bf3093e658 100644
    --- a/tests/_support/Commands/AppInfo.php
    +++ b/tests/_support/Commands/AppInfo.php
    @@ -14,6 +14,7 @@
     use CodeIgniter\CLI\BaseCommand;
     use CodeIgniter\CLI\CLI;
     use CodeIgniter\CodeIgniter;
    +use RuntimeException;
     
     class AppInfo extends BaseCommand
     {
    @@ -31,7 +32,7 @@ public function bomb()
         {
             try {
                 CLI::color('test', 'white', 'Background');
    -        } catch (\RuntimeException $oops) {
    +        } catch (RuntimeException $oops) {
                 $this->showError($oops);
             }
         }
    diff --git a/tests/_support/Commands/InvalidCommand.php b/tests/_support/Commands/InvalidCommand.php
    index a6d13d6fe494..5b4acf936b08 100644
    --- a/tests/_support/Commands/InvalidCommand.php
    +++ b/tests/_support/Commands/InvalidCommand.php
    @@ -14,6 +14,7 @@
     use CodeIgniter\CLI\BaseCommand;
     use CodeIgniter\CLI\CLI;
     use CodeIgniter\CodeIgniter;
    +use ReflectionException;
     
     class InvalidCommand extends BaseCommand
     {
    @@ -23,7 +24,7 @@ class InvalidCommand extends BaseCommand
     
         public function __construct()
         {
    -        throw new \ReflectionException();
    +        throw new ReflectionException();
         }
     
         public function run(array $params)
    diff --git a/tests/_support/Controllers/Popcorn.php b/tests/_support/Controllers/Popcorn.php
    index a0aa972c635f..71a316685a32 100644
    --- a/tests/_support/Controllers/Popcorn.php
    +++ b/tests/_support/Controllers/Popcorn.php
    @@ -13,6 +13,7 @@
     
     use CodeIgniter\API\ResponseTrait;
     use CodeIgniter\Controller;
    +use RuntimeException;
     
     /**
      * This is a testing only controller, intended to blow up in multiple
    @@ -34,7 +35,7 @@ public function pop()
     
         public function popper()
         {
    -        throw new \RuntimeException('Surprise', 500);
    +        throw new RuntimeException('Surprise', 500);
         }
     
         public function weasel()
    diff --git a/tests/_support/Widgets/SomeWidget.php b/tests/_support/Widgets/SomeWidget.php
    index 380449f14b9b..c6e2b3da8652 100644
    --- a/tests/_support/Widgets/SomeWidget.php
    +++ b/tests/_support/Widgets/SomeWidget.php
    @@ -11,7 +11,9 @@
     
     namespace Tests\Support\Widgets;
     
    +use stdClass;
    +
     // Extends a trivial class to test the instanceOf directive
    -class SomeWidget extends \stdClass
    +class SomeWidget extends stdClass
     {
     }
    diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php
    index da1ef5b3c5ef..e1e683c98d07 100644
    --- a/tests/system/I18n/TimeTest.php
    +++ b/tests/system/I18n/TimeTest.php
    @@ -90,7 +90,7 @@ public function testTimeWithDateTimeZone()
                 'yyyy-MM-dd HH:mm:ss'
             );
     
    -        $time = new Time('now', new \DateTimeZone('Europe/London'), 'fr_FR');
    +        $time = new Time('now', new DateTimeZone('Europe/London'), 'fr_FR');
     
             $this->assertSame($formatter->format($time), (string) $time);
         }
    @@ -101,13 +101,13 @@ public function testToDateTime()
     
             $obj = $time->toDateTime();
     
    -        $this->assertInstanceOf(\DateTime::class, $obj);
    +        $this->assertInstanceOf(DateTime::class, $obj);
         }
     
         public function testNow()
         {
             $time  = Time::now();
    -        $time1 = new \DateTime();
    +        $time1 = new DateTime();
     
             $this->assertInstanceOf(Time::class, $time);
             $this->assertSame($time->getTimestamp(), $time1->getTimestamp());
    @@ -116,7 +116,7 @@ public function testNow()
         public function testParse()
         {
             $time  = Time::parse('next Tuesday', 'America/Chicago');
    -        $time1 = new \DateTime('now', new \DateTimeZone('America/Chicago'));
    +        $time1 = new DateTime('now', new DateTimeZone('America/Chicago'));
             $time1->modify('next Tuesday');
     
             $this->assertSame($time->getTimestamp(), $time1->getTimestamp());
    @@ -134,7 +134,7 @@ public function testToDateTimeStringWithTimeZone()
         {
             $time = Time::parse('2017-01-12 00:00', 'Europe/London');
     
    -        $expects = new \DateTime('2017-01-12', new \DateTimeZone('Europe/London'));
    +        $expects = new DateTime('2017-01-12', new DateTimeZone('Europe/London'));
     
             $this->assertSame($expects->format('Y-m-d H:i:s'), $time->toDateTimeString());
         }
    @@ -204,7 +204,7 @@ public function testCreateFromTimeLocalized()
     
         public function testCreateFromFormat()
         {
    -        $now = new \DateTime('now');
    +        $now = new DateTime('now');
     
             Time::setTestNow($now);
             $time = Time::createFromFormat('F j, Y', 'January 15, 2017', 'America/Chicago');
    @@ -222,7 +222,7 @@ public function testCreateFromFormatWithTimezoneString()
     
         public function testCreateFromFormatWithTimezoneObject()
         {
    -        $tz = new \DateTimeZone('Europe/London');
    +        $tz = new DateTimeZone('Europe/London');
     
             $time = Time::createFromFormat('F j, Y', 'January 15, 2017', $tz);
     
    @@ -422,7 +422,7 @@ public function testGetTimezone()
         {
             $instance = Time::now()->getTimezone();
     
    -        $this->assertInstanceOf(\DateTimeZone::class, $instance);
    +        $this->assertInstanceOf(DateTimeZone::class, $instance);
         }
     
         public function testGetTimezonename()
    @@ -776,7 +776,7 @@ public function testEqualWithSame()
         public function testEqualWithDateTime()
         {
             $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago');
    -        $time2 = new \DateTime('January 11, 2017 03:50:00', new \DateTimeZone('Europe/London'));
    +        $time2 = new DateTime('January 11, 2017 03:50:00', new DateTimeZone('Europe/London'));
     
             $this->assertTrue($time1->equals($time2));
         }
    @@ -784,7 +784,7 @@ public function testEqualWithDateTime()
         public function testEqualWithSameDateTime()
         {
             $time1 = Time::parse('January 10, 2017 21:50:00', 'America/Chicago');
    -        $time2 = new \DateTime('January 10, 2017 21:50:00', new \DateTimeZone('America/Chicago'));
    +        $time2 = new DateTime('January 10, 2017 21:50:00', new DateTimeZone('America/Chicago'));
     
             $this->assertTrue($time1->equals($time2));
         }
    
    From 9cbe0f25159d7cbf2fe18d99b60c905a2a9f3701 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 10:26:32 +0900
    Subject: [PATCH 0533/2325] fix: make $unsharedHeaders protected
    
    To override the values.
    ---
     system/HTTP/CURLRequest.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index 0b6b1cfb9005..baf97d2b891d 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -77,7 +77,7 @@ class CURLRequest extends Request
          *
          * @var string[]
          */
    -    private $unsharedHeaders = [
    +    protected $unsharedHeaders = [
             'Content-Length',
             'Content-Type',
         ];
    
    From c9bac5f99a40ebc878c245efb1745b84b84d8a9d Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 11:16:39 +0900
    Subject: [PATCH 0534/2325] fix: reset $unsharedHeaders after sending request
    
    If user setHeader() that is defined in $unsharedHeaders, the header will be removed
    before sending request, and there is no way to send the header.
    
    The reason I didn't do the reset after sending is because a test failed.
    This time I modify the test, too.
    ---
     system/HTTP/CURLRequest.php           | 9 ++++-----
     tests/system/HTTP/CURLRequestTest.php | 5 ++++-
     2 files changed, 8 insertions(+), 6 deletions(-)
    
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index baf97d2b891d..b195249589e9 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -116,11 +116,6 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response
          */
         public function request($method, string $url, array $options = []): ResponseInterface
         {
    -        // Reset unshared headers
    -        foreach ($this->unsharedHeaders as $header) {
    -            $this->removeHeader($header);
    -        }
    -
             $this->parseOptions($options);
     
             $url = $this->prepareURL($url);
    @@ -129,6 +124,10 @@ public function request($method, string $url, array $options = []): ResponseInte
     
             $this->send($method, $url);
     
    +        // Reset unshared headers
    +        foreach ($this->unsharedHeaders as $header) {
    +            $this->removeHeader($header);
    +        }
             // Reset unshared configs
             unset($this->config['multipart'], $this->config['form_params']);
     
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index 33fb4d2adfdb..435a647ecf90 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -912,7 +912,10 @@ public function testSetJSON()
             $this->request->setJSON($params)->post('/post');
     
             $this->assertSame(json_encode($params), $this->request->getBody());
    -        $this->assertSame('application/json', $this->request->getHeaderLine('Content-Type'));
    +        $this->assertSame(
    +            'Content-Type: application/json',
    +            $this->request->curl_options[CURLOPT_HTTPHEADER][0]
    +        );
         }
     
         public function testHTTPv1()
    
    From d39543ece518bade48715451e69992aacefa1ca2 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 11:33:31 +0900
    Subject: [PATCH 0535/2325] docs: improve changelogs/v4.1.5.rst format
    
    ---
     user_guide_src/source/changelogs/v4.1.5.rst | 25 +++++++++++++--------
     1 file changed, 16 insertions(+), 9 deletions(-)
    
    diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst
    index 3290763f0ed3..d1d9fd58aa2c 100644
    --- a/user_guide_src/source/changelogs/v4.1.5.rst
    +++ b/user_guide_src/source/changelogs/v4.1.5.rst
    @@ -1,28 +1,35 @@
     Version 4.1.5
    -=============
    +#############
     
     Release Date: Not released
     
     **4.1.5 release of CodeIgniter4**
     
    -BREAKING:
    +.. contents::
    +    :local:
    +    :depth: 1
     
    -Fixed `a bug `_ on CSRF protection.
    -Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied.
    -If you use such requests, you need to send CSRF token.
    +BREAKING
    +========
     
    -Enhancements:
    +- Fixed `a bug `_ on CSRF protection. Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied. If you use such requests, you need to send CSRF token.
    +
    +Enhancements
    +============
     
     - Added Cache config for reserved characters
     - The ``addForeignKey`` function of the ``Forge`` class can now define composite foreign keys in an array
     - The ``dropKey`` function of the ``Forge`` class can remove key
     
    -Changes:
    +Changes
    +=======
     
     - Always escape identifiers in the ``set``, ``setUpdateBatch``, and ``insertBatch`` functions in ``BaseBuilder``.
     
    -Deprecations:
    +Deprecations
    +============
     
     - Deprecated ``CodeIgniter\\Cache\\Handlers\\BaseHandler::RESERVED_CHARACTERS`` in favor of the new config property
     
    -Bugs Fixed:
    +Bugs Fixed
    +==========
    
    From 9a6a0d3e708e1dbca2b8efb48f16ac00cbe492cf Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 11:38:33 +0900
    Subject: [PATCH 0536/2325] docs: add upgrading and changelog
    
    ---
     user_guide_src/source/changelogs/v4.1.5.rst        | 1 +
     user_guide_src/source/installation/upgrade_415.rst | 8 ++++++++
     2 files changed, 9 insertions(+)
    
    diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst
    index d1d9fd58aa2c..6e9c96ded738 100644
    --- a/user_guide_src/source/changelogs/v4.1.5.rst
    +++ b/user_guide_src/source/changelogs/v4.1.5.rst
    @@ -13,6 +13,7 @@ BREAKING
     ========
     
     - Fixed `a bug `_ on CSRF protection. Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied. If you use such requests, you need to send CSRF token.
    +- In the previous version, ``CURLRequest`` sends request headers from the browser, because of a bug. Since this version it does not send them.
     
     Enhancements
     ============
    diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst
    index 6c20797775af..84750e834c12 100644
    --- a/user_guide_src/source/installation/upgrade_415.rst
    +++ b/user_guide_src/source/installation/upgrade_415.rst
    @@ -53,6 +53,14 @@ If you want the same behavior as the previous version, set the CSRF filter like
     
     Protecting **GET** method needs only when you use ``form_open()`` auto-generation of CSRF field.
     
    +CURLRequest header change
    +-------------------------
    +
    +Because of a bug, the previous version of ``CURLRequest`` sends the request headers from the browser request.
    +The bug was fixed. If your requests depend on the headers, your requests might fail after upgrading.
    +In this case, add the necessary headers manually.
    +See `CURLRequest Class <../libraries/curlrequest.html#headers>`_ for how to add.
    +
     Breaking Enhancements
     =====================
     
    
    From f5c1d2dbece72deb733e55368ccac173188eb205 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 13:17:27 +0900
    Subject: [PATCH 0537/2325] docs: fix method name
    
    ---
     user_guide_src/source/helpers/security_helper.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/helpers/security_helper.rst b/user_guide_src/source/helpers/security_helper.rst
    index b0d93bf81eec..2c3812a49def 100644
    --- a/user_guide_src/source/helpers/security_helper.rst
    +++ b/user_guide_src/source/helpers/security_helper.rst
    @@ -27,7 +27,7 @@ The following functions are available:
     
         Provides protection against directory traversal.
     
    -    This function is an alias for ``\CodeIgniter\Security::sanitize_filename()``.
    +    This function is an alias for ``\CodeIgniter\Security::sanitizeFilename()``.
         For more info, please see the :doc:`Security Library <../libraries/security>`
         documentation.
     
    
    From 0a38cf342f3736c6710c25eb0910e98db95e6658 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 13:20:36 +0900
    Subject: [PATCH 0538/2325] docs: replace csrf with CSRF
    
    ---
     user_guide_src/source/installation/upgrade_security.rst | 6 +++---
     1 file changed, 3 insertions(+), 3 deletions(-)
    
    diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst
    index 5f2d8ecfdb66..606ac4139fa8 100644
    --- a/user_guide_src/source/installation/upgrade_security.rst
    +++ b/user_guide_src/source/installation/upgrade_security.rst
    @@ -13,15 +13,15 @@ Documentations
     - :doc:`Security Documentation Codeigniter 4.X `
     
     .. note::
    -    If you use the `form helper `_, then form_open() will automatically insert a hidden csrf field in your forms. So you do not have to upgrade this by yourself.
    +    If you use the `form helper `_, then form_open() will automatically insert a hidden CSRF field in your forms. So you do not have to upgrade this by yourself.
     
     What has been changed
     =====================
    -- The method to implement csrf tokens to html forms has been changed.
    +- The method to implement CSRF tokens to html forms has been changed.
     
     Upgrade Guide
     =============
    -1. To enable csrf protection in CI4 you have to enable it in ``app/Config/Filters.php``::
    +1. To enable CSRF protection in CI4 you have to enable it in ``app/Config/Filters.php``::
     
         public $globals = [
             'before' => [
    
    From 06cc51c18ddb0a8d5d3f0acc802edb568ab0d3d0 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 13:23:21 +0900
    Subject: [PATCH 0539/2325] docs: fix 404 link and make the note more accurate
    
    ---
     user_guide_src/source/installation/upgrade_security.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst
    index 606ac4139fa8..7f991b0bdb47 100644
    --- a/user_guide_src/source/installation/upgrade_security.rst
    +++ b/user_guide_src/source/installation/upgrade_security.rst
    @@ -13,7 +13,7 @@ Documentations
     - :doc:`Security Documentation Codeigniter 4.X `
     
     .. note::
    -    If you use the `form helper `_, then form_open() will automatically insert a hidden CSRF field in your forms. So you do not have to upgrade this by yourself.
    +    If you use the :doc:`form helper ` and enable the CSRF filter globally, then ``form_open()`` will automatically insert a hidden CSRF field in your forms. So you do not have to upgrade this by yourself.
     
     What has been changed
     =====================
    
    From 613b9809b5b58ff35a39aa553ccf9a76bce82413 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 16:00:59 +0900
    Subject: [PATCH 0540/2325] fix: remove $unsharedHeaders and add
     $defaultOptions
    
    $defaultOptions is options passed in the constructor.
    They are applied for all requests.
    All request headers are cleared after sending request,
    and $defaultOptions are set again.
    ---
     system/HTTP/CURLRequest.php | 23 +++++++++++------------
     1 file changed, 11 insertions(+), 12 deletions(-)
    
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index b195249589e9..4d2afdbfd856 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -73,14 +73,11 @@ class CURLRequest extends Request
         protected $delay = 0.0;
     
         /**
    -     * Request headers that are not shared between requests.
    +     * Default options. Applied to all requests.
          *
    -     * @var string[]
    +     * @var array
          */
    -    protected $unsharedHeaders = [
    -        'Content-Length',
    -        'Content-Type',
    -    ];
    +    private $defaultOptions;
     
         /**
          * Takes an array of options to set the following possible class properties:
    @@ -102,8 +99,9 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response
     
             parent::__construct($config);
     
    -        $this->response = $response;
    -        $this->baseURI  = $uri->useRawQueryString();
    +        $this->response       = $response;
    +        $this->baseURI        = $uri->useRawQueryString();
    +        $this->defaultOptions = $options;
     
             $this->parseOptions($options);
         }
    @@ -124,12 +122,13 @@ public function request($method, string $url, array $options = []): ResponseInte
     
             $this->send($method, $url);
     
    -        // Reset unshared headers
    -        foreach ($this->unsharedHeaders as $header) {
    -            $this->removeHeader($header);
    -        }
    +        // Reset headers
    +        $this->headers   = [];
    +        $this->headerMap = [];
             // Reset unshared configs
             unset($this->config['multipart'], $this->config['form_params']);
    +        // Set the default options for next request
    +        $this->parseOptions($this->defaultOptions);
     
             return $this->response;
         }
    
    From 8b086428d951f031c979423a61a18704082bc972 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 16:22:44 +0900
    Subject: [PATCH 0541/2325] docs: fix changelogs/v4.1.5.rst
    
    The explanation was not accurate.
    
    Co-authored-by: Michal Sniatala 
    ---
     user_guide_src/source/changelogs/v4.1.5.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst
    index 6e9c96ded738..f763123fbd85 100644
    --- a/user_guide_src/source/changelogs/v4.1.5.rst
    +++ b/user_guide_src/source/changelogs/v4.1.5.rst
    @@ -13,7 +13,7 @@ BREAKING
     ========
     
     - Fixed `a bug `_ on CSRF protection. Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied. If you use such requests, you need to send CSRF token.
    -- In the previous version, ``CURLRequest`` sends request headers from the browser, because of a bug. Since this version it does not send them.
    +- In the previous version, if you didn't provide your own headers, ``CURLRequest`` would send the request-headers from the browser, due to a bug. As of this version, it does not send them.
     
     Enhancements
     ============
    
    From 182c25264332e5a5331a1025bf33afc4cd2e6fdb Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 16:23:40 +0900
    Subject: [PATCH 0542/2325] docs: fix upgrade_415.rst
    
    The explanation was not accurate.
    
    Co-authored-by: Michal Sniatala 
    ---
     user_guide_src/source/installation/upgrade_415.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst
    index 84750e834c12..7a8c51f985ae 100644
    --- a/user_guide_src/source/installation/upgrade_415.rst
    +++ b/user_guide_src/source/installation/upgrade_415.rst
    @@ -56,7 +56,7 @@ Protecting **GET** method needs only when you use ``form_open()`` auto-generatio
     CURLRequest header change
     -------------------------
     
    -Because of a bug, the previous version of ``CURLRequest`` sends the request headers from the browser request.
    +In the previous version, if you didn't provide your own headers, ``CURLRequest`` would send the request-headers from the browser.
     The bug was fixed. If your requests depend on the headers, your requests might fail after upgrading.
     In this case, add the necessary headers manually.
     See `CURLRequest Class <../libraries/curlrequest.html#headers>`_ for how to add.
    
    From aed89d9119f6ec811757bb7c4fadf1b42e2242d9 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 17:44:10 +0900
    Subject: [PATCH 0543/2325] fix: add config $CURLRequestShareOptions for the
     CURLRequest
    
    If $CURLRequestShareOptions is false, reset all config after sending a request.
    If true, keep the all config (the same as before).
    ---
     app/Config/App.php                    | 11 +++++++++
     system/HTTP/CURLRequest.php           | 35 +++++++++++++++++++++++----
     tests/system/HTTP/CURLRequestTest.php | 12 +++++----
     3 files changed, 48 insertions(+), 10 deletions(-)
    
    diff --git a/app/Config/App.php b/app/Config/App.php
    index 88b295e9a010..57c9b8a45c46 100644
    --- a/app/Config/App.php
    +++ b/app/Config/App.php
    @@ -461,4 +461,15 @@ class App extends BaseConfig
          * @var bool
          */
         public $CSPEnabled = false;
    +
    +    /**
    +     * --------------------------------------------------------------------------
    +     * CURLRequest Share Options
    +     * --------------------------------------------------------------------------
    +     *
    +     * Whether share options between requests or not.
    +     *
    +     * @var bool
    +     */
    +    public $CURLRequestShareOptions = true;
     }
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index 4d2afdbfd856..4a58e5992afc 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -42,7 +42,14 @@ class CURLRequest extends Request
          *
          * @var array
          */
    -    protected $config = [
    +    protected $config;
    +
    +    /**
    +     * The default setting values
    +     *
    +     * @var array
    +     */
    +    private $defaultConfig = [
             'timeout'         => 0.0,
             'connect_timeout' => 150,
             'debug'           => false,
    @@ -79,6 +86,13 @@ class CURLRequest extends Request
          */
         private $defaultOptions;
     
    +    /**
    +     * Whether share options between requests or not.
    +     *
    +     * @var bool
    +     */
    +    private $shareOptions;
    +
         /**
          * Takes an array of options to set the following possible class properties:
          *
    @@ -102,6 +116,8 @@ public function __construct(App $config, URI $uri, ?ResponseInterface $response
             $this->response       = $response;
             $this->baseURI        = $uri->useRawQueryString();
             $this->defaultOptions = $options;
    +        $this->config         = $this->defaultConfig;
    +        $this->shareOptions   = $config->CURLRequestShareOptions ?? true;
     
             $this->parseOptions($options);
         }
    @@ -122,15 +138,24 @@ public function request($method, string $url, array $options = []): ResponseInte
     
             $this->send($method, $url);
     
    +        if ($this->shareOptions === false) {
    +            $this->resetOptions();
    +        }
    +
    +        return $this->response;
    +    }
    +
    +    private function resetOptions()
    +    {
             // Reset headers
             $this->headers   = [];
             $this->headerMap = [];
    -        // Reset unshared configs
    -        unset($this->config['multipart'], $this->config['form_params']);
    +
    +        // Reset configs
    +        $this->config = $this->defaultConfig;
    +
             // Set the default options for next request
             $this->parseOptions($this->defaultOptions);
    -
    -        return $this->response;
         }
     
         /**
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index 435a647ecf90..7237323f0be4 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -36,11 +36,13 @@ protected function setUp(): void
             $this->request = $this->getRequest();
         }
     
    -    protected function getRequest(array $options = [])
    +    protected function getRequest(array $options = [], $shareOptions = true)
         {
    -        $uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    +        $uri                          = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    +        $app                          = new App();
    +        $app->CURLRequestShareOptions = $shareOptions;
     
    -        return new MockCURLRequest(($app = new App()), $uri, new Response($app), $options);
    +        return new MockCURLRequest(($app), $uri, new Response($app), $options);
         }
     
         /**
    @@ -197,12 +199,12 @@ public function testOptionsHeadersNotUsingPopulate()
             $this->assertSame('', $request->header('Accept-Encoding')->getValue());
         }
     
    -    public function testHeaderContentLengthNotSharedBetweenRequests()
    +    public function testHeaderContentLengthNotSharedBetweenRequestsWhenSharedOptionsFalse()
         {
             $options = [
                 'base_uri' => 'http://www.foo.com/api/v1/',
             ];
    -        $request = $this->getRequest($options);
    +        $request = $this->getRequest($options, false);
     
             $request->post('example', [
                 'form_params' => [
    
    From 436013e118aa681bdaf4bdfd5c93125fe5fbe224 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 18:42:50 +0900
    Subject: [PATCH 0544/2325] test: add tests for $CURLRequestShareOptions =
     false
    
    ---
     .../HTTP/CURLRequestDoNotShareOptionsTest.php | 975 ++++++++++++++++++
     tests/system/HTTP/CURLRequestTest.php         |  21 +-
     2 files changed, 977 insertions(+), 19 deletions(-)
     create mode 100644 tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    
    diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    new file mode 100644
    index 000000000000..d40356118f79
    --- /dev/null
    +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    @@ -0,0 +1,975 @@
    +
    + *
    + * For the full copyright and license information, please view
    + * the LICENSE file that was distributed with this source code.
    + */
    +
    +namespace CodeIgniter\HTTP;
    +
    +use CodeIgniter\Config\Services;
    +use CodeIgniter\HTTP\Exceptions\HTTPException;
    +use CodeIgniter\Test\CIUnitTestCase;
    +use CodeIgniter\Test\Mock\MockCURLRequest;
    +use Config\App;
    +use CURLFile;
    +
    +/**
    + * @internal
    + */
    +final class CURLRequestDoNotShareOptionsTest extends CIUnitTestCase
    +{
    +    /**
    +     * @var MockCURLRequest
    +     */
    +    protected $request;
    +
    +    protected function setUp(): void
    +    {
    +        parent::setUp();
    +
    +        Services::reset();
    +        $this->request = $this->getRequest();
    +    }
    +
    +    protected function getRequest(array $options = [])
    +    {
    +        $uri                          = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    +        $app                          = new App();
    +        $app->CURLRequestShareOptions = false;
    +
    +        return new MockCURLRequest(($app), $uri, new Response($app), $options);
    +    }
    +
    +    /**
    +     * @see https://github.com/codeigniter4/CodeIgniter4/issues/4707
    +     */
    +    public function testPrepareURLIgnoresAppConfig()
    +    {
    +        config('App')->baseURL = 'http://example.com/fruit/';
    +
    +        $request = $this->getRequest(['base_uri' => 'http://example.com/v1/']);
    +
    +        $method = $this->getPrivateMethodInvoker($request, 'prepareURL');
    +
    +        $this->assertSame('http://example.com/v1/bananas', $method('bananas'));
    +    }
    +
    +    /**
    +     * @see https://github.com/codeigniter4/CodeIgniter4/issues/1029
    +     */
    +    public function testGetRemembersBaseURI()
    +    {
    +        $request = $this->getRequest(['base_uri' => 'http://www.foo.com/api/v1/']);
    +
    +        $request->get('products');
    +
    +        $options = $request->curl_options;
    +
    +        $this->assertSame('http://www.foo.com/api/v1/products', $options[CURLOPT_URL]);
    +    }
    +
    +    /**
    +     * @see https://github.com/codeigniter4/CodeIgniter4/issues/1029
    +     */
    +    public function testGetRemembersBaseURIWithHelperMethod()
    +    {
    +        $request = Services::curlrequest(['base_uri' => 'http://www.foo.com/api/v1/']);
    +
    +        $uri = $this->getPrivateProperty($request, 'baseURI');
    +        $this->assertSame('www.foo.com', $uri->getHost());
    +        $this->assertSame('/api/v1/', $uri->getPath());
    +    }
    +
    +    public function testSendReturnsResponse()
    +    {
    +        $output = 'Howdy Stranger.';
    +
    +        $response = $this->request->setOutput($output)->send('get', 'http://example.com');
    +
    +        $this->assertInstanceOf('CodeIgniter\\HTTP\\Response', $response);
    +        $this->assertSame($output, $response->getBody());
    +    }
    +
    +    public function testGetSetsCorrectMethod()
    +    {
    +        $this->request->get('http://example.com');
    +
    +        $this->assertSame('get', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('GET', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testDeleteSetsCorrectMethod()
    +    {
    +        $this->request->delete('http://example.com');
    +
    +        $this->assertSame('delete', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('DELETE', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testHeadSetsCorrectMethod()
    +    {
    +        $this->request->head('http://example.com');
    +
    +        $this->assertSame('head', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('HEAD', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testOptionsSetsCorrectMethod()
    +    {
    +        $this->request->options('http://example.com');
    +
    +        $this->assertSame('options', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('OPTIONS', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testOptionsBaseURIOption()
    +    {
    +        $options = ['base_uri' => 'http://www.foo.com/api/v1/'];
    +        $request = $this->getRequest($options);
    +
    +        $this->assertSame('http://www.foo.com/api/v1/', $request->getBaseURI()->__toString());
    +    }
    +
    +    public function testOptionsBaseURIOverride()
    +    {
    +        $options = [
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'baseURI'  => 'http://bogus/com',
    +        ];
    +        $request = $this->getRequest($options);
    +
    +        $this->assertSame('http://bogus/com', $request->getBaseURI()->__toString());
    +    }
    +
    +    public function testOptionsHeaders()
    +    {
    +        $options = [
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'headers'  => ['fruit' => 'apple'],
    +        ];
    +        $request = $this->getRequest();
    +        $this->assertNull($request->header('fruit'));
    +
    +        $request = $this->getRequest($options);
    +        $this->assertSame('apple', $request->header('fruit')->getValue());
    +    }
    +
    +    /**
    +     * @backupGlobals enabled
    +     */
    +    public function testOptionsHeadersNotUsingPopulate()
    +    {
    +        $_SERVER['HTTP_HOST']            = 'site1.com';
    +        $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US';
    +        $_SERVER['HTTP_ACCEPT_ENCODING'] = 'gzip, deflate, br';
    +
    +        $options = [
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'headers'  => [
    +                'Host'            => 'www.foo.com',
    +                'Accept-Encoding' => '',
    +            ],
    +        ];
    +        $request = $this->getRequest($options);
    +        $request->get('example');
    +        // if headers for the request are defined we use them
    +        $this->assertNull($request->header('Accept-Language'));
    +        $this->assertSame('www.foo.com', $request->header('Host')->getValue());
    +        $this->assertSame('', $request->header('Accept-Encoding')->getValue());
    +    }
    +
    +    public function testHeaderContentLengthNotSharedBetweenRequests()
    +    {
    +        $options = [
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +        ];
    +        $request = $this->getRequest($options, false);
    +
    +        $request->post('example', [
    +            'form_params' => [
    +                'q' => 'keyword',
    +            ],
    +        ]);
    +        $request->get('example');
    +
    +        $this->assertNull($request->header('Content-Length'));
    +    }
    +
    +    /**
    +     * @backupGlobals enabled
    +     */
    +    public function testHeaderContentLengthNotSharedBetweenClients()
    +    {
    +        $_SERVER['HTTP_CONTENT_LENGTH'] = '10';
    +
    +        $options = [
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +        ];
    +        $request = $this->getRequest($options);
    +        $request->post('example', [
    +            'form_params' => [
    +                'q' => 'keyword',
    +            ],
    +        ]);
    +
    +        $request = $this->getRequest($options);
    +        $request->get('example');
    +
    +        $this->assertNull($request->header('Content-Length'));
    +    }
    +
    +    public function testOptionsDelay()
    +    {
    +        $options = [
    +            'delay'   => 2000,
    +            'headers' => ['fruit' => 'apple'],
    +        ];
    +        $request = $this->getRequest();
    +        $this->assertSame(0.0, $request->getDelay());
    +
    +        $request = $this->getRequest($options);
    +        $this->assertSame(2.0, $request->getDelay());
    +    }
    +
    +    public function testPatchSetsCorrectMethod()
    +    {
    +        $this->request->patch('http://example.com');
    +
    +        $this->assertSame('patch', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('PATCH', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testPostSetsCorrectMethod()
    +    {
    +        $this->request->post('http://example.com');
    +
    +        $this->assertSame('post', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('POST', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testPutSetsCorrectMethod()
    +    {
    +        $this->request->put('http://example.com');
    +
    +        $this->assertSame('put', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('PUT', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testCustomMethodSetsCorrectMethod()
    +    {
    +        $this->request->request('custom', 'http://example.com');
    +
    +        $this->assertSame('custom', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testRequestMethodGetsSanitized()
    +    {
    +        $this->request->request('', 'http://example.com');
    +
    +        $this->assertSame('custom', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CUSTOMREQUEST, $options);
    +        $this->assertSame('CUSTOM', $options[CURLOPT_CUSTOMREQUEST]);
    +    }
    +
    +    public function testRequestSetsBasicCurlOptions()
    +    {
    +        $this->request->request('get', 'http://example.com');
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_URL, $options);
    +        $this->assertSame('http://example.com', $options[CURLOPT_URL]);
    +
    +        $this->assertArrayHasKey(CURLOPT_RETURNTRANSFER, $options);
    +        $this->assertTrue($options[CURLOPT_RETURNTRANSFER]);
    +
    +        $this->assertArrayHasKey(CURLOPT_HEADER, $options);
    +        $this->assertTrue($options[CURLOPT_HEADER]);
    +
    +        $this->assertArrayHasKey(CURLOPT_FRESH_CONNECT, $options);
    +        $this->assertTrue($options[CURLOPT_FRESH_CONNECT]);
    +
    +        $this->assertArrayHasKey(CURLOPT_TIMEOUT_MS, $options);
    +        $this->assertSame(0.0, $options[CURLOPT_TIMEOUT_MS]);
    +
    +        $this->assertArrayHasKey(CURLOPT_CONNECTTIMEOUT_MS, $options);
    +        $this->assertSame(150000.0, $options[CURLOPT_CONNECTTIMEOUT_MS]);
    +    }
    +
    +    public function testAuthBasicOption()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'auth' => [
    +                'username',
    +                'password',
    +            ],
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_USERPWD, $options);
    +        $this->assertSame('username:password', $options[CURLOPT_USERPWD]);
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options);
    +        $this->assertSame(CURLAUTH_BASIC, $options[CURLOPT_HTTPAUTH]);
    +    }
    +
    +    public function testAuthBasicOptionExplicit()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'auth' => [
    +                'username',
    +                'password',
    +                'basic',
    +            ],
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_USERPWD, $options);
    +        $this->assertSame('username:password', $options[CURLOPT_USERPWD]);
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options);
    +        $this->assertSame(CURLAUTH_BASIC, $options[CURLOPT_HTTPAUTH]);
    +    }
    +
    +    public function testAuthDigestOption()
    +    {
    +        $output = "HTTP/1.1 401 Unauthorized
    +		Server: ddos-guard
    +		Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT
    +		WWW-Authenticate: Digest\x0d\x0a\x0d\x0aHTTP/1.1 200 OK
    +		Server: ddos-guard
    +		Connection: keep-alive
    +		Keep-Alive: timeout=60
    +		Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT
    +		Date: Tue, 07 Jul 2020 15:13:14 GMT
    +		Expires: Thu, 19 Nov 1981 08:52:00 GMT
    +		Cache-Control: no-store, no-cache, must-revalidate
    +		Pragma: no-cache
    +		Set-Cookie: PHPSESSID=80pd3hlg38mvjnelpvokp9lad0; path=/
    +		Content-Type: application/xml; charset=utf-8
    +		Transfer-Encoding: chunked\x0d\x0a\x0d\x0aUpdate success! config";
    +
    +        $this->request->setOutput($output);
    +
    +        $response = $this->request->request('get', 'http://example.com', [
    +            'auth' => [
    +                'username',
    +                'password',
    +                'digest',
    +            ],
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertSame('Update success! config', $response->getBody());
    +        $this->assertSame(200, $response->getStatusCode());
    +
    +        $this->assertArrayHasKey(CURLOPT_USERPWD, $options);
    +        $this->assertSame('username:password', $options[CURLOPT_USERPWD]);
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options);
    +        $this->assertSame(CURLAUTH_DIGEST, $options[CURLOPT_HTTPAUTH]);
    +    }
    +
    +    public function testSetAuthBasic()
    +    {
    +        $this->request->setAuth('username', 'password')->get('http://example.com');
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_USERPWD, $options);
    +        $this->assertSame('username:password', $options[CURLOPT_USERPWD]);
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options);
    +        $this->assertSame(CURLAUTH_BASIC, $options[CURLOPT_HTTPAUTH]);
    +    }
    +
    +    public function testSetAuthDigest()
    +    {
    +        $output = "HTTP/1.1 401 Unauthorized
    +		Server: ddos-guard
    +		Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT
    +		WWW-Authenticate: Digest\x0d\x0a\x0d\x0aHTTP/1.1 200 OK
    +		Server: ddos-guard
    +		Connection: keep-alive
    +		Keep-Alive: timeout=60
    +		Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT
    +		Date: Tue, 07 Jul 2020 15:13:14 GMT
    +		Expires: Thu, 19 Nov 1981 08:52:00 GMT
    +		Cache-Control: no-store, no-cache, must-revalidate
    +		Pragma: no-cache
    +		Set-Cookie: PHPSESSID=80pd3hlg38mvjnelpvokp9lad0; path=/
    +		Content-Type: application/xml; charset=utf-8
    +		Transfer-Encoding: chunked\x0d\x0a\x0d\x0aUpdate success! config";
    +
    +        $this->request->setOutput($output);
    +
    +        $response = $this->request->setAuth('username', 'password', 'digest')->get('http://example.com');
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertSame('Update success! config', $response->getBody());
    +        $this->assertSame(200, $response->getStatusCode());
    +
    +        $this->assertArrayHasKey(CURLOPT_USERPWD, $options);
    +        $this->assertSame('username:password', $options[CURLOPT_USERPWD]);
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTPAUTH, $options);
    +        $this->assertSame(CURLAUTH_DIGEST, $options[CURLOPT_HTTPAUTH]);
    +    }
    +
    +    public function testCertOption()
    +    {
    +        $file = __FILE__;
    +
    +        $this->request->request('get', 'http://example.com', [
    +            'cert' => $file,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_SSLCERT, $options);
    +        $this->assertSame($file, $options[CURLOPT_SSLCERT]);
    +    }
    +
    +    public function testCertOptionWithPassword()
    +    {
    +        $file = __FILE__;
    +
    +        $this->request->request('get', 'http://example.com', [
    +            'cert' => [
    +                $file,
    +                'password',
    +            ],
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_SSLCERT, $options);
    +        $this->assertSame($file, $options[CURLOPT_SSLCERT]);
    +
    +        $this->assertArrayHasKey(CURLOPT_SSLCERTPASSWD, $options);
    +        $this->assertSame('password', $options[CURLOPT_SSLCERTPASSWD]);
    +    }
    +
    +    public function testMissingCertOption()
    +    {
    +        $file = 'something_obviously_bogus';
    +        $this->expectException(HTTPException::class);
    +
    +        $this->request->request('get', 'http://example.com', [
    +            'cert' => $file,
    +        ]);
    +    }
    +
    +    public function testSSLVerification()
    +    {
    +        $file = __FILE__;
    +
    +        $this->request->request('get', 'http://example.com', [
    +            'verify'  => 'yes',
    +            'ssl_key' => $file,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_CAINFO, $options);
    +        $this->assertSame($file, $options[CURLOPT_CAINFO]);
    +
    +        $this->assertArrayHasKey(CURLOPT_SSL_VERIFYPEER, $options);
    +        $this->assertSame(1, $options[CURLOPT_SSL_VERIFYPEER]);
    +    }
    +
    +    public function testSSLWithBadKey()
    +    {
    +        $file = 'something_obviously_bogus';
    +        $this->expectException(HTTPException::class);
    +
    +        $this->request->request('get', 'http://example.com', [
    +            'verify'  => 'yes',
    +            'ssl_key' => $file,
    +        ]);
    +    }
    +
    +    public function testDebugOptionTrue()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'debug' => true,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_VERBOSE, $options);
    +        $this->assertSame(1, $options[CURLOPT_VERBOSE]);
    +
    +        $this->assertArrayHasKey(CURLOPT_STDERR, $options);
    +        $this->assertIsResource($options[CURLOPT_STDERR]);
    +    }
    +
    +    public function testDebugOptionFalse()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'debug' => false,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayNotHasKey(CURLOPT_VERBOSE, $options);
    +        $this->assertArrayNotHasKey(CURLOPT_STDERR, $options);
    +    }
    +
    +    public function testDebugOptionFile()
    +    {
    +        $file = SUPPORTPATH . 'Files/baker/banana.php';
    +
    +        $this->request->request('get', 'http://example.com', [
    +            'debug' => $file,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_VERBOSE, $options);
    +        $this->assertSame(1, $options[CURLOPT_VERBOSE]);
    +
    +        $this->assertArrayHasKey(CURLOPT_STDERR, $options);
    +        $this->assertIsResource($options[CURLOPT_STDERR]);
    +    }
    +
    +    public function testDecodeContent()
    +    {
    +        $this->request->setHeader('Accept-Encoding', 'cobol');
    +        $this->request->request('get', 'http://example.com', [
    +            'decode_content' => true,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_ENCODING, $options);
    +        $this->assertSame('cobol', $options[CURLOPT_ENCODING]);
    +    }
    +
    +    public function testDecodeContentWithoutAccept()
    +    {
    +        //      $this->request->setHeader('Accept-Encoding', 'cobol');
    +        $this->request->request('get', 'http://example.com', [
    +            'decode_content' => true,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_ENCODING, $options);
    +        $this->assertSame('', $options[CURLOPT_ENCODING]);
    +        $this->assertArrayHasKey(CURLOPT_HTTPHEADER, $options);
    +        $this->assertSame('Accept-Encoding', $options[CURLOPT_HTTPHEADER]);
    +    }
    +
    +    public function testAllowRedirectsOptionFalse()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'allow_redirects' => false,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options);
    +        $this->assertSame(0, $options[CURLOPT_FOLLOWLOCATION]);
    +
    +        $this->assertArrayNotHasKey(CURLOPT_MAXREDIRS, $options);
    +        $this->assertArrayNotHasKey(CURLOPT_REDIR_PROTOCOLS, $options);
    +    }
    +
    +    public function testAllowRedirectsOptionTrue()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'allow_redirects' => true,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options);
    +        $this->assertSame(1, $options[CURLOPT_FOLLOWLOCATION]);
    +
    +        $this->assertArrayHasKey(CURLOPT_MAXREDIRS, $options);
    +        $this->assertSame(5, $options[CURLOPT_MAXREDIRS]);
    +        $this->assertArrayHasKey(CURLOPT_REDIR_PROTOCOLS, $options);
    +        $this->assertSame(CURLPROTO_HTTP | CURLPROTO_HTTPS, $options[CURLOPT_REDIR_PROTOCOLS]);
    +    }
    +
    +    public function testAllowRedirectsOptionDefaults()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'allow_redirects' => true,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options);
    +        $this->assertSame(1, $options[CURLOPT_FOLLOWLOCATION]);
    +
    +        $this->assertArrayHasKey(CURLOPT_MAXREDIRS, $options);
    +        $this->assertArrayHasKey(CURLOPT_REDIR_PROTOCOLS, $options);
    +    }
    +
    +    public function testAllowRedirectsArray()
    +    {
    +        $this->request->request('get', 'http://example.com', [
    +            'allow_redirects' => ['max' => 2],
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_FOLLOWLOCATION, $options);
    +        $this->assertSame(1, $options[CURLOPT_FOLLOWLOCATION]);
    +
    +        $this->assertArrayHasKey(CURLOPT_MAXREDIRS, $options);
    +        $this->assertSame(2, $options[CURLOPT_MAXREDIRS]);
    +    }
    +
    +    public function testSendWithQuery()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'query'    => [
    +                'name' => 'Henry',
    +                'd.t'  => 'value',
    +            ],
    +        ]);
    +
    +        $request->get('products');
    +
    +        $options = $request->curl_options;
    +
    +        $this->assertSame('http://www.foo.com/api/v1/products?name=Henry&d.t=value', $options[CURLOPT_URL]);
    +    }
    +
    +    public function testSendWithDelay()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $request->get('products');
    +
    +        // we still need to check the code coverage to make sure this was done
    +        $this->assertSame(1.0, $request->getDelay());
    +    }
    +
    +    public function testSendContinued()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $request->setOutput("HTTP/1.1 100 Continue\x0d\x0a\x0d\x0aHi there");
    +        $response = $request->get('answer');
    +        $this->assertSame('Hi there', $response->getBody());
    +    }
    +
    +    /**
    +     * See: https://github.com/codeigniter4/CodeIgniter4/issues/3261
    +     */
    +    public function testSendContinuedWithManyHeaders()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $output = "HTTP/1.1 100 Continue
    +Server: ddos-guard
    +Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT\x0d\x0a\x0d\x0aHTTP/1.1 200 OK
    +Server: ddos-guard
    +Connection: keep-alive
    +Keep-Alive: timeout=60
    +Set-Cookie: __ddg1=z177j4mLtqzC07v0zviU; Domain=.site.ru; HttpOnly; Path=/; Expires=Wed, 07-Jul-2021 15:13:14 GMT
    +Date: Tue, 07 Jul 2020 15:13:14 GMT
    +Expires: Thu, 19 Nov 1981 08:52:00 GMT
    +Cache-Control: no-store, no-cache, must-revalidate
    +Pragma: no-cache
    +Set-Cookie: PHPSESSID=80pd3hlg38mvjnelpvokp9lad0; path=/
    +Content-Type: application/xml; charset=utf-8
    +Transfer-Encoding: chunked\x0d\x0a\x0d\x0aUpdate success! config";
    +
    +        $request->setOutput($output);
    +        $response = $request->get('answer');
    +
    +        $this->assertSame('Update success! config', $response->getBody());
    +
    +        $responseHeaderKeys = [
    +            'Cache-control',
    +            'Content-Type',
    +            'Server',
    +            'Connection',
    +            'Keep-Alive',
    +            'Set-Cookie',
    +            'Date',
    +            'Expires',
    +            'Pragma',
    +            'Transfer-Encoding',
    +        ];
    +        $this->assertSame($responseHeaderKeys, array_keys($response->headers()));
    +
    +        $this->assertSame(200, $response->getStatusCode());
    +    }
    +
    +    public function testSplitResponse()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $request->setOutput("Accept: text/html\x0d\x0a\x0d\x0aHi there");
    +        $response = $request->get('answer');
    +        $this->assertSame('Hi there', $response->getBody());
    +    }
    +
    +    public function testApplyBody()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $request->setBody('name=George');
    +        $request->setOutput('Hi there');
    +        $response = $request->post('answer');
    +
    +        $this->assertSame('Hi there', $response->getBody());
    +        $this->assertSame('name=George', $request->curl_options[CURLOPT_POSTFIELDS]);
    +    }
    +
    +    public function testResponseHeaders()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $request->setOutput("HTTP/2.0 234 Ohoh\x0d\x0aAccept: text/html\x0d\x0a\x0d\x0aHi there");
    +        $response = $request->get('bogus');
    +
    +        $this->assertSame('2.0', $response->getProtocolVersion());
    +        $this->assertSame(234, $response->getStatusCode());
    +    }
    +
    +    public function testResponseHeadersShortProtocol()
    +    {
    +        $request = $this->getRequest([
    +            'base_uri' => 'http://www.foo.com/api/v1/',
    +            'delay'    => 1000,
    +        ]);
    +
    +        $request->setOutput("HTTP/2 235 Ohoh\x0d\x0aAccept: text/html\x0d\x0a\x0d\x0aHi there shortie");
    +        $response = $request->get('bogus');
    +
    +        $this->assertSame('2.0', $response->getProtocolVersion());
    +        $this->assertSame(235, $response->getStatusCode());
    +    }
    +
    +    public function testPostFormEncoded()
    +    {
    +        $params = [
    +            'foo' => 'bar',
    +            'baz' => [
    +                'hi',
    +                'there',
    +            ],
    +        ];
    +        $this->request->request('POST', '/post', [
    +            'form_params' => $params,
    +        ]);
    +
    +        $this->assertSame('post', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $expected = http_build_query($params);
    +        $this->assertArrayHasKey(CURLOPT_POSTFIELDS, $options);
    +        $this->assertSame($expected, $options[CURLOPT_POSTFIELDS]);
    +    }
    +
    +    public function testPostFormMultipart()
    +    {
    +        $params = [
    +            'foo' => 'bar',
    +            'baz' => [
    +                'hi',
    +                'there',
    +            ],
    +            'afile' => new CURLFile(__FILE__),
    +        ];
    +        $this->request->request('POST', '/post', [
    +            'multipart' => $params,
    +        ]);
    +
    +        $this->assertSame('post', $this->request->getMethod());
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_POSTFIELDS, $options);
    +        $this->assertSame($params, $options[CURLOPT_POSTFIELDS]);
    +    }
    +
    +    public function testSetForm()
    +    {
    +        $params = [
    +            'foo' => 'bar',
    +            'baz' => [
    +                'hi',
    +                'there',
    +            ],
    +        ];
    +
    +        $this->request->setForm($params)->post('/post');
    +
    +        $this->assertSame(
    +            http_build_query($params),
    +            $this->request->curl_options[CURLOPT_POSTFIELDS]
    +        );
    +
    +        $params['afile'] = new CURLFile(__FILE__);
    +
    +        $this->request->setForm($params, true)->post('/post');
    +
    +        $this->assertSame(
    +            $params,
    +            $this->request->curl_options[CURLOPT_POSTFIELDS]
    +        );
    +    }
    +
    +    public function testJSONData()
    +    {
    +        $params = [
    +            'foo' => 'bar',
    +            'baz' => [
    +                'hi',
    +                'there',
    +            ],
    +        ];
    +        $this->request->request('POST', '/post', [
    +            'json' => $params,
    +        ]);
    +
    +        $this->assertSame('post', $this->request->getMethod());
    +
    +        $expected = json_encode($params);
    +        $this->assertSame($expected, $this->request->getBody());
    +    }
    +
    +    public function testSetJSON()
    +    {
    +        $params = [
    +            'foo' => 'bar',
    +            'baz' => [
    +                'hi',
    +                'there',
    +            ],
    +        ];
    +        $this->request->setJSON($params)->post('/post');
    +
    +        $this->assertSame(json_encode($params), $this->request->getBody());
    +        $this->assertSame(
    +            'Content-Type: application/json',
    +            $this->request->curl_options[CURLOPT_HTTPHEADER][0]
    +        );
    +    }
    +
    +    public function testHTTPv1()
    +    {
    +        $this->request->request('POST', '/post', [
    +            'version' => 1.0,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options);
    +        $this->assertSame(CURL_HTTP_VERSION_1_0, $options[CURLOPT_HTTP_VERSION]);
    +    }
    +
    +    public function testHTTPv11()
    +    {
    +        $this->request->request('POST', '/post', [
    +            'version' => 1.1,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_HTTP_VERSION, $options);
    +        $this->assertSame(CURL_HTTP_VERSION_1_1, $options[CURLOPT_HTTP_VERSION]);
    +    }
    +
    +    public function testCookieOption()
    +    {
    +        $holder = SUPPORTPATH . 'HTTP/Files/CookiesHolder.txt';
    +        $this->request->request('POST', '/post', [
    +            'cookie' => $holder,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_COOKIEJAR, $options);
    +        $this->assertSame($holder, $options[CURLOPT_COOKIEJAR]);
    +        $this->assertArrayHasKey(CURLOPT_COOKIEFILE, $options);
    +        $this->assertSame($holder, $options[CURLOPT_COOKIEFILE]);
    +    }
    +
    +    public function testUserAgentOption()
    +    {
    +        $agent = 'CodeIgniter Framework';
    +
    +        $this->request->request('POST', '/post', [
    +            'user_agent' => $agent,
    +        ]);
    +
    +        $options = $this->request->curl_options;
    +
    +        $this->assertArrayHasKey(CURLOPT_USERAGENT, $options);
    +        $this->assertSame($agent, $options[CURLOPT_USERAGENT]);
    +    }
    +}
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index 7237323f0be4..2d71572f3c94 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -36,11 +36,11 @@ protected function setUp(): void
             $this->request = $this->getRequest();
         }
     
    -    protected function getRequest(array $options = [], $shareOptions = true)
    +    protected function getRequest(array $options = [])
         {
             $uri                          = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
             $app                          = new App();
    -        $app->CURLRequestShareOptions = $shareOptions;
    +        $app->CURLRequestShareOptions = true;
     
             return new MockCURLRequest(($app), $uri, new Response($app), $options);
         }
    @@ -199,23 +199,6 @@ public function testOptionsHeadersNotUsingPopulate()
             $this->assertSame('', $request->header('Accept-Encoding')->getValue());
         }
     
    -    public function testHeaderContentLengthNotSharedBetweenRequestsWhenSharedOptionsFalse()
    -    {
    -        $options = [
    -            'base_uri' => 'http://www.foo.com/api/v1/',
    -        ];
    -        $request = $this->getRequest($options, false);
    -
    -        $request->post('example', [
    -            'form_params' => [
    -                'q' => 'keyword',
    -            ],
    -        ]);
    -        $request->get('example');
    -
    -        $this->assertNull($request->header('Content-Length'));
    -    }
    -
         /**
          * @backupGlobals enabled
          */
    
    From 9e88ec4a41e1930c83970e6c0d7ca02763b8d4da Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 29 Oct 2021 18:56:06 +0900
    Subject: [PATCH 0545/2325] test: add tests for sharing options
    
    ---
     .../HTTP/CURLRequestDoNotShareOptionsTest.php | 21 +++++++++++++++++++
     tests/system/HTTP/CURLRequestTest.php         | 21 +++++++++++++++++++
     2 files changed, 42 insertions(+)
    
    diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    index d40356118f79..ae6aef2ad74d 100644
    --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    @@ -199,6 +199,27 @@ public function testOptionsHeadersNotUsingPopulate()
             $this->assertSame('', $request->header('Accept-Encoding')->getValue());
         }
     
    +    public function testDefaultOptionsAreSharedBetweenRequests()
    +    {
    +        $options = [
    +            'form_params' => ['studio' => 1],
    +            'user_agent'  => 'CodeIgniter Framework v4',
    +        ];
    +        $request = $this->getRequest($options);
    +
    +        $request->request('POST', 'https://realestate1.example.com');
    +
    +        $this->assertSame('https://realestate1.example.com', $request->curl_options[CURLOPT_URL]);
    +        $this->assertSame('studio=1', $request->curl_options[CURLOPT_POSTFIELDS]);
    +        $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]);
    +
    +        $request->request('POST', 'https://realestate2.example.com');
    +
    +        $this->assertSame('https://realestate2.example.com', $request->curl_options[CURLOPT_URL]);
    +        $this->assertSame('studio=1', $request->curl_options[CURLOPT_POSTFIELDS]);
    +        $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]);
    +    }
    +
         public function testHeaderContentLengthNotSharedBetweenRequests()
         {
             $options = [
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index 2d71572f3c94..de7ef08b59fc 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -199,6 +199,27 @@ public function testOptionsHeadersNotUsingPopulate()
             $this->assertSame('', $request->header('Accept-Encoding')->getValue());
         }
     
    +    public function testOptionsAreSharedBetweenRequests()
    +    {
    +        $options = [
    +            'form_params' => ['studio' => 1],
    +            'user_agent'  => 'CodeIgniter Framework v4',
    +        ];
    +        $request = $this->getRequest($options);
    +
    +        $request->request('POST', 'https://realestate1.example.com');
    +
    +        $this->assertSame('https://realestate1.example.com', $request->curl_options[CURLOPT_URL]);
    +        $this->assertSame('studio=1', $request->curl_options[CURLOPT_POSTFIELDS]);
    +        $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]);
    +
    +        $request->request('POST', 'https://realestate2.example.com');
    +
    +        $this->assertSame('https://realestate2.example.com', $request->curl_options[CURLOPT_URL]);
    +        $this->assertSame('studio=1', $request->curl_options[CURLOPT_POSTFIELDS]);
    +        $this->assertSame('CodeIgniter Framework v4', $request->curl_options[CURLOPT_USERAGENT]);
    +    }
    +
         /**
          * @backupGlobals enabled
          */
    
    From b648d2d724a0f313b664fd515f0023911381403b Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 18:18:25 +0800
    Subject: [PATCH 0546/2325] Cleanup php-cs-fixer config files
    
    ---
     .no-header.php-cs-fixer.dist.php | 21 +--------------------
     .php-cs-fixer.dist.php           | 21 +--------------------
     2 files changed, 2 insertions(+), 40 deletions(-)
    
    diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php
    index a3030aa98f58..12acddb81087 100644
    --- a/.no-header.php-cs-fixer.dist.php
    +++ b/.no-header.php-cs-fixer.dist.php
    @@ -27,26 +27,7 @@
         ])
         ->notName('#Logger\.php$#');
     
    -$overrides = [
    -    // @TODO Remove once these are live in coding-standard
    -    'assign_null_coalescing_to_coalesce_equal' => false, // requires 7.4+
    -    'class_attributes_separation'              => [
    -        'elements' => [
    -            'const'        => 'none',
    -            'property'     => 'none',
    -            'method'       => 'one',
    -            'trait_import' => 'none',
    -        ],
    -    ],
    -    'control_structure_continuation_position' => ['position' => 'same_line'],
    -    'empty_loop_condition'                    => ['style' => 'while'],
    -    'integer_literal_case'                    => true,
    -    'modernize_strpos'                        => false, // requires 8.0+
    -    'no_alternative_syntax'                   => ['fix_non_monolithic_code' => false],
    -    'no_space_around_double_colon'            => true,
    -    'octal_notation'                          => false, // requires 8.1+
    -    'string_length_to_empty'                  => true,
    -];
    +$overrides = [];
     
     $options = [
         'cacheFile'    => 'build/.no-header.php-cs-fixer.cache',
    diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
    index 743062d44a88..3c9e05fe3b74 100644
    --- a/.php-cs-fixer.dist.php
    +++ b/.php-cs-fixer.dist.php
    @@ -34,26 +34,7 @@
             __DIR__ . '/spark',
         ]);
     
    -$overrides = [
    -    // @TODO Remove once these are live in coding-standard
    -    'assign_null_coalescing_to_coalesce_equal' => false, // requires 7.4+
    -    'class_attributes_separation'              => [
    -        'elements' => [
    -            'const'        => 'none',
    -            'property'     => 'none',
    -            'method'       => 'one',
    -            'trait_import' => 'none',
    -        ],
    -    ],
    -    'control_structure_continuation_position' => ['position' => 'same_line'],
    -    'empty_loop_condition'                    => ['style' => 'while'],
    -    'integer_literal_case'                    => true,
    -    'modernize_strpos'                        => false, // requires 8.0+
    -    'no_alternative_syntax'                   => ['fix_non_monolithic_code' => false],
    -    'no_space_around_double_colon'            => true,
    -    'octal_notation'                          => false, // requires 8.1+
    -    'string_length_to_empty'                  => true,
    -];
    +$overrides = [];
     
     $options = [
         'cacheFile'    => 'build/.php-cs-fixer.cache',
    
    From 3ac80c37d8482716c7189bcca69bc43d1dc4823d Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 18:23:05 +0800
    Subject: [PATCH 0547/2325] Run `builds` thru CS lint
    
    ---
     .no-header.php-cs-fixer.dist.php |   5 +-
     admin/starter/builds             | 236 ++++++++++++++-----------------
     2 files changed, 111 insertions(+), 130 deletions(-)
    
    diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php
    index a3030aa98f58..f3b427daec4a 100644
    --- a/.no-header.php-cs-fixer.dist.php
    +++ b/.no-header.php-cs-fixer.dist.php
    @@ -25,7 +25,10 @@
             __DIR__ . '/app',
             __DIR__ . '/public',
         ])
    -    ->notName('#Logger\.php$#');
    +    ->notName('#Logger\.php$#')
    +    ->append([
    +        __DIR__ . '/admin/starter/builds',
    +    ]);
     
     $overrides = [
         // @TODO Remove once these are live in coding-standard
    diff --git a/admin/starter/builds b/admin/starter/builds
    index 268e7a819c22..1ac374f57a75 100755
    --- a/admin/starter/builds
    +++ b/admin/starter/builds
    @@ -15,149 +15,127 @@ define('GITHUB_URL', 'https://github.com/codeigniter4/codeigniter4');
      */
     
     // Determine the requested stability
    -if (empty($argv[1]) || ! in_array($argv[1], ['release', 'development']))
    -{
    -	echo 'Usage: php builds [release|development]' . PHP_EOL;
    -	exit;
    +if (empty($argv[1]) || ! in_array($argv[1], ['release', 'development'], true)) {
    +    echo 'Usage: php builds [release|development]' . PHP_EOL;
    +
    +    exit;
     }
     
    -$dev = $argv[1] == 'development';
    +$dev = $argv[1] === 'development';
    +
     $modified = [];
     
    -/* Locate each file and update it for the requested stability */
    +// Locate each file and update it for the requested stability
     
     // Composer.json
     $file = __DIR__ . DIRECTORY_SEPARATOR . 'composer.json';
     
    -if (is_file($file))
    -{
    -	// Make sure we can read it
    -	if ($contents = file_get_contents($file))
    -	{
    -		if ($array = json_decode($contents, true))
    -		{
    -			// Development
    -			if ($dev)
    -			{
    -				// Set 'minimum-stability'
    -				$array['minimum-stability'] = 'dev';
    -				$array['prefer-stable']     = true;
    -
    -				// Make sure the repo is configured
    -				if (! isset($array['repositories']))
    -				{
    -					$array['repositories'] = [];
    -				}
    -
    -				// Check for the CodeIgniter repo
    -				$found = false;
    -				foreach ($array['repositories'] as $repository)
    -				{
    -					if ($repository['url'] == GITHUB_URL)
    -					{
    -						$found = true;
    -						break;
    -					}
    -				}
    -
    -				// Add the repo if it was not found
    -				if (! $found)
    -				{
    -					$array['repositories'][] = [
    -						'type' => 'vcs',
    -						'url'  => GITHUB_URL,
    -					];
    -				}
    -
    -				// Define the "require"
    -				$array['require']['codeigniter4/codeigniter4'] = 'dev-develop';
    -				unset($array['require']['codeigniter4/framework']);
    -			}
    -
    -			// Release
    -			else
    -			{
    -				// Clear 'minimum-stability'
    -				unset($array['minimum-stability']);
    -
    -				// If the repo is configured then clear it
    -				if (isset($array['repositories']))
    -				{
    -					// Check for the CodeIgniter repo
    -					foreach ($array['repositories'] as $i => $repository)
    -					{
    -						if ($repository['url'] == GITHUB_URL)
    -						{
    -							unset($array['repositories'][$i]);
    -							break;
    -						}
    -					}
    -					if (empty($array['repositories']))
    -					{
    -						unset($array['repositories']);
    -					}
    -				}
    -
    -				// Define the "require"
    -				$array['require']['codeigniter4/framework'] = LATEST_RELEASE;
    -				unset($array['require']['codeigniter4/codeigniter4']);
    -			}
    -
    -			// Write out a new composer.json
    -			file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES) . PHP_EOL);
    -			$modified[] = $file;
    -		}
    -		else
    -		{
    -			echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL;
    -		}
    -	}
    -	else
    -	{
    -		echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL;
    -	}
    +if (is_file($file)) {
    +    // Make sure we can read it
    +    if ($contents = file_get_contents($file)) {
    +        if ($array = json_decode($contents, true)) {
    +            // Development
    +            if ($dev) {
    +                // Set 'minimum-stability'
    +                $array['minimum-stability'] = 'dev';
    +                $array['prefer-stable']     = true;
    +
    +                // Make sure the repo is configured
    +                if (! isset($array['repositories'])) {
    +                    $array['repositories'] = [];
    +                }
    +
    +                // Check for the CodeIgniter repo
    +                $found = false;
    +
    +                foreach ($array['repositories'] as $repository) {
    +                    if ($repository['url'] === GITHUB_URL) {
    +                        $found = true;
    +                        break;
    +                    }
    +                }
    +
    +                // Add the repo if it was not found
    +                if (! $found) {
    +                    $array['repositories'][] = [
    +                        'type' => 'vcs',
    +                        'url'  => GITHUB_URL,
    +                    ];
    +                }
    +
    +                // Define the "require"
    +                $array['require']['codeigniter4/codeigniter4'] = 'dev-develop';
    +                unset($array['require']['codeigniter4/framework']);
    +            }
    +
    +            // Release
    +            else {
    +                // Clear 'minimum-stability'
    +                unset($array['minimum-stability']);
    +
    +                // If the repo is configured then clear it
    +                if (isset($array['repositories'])) {
    +                    // Check for the CodeIgniter repo
    +                    foreach ($array['repositories'] as $i => $repository) {
    +                        if ($repository['url'] === GITHUB_URL) {
    +                            unset($array['repositories'][$i]);
    +                            break;
    +                        }
    +                    }
    +                    if (empty($array['repositories'])) {
    +                        unset($array['repositories']);
    +                    }
    +                }
    +
    +                // Define the "require"
    +                $array['require']['codeigniter4/framework'] = LATEST_RELEASE;
    +                unset($array['require']['codeigniter4/codeigniter4']);
    +            }
    +
    +            // Write out a new composer.json
    +            file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
    +            $modified[] = $file;
    +        } else {
    +            echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL;
    +        }
    +    } else {
    +        echo 'Warning: Unable to read composer.json! Skipping...' . PHP_EOL;
    +    }
     }
     
     // Paths config and PHPUnit XMLs
     $files = [
    -	__DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php',
    -	__DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist',
    -	__DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml',
    +    __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php',
    +    __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist',
    +    __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml',
     ];
     
    -foreach ($files as $file)
    -{
    -	if (is_file($file))
    -	{
    -		$contents = file_get_contents($file);
    -
    -		// Development
    -		if ($dev)
    -		{
    -			$contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents);
    -		}
    -
    -		// Release
    -		else
    -		{
    -			$contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents);
    -		}
    -
    -		file_put_contents($file, $contents);
    -		$modified[] = $file;
    -	}
    -}
    +foreach ($files as $file) {
    +    if (is_file($file)) {
    +        $contents = file_get_contents($file);
    +
    +        // Development
    +        if ($dev) {
    +            $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents);
    +        }
     
    -if (empty($modified))
    -{
    -	echo 'No files modified' . PHP_EOL;
    +        // Release
    +        else {
    +            $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents);
    +        }
    +
    +        file_put_contents($file, $contents);
    +        $modified[] = $file;
    +    }
     }
    -else
    -{
    -	echo 'The following files were modified:' . PHP_EOL;
    -	foreach ($modified as $file)
    -	{
    -		echo " * {$file}" . PHP_EOL;
    -	}
    -	echo 'Run `composer update` to sync changes with your vendor folder' . PHP_EOL;
    +
    +if (empty($modified)) {
    +    echo 'No files modified' . PHP_EOL;
    +} else {
    +    echo 'The following files were modified:' . PHP_EOL;
    +
    +    foreach ($modified as $file) {
    +        echo " * {$file}" . PHP_EOL;
    +    }
    +    echo 'Run `composer update` to sync changes with your vendor folder' . PHP_EOL;
     }
    
    From ef47af446062befef5181eada32be3d0e7c13b26 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 18:26:03 +0800
    Subject: [PATCH 0548/2325] Remove unnecessary comments
    
    ---
     admin/starter/builds | 31 +++++++------------------------
     1 file changed, 7 insertions(+), 24 deletions(-)
    
    diff --git a/admin/starter/builds b/admin/starter/builds
    index 1ac374f57a75..3ef9fd3d6ec7 100755
    --- a/admin/starter/builds
    +++ b/admin/starter/builds
    @@ -27,25 +27,19 @@ $modified = [];
     
     // Locate each file and update it for the requested stability
     
    -// Composer.json
     $file = __DIR__ . DIRECTORY_SEPARATOR . 'composer.json';
     
     if (is_file($file)) {
    -    // Make sure we can read it
         if ($contents = file_get_contents($file)) {
             if ($array = json_decode($contents, true)) {
    -            // Development
                 if ($dev) {
    -                // Set 'minimum-stability'
                     $array['minimum-stability'] = 'dev';
                     $array['prefer-stable']     = true;
     
    -                // Make sure the repo is configured
                     if (! isset($array['repositories'])) {
                         $array['repositories'] = [];
                     }
     
    -                // Check for the CodeIgniter repo
                     $found = false;
     
                     foreach ($array['repositories'] as $repository) {
    @@ -55,7 +49,6 @@ if (is_file($file)) {
                         }
                     }
     
    -                // Add the repo if it was not found
                     if (! $found) {
                         $array['repositories'][] = [
                             'type' => 'vcs',
    @@ -63,37 +56,30 @@ if (is_file($file)) {
                         ];
                     }
     
    -                // Define the "require"
                     $array['require']['codeigniter4/codeigniter4'] = 'dev-develop';
                     unset($array['require']['codeigniter4/framework']);
    -            }
    -
    -            // Release
    -            else {
    -                // Clear 'minimum-stability'
    +            } else {
                     unset($array['minimum-stability']);
     
    -                // If the repo is configured then clear it
                     if (isset($array['repositories'])) {
    -                    // Check for the CodeIgniter repo
                         foreach ($array['repositories'] as $i => $repository) {
                             if ($repository['url'] === GITHUB_URL) {
                                 unset($array['repositories'][$i]);
                                 break;
                             }
                         }
    +
                         if (empty($array['repositories'])) {
                             unset($array['repositories']);
                         }
                     }
     
    -                // Define the "require"
                     $array['require']['codeigniter4/framework'] = LATEST_RELEASE;
                     unset($array['require']['codeigniter4/codeigniter4']);
                 }
     
    -            // Write out a new composer.json
                 file_put_contents($file, json_encode($array, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . PHP_EOL);
    +
                 $modified[] = $file;
             } else {
                 echo 'Warning: Unable to decode composer.json! Skipping...' . PHP_EOL;
    @@ -103,7 +89,6 @@ if (is_file($file)) {
         }
     }
     
    -// Paths config and PHPUnit XMLs
     $files = [
         __DIR__ . DIRECTORY_SEPARATOR . 'app/Config/Paths.php',
         __DIR__ . DIRECTORY_SEPARATOR . 'phpunit.xml.dist',
    @@ -114,17 +99,14 @@ foreach ($files as $file) {
         if (is_file($file)) {
             $contents = file_get_contents($file);
     
    -        // Development
             if ($dev) {
                 $contents = str_replace('vendor/codeigniter4/framework', 'vendor/codeigniter4/codeigniter4', $contents);
    -        }
    -
    -        // Release
    -        else {
    +        } else {
                 $contents = str_replace('vendor/codeigniter4/codeigniter4', 'vendor/codeigniter4/framework', $contents);
             }
     
             file_put_contents($file, $contents);
    +
             $modified[] = $file;
         }
     }
    @@ -137,5 +119,6 @@ if (empty($modified)) {
         foreach ($modified as $file) {
             echo " * {$file}" . PHP_EOL;
         }
    -    echo 'Run `composer update` to sync changes with your vendor folder' . PHP_EOL;
    +
    +    echo 'Run `composer update` to sync changes with your vendor folder.' . PHP_EOL;
     }
    
    From 1a048f9ba3dd723efd0809b677175e03e83bb558 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 18:33:02 +0800
    Subject: [PATCH 0549/2325] Other optimizations
    
    ---
     admin/starter/builds | 17 +++++++++--------
     1 file changed, 9 insertions(+), 8 deletions(-)
    
    diff --git a/admin/starter/builds b/admin/starter/builds
    index 3ef9fd3d6ec7..4a3fe3d53139 100755
    --- a/admin/starter/builds
    +++ b/admin/starter/builds
    @@ -30,15 +30,16 @@ $modified = [];
     $file = __DIR__ . DIRECTORY_SEPARATOR . 'composer.json';
     
     if (is_file($file)) {
    -    if ($contents = file_get_contents($file)) {
    -        if ($array = json_decode($contents, true)) {
    +    $contents = file_get_contents($file);
    +
    +    if ((string) $contents !== '') {
    +        $array = json_decode($contents, true);
    +
    +        if (is_array($array)) {
                 if ($dev) {
                     $array['minimum-stability'] = 'dev';
                     $array['prefer-stable']     = true;
    -
    -                if (! isset($array['repositories'])) {
    -                    $array['repositories'] = [];
    -                }
    +                $array['repositories']      = $array['repositories'] ?? [];
     
                     $found = false;
     
    @@ -111,8 +112,8 @@ foreach ($files as $file) {
         }
     }
     
    -if (empty($modified)) {
    -    echo 'No files modified' . PHP_EOL;
    +if ($modified !== []) {
    +    echo 'No files modified.' . PHP_EOL;
     } else {
         echo 'The following files were modified:' . PHP_EOL;
     
    
    From c28ae89840bfafd605ac2314fc9c1a0fd7ead164 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 18:45:33 +0800
    Subject: [PATCH 0550/2325] Disable blank issues
    
    ---
     .github/ISSUE_TEMPLATE/config.yml          |  9 +++++++++
     .github/ISSUE_TEMPLATE/support-question.md | 11 -----------
     2 files changed, 9 insertions(+), 11 deletions(-)
     create mode 100644 .github/ISSUE_TEMPLATE/config.yml
     delete mode 100644 .github/ISSUE_TEMPLATE/support-question.md
    
    diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
    new file mode 100644
    index 000000000000..69bb11b44fe8
    --- /dev/null
    +++ b/.github/ISSUE_TEMPLATE/config.yml
    @@ -0,0 +1,9 @@
    +blank_issues_enabled: false
    +contact_links:
    +  - name: CodeIgniter Forum
    +    url: https://forum.codeigniter.com
    +    about: Please ask your support questions in the forums. Thanks!
    +
    +  - name: CodeIgniter Slack channel
    +    url: https://codeigniterchat.slack.com
    +    about: Engage with other members of the community in our Slack channel.
    diff --git a/.github/ISSUE_TEMPLATE/support-question.md b/.github/ISSUE_TEMPLATE/support-question.md
    deleted file mode 100644
    index 390991ac99d0..000000000000
    --- a/.github/ISSUE_TEMPLATE/support-question.md
    +++ /dev/null
    @@ -1,11 +0,0 @@
    ----
    -name: Support question
    -about: How to ask a support question
    -title: ''
    -labels: ''
    -assignees: ''
    -
    ----
    -
    -Please ask support questions on our [forum](https://forum.codeigniter.com/forum-30.html).
    -We use github issues to track bugs and planned work.
    
    From d7364cdd1d9fa54379adc4682f433cb3d36fabcb Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 19:22:00 +0800
    Subject: [PATCH 0551/2325] Speed up `CommonSingleServiceTest`
    
    ---
     tests/system/CommonSingleServiceTest.php | 58 +++++++++++++++++-------
     1 file changed, 41 insertions(+), 17 deletions(-)
    
    diff --git a/tests/system/CommonSingleServiceTest.php b/tests/system/CommonSingleServiceTest.php
    index ede9d9b0445e..bc2f4a1f60c8 100644
    --- a/tests/system/CommonSingleServiceTest.php
    +++ b/tests/system/CommonSingleServiceTest.php
    @@ -11,6 +11,7 @@
     
     namespace CodeIgniter;
     
    +use CodeIgniter\Autoloader\FileLocator;
     use CodeIgniter\Config\Services;
     use CodeIgniter\Test\CIUnitTestCase;
     use CodeIgniter\Test\Mock\MockSecurity;
    @@ -42,6 +43,17 @@ public function testSingleServiceWithNoParamsSupplied(string $service): void
          */
         public function testSingleServiceWithAtLeastOneParamSupplied(string $service): void
         {
    +        if ($service === 'commands') {
    +            $locator = $this->getMockBuilder(FileLocator::class)
    +                ->setConstructorArgs([Services::autoloader()])
    +                ->onlyMethods(['listFiles'])
    +                ->getMock();
    +
    +            // `Commands::discoverCommand()` is an expensive operation
    +            $locator->method('listFiles')->with('Commands/')->willReturn([]);
    +            Services::injectMock('locator', $locator);
    +        }
    +
             $params = [];
             $method = new ReflectionMethod(Services::class, $service);
     
    @@ -52,6 +64,10 @@ public function testSingleServiceWithAtLeastOneParamSupplied(string $service): v
     
             $this->assertSame(get_class($service1), get_class($service2));
             $this->assertNotSame($service1, $service2);
    +
    +        if ($service === 'commands') {
    +            $this->resetServices();
    +        }
         }
     
         public function testSingleServiceWithAllParamsSupplied(): void
    @@ -76,25 +92,33 @@ public function testSingleServiceWithGibberishGiven(): void
     
         public static function serviceNamesProvider(): iterable
         {
    -        $methods = (new ReflectionClass(Services::class))->getMethods(ReflectionMethod::IS_PUBLIC);
    -
    -        foreach ($methods as $method) {
    -            $name = $method->getName();
    -            $excl = [
    -                '__callStatic',
    -                'serviceExists',
    -                'reset',
    -                'resetSingle',
    -                'injectMock',
    -                'encrypter', // Encrypter needs a starter key
    -                'session', // Headers already sent
    -            ];
    -
    -            if (in_array($name, $excl, true)) {
    -                continue;
    +        static $services = [];
    +        static $excl     = [
    +            '__callStatic',
    +            'serviceExists',
    +            'reset',
    +            'resetSingle',
    +            'injectMock',
    +            'encrypter', // Encrypter needs a starter key
    +            'session', // Headers already sent
    +        ];
    +
    +        if ($services === []) {
    +            $methods = (new ReflectionClass(Services::class))->getMethods(ReflectionMethod::IS_PUBLIC);
    +
    +            foreach ($methods as $method) {
    +                $name = $method->getName();
    +
    +                if (in_array($name, $excl, true)) {
    +                    continue;
    +                }
    +
    +                $services[$name] = [$name];
                 }
     
    -            yield $name => [$name];
    +            ksort($services);
             }
    +
    +        yield from $services;
         }
     }
    
    From ec303bf1ca4ccecea4912ec782879fa123022438 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Fri, 29 Oct 2021 19:35:37 +0800
    Subject: [PATCH 0552/2325] Replace explicit calls to `Services::reset()` in
     tests
    
    ---
     tests/system/CodeIgniterTest.php                | 2 +-
     tests/system/CommonHelperTest.php               | 4 ++--
     tests/system/Config/ServicesTest.php            | 2 +-
     tests/system/Filters/FiltersTest.php            | 2 +-
     tests/system/HTTP/CURLRequestTest.php           | 2 +-
     tests/system/HTTP/URITest.php                   | 6 +++---
     tests/system/RESTful/ResourceControllerTest.php | 2 +-
     tests/system/RESTful/ResourcePresenterTest.php  | 2 +-
     8 files changed, 11 insertions(+), 11 deletions(-)
    
    diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php
    index 0e6de8eadda0..f7838105af4d 100644
    --- a/tests/system/CodeIgniterTest.php
    +++ b/tests/system/CodeIgniterTest.php
    @@ -36,7 +36,7 @@ final class CodeIgniterTest extends CIUnitTestCase
         protected function setUp(): void
         {
             parent::setUp();
    -        Services::reset();
    +        $this->resetServices();
     
             $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
     
    diff --git a/tests/system/CommonHelperTest.php b/tests/system/CommonHelperTest.php
    index 18e0a1022f8d..ce472e56b8be 100644
    --- a/tests/system/CommonHelperTest.php
    +++ b/tests/system/CommonHelperTest.php
    @@ -32,7 +32,7 @@ final class CommonHelperTest extends CIUnitTestCase
     
         protected function setUp(): void
         {
    -        Services::reset();
    +        $this->resetServices();
             parent::setUp();
             $this->cleanUpDummyHelpers();
         }
    @@ -41,7 +41,7 @@ protected function tearDown(): void
         {
             parent::tearDown();
             $this->cleanUpDummyHelpers();
    -        Services::reset();
    +        $this->resetServices();
         }
     
         private function createDummyHelpers(): void
    diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php
    index 2712bdce8dd5..77a0c77097fc 100644
    --- a/tests/system/Config/ServicesTest.php
    +++ b/tests/system/Config/ServicesTest.php
    @@ -64,7 +64,7 @@ protected function setUp(): void
         protected function tearDown(): void
         {
             $_SERVER = $this->original;
    -        Services::reset();
    +        $this->resetServices();
         }
     
         public function testCanReplaceFrameworkServices()
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index dae4074cd134..5451f4b239f4 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -40,7 +40,7 @@ final class FiltersTest extends CIUnitTestCase
         protected function setUp(): void
         {
             parent::setUp();
    -        Services::reset();
    +        $this->resetServices();
     
             $defaults = [
                 'Config'        => APPPATH . 'Config',
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index c1ac77765a44..694d8929dc09 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -32,7 +32,7 @@ protected function setUp(): void
         {
             parent::setUp();
     
    -        Services::reset();
    +        $this->resetServices();
             $this->request = $this->getRequest();
         }
     
    diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php
    index 89cb106ed607..acd491bccb9d 100644
    --- a/tests/system/HTTP/URITest.php
    +++ b/tests/system/HTTP/URITest.php
    @@ -861,7 +861,7 @@ public function testSetBadSegmentSilent()
     
         public function testBasedNoIndex()
         {
    -        Services::reset();
    +        $this->resetServices();
     
             $_SERVER['HTTP_HOST']   = 'example.com';
             $_SERVER['REQUEST_URI'] = '/ci/v4/controller/method';
    @@ -888,7 +888,7 @@ public function testBasedNoIndex()
     
         public function testBasedWithIndex()
         {
    -        Services::reset();
    +        $this->resetServices();
     
             $_SERVER['HTTP_HOST']   = 'example.com';
             $_SERVER['REQUEST_URI'] = '/ci/v4/index.php/controller/method';
    @@ -915,7 +915,7 @@ public function testBasedWithIndex()
     
         public function testForceGlobalSecureRequests()
         {
    -        Services::reset();
    +        $this->resetServices();
     
             $_SERVER['HTTP_HOST']   = 'example.com';
             $_SERVER['REQUEST_URI'] = '/ci/v4/controller/method';
    diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php
    index 185088da1505..ec8d13af7a2d 100644
    --- a/tests/system/RESTful/ResourceControllerTest.php
    +++ b/tests/system/RESTful/ResourceControllerTest.php
    @@ -54,7 +54,7 @@ protected function setUp(): void
         {
             parent::setUp();
     
    -        Services::reset();
    +        $this->resetServices();
     
             $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
     
    diff --git a/tests/system/RESTful/ResourcePresenterTest.php b/tests/system/RESTful/ResourcePresenterTest.php
    index e32ce9aba5d3..26ea1084b196 100644
    --- a/tests/system/RESTful/ResourcePresenterTest.php
    +++ b/tests/system/RESTful/ResourcePresenterTest.php
    @@ -48,7 +48,7 @@ protected function setUp(): void
         {
             parent::setUp();
     
    -        Services::reset();
    +        $this->resetServices();
     
             $_SERVER['SERVER_PROTOCOL'] = 'HTTP/1.1';
     
    
    From 88c45d6947053ff76c44b8f028e5e27a1dc26845 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Sat, 30 Oct 2021 00:16:12 +0800
    Subject: [PATCH 0553/2325] Fix wrong logic
    
    ---
     admin/starter/builds | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/admin/starter/builds b/admin/starter/builds
    index 4a3fe3d53139..0b10a150ac59 100755
    --- a/admin/starter/builds
    +++ b/admin/starter/builds
    @@ -112,7 +112,7 @@ foreach ($files as $file) {
         }
     }
     
    -if ($modified !== []) {
    +if ($modified === []) {
         echo 'No files modified.' . PHP_EOL;
     } else {
         echo 'The following files were modified:' . PHP_EOL;
    
    From a6c06cc990e73e3c1ee39004b5e51aabfbfa27f2 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sat, 30 Oct 2021 08:58:11 +0900
    Subject: [PATCH 0554/2325] refactor: remove unnecessary second param
    
    ---
     tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    index ae6aef2ad74d..fd440bbcffdd 100644
    --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    @@ -225,7 +225,7 @@ public function testHeaderContentLengthNotSharedBetweenRequests()
             $options = [
                 'base_uri' => 'http://www.foo.com/api/v1/',
             ];
    -        $request = $this->getRequest($options, false);
    +        $request = $this->getRequest($options);
     
             $request->post('example', [
                 'form_params' => [
    
    From f53a1da13bec07c5a30a2f658a6658e14d1dbaa9 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sat, 30 Oct 2021 09:22:54 +0900
    Subject: [PATCH 0555/2325] refactor: move Config\App::$CURLRequestShareOptions
     to Config\CURLRequest::$shareOptions
    
    ---
     app/Config/App.php                            | 11 -----------
     app/Config/CURLRequest.php                    | 19 +++++++++++++++++++
     system/HTTP/CURLRequest.php                   |  8 ++++++--
     .../HTTP/CURLRequestDoNotShareOptionsTest.php | 11 ++++++++---
     tests/system/HTTP/CURLRequestTest.php         | 11 ++++++++---
     5 files changed, 41 insertions(+), 19 deletions(-)
     create mode 100644 app/Config/CURLRequest.php
    
    diff --git a/app/Config/App.php b/app/Config/App.php
    index 57c9b8a45c46..88b295e9a010 100644
    --- a/app/Config/App.php
    +++ b/app/Config/App.php
    @@ -461,15 +461,4 @@ class App extends BaseConfig
          * @var bool
          */
         public $CSPEnabled = false;
    -
    -    /**
    -     * --------------------------------------------------------------------------
    -     * CURLRequest Share Options
    -     * --------------------------------------------------------------------------
    -     *
    -     * Whether share options between requests or not.
    -     *
    -     * @var bool
    -     */
    -    public $CURLRequestShareOptions = true;
     }
    diff --git a/app/Config/CURLRequest.php b/app/Config/CURLRequest.php
    new file mode 100644
    index 000000000000..c16cffac4e0a
    --- /dev/null
    +++ b/app/Config/CURLRequest.php
    @@ -0,0 +1,19 @@
    +response       = $response;
             $this->baseURI        = $uri->useRawQueryString();
             $this->defaultOptions = $options;
    -        $this->config         = $this->defaultConfig;
    -        $this->shareOptions   = $config->CURLRequestShareOptions ?? true;
     
    +        /** @var ConfigCURLRequest|null $configCURLRequest */
    +        $configCURLRequest  = config('CURLRequest');
    +        $this->shareOptions = $configCURLRequest->shareOptions ?? true;
    +
    +        $this->config = $this->defaultConfig;
             $this->parseOptions($options);
         }
     
    diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    index fd440bbcffdd..4d35d4510271 100644
    --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php
    @@ -11,11 +11,13 @@
     
     namespace CodeIgniter\HTTP;
     
    +use CodeIgniter\Config\Factories;
     use CodeIgniter\Config\Services;
     use CodeIgniter\HTTP\Exceptions\HTTPException;
     use CodeIgniter\Test\CIUnitTestCase;
     use CodeIgniter\Test\Mock\MockCURLRequest;
     use Config\App;
    +use Config\CURLRequest as ConfigCURLRequest;
     use CURLFile;
     
     /**
    @@ -38,9 +40,12 @@ protected function setUp(): void
     
         protected function getRequest(array $options = [])
         {
    -        $uri                          = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    -        $app                          = new App();
    -        $app->CURLRequestShareOptions = false;
    +        $uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    +        $app = new App();
    +
    +        $config               = new ConfigCURLRequest();
    +        $config->shareOptions = false;
    +        Factories::injectMock('config', 'CURLRequest', $config);
     
             return new MockCURLRequest(($app), $uri, new Response($app), $options);
         }
    diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php
    index de7ef08b59fc..64562f37fd65 100644
    --- a/tests/system/HTTP/CURLRequestTest.php
    +++ b/tests/system/HTTP/CURLRequestTest.php
    @@ -11,11 +11,13 @@
     
     namespace CodeIgniter\HTTP;
     
    +use CodeIgniter\Config\Factories;
     use CodeIgniter\Config\Services;
     use CodeIgniter\HTTP\Exceptions\HTTPException;
     use CodeIgniter\Test\CIUnitTestCase;
     use CodeIgniter\Test\Mock\MockCURLRequest;
     use Config\App;
    +use Config\CURLRequest as ConfigCURLRequest;
     use CURLFile;
     
     /**
    @@ -38,9 +40,12 @@ protected function setUp(): void
     
         protected function getRequest(array $options = [])
         {
    -        $uri                          = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    -        $app                          = new App();
    -        $app->CURLRequestShareOptions = true;
    +        $uri = isset($options['base_uri']) ? new URI($options['base_uri']) : new URI();
    +        $app = new App();
    +
    +        $config               = new ConfigCURLRequest();
    +        $config->shareOptions = true;
    +        Factories::injectMock('config', 'CURLRequest', $config);
     
             return new MockCURLRequest(($app), $uri, new Response($app), $options);
         }
    
    From 772a40819e99c8f5d97ff97412d8ae0f96ae562e Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sat, 30 Oct 2021 09:35:49 +0900
    Subject: [PATCH 0556/2325] fix: change from private to protected
    
    ---
     system/HTTP/CURLRequest.php | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index 1b8b474e5022..5f857d9319b5 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -50,7 +50,7 @@ class CURLRequest extends Request
          *
          * @var array
          */
    -    private $defaultConfig = [
    +    protected $defaultConfig = [
             'timeout'         => 0.0,
             'connect_timeout' => 150,
             'debug'           => false,
    @@ -149,7 +149,7 @@ public function request($method, string $url, array $options = []): ResponseInte
             return $this->response;
         }
     
    -    private function resetOptions()
    +    protected function resetOptions()
         {
             // Reset headers
             $this->headers   = [];
    
    From 3901496bc283871a0e02da72923d0dc0eb274181 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sat, 30 Oct 2021 09:39:58 +0900
    Subject: [PATCH 0557/2325] docs: add PHPDoc comments
    
    ---
     app/Config/CURLRequest.php  | 3 +++
     system/HTTP/CURLRequest.php | 8 +++++++-
     2 files changed, 10 insertions(+), 1 deletion(-)
    
    diff --git a/app/Config/CURLRequest.php b/app/Config/CURLRequest.php
    index c16cffac4e0a..b4c8e5c4f13c 100644
    --- a/app/Config/CURLRequest.php
    +++ b/app/Config/CURLRequest.php
    @@ -13,6 +13,9 @@ class CURLRequest extends BaseConfig
          *
          * Whether share options between requests or not.
          *
    +     * If true, all the options won't be reset between requests.
    +     * It may cause an error request with unnecessary headers.
    +     *
          * @var bool
          */
         public $shareOptions = true;
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index 5f857d9319b5..a3c92511adda 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -81,7 +81,7 @@ class CURLRequest extends Request
         protected $delay = 0.0;
     
         /**
    -     * Default options. Applied to all requests.
    +     * The default options from the constructor. Applied to all requests.
          *
          * @var array
          */
    @@ -90,6 +90,9 @@ class CURLRequest extends Request
         /**
          * Whether share options between requests or not.
          *
    +     * If true, all the options won't be reset between requests.
    +     * It may cause an error request with unnecessary headers.
    +     *
          * @var bool
          */
         private $shareOptions;
    @@ -149,6 +152,9 @@ public function request($method, string $url, array $options = []): ResponseInte
             return $this->response;
         }
     
    +    /**
    +     * Reset all options to default.
    +     */
         protected function resetOptions()
         {
             // Reset headers
    
    From 8a5973b0de4f4cdf6d2c89006d6a4bf91847e8de Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sat, 30 Oct 2021 09:55:09 +0900
    Subject: [PATCH 0558/2325] config: add curlrequest.shareOptions
    
    ---
     env | 6 ++++++
     1 file changed, 6 insertions(+)
    
    diff --git a/env b/env
    index 0b6aa1720782..6e30e34b7ddb 100644
    --- a/env
    +++ b/env
    @@ -124,3 +124,9 @@
     #--------------------------------------------------------------------
     
     # logger.threshold = 4
    +
    +#--------------------------------------------------------------------
    +# CURLRequest
    +#--------------------------------------------------------------------
    +
    +# curlrequest.shareOptions = true
    
    From 88963ba2e85f9e0c731ed56c8fdb32108289e757 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sat, 30 Oct 2021 10:31:47 +0900
    Subject: [PATCH 0559/2325] docs: add about CURLRequest $shareOptions
    
    ---
     .../source/libraries/curlrequest.rst          | 21 ++++++++++++++++++-
     1 file changed, 20 insertions(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst
    index c9c69ea7ae08..0074523d79fd 100644
    --- a/user_guide_src/source/libraries/curlrequest.rst
    +++ b/user_guide_src/source/libraries/curlrequest.rst
    @@ -19,6 +19,21 @@ to change very little to move over to use Guzzle.
         in your version of PHP. This is a very common library that is typically available but not all hosts
         will provide it, so please check with your host to verify if you run into problems.
     
    +**********************
    +Config for CURLRequest
    +**********************
    +
    +Sharing Options
    +===============
    +
    +Due to historical reasons, by default, the CURLRequest shares all the options between requests.
    +If you send more than one request with an instance of the class,
    +this behavior may cause an error request with unnecessary headers.
    +
    +You can change the behavior by editing the following config parameter value in **app/Config/CURLRequest.php** to ``false``::
    +
    +    public $shareOptions = false;
    +
     *******************
     Loading the Library
     *******************
    @@ -38,9 +53,11 @@ The options are described later in this document::
         ];
         $client = \Config\Services::curlrequest($options);
     
    +.. note:: When ``$shareOptions`` is false, the default options passed to the class constructor will be used for all requests. Other options will be reset after sending a request.
    +
     When creating the class manually, you need to pass a few dependencies in. The first parameter is an
     instance of the ``Config\App`` class. The second parameter is a URI instance. The third
    -parameter is a Response object. The fourth parameter is the optional ``$options`` array::
    +parameter is a Response object. The fourth parameter is the optional default ``$options`` array::
     
         $client = new \CodeIgniter\HTTP\CURLRequest(
             new \Config\App(),
    @@ -70,6 +87,8 @@ a Response instance to you. This takes the HTTP method, the url and an array of
             'auth' => ['user', 'pass'],
         ]);
     
    +.. note:: When ``$shareOptions`` is false, the options passed to the method will be used for the request. After sending the request, they will be cleared. If you want to use the options to all requests, pass the options in the constructor.
    +
     Since the response is an instance of ``CodeIgniter\HTTP\Response`` you have all of the normal information
     available to you::
     
    
    From 916a7b01325edd3ad7e1e30068654337a1103205 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sun, 31 Oct 2021 11:37:54 +0900
    Subject: [PATCH 0560/2325] refactor: remove static variable and add a proptery
     for it
    
    It makes escape chars wrong on PHP 8.1.
    See
    Usage of static Variables in Inherited Methods
    https://www.php.net/manual/en/migration81.incompatible.php
    ---
     system/Database/BaseConnection.php | 21 +++++++++++++--------
     1 file changed, 13 insertions(+), 8 deletions(-)
    
    diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php
    index 9cb44e246296..8525755f6950 100644
    --- a/system/Database/BaseConnection.php
    +++ b/system/Database/BaseConnection.php
    @@ -238,6 +238,13 @@ abstract class BaseConnection implements ConnectionInterface
          */
         public $likeEscapeChar = '!';
     
    +    /**
    +     * RegExp used to escape identifiers
    +     *
    +     * @var array
    +     */
    +    protected $pregEscapeChar = [];
    +
         /**
          * Holds previously looked up data
          * for performance reasons.
    @@ -1119,29 +1126,27 @@ public function escapeIdentifiers($item)
                 return $item;
             }
     
    -        static $pregEc = [];
    -
    -        if (empty($pregEc)) {
    +        if (empty($this->pregEscapeChar)) {
                 if (is_array($this->escapeChar)) {
    -                $pregEc = [
    +                $this->pregEscapeChar = [
                         preg_quote($this->escapeChar[0], '/'),
                         preg_quote($this->escapeChar[1], '/'),
                         $this->escapeChar[0],
                         $this->escapeChar[1],
                     ];
                 } else {
    -                $pregEc[0] = $pregEc[1] = preg_quote($this->escapeChar, '/');
    -                $pregEc[2] = $pregEc[3] = $this->escapeChar;
    +                $this->pregEscapeChar[0] = $this->pregEscapeChar[1] = preg_quote($this->escapeChar, '/');
    +                $this->pregEscapeChar[2] = $this->pregEscapeChar[3] = $this->escapeChar;
                 }
             }
     
             foreach ($this->reservedIdentifiers as $id) {
                 if (strpos($item, '.' . $id) !== false) {
    -                return preg_replace('/' . $pregEc[0] . '?([^' . $pregEc[1] . '\.]+)' . $pregEc[1] . '?\./i', $pregEc[2] . '$1' . $pregEc[3] . '.', $item);
    +                return preg_replace('/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?\./i', $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '.', $item);
                 }
             }
     
    -        return preg_replace('/' . $pregEc[0] . '?([^' . $pregEc[1] . '\.]+)' . $pregEc[1] . '?(\.)?/i', $pregEc[2] . '$1' . $pregEc[3] . '$2', $item);
    +        return preg_replace('/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?(\.)?/i', $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '$2', $item);
         }
     
         /**
    
    From 601d29523f7a921655b471931c02e9c505b191e7 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sun, 31 Oct 2021 11:44:41 +0900
    Subject: [PATCH 0561/2325] refactor: break long lines
    
    ---
     system/Database/BaseConnection.php | 12 ++++++++++--
     1 file changed, 10 insertions(+), 2 deletions(-)
    
    diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php
    index 8525755f6950..3a50e43ffd21 100644
    --- a/system/Database/BaseConnection.php
    +++ b/system/Database/BaseConnection.php
    @@ -1142,11 +1142,19 @@ public function escapeIdentifiers($item)
     
             foreach ($this->reservedIdentifiers as $id) {
                 if (strpos($item, '.' . $id) !== false) {
    -                return preg_replace('/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?\./i', $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '.', $item);
    +                return preg_replace(
    +                    '/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?\./i',
    +                    $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '.',
    +                    $item
    +                );
                 }
             }
     
    -        return preg_replace('/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?(\.)?/i', $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '$2', $item);
    +        return preg_replace(
    +            '/' . $this->pregEscapeChar[0] . '?([^' . $this->pregEscapeChar[1] . '\.]+)' . $this->pregEscapeChar[1] . '?(\.)?/i',
    +            $this->pregEscapeChar[2] . '$1' . $this->pregEscapeChar[3] . '$2',
    +            $item
    +        );
         }
     
         /**
    
    From c36ce02b4b5c9686d632312b75237434e237fe6e Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sun, 31 Oct 2021 11:57:51 +0900
    Subject: [PATCH 0562/2325] refactor: remove static variables and add
     properties
    
    To prevent inappropriate behavior when inheriting by using the values of the parent class on PHP 8.1.
    
    Usage of static Variables in Inherited Methods
    https://www.php.net/manual/en/migration81.incompatible.php
    ---
     system/Database/BaseBuilder.php | 30 ++++++++++++++++++++----------
     1 file changed, 20 insertions(+), 10 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index f87f21bf7308..73865aed79ee 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -244,6 +244,20 @@ class BaseBuilder
             'RIGHT OUTER',
         ];
     
    +    /**
    +     * Strings that determine if a string represents a literal value or a field name
    +     *
    +     * @var string[]
    +     */
    +    protected $isLiteralStr = [];
    +
    +    /**
    +     * RegExp used to get operators
    +     *
    +     * @var string[]
    +     */
    +    protected $pregOperators = [];
    +
         /**
          * Constructor
          *
    @@ -2515,13 +2529,11 @@ protected function isLiteral(string $str): bool
                 return true;
             }
     
    -        static $_str;
    -
    -        if (empty($_str)) {
    -            $_str = ($this->db->escapeChar !== '"') ? ['"', "'"] : ["'"];
    +        if (empty($this->isLiteralStr)) {
    +            $this->isLiteralStr = ($this->db->escapeChar !== '"') ? ['"', "'"] : ["'"];
             }
     
    -        return in_array($str[0], $_str, true);
    +        return in_array($str[0], $this->isLiteralStr, true);
         }
     
         /**
    @@ -2610,11 +2622,9 @@ protected function hasOperator(string $str): bool
          */
         protected function getOperator(string $str, bool $list = false)
         {
    -        static $_operators;
    -
    -        if (empty($_operators)) {
    +        if (empty($this->pregOperators)) {
                 $_les       = ($this->db->likeEscapeStr !== '') ? '\s+' . preg_quote(trim(sprintf($this->db->likeEscapeStr, $this->db->likeEscapeChar)), '/') : '';
    -            $_operators = [
    +            $this->pregOperators = [
                     '\s*(?:<|>|!)?=\s*', // =, <=, >=, !=
                     '\s*<>?\s*', // <, <>
                     '\s*>\s*', // >
    @@ -2630,7 +2640,7 @@ protected function getOperator(string $str, bool $list = false)
                 ];
             }
     
    -        return preg_match_all('/' . implode('|', $_operators) . '/i', $str, $match) ? ($list ? $match[0] : $match[0][0]) : false;
    +        return preg_match_all('/' . implode('|', $this->pregOperators) . '/i', $str, $match) ? ($list ? $match[0] : $match[0][0]) : false;
         }
     
         /**
    
    From dbfacc0fefca07f68dbbc953dccee066124092a4 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Sun, 31 Oct 2021 12:03:04 +0900
    Subject: [PATCH 0563/2325] refactor: break long lines
    
    ---
     system/Database/BaseBuilder.php | 15 ++++++++++++---
     1 file changed, 12 insertions(+), 3 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 73865aed79ee..150ed3b5cf5a 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -2612,7 +2612,10 @@ protected function resetWrite()
          */
         protected function hasOperator(string $str): bool
         {
    -        return (bool) preg_match('/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i', trim($str));
    +        return (bool) preg_match(
    +            '/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i',
    +            trim($str)
    +        );
         }
     
         /**
    @@ -2623,7 +2626,9 @@ protected function hasOperator(string $str): bool
         protected function getOperator(string $str, bool $list = false)
         {
             if (empty($this->pregOperators)) {
    -            $_les       = ($this->db->likeEscapeStr !== '') ? '\s+' . preg_quote(trim(sprintf($this->db->likeEscapeStr, $this->db->likeEscapeChar)), '/') : '';
    +            $_les = ($this->db->likeEscapeStr !== '')
    +                ? '\s+' . preg_quote(trim(sprintf($this->db->likeEscapeStr, $this->db->likeEscapeChar)), '/')
    +                : '';
                 $this->pregOperators = [
                     '\s*(?:<|>|!)?=\s*', // =, <=, >=, !=
                     '\s*<>?\s*', // <, <>
    @@ -2640,7 +2645,11 @@ protected function getOperator(string $str, bool $list = false)
                 ];
             }
     
    -        return preg_match_all('/' . implode('|', $this->pregOperators) . '/i', $str, $match) ? ($list ? $match[0] : $match[0][0]) : false;
    +        return preg_match_all(
    +            '/' . implode('|', $this->pregOperators) . '/i',
    +            $str,
    +            $match
    +        ) ? ($list ? $match[0] : $match[0][0]) : false;
         }
     
         /**
    
    From 833ca561ac26798d626a7d732f02b90012c6457c Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Sun, 31 Oct 2021 18:39:55 +0800
    Subject: [PATCH 0564/2325] Apply suggestions from code review
    
    ---
     system/Database/BaseBuilder.php | 12 ++++++------
     1 file changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 150ed3b5cf5a..886ce928e132 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -2529,8 +2529,8 @@ protected function isLiteral(string $str): bool
                 return true;
             }
     
    -        if (empty($this->isLiteralStr)) {
    -            $this->isLiteralStr = ($this->db->escapeChar !== '"') ? ['"', "'"] : ["'"];
    +        if ($this->isLiteralStr === []) {
    +            $this->isLiteralStr = $this->db->escapeChar !== '"' ? ['"', "'"] : ["'"];
             }
     
             return in_array($str[0], $this->isLiteralStr, true);
    @@ -2612,10 +2612,10 @@ protected function resetWrite()
          */
         protected function hasOperator(string $str): bool
         {
    -        return (bool) preg_match(
    +        return preg_match(
                 '/(<|>|!|=|\sIS NULL|\sIS NOT NULL|\sEXISTS|\sBETWEEN|\sLIKE|\sIN\s*\(|\s)/i',
                 trim($str)
    -        );
    +        ) === 1;
         }
     
         /**
    @@ -2625,8 +2625,8 @@ protected function hasOperator(string $str): bool
          */
         protected function getOperator(string $str, bool $list = false)
         {
    -        if (empty($this->pregOperators)) {
    -            $_les = ($this->db->likeEscapeStr !== '')
    +        if ($this->pregOperators === []) {
    +            $_les = $this->db->likeEscapeStr !== ''
                     ? '\s+' . preg_quote(trim(sprintf($this->db->likeEscapeStr, $this->db->likeEscapeChar)), '/')
                     : '';
                 $this->pregOperators = [
    
    From 8d5dc08576f433b432d383e9192c51b077366cd3 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Sun, 31 Oct 2021 18:41:59 +0800
    Subject: [PATCH 0565/2325] Change empty to is identical check
    
    ---
     system/Database/BaseConnection.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php
    index 3a50e43ffd21..ebb63b7f5827 100644
    --- a/system/Database/BaseConnection.php
    +++ b/system/Database/BaseConnection.php
    @@ -1126,7 +1126,7 @@ public function escapeIdentifiers($item)
                 return $item;
             }
     
    -        if (empty($this->pregEscapeChar)) {
    +        if ($this->pregEscapeChar === []) {
                 if (is_array($this->escapeChar)) {
                     $this->pregEscapeChar = [
                         preg_quote($this->escapeChar[0], '/'),
    
    From ef7d23dbd340649302abd90d50c246f9c54cedfa Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Sun, 31 Oct 2021 19:37:52 +0800
    Subject: [PATCH 0566/2325] Replace usage of `FILTER_SANITIZE_STRING`
    
    ---
     system/HTTP/CLIRequest.php        |  8 +++-----
     system/HTTP/CURLRequest.php       | 12 +++---------
     system/Router/RouteCollection.php |  8 ++++----
     3 files changed, 10 insertions(+), 18 deletions(-)
    
    diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php
    index b8db857fce54..fcc2a51389d2 100644
    --- a/system/HTTP/CLIRequest.php
    +++ b/system/HTTP/CLIRequest.php
    @@ -15,8 +15,6 @@
     use RuntimeException;
     
     /**
    - * Class CLIRequest
    - *
      * Represents a request from the command-line. Provides additional
      * tools to interact with that request since CLI requests are not
      * static like HTTP requests might be.
    @@ -172,17 +170,17 @@ protected function parseCommand()
                     if ($optionValue) {
                         $optionValue = false;
                     } else {
    -                    $this->segments[] = filter_var($arg, FILTER_SANITIZE_STRING);
    +                    $this->segments[] = esc(strip_tags($arg));
                     }
     
                     continue;
                 }
     
    -            $arg   = filter_var(ltrim($arg, '-'), FILTER_SANITIZE_STRING);
    +            $arg   = esc(strip_tags(ltrim($arg, '-')));
                 $value = null;
     
                 if (isset($args[$i + 1]) && mb_strpos($args[$i + 1], '-') !== 0) {
    -                $value       = filter_var($args[$i + 1], FILTER_SANITIZE_STRING);
    +                $value       = esc(strip_tags($args[$i + 1]));
                     $optionValue = true;
                 }
     
    diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php
    index 3be8214d42b4..cb723c31adff 100644
    --- a/system/HTTP/CURLRequest.php
    +++ b/system/HTTP/CURLRequest.php
    @@ -16,10 +16,7 @@
     use InvalidArgumentException;
     
     /**
    - * Class OutgoingRequest
    - *
    - * A lightweight HTTP client for sending synchronous HTTP requests
    - * via cURL.
    + * A lightweight HTTP client for sending synchronous HTTP requests via cURL.
      */
     class CURLRequest extends Request
     {
    @@ -84,10 +81,7 @@ class CURLRequest extends Request
         public function __construct(App $config, URI $uri, ?ResponseInterface $response = null, array $options = [])
         {
             if (! function_exists('curl_version')) {
    -            // we won't see this during travis-CI
    -            // @codeCoverageIgnoreStart
    -            throw HTTPException::forMissingCurl();
    -            // @codeCoverageIgnoreEnd
    +            throw HTTPException::forMissingCurl(); // @codeCoverageIgnore
             }
     
             parent::__construct($config);
    @@ -110,7 +104,7 @@ public function request($method, string $url, array $options = []): ResponseInte
     
             $url = $this->prepareURL($url);
     
    -        $method = filter_var($method, FILTER_SANITIZE_STRING);
    +        $method = esc(strip_tags($method));
     
             $this->send($method, $url);
     
    diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php
    index 1dcbfe9f590d..15a2d3d79e3e 100644
    --- a/system/Router/RouteCollection.php
    +++ b/system/Router/RouteCollection.php
    @@ -19,8 +19,6 @@
     use InvalidArgumentException;
     
     /**
    - * Class RouteCollection
    - *
      * @todo Implement nested resource routing (See CakePHP)
      */
     class RouteCollection implements RouteCollectionInterface
    @@ -663,10 +661,11 @@ public function resource(string $name, ?array $options = null): RouteCollectionI
             // resources are sent to, we need to have a new name
             // to store the values in.
             $newName = implode('\\', array_map('ucfirst', explode('/', $name)));
    +
             // If a new controller is specified, then we replace the
             // $name value with the name of the new controller.
             if (isset($options['controller'])) {
    -            $newName = ucfirst(filter_var($options['controller'], FILTER_SANITIZE_STRING));
    +            $newName = ucfirst(esc(strip_tags($options['controller'])));
             }
     
             // In order to allow customization of allowed id values
    @@ -756,10 +755,11 @@ public function presenter(string $name, ?array $options = null): RouteCollection
             // resources are sent to, we need to have a new name
             // to store the values in.
             $newName = implode('\\', array_map('ucfirst', explode('/', $name)));
    +
             // If a new controller is specified, then we replace the
             // $name value with the name of the new controller.
             if (isset($options['controller'])) {
    -            $newName = ucfirst(filter_var($options['controller'], FILTER_SANITIZE_STRING));
    +            $newName = ucfirst(esc(strip_tags($options['controller'])));
             }
     
             // In order to allow customization of allowed id values
    
    From 6a689bf9768bcb660bfba3886b640ab5d5b3c4b3 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Sun, 31 Oct 2021 20:36:38 +0800
    Subject: [PATCH 0567/2325] Enable `ordered_class_elements` rule
    
    ---
     .no-header.php-cs-fixer.dist.php                 | 12 +++++++++++-
     .php-cs-fixer.dist.php                           | 12 +++++++++++-
     tests/_support/Publishers/TestPublisher.php      | 16 ++++++++--------
     tests/system/Cache/Handlers/FileHandlerTest.php  |  3 +--
     .../Cache/Handlers/MemcachedHandlerTest.php      |  4 ++--
     .../system/Cache/Handlers/PredisHandlerTest.php  |  4 ++--
     tests/system/Cache/Handlers/RedisHandlerTest.php |  4 ++--
     7 files changed, 37 insertions(+), 18 deletions(-)
    
    diff --git a/.no-header.php-cs-fixer.dist.php b/.no-header.php-cs-fixer.dist.php
    index 153ac5bd1328..9417a859e07e 100644
    --- a/.no-header.php-cs-fixer.dist.php
    +++ b/.no-header.php-cs-fixer.dist.php
    @@ -30,7 +30,17 @@
             __DIR__ . '/admin/starter/builds',
         ]);
     
    -$overrides = [];
    +$overrides = [
    +    'ordered_class_elements' => [
    +        'order' => [
    +            'use_trait',
    +            'constant',
    +            'property',
    +            'method',
    +        ],
    +        'sort_algorithm' => 'none',
    +    ],
    +];
     
     $options = [
         'cacheFile'    => 'build/.no-header.php-cs-fixer.cache',
    diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
    index 3c9e05fe3b74..5df3c5e90a52 100644
    --- a/.php-cs-fixer.dist.php
    +++ b/.php-cs-fixer.dist.php
    @@ -34,7 +34,17 @@
             __DIR__ . '/spark',
         ]);
     
    -$overrides = [];
    +$overrides = [
    +    'ordered_class_elements' => [
    +        'order' => [
    +            'use_trait',
    +            'constant',
    +            'property',
    +            'method',
    +        ],
    +        'sort_algorithm' => 'none',
    +    ],
    +];
     
     $options = [
         'cacheFile'    => 'build/.php-cs-fixer.cache',
    diff --git a/tests/_support/Publishers/TestPublisher.php b/tests/_support/Publishers/TestPublisher.php
    index 357e50f17e1a..95d9fa72c250 100644
    --- a/tests/_support/Publishers/TestPublisher.php
    +++ b/tests/_support/Publishers/TestPublisher.php
    @@ -15,14 +15,6 @@
     
     final class TestPublisher extends Publisher
     {
    -    /**
    -     * Fakes an error on the given file.
    -     */
    -    public static function setResult(bool $result)
    -    {
    -        self::$result = $result;
    -    }
    -
         /**
          * Return value for publish()
          *
    @@ -44,6 +36,14 @@ public static function setResult(bool $result)
          */
         protected $destination = WRITEPATH;
     
    +    /**
    +     * Fakes an error on the given file.
    +     */
    +    public static function setResult(bool $result)
    +    {
    +        self::$result = $result;
    +    }
    +
         /**
          * Fakes a publish event so no files are actually copied.
          */
    diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php
    index 3f82375354fe..f0aa76ea610d 100644
    --- a/tests/system/Cache/Handlers/FileHandlerTest.php
    +++ b/tests/system/Cache/Handlers/FileHandlerTest.php
    @@ -20,6 +20,7 @@
     final class FileHandlerTest extends AbstractHandlerTest
     {
         private static $directory = 'FileHandler';
    +    private $config;
     
         private static function getKeyArray()
         {
    @@ -30,8 +31,6 @@ private static function getKeyArray()
             ];
         }
     
    -    private $config;
    -
         protected function setUp(): void
         {
             parent::setUp();
    diff --git a/tests/system/Cache/Handlers/MemcachedHandlerTest.php b/tests/system/Cache/Handlers/MemcachedHandlerTest.php
    index 240225fd8bc0..38005d87ed5b 100644
    --- a/tests/system/Cache/Handlers/MemcachedHandlerTest.php
    +++ b/tests/system/Cache/Handlers/MemcachedHandlerTest.php
    @@ -22,6 +22,8 @@
      */
     final class MemcachedHandlerTest extends AbstractHandlerTest
     {
    +    private $config;
    +
         private static function getKeyArray()
         {
             return [
    @@ -31,8 +33,6 @@ private static function getKeyArray()
             ];
         }
     
    -    private $config;
    -
         protected function setUp(): void
         {
             parent::setUp();
    diff --git a/tests/system/Cache/Handlers/PredisHandlerTest.php b/tests/system/Cache/Handlers/PredisHandlerTest.php
    index 9b762f9c27f1..cdc79adf68b4 100644
    --- a/tests/system/Cache/Handlers/PredisHandlerTest.php
    +++ b/tests/system/Cache/Handlers/PredisHandlerTest.php
    @@ -21,6 +21,8 @@
      */
     final class PredisHandlerTest extends AbstractHandlerTest
     {
    +    private $config;
    +
         private static function getKeyArray()
         {
             return [
    @@ -30,8 +32,6 @@ private static function getKeyArray()
             ];
         }
     
    -    private $config;
    -
         protected function setUp(): void
         {
             parent::setUp();
    diff --git a/tests/system/Cache/Handlers/RedisHandlerTest.php b/tests/system/Cache/Handlers/RedisHandlerTest.php
    index 32d0cdf8223e..4eb8f8b08560 100644
    --- a/tests/system/Cache/Handlers/RedisHandlerTest.php
    +++ b/tests/system/Cache/Handlers/RedisHandlerTest.php
    @@ -21,6 +21,8 @@
      */
     final class RedisHandlerTest extends AbstractHandlerTest
     {
    +    private $config;
    +
         private static function getKeyArray()
         {
             return [
    @@ -30,8 +32,6 @@ private static function getKeyArray()
             ];
         }
     
    -    private $config;
    -
         protected function setUp(): void
         {
             parent::setUp();
    
    From d8b750b3b815fc935e5f0e48bd1903d6f12a3c46 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 26 Oct 2021 15:41:11 +0900
    Subject: [PATCH 0568/2325] test: refactor: $request -> $this->request
    
    ---
     tests/system/Filters/FiltersTest.php | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 5451f4b239f4..302aa985e474 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -61,8 +61,8 @@ public function testProcessMethodDetectsCLI()
                     'cli' => ['foo'],
                 ],
             ];
    -        $request = new CLIRequest(new MockAppConfig());
    -        $filters = new Filters((object) $config, $request, $this->response);
    +        $this->request = new CLIRequest(new MockAppConfig());
    +        $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $expected = [
                 'before' => ['foo'],
    
    From 1f4ba303f9ef953fcd932a78f4bc224819fc241d Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 26 Oct 2021 15:49:57 +0900
    Subject: [PATCH 0569/2325] test: refactor: reset $_SERVER
    
    ---
     tests/system/Filters/FiltersTest.php | 8 ++++++++
     1 file changed, 8 insertions(+)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 302aa985e474..ce01c7757004 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -50,11 +50,19 @@ protected function setUp(): void
     
             Services::autoloader()->addNamespace($defaults);
     
    +        $_SERVER = [];
    +
             $this->response = Services::response();
         }
     
         public function testProcessMethodDetectsCLI()
         {
    +        $_SERVER['argv'] = [
    +            'spark',
    +            'list',
    +        ];
    +        $_SERVER['argc'] = 2;
    +
             $config = [
                 'aliases' => ['foo' => ''],
                 'methods' => [
    
    From 3ea1ede69a0c78f33251ef6ba0fde57d19274188 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 26 Oct 2021 15:50:44 +0900
    Subject: [PATCH 0570/2325] test: refactor: change the position of line breaks
    
    Separate arrange, act, assert.
    ---
     tests/system/Filters/FiltersTest.php | 92 +++++++++++-----------------
     1 file changed, 36 insertions(+), 56 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index ce01c7757004..57c3f06753f3 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -40,6 +40,7 @@ final class FiltersTest extends CIUnitTestCase
         protected function setUp(): void
         {
             parent::setUp();
    +
             $this->resetServices();
     
             $defaults = [
    @@ -47,7 +48,6 @@ protected function setUp(): void
                 'App'           => APPPATH,
                 'Tests\Support' => TESTPATH . '_support',
             ];
    -
             Services::autoloader()->addNamespace($defaults);
     
             $_SERVER = [];
    @@ -76,7 +76,6 @@ public function testProcessMethodDetectsCLI()
                 'before' => ['foo'],
                 'after'  => [],
             ];
    -
             $this->assertSame($expected, $filters->initialize()->getFilters());
         }
     
    @@ -97,7 +96,6 @@ public function testProcessMethodDetectsGetRequests()
                 'before' => ['foo'],
                 'after'  => [],
             ];
    -
             $this->assertSame($expected, $filters->initialize()->getFilters());
         }
     
    @@ -122,7 +120,6 @@ public function testProcessMethodRespectsMethod()
                 'before' => ['bar'],
                 'after'  => [],
             ];
    -
             $this->assertSame($expected, $filters->initialize()->getFilters());
         }
     
    @@ -147,7 +144,6 @@ public function testProcessMethodIgnoresMethod()
                 'before' => [],
                 'after'  => [],
             ];
    -
             $this->assertSame($expected, $filters->initialize()->getFilters());
         }
     
    @@ -181,7 +177,6 @@ public function testProcessMethodProcessGlobals()
                 ],
                 'after' => ['baz'],
             ];
    -
             $this->assertSame($expected, $filters->initialize()->getFilters());
         }
     
    @@ -222,15 +217,14 @@ public function testProcessMethodProcessGlobalsWithExcept(array $except)
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'bar',
                 ],
                 'after' => ['baz'],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -253,13 +247,12 @@ public function testProcessMethodProcessesFiltersBefore()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => ['foo'],
                 'after'  => [],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -282,15 +275,14 @@ public function testProcessMethodProcessesFiltersAfter()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'users/foo/bar';
     
    +        $uri      = 'users/foo/bar';
             $expected = [
                 'before' => [],
                 'after'  => [
                     'foo',
                 ],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -329,8 +321,8 @@ public function testProcessMethodProcessesCombined()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'barg',
    @@ -339,7 +331,6 @@ public function testProcessMethodProcessesCombined()
                 ],
                 'after' => ['bazg'],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -371,8 +362,8 @@ public function testProcessMethodProcessesCombinedAfterForToolbar()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => ['bar'],
                 'after'  => [
    @@ -381,7 +372,6 @@ public function testProcessMethodProcessesCombinedAfterForToolbar()
                     'toolbar',
                 ],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -400,8 +390,8 @@ public function testRunThrowsWithInvalidAlias()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $this->expectException(FilterException::class);
    -        $uri = 'admin/foo/bar';
     
    +        $uri = 'admin/foo/bar';
             $filters->run($uri);
         }
     
    @@ -418,8 +408,8 @@ public function testCustomFiltersLoad()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
     
             $this->assertSame('http://hellowworld.com', $request->url);
    @@ -440,8 +430,8 @@ public function testRunThrowsWithInvalidClassType()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $this->expectException(FilterException::class);
    -        $uri = 'admin/foo/bar';
     
    +        $uri = 'admin/foo/bar';
             $filters->run($uri);
         }
     
    @@ -458,8 +448,8 @@ public function testRunDoesBefore()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
     
             $this->assertSame('http://google.com', $request->url);
    @@ -478,8 +468,8 @@ public function testRunDoesAfter()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'after');
     
             $this->assertSame('http://google.com', $response->csp);
    @@ -498,9 +488,10 @@ public function testShortCircuit()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'before');
    +
             $this->assertTrue($response instanceof ResponseInterface);
             $this->assertSame('http://google.com', $response->csp);
         }
    @@ -524,8 +515,8 @@ public function testOtherResult()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'before');
     
             $this->assertSame('This is curious', $response);
    @@ -553,15 +544,14 @@ public function testBeforeExceptString()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'bar',
                 ],
                 'after' => ['baz'],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -587,8 +577,8 @@ public function testBeforeExceptInapplicable()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'foo',
    @@ -596,7 +586,6 @@ public function testBeforeExceptInapplicable()
                 ],
                 'after' => ['baz'],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -622,15 +611,14 @@ public function testAfterExceptString()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'bar',
                 ],
                 'after' => ['baz'],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -656,8 +644,8 @@ public function testAfterExceptInapplicable()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'bar',
    @@ -667,7 +655,6 @@ public function testAfterExceptInapplicable()
                     'baz',
                 ],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -686,9 +673,7 @@ public function testAddFilter()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $filters = $filters->addFilter('Some\Class', 'some_alias');
    -
             $filters = $filters->initialize('admin/foo/bar');
    -
             $filters = $filters->getFilters();
     
             $this->assertTrue(in_array('some_alias', $filters['before'], true));
    @@ -705,7 +690,6 @@ public function testAddFilterSection()
             $filters = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
                 ->initialize('admin/foo/bar');
    -
             $list = $filters->getFilters();
     
             $this->assertTrue(in_array('another', $list['before'], true));
    @@ -723,7 +707,6 @@ public function testInitializeTwice()
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
                 ->initialize('admin/foo/bar')
                 ->initialize();
    -
             $list = $filters->getFilters();
     
             $this->assertTrue(in_array('another', $list['before'], true));
    @@ -744,9 +727,7 @@ public function testEnableFilter()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $filters = $filters->initialize('admin/foo/bar');
    -
             $filters->enableFilter('google', 'before');
    -
             $filters = $filters->getFilters();
     
             $this->assertTrue(in_array('google', $filters['before'], true));
    @@ -765,11 +746,10 @@ public function testEnableFilterWithArguments()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $filters       = $filters->initialize('admin/foo/bar');
     
    +        $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('role:admin , super', 'before');
             $filters->enableFilter('role:admin , super', 'after');
    -
             $found = $filters->getFilters();
     
             $this->assertTrue(in_array('role', $found['before'], true));
    @@ -777,9 +757,11 @@ public function testEnableFilterWithArguments()
             $this->assertSame(['role' => ['admin', 'super']], $filters->getArguments());
     
             $response = $filters->run('admin/foo/bar', 'before');
    +
             $this->assertSame('admin;super', $response);
     
             $response = $filters->run('admin/foo/bar', 'after');
    +
             $this->assertSame('admin;super', $response->getBody());
         }
     
    @@ -798,18 +780,18 @@ public function testEnableFilterWithNoArguments()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $filters = $filters->initialize('admin/foo/bar');
    -
             $filters->enableFilter('role', 'before');
             $filters->enableFilter('role', 'after');
    -
             $found = $filters->getFilters();
     
             $this->assertTrue(in_array('role', $found['before'], true));
     
             $response = $filters->run('admin/foo/bar', 'before');
    +
             $this->assertSame('Is null', $response);
     
             $response = $filters->run('admin/foo/bar', 'after');
    +
             $this->assertSame('Is null', $response->getBody());
         }
     
    @@ -830,7 +812,6 @@ public function testEnableNonFilter()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $filters = $filters->initialize('admin/foo/bar');
    -
             $filters->enableFilter('goggle', 'before');
         }
     
    @@ -867,8 +848,8 @@ public function testMatchesURICaseInsensitively()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri      = 'admin/foo/bar';
             $expected = [
                 'before' => [
                     'bar',
    @@ -879,7 +860,6 @@ public function testMatchesURICaseInsensitively()
                     'frak',
                 ],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -905,7 +885,9 @@ public function testFilterMatching()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin';
    +
    +        $uri    = 'admin';
    +        $actual = $filters->initialize($uri)->getFilters();
     
             $expected = [
                 'before' => [
    @@ -913,8 +895,6 @@ public function testFilterMatching()
                 ],
                 'after' => [],
             ];
    -
    -        $actual = $filters->initialize($uri)->getFilters();
             $this->assertSame($expected, $actual);
         }
     
    @@ -944,7 +924,9 @@ public function testGlobalFilterMatching()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin';
    +
    +        $uri    = 'admin';
    +        $actual = $filters->initialize($uri)->getFilters();
     
             $expected = [
                 'before' => [
    @@ -955,8 +937,6 @@ public function testGlobalFilterMatching()
                     'two',
                 ],
             ];
    -
    -        $actual = $filters->initialize($uri)->getFilters();
             $this->assertSame($expected, $actual);
         }
     
    @@ -993,8 +973,8 @@ public function testCombinedFilterMatching()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin123';
     
    +        $uri      = 'admin123';
             $expected = [
                 'before' => [
                     'one',
    @@ -1005,7 +985,6 @@ public function testCombinedFilterMatching()
                     'two',
                 ],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -1039,8 +1018,8 @@ public function testSegmentedFilterMatching()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/123';
     
    +        $uri      = 'admin/123';
             $expected = [
                 'before' => [
                     'frak',
    @@ -1049,7 +1028,6 @@ public function testSegmentedFilterMatching()
                     'frak',
                 ],
             ];
    -
             $this->assertSame($expected, $filters->initialize($uri)->getFilters());
         }
     
    @@ -1073,9 +1051,10 @@ public function testFilterAlitasMultiple()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin/foo/bar';
     
    +        $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    +
             $this->assertSame('http://exampleMultipleURL.com', $request->url);
             $this->assertSame('http://exampleMultipleCSP.com', $request->csp);
         }
    @@ -1099,6 +1078,7 @@ public function testFilterClass()
             $filters       = new Filters((object) $config, $this->request, $this->response);
     
             $filters->run('admin/foo/bar', 'before');
    +
             $expected = [
                 'before' => [],
                 'after'  => [
    @@ -1125,8 +1105,8 @@ public function testReset()
             ];
             $this->request = Services::request();
             $filters       = new Filters((object) $config, $this->request, $this->response);
    -        $uri           = 'admin';
     
    +        $uri = 'admin';
             $this->assertSame(['foo'], $filters->initialize($uri)->getFilters()['before']);
             $this->assertSame([], $filters->reset()->getFilters()['before']);
         }
    
    From 64b37786528de76c3950d3a03b120d24b554d882 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 26 Oct 2021 16:12:42 +0900
    Subject: [PATCH 0571/2325] test: refactor: extract createFilters() method
    
    ---
     tests/system/Filters/FiltersTest.php | 117 +++++++++++----------------
     1 file changed, 46 insertions(+), 71 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 57c3f06753f3..a1e2f0814588 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -55,6 +55,13 @@ protected function setUp(): void
             $this->response = Services::response();
         }
     
    +    private function createFilters($config, $request = null): Filters
    +    {
    +        $request = $request ?? Services::request();
    +
    +        return new Filters($config, $request, $this->response);
    +    }
    +
         public function testProcessMethodDetectsCLI()
         {
             $_SERVER['argv'] = [
    @@ -69,8 +76,10 @@ public function testProcessMethodDetectsCLI()
                     'cli' => ['foo'],
                 ],
             ];
    -        $this->request = new CLIRequest(new MockAppConfig());
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters(
    +            (object) $config,
    +            new CLIRequest(new MockAppConfig())
    +        );
     
             $expected = [
                 'before' => ['foo'],
    @@ -89,8 +98,7 @@ public function testProcessMethodDetectsGetRequests()
                     'get' => ['foo'],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $expected = [
                 'before' => ['foo'],
    @@ -113,8 +121,7 @@ public function testProcessMethodRespectsMethod()
                     'get'  => ['bar'],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $expected = [
                 'before' => ['bar'],
    @@ -137,8 +144,7 @@ public function testProcessMethodIgnoresMethod()
                     'get'  => ['bar'],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $expected = [
                 'before' => [],
    @@ -167,8 +173,7 @@ public function testProcessMethodProcessGlobals()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $expected = [
                 'before' => [
    @@ -215,8 +220,7 @@ public function testProcessMethodProcessGlobalsWithExcept(array $except)
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -245,8 +249,7 @@ public function testProcessMethodProcessesFiltersBefore()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -273,8 +276,7 @@ public function testProcessMethodProcessesFiltersAfter()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'users/foo/bar';
             $expected = [
    @@ -319,8 +321,7 @@ public function testProcessMethodProcessesCombined()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -360,8 +361,7 @@ public function testProcessMethodProcessesCombinedAfterForToolbar()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -386,8 +386,7 @@ public function testRunThrowsWithInvalidAlias()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $this->expectException(FilterException::class);
     
    @@ -406,8 +405,7 @@ public function testCustomFiltersLoad()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    @@ -426,8 +424,7 @@ public function testRunThrowsWithInvalidClassType()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $this->expectException(FilterException::class);
     
    @@ -446,8 +443,7 @@ public function testRunDoesBefore()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    @@ -466,8 +462,7 @@ public function testRunDoesAfter()
                     'after'  => ['google'],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'after');
    @@ -486,8 +481,7 @@ public function testShortCircuit()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'before');
    @@ -513,8 +507,7 @@ public function testOtherResult()
                     'after' => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'before');
    @@ -542,8 +535,7 @@ public function testBeforeExceptString()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -575,8 +567,7 @@ public function testBeforeExceptInapplicable()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -609,8 +600,7 @@ public function testAfterExceptString()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -642,8 +632,7 @@ public function testAfterExceptInapplicable()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -669,8 +658,7 @@ public function testAddFilter()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $filters = $filters->addFilter('Some\Class', 'some_alias');
             $filters = $filters->initialize('admin/foo/bar');
    @@ -699,9 +687,8 @@ public function testInitializeTwice()
         {
             $_SERVER['REQUEST_METHOD'] = 'GET';
     
    -        $config        = [];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $config  = [];
    +        $filters = $this->createFilters((object) $config);
     
             $filters = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
    @@ -723,8 +710,7 @@ public function testEnableFilter()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('google', 'before');
    @@ -744,8 +730,7 @@ public function testEnableFilterWithArguments()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('role:admin , super', 'before');
    @@ -776,8 +761,7 @@ public function testEnableFilterWithNoArguments()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('role', 'before');
    @@ -808,8 +792,7 @@ public function testEnableNonFilter()
                     'after'  => [],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('goggle', 'before');
    @@ -846,8 +829,7 @@ public function testMatchesURICaseInsensitively()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -883,8 +865,7 @@ public function testFilterMatching()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri    = 'admin';
             $actual = $filters->initialize($uri)->getFilters();
    @@ -922,8 +903,7 @@ public function testGlobalFilterMatching()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri    = 'admin';
             $actual = $filters->initialize($uri)->getFilters();
    @@ -971,8 +951,7 @@ public function testCombinedFilterMatching()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin123';
             $expected = [
    @@ -1016,8 +995,7 @@ public function testSegmentedFilterMatching()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri      = 'admin/123';
             $expected = [
    @@ -1049,8 +1027,7 @@ public function testFilterAlitasMultiple()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    @@ -1074,8 +1051,7 @@ public function testFilterClass()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $filters->run('admin/foo/bar', 'before');
     
    @@ -1103,8 +1079,7 @@ public function testReset()
                     ],
                 ],
             ];
    -        $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filters = $this->createFilters((object) $config);
     
             $uri = 'admin';
             $this->assertSame(['foo'], $filters->initialize($uri)->getFilters()['before']);
    
    From df72c88730dde34778aa73db4c08e7ec51a29ada Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 26 Oct 2021 16:17:19 +0900
    Subject: [PATCH 0572/2325] test: refactor: use ::class keyword
    
    ---
     tests/system/Filters/FiltersTest.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index a1e2f0814588..1a7036c29163 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -781,7 +781,7 @@ public function testEnableFilterWithNoArguments()
     
         public function testEnableNonFilter()
         {
    -        $this->expectException('CodeIgniter\Filters\Exceptions\FilterException');
    +        $this->expectException(FilterException::class);
     
             $_SERVER['REQUEST_METHOD'] = 'GET';
     
    
    From 908c5627c4410175cf0e38e08acb74a7e7bd021a Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 26 Oct 2021 16:21:12 +0900
    Subject: [PATCH 0573/2325] test: refactor: remove unused property
    
    ---
     tests/system/Filters/FiltersTest.php | 1 -
     1 file changed, 1 deletion(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 1a7036c29163..9ae75c58daee 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -34,7 +34,6 @@
      */
     final class FiltersTest extends CIUnitTestCase
     {
    -    protected $request;
         protected $response;
     
         protected function setUp(): void
    
    From 01fc23707987243f3751dfef9c595e96173c865e Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 28 Oct 2021 10:20:11 +0900
    Subject: [PATCH 0574/2325] test: refactor: fix wrong config class type
    
    ---
     tests/system/Filters/FiltersTest.php | 148 ++++++++++++++++++++-------
     1 file changed, 109 insertions(+), 39 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 9ae75c58daee..8876a3c46956 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -17,6 +17,8 @@
     use CodeIgniter\HTTP\ResponseInterface;
     use CodeIgniter\Test\CIUnitTestCase;
     use CodeIgniter\Test\Mock\MockAppConfig;
    +use Config\Filters as FiltersConfig;
    +use LogicException;
     
     require_once __DIR__ . '/fixtures/GoogleMe.php';
     require_once __DIR__ . '/fixtures/GoogleYou.php';
    @@ -54,13 +56,37 @@ protected function setUp(): void
             $this->response = Services::response();
         }
     
    -    private function createFilters($config, $request = null): Filters
    +    private function createFilters(FiltersConfig $config, $request = null): Filters
         {
             $request = $request ?? Services::request();
     
             return new Filters($config, $request, $this->response);
         }
     
    +    /**
    +     * @template T
    +     *
    +     * @param class-string $classname
    +     *
    +     * @return T
    +     */
    +    private function createConfigFromArray(string $classname, array $config)
    +    {
    +        $configObj = new $classname();
    +
    +        foreach ($config as $key => $value) {
    +            if (property_exists($configObj, $key)) {
    +                $configObj->{$key} = $value;
    +            } else {
    +                throw new LogicException(
    +                    'No such property: ' . $classname . '::$' . $key
    +                );
    +            }
    +        }
    +
    +        return $configObj;
    +    }
    +
         public function testProcessMethodDetectsCLI()
         {
             $_SERVER['argv'] = [
    @@ -71,12 +97,14 @@ public function testProcessMethodDetectsCLI()
     
             $config = [
                 'aliases' => ['foo' => ''],
    +            'globals' => [],
                 'methods' => [
                     'cli' => ['foo'],
                 ],
             ];
    -        $filters = $this->createFilters(
    -            (object) $config,
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters(
    +            $filtersConfig,
                 new CLIRequest(new MockAppConfig())
             );
     
    @@ -93,11 +121,13 @@ public function testProcessMethodDetectsGetRequests()
     
             $config = [
                 'aliases' => ['foo' => ''],
    +            'globals' => [],
                 'methods' => [
                     'get' => ['foo'],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $expected = [
                 'before' => ['foo'],
    @@ -115,12 +145,14 @@ public function testProcessMethodRespectsMethod()
                     'foo' => '',
                     'bar' => '',
                 ],
    +            'globals' => [],
                 'methods' => [
                     'post' => ['foo'],
                     'get'  => ['bar'],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $expected = [
                 'before' => ['bar'],
    @@ -138,12 +170,14 @@ public function testProcessMethodIgnoresMethod()
                     'foo' => '',
                     'bar' => '',
                 ],
    +            'globals' => [],
                 'methods' => [
                     'post' => ['foo'],
                     'get'  => ['bar'],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $expected = [
                 'before' => [],
    @@ -172,7 +206,8 @@ public function testProcessMethodProcessGlobals()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $expected = [
                 'before' => [
    @@ -219,7 +254,8 @@ public function testProcessMethodProcessGlobalsWithExcept(array $except)
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -241,6 +277,7 @@ public function testProcessMethodProcessesFiltersBefore()
                     'bar' => '',
                     'baz' => '',
                 ],
    +            'globals' => [],
                 'filters' => [
                     'foo' => [
                         'before' => ['admin/*'],
    @@ -248,7 +285,8 @@ public function testProcessMethodProcessesFiltersBefore()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -268,6 +306,7 @@ public function testProcessMethodProcessesFiltersAfter()
                     'bar' => '',
                     'baz' => '',
                 ],
    +            'globals' => [],
                 'filters' => [
                     'foo' => [
                         'before' => ['admin/*'],
    @@ -275,7 +314,8 @@ public function testProcessMethodProcessesFiltersAfter()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'users/foo/bar';
             $expected = [
    @@ -320,7 +360,8 @@ public function testProcessMethodProcessesCombined()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -360,7 +401,8 @@ public function testProcessMethodProcessesCombinedAfterForToolbar()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -385,7 +427,8 @@ public function testRunThrowsWithInvalidAlias()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $this->expectException(FilterException::class);
     
    @@ -404,7 +447,8 @@ public function testCustomFiltersLoad()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    @@ -423,7 +467,8 @@ public function testRunThrowsWithInvalidClassType()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $this->expectException(FilterException::class);
     
    @@ -442,7 +487,8 @@ public function testRunDoesBefore()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    @@ -461,7 +507,8 @@ public function testRunDoesAfter()
                     'after'  => ['google'],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'after');
    @@ -480,7 +527,8 @@ public function testShortCircuit()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'before');
    @@ -506,7 +554,8 @@ public function testOtherResult()
                     'after' => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $response = $filters->run($uri, 'before');
    @@ -534,7 +583,8 @@ public function testBeforeExceptString()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -566,7 +616,8 @@ public function testBeforeExceptInapplicable()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -599,7 +650,8 @@ public function testAfterExceptString()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -631,7 +683,8 @@ public function testAfterExceptInapplicable()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -657,7 +710,8 @@ public function testAddFilter()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters->addFilter('Some\Class', 'some_alias');
             $filters = $filters->initialize('admin/foo/bar');
    @@ -672,7 +726,8 @@ public function testAddFilterSection()
     
             $config        = [];
             $this->request = Services::request();
    -        $filters       = new Filters((object) $config, $this->request, $this->response);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = new Filters($filtersConfig, $this->request, $this->response);
     
             $filters = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
    @@ -686,8 +741,9 @@ public function testInitializeTwice()
         {
             $_SERVER['REQUEST_METHOD'] = 'GET';
     
    -        $config  = [];
    -        $filters = $this->createFilters((object) $config);
    +        $config        = [];
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
    @@ -709,7 +765,8 @@ public function testEnableFilter()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('google', 'before');
    @@ -729,7 +786,8 @@ public function testEnableFilterWithArguments()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('role:admin , super', 'before');
    @@ -760,7 +818,8 @@ public function testEnableFilterWithNoArguments()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('role', 'before');
    @@ -791,7 +850,8 @@ public function testEnableNonFilter()
                     'after'  => [],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters->initialize('admin/foo/bar');
             $filters->enableFilter('goggle', 'before');
    @@ -828,7 +888,8 @@ public function testMatchesURICaseInsensitively()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/foo/bar';
             $expected = [
    @@ -857,6 +918,7 @@ public function testFilterMatching()
                     'bar'  => '',
                     'frak' => '',
                 ],
    +            'globals' => [],
                 'filters' => [
                     'frak' => [
                         'before' => ['admin*'],
    @@ -864,7 +926,8 @@ public function testFilterMatching()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri    = 'admin';
             $actual = $filters->initialize($uri)->getFilters();
    @@ -902,7 +965,8 @@ public function testGlobalFilterMatching()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri    = 'admin';
             $actual = $filters->initialize($uri)->getFilters();
    @@ -950,7 +1014,8 @@ public function testCombinedFilterMatching()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin123';
             $expected = [
    @@ -994,7 +1059,8 @@ public function testSegmentedFilterMatching()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri      = 'admin/123';
             $expected = [
    @@ -1026,7 +1092,8 @@ public function testFilterAlitasMultiple()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri     = 'admin/foo/bar';
             $request = $filters->run($uri, 'before');
    @@ -1050,7 +1117,8 @@ public function testFilterClass()
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters->run('admin/foo/bar', 'before');
     
    @@ -1072,13 +1140,15 @@ public function testReset()
                 'aliases' => [
                     'foo' => '',
                 ],
    +            'globals' => [],
                 'filters' => [
                     'foo' => [
                         'before' => ['admin*'],
                     ],
                 ],
             ];
    -        $filters = $this->createFilters((object) $config);
    +        $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $uri = 'admin';
             $this->assertSame(['foo'], $filters->initialize($uri)->getFilters()['before']);
    
    From 1d9c1b6e2b98972a528c9162caa5a6c4e24345a2 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 28 Oct 2021 10:28:48 +0900
    Subject: [PATCH 0575/2325] test: refactor: remove $this->request that I forgot
     to remove
    
    ---
     tests/system/Filters/FiltersTest.php | 3 +--
     1 file changed, 1 insertion(+), 2 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 8876a3c46956..1ef5e0293c01 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -725,9 +725,8 @@ public function testAddFilterSection()
             $_SERVER['REQUEST_METHOD'] = 'GET';
     
             $config        = [];
    -        $this->request = Services::request();
             $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
    -        $filters       = new Filters($filtersConfig, $this->request, $this->response);
    +        $filters       = $this->createFilters($filtersConfig);
     
             $filters = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
    
    From 24713d43aec82f675e4a510e01343e2cf2b19104 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 28 Oct 2021 10:33:37 +0900
    Subject: [PATCH 0576/2325] test: refactor: use method chaining
    
    ---
     tests/system/Filters/FiltersTest.php | 12 ++++++------
     1 file changed, 6 insertions(+), 6 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 1ef5e0293c01..7cd014968e3d 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -728,10 +728,10 @@ public function testAddFilterSection()
             $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
             $filters       = $this->createFilters($filtersConfig);
     
    -        $filters = $filters
    +        $list = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
    -            ->initialize('admin/foo/bar');
    -        $list = $filters->getFilters();
    +            ->initialize('admin/foo/bar')
    +            ->getFilters();
     
             $this->assertTrue(in_array('another', $list['before'], true));
         }
    @@ -744,11 +744,11 @@ public function testInitializeTwice()
             $filtersConfig = $this->createConfigFromArray(FiltersConfig::class, $config);
             $filters       = $this->createFilters($filtersConfig);
     
    -        $filters = $filters
    +        $list = $filters
                 ->addFilter('Some\OtherClass', 'another', 'before', 'globals')
                 ->initialize('admin/foo/bar')
    -            ->initialize();
    -        $list = $filters->getFilters();
    +            ->initialize()
    +            ->getFilters();
     
             $this->assertTrue(in_array('another', $list['before'], true));
         }
    
    From 3b2fd6ea3144a75092d12293bf55798845227205 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 09:28:58 +0900
    Subject: [PATCH 0577/2325] refactor: remove else
    
    ---
     tests/system/Filters/FiltersTest.php | 10 ++++++----
     1 file changed, 6 insertions(+), 4 deletions(-)
    
    diff --git a/tests/system/Filters/FiltersTest.php b/tests/system/Filters/FiltersTest.php
    index 7cd014968e3d..20fdf8770863 100644
    --- a/tests/system/Filters/FiltersTest.php
    +++ b/tests/system/Filters/FiltersTest.php
    @@ -77,11 +77,13 @@ private function createConfigFromArray(string $classname, array $config)
             foreach ($config as $key => $value) {
                 if (property_exists($configObj, $key)) {
                     $configObj->{$key} = $value;
    -            } else {
    -                throw new LogicException(
    -                    'No such property: ' . $classname . '::$' . $key
    -                );
    +
    +                continue;
                 }
    +
    +            throw new LogicException(
    +                'No such property: ' . $classname . '::$' . $key
    +            );
             }
     
             return $configObj;
    
    From d1f1f6b2425104a412128331cc3795ec446e1237 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 14:04:14 +0900
    Subject: [PATCH 0578/2325] fix: `$this->request->setLocale()` does not work
     for `lang()` in 404 controller
    
    Fixes #5261
    ---
     system/Exceptions/PageNotFoundException.php | 25 +++++++++++++++++----
     1 file changed, 21 insertions(+), 4 deletions(-)
    
    diff --git a/system/Exceptions/PageNotFoundException.php b/system/Exceptions/PageNotFoundException.php
    index 444776c087a2..2a773f1785dc 100644
    --- a/system/Exceptions/PageNotFoundException.php
    +++ b/system/Exceptions/PageNotFoundException.php
    @@ -11,6 +11,7 @@
     
     namespace CodeIgniter\Exceptions;
     
    +use Config\Services;
     use OutOfBoundsException;
     
     class PageNotFoundException extends OutOfBoundsException implements ExceptionInterface
    @@ -26,21 +27,37 @@ class PageNotFoundException extends OutOfBoundsException implements ExceptionInt
     
         public static function forPageNotFound(?string $message = null)
         {
    -        return new static($message ?? lang('HTTP.pageNotFound'));
    +        return new static($message ?? self::lang('HTTP.pageNotFound'));
         }
     
         public static function forEmptyController()
         {
    -        return new static(lang('HTTP.emptyController'));
    +        return new static(self::lang('HTTP.emptyController'));
         }
     
         public static function forControllerNotFound(string $controller, string $method)
         {
    -        return new static(lang('HTTP.controllerNotFound', [$controller, $method]));
    +        return new static(self::lang('HTTP.controllerNotFound', [$controller, $method]));
         }
     
         public static function forMethodNotFound(string $method)
         {
    -        return new static(lang('HTTP.methodNotFound', [$method]));
    +        return new static(self::lang('HTTP.methodNotFound', [$method]));
    +    }
    +
    +    /**
    +     * Get translated system message
    +     *
    +     * Use a non-shared Language instance in the Services.
    +     * If a shared instance is created, the Language will
    +     * have the current locale, so even if users call
    +     * `$this->request->setLocale()` in the controller afterwards,
    +     * the Language locale will not be changed.
    +     */
    +    private static function lang(string $line, array $args = []): string
    +    {
    +        $lang = Services::language(null, false);
    +
    +        return $lang->getLine($line, $args);
         }
     }
    
    From 51966d0c407866f2bdc0dda39a714c0cec8d35aa Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA" 
    Date: Sun, 31 Oct 2021 20:17:00 +0800
    Subject: [PATCH 0579/2325] Convert bug report to new syntax
    
    ---
     .github/ISSUE_TEMPLATE/bug_report.md  | 40 -----------
     .github/ISSUE_TEMPLATE/bug_report.yml | 99 +++++++++++++++++++++++++++
     2 files changed, 99 insertions(+), 40 deletions(-)
     delete mode 100644 .github/ISSUE_TEMPLATE/bug_report.md
     create mode 100644 .github/ISSUE_TEMPLATE/bug_report.yml
    
    diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
    deleted file mode 100644
    index dc6c9e37de1f..000000000000
    --- a/.github/ISSUE_TEMPLATE/bug_report.md
    +++ /dev/null
    @@ -1,40 +0,0 @@
    ----
    -name: Bug report
    -about: Create a report to help us improve
    -title: 'Bug: '
    -labels: bug
    -assignees: ''
    -
    ----
    -
    ----
    -name: Bug report
    -about: Help us improve the framework by reporting bugs!
    -
    ----
    -
    -**Direction**
    -We use github issues to track bugs, not for support.  
    -If you have a support question, or a feature request, raise these as threads on our
    -[forum](https://forum.codeigniter.com/index.php).
    -
    -**Describe the bug**
    -A clear and concise description of what the bug is.
    -
    -**CodeIgniter 4 version**
    -Which version (and branch, if applicable) the bug is in.
    -
    -**Affected module(s)**
    -Which package or class is the bug in, if known.
    -
    -**Expected behavior, and steps to reproduce if appropriate**
    -A clear and concise description of what you expected to happen,
    -and how you got there.  
    -Feel free to include a text/log extract, but use a pastebin facility for any
    -screenshots you deem necessary.
    -
    -**Context**
    - - OS: [e.g. Windows 99]
    - - Web server: [e.g. Apache 1.2.3]
    - - PHP version: [e.g. 6.5.4]
    - - Database:  [e.g. MySQL]
    diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
    new file mode 100644
    index 000000000000..c20dd368f41a
    --- /dev/null
    +++ b/.github/ISSUE_TEMPLATE/bug_report.yml
    @@ -0,0 +1,99 @@
    +name: Bug report
    +description: Create a report to help us improve CodeIgniter
    +title: "Bug: "
    +labels: ['bug']
    +
    +body:
    +  - type: markdown
    +    attributes:
    +      value: |
    +        Thanks for taking the time to fill out this bug report! Before you begin, please
    +        ensure that there are no existing issues, whether still open or closed, related
    +        to your report. If there is, your report will be closed promptly.
    +
    +  - type: dropdowm
    +    id: php-version
    +    attributes:
    +      label: PHP Version
    +      description: Which PHP versions did you run your code?
    +      multiple: true
    +      options:
    +        - '7.3'
    +        - '7.4'
    +        - '8.0'
    +        - '8.1'
    +    validations:
    +      required: true
    +
    +  - type: input
    +    id: codeigniter-version
    +    attributes:
    +      label: CodeIgniter4 Version
    +    validations:
    +      required: true
    +
    +  - type: dropdown
    +    id: operating-systems
    +    attributes:
    +      label: Which operating systems have you tested for this bug?
    +      description: You may select more than one.
    +      multiple: true
    +      options:
    +        - macOS
    +        - Windows
    +        - Linux
    +    validations:
    +      required: true
    +
    +  - type: dropdown
    +    id: server
    +    attributes:
    +      label: Which server did you use?
    +      options:
    +        - apache
    +        - cli
    +        - cli-server (PHP built-in webserver)
    +        - cgi-fcgi
    +        - fpm-fcgi
    +        - phpdbg
    +    validations:
    +      required: true
    +
    +  - type: input
    +    id: database
    +    attributes:
    +      label: Database
    +    validations:
    +      required: false
    +
    +  - type: textarea
    +    id: description
    +    attributes:
    +      label: What happened?
    +      placeholder: Tell us what you see!
    +    validations:
    +      required: true
    +
    +  - type: textarea
    +    attributes:
    +      label: Steps to Reproduce
    +      description: Steps to reproduce the behavior.
    +    validations:
    +      required: true
    +
    +  - type: textarea
    +    attributes:
    +      label: Expected Output
    +      description: What do you expect to happen instead of this filed bug?
    +    validations:
    +      required: true
    +
    +  - type: textarea
    +    attributes:
    +      label: Anything else?
    +      description: |
    +        Links? References? Anything that will give us more context about the issue you are encountering!
    +
    +        Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
    +    validations:
    +      required: false
    
    From c833671022b89ba29a01c86ee27260d6d8504f35 Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Mon, 1 Nov 2021 13:36:44 +0800
    Subject: [PATCH 0580/2325] Fix typo: dropdowm --> dropdown
    
    ---
     .github/ISSUE_TEMPLATE/bug_report.yml | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
    index c20dd368f41a..9536a359300b 100644
    --- a/.github/ISSUE_TEMPLATE/bug_report.yml
    +++ b/.github/ISSUE_TEMPLATE/bug_report.yml
    @@ -11,7 +11,7 @@ body:
             ensure that there are no existing issues, whether still open or closed, related
             to your report. If there is, your report will be closed promptly.
     
    -  - type: dropdowm
    +  - type: dropdown
         id: php-version
         attributes:
           label: PHP Version
    
    From f2ca146bc68332dacbda5f03792c8b94cf88f1c3 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 16:19:11 +0900
    Subject: [PATCH 0581/2325] feat: add valid_url_strict rule
    
    Fixes #3156
    ---
     system/Validation/FormatRules.php             | 31 +++++++-
     tests/system/Validation/FormatRulesTest.php   | 71 +++++++++++++++++--
     .../source/libraries/validation.rst           | 10 ++-
     3 files changed, 104 insertions(+), 8 deletions(-)
    
    diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php
    index 6ee13c3f31df..482765212f0b 100644
    --- a/system/Validation/FormatRules.php
    +++ b/system/Validation/FormatRules.php
    @@ -268,7 +268,10 @@ public function valid_ip(?string $ip = null, ?string $which = null): bool
         }
     
         /**
    -     * Checks a URL to ensure it's formed correctly.
    +     * Checks a string to ensure it is (loosely) a URL.
    +     *
    +     * Warning: this rule will pass basic strings like
    +     * "banana"; use valid_url_strict for a stricter rule.
          *
          * @param string $str
          */
    @@ -291,6 +294,32 @@ public function valid_url(?string $str = null): bool
             return filter_var($str, FILTER_VALIDATE_URL) !== false;
         }
     
    +    /**
    +     * Checks a URL to ensure it's formed correctly.
    +     *
    +     * @param string|null $validSchemes comma separated list of allowed schemes
    +     */
    +    public function valid_url_strict(?string $str = null, ?string $validSchemes = null): bool
    +    {
    +        if (empty($str)) {
    +            return false;
    +        }
    +
    +        if ($validSchemes === null) {
    +            $validSchemes = 'http,https,mailto,tel,sms';
    +        }
    +
    +        $scheme           = strtolower(parse_url($str, PHP_URL_SCHEME));
    +        $validSchemes     = strtolower($validSchemes);
    +        $validSchemeArray = explode(',', $validSchemes);
    +
    +        if (! in_array(($scheme), $validSchemeArray, true)) {
    +            return false;
    +        }
    +
    +        return filter_var($str, FILTER_VALIDATE_URL) !== false;
    +    }
    +
         /**
          * Checks for a valid date and matches a given date format
          *
    diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php
    index eb457a0c3a2f..30f89e15df94 100644
    --- a/tests/system/Validation/FormatRulesTest.php
    +++ b/tests/system/Validation/FormatRulesTest.php
    @@ -88,7 +88,7 @@ public function testRegexMatchFalse()
         /**
          * @dataProvider urlProvider
          */
    -    public function testValidURL(?string $url, bool $expected)
    +    public function testValidURL(?string $url, bool $isLoose, bool $isStrict)
         {
             $data = [
                 'foo' => $url,
    @@ -98,7 +98,36 @@ public function testValidURL(?string $url, bool $expected)
                 'foo' => 'valid_url',
             ]);
     
    -        $this->assertSame($expected, $this->validation->run($data));
    +        $this->assertSame($isLoose, $this->validation->run($data));
    +    }
    +
    +    /**
    +     * @dataProvider urlProvider
    +     */
    +    public function testValidURLStrict(?string $url, bool $isLoose, bool $isStrict)
    +    {
    +        $data = [
    +            'foo' => $url,
    +        ];
    +
    +        $this->validation->setRules([
    +            'foo' => 'valid_url_strict',
    +        ]);
    +
    +        $this->assertSame($isStrict, $this->validation->run($data));
    +    }
    +
    +    public function testValidURLStrictWithSchema()
    +    {
    +        $data = [
    +            'foo' => 'http://www.codeigniter.com',
    +        ];
    +
    +        $this->validation->setRules([
    +            'foo' => 'valid_url_strict[https]',
    +        ]);
    +
    +        $this->assertFalse($this->validation->run($data));
         }
     
         public function urlProvider()
    @@ -107,61 +136,91 @@ public function urlProvider()
                 [
                     'www.codeigniter.com',
                     true,
    +                false,
                 ],
                 [
                     'http://codeigniter.com',
                     true,
    +                true,
                 ],
    -            //https://bugs.php.net/bug.php?id=51192
    +            // https://bugs.php.net/bug.php?id=51192
                 [
                     'http://accept-dashes.tld',
                     true,
    +                true,
                 ],
                 [
                     'http://reject_underscores',
                     false,
    +                false,
                 ],
    -            // https://github.com/codeigniter4/CodeIgniter/issues/4415
    +            // https://github.com/bcit-ci/CodeIgniter/issues/4415
                 [
                     'http://[::1]/ipv6',
                     true,
    +                true,
                 ],
                 [
                     'htt://www.codeigniter.com',
                     false,
    +                false,
                 ],
                 [
                     '',
                     false,
    +                false,
    +            ],
    +            // https://github.com/codeigniter4/CodeIgniter4/issues/3156
    +            [
    +                'codeigniter',
    +                true,   // What?
    +                false,
                 ],
                 [
                     'code igniter',
                     false,
    +                false,
                 ],
                 [
                     null,
                     false,
    +                false,
                 ],
                 [
                     'http://',
    -                true,
    -            ], // this is apparently valid!
    +                true,   // Why?
    +                false,
    +            ],
                 [
                     'http:///oops.com',
                     false,
    +                false,
                 ],
                 [
                     '123.com',
                     true,
    +                false,
                 ],
                 [
                     'abc.123',
                     true,
    +                false,
                 ],
                 [
                     'http:8080//abc.com',
    +                true,   // Insane?
    +                false,
    +            ],
    +            [
    +                'mailto:support@codeigniter.com',
    +                true,
                     true,
                 ],
    +            [
    +                '//example.com',
    +                false,
    +                false,
    +            ],
             ];
         }
     
    diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst
    index 1779877c50b1..83d22ace13e6 100644
    --- a/user_guide_src/source/libraries/validation.rst
    +++ b/user_guide_src/source/libraries/validation.rst
    @@ -860,7 +860,15 @@ valid_emails            No         Fails if any value provided in a comma
     valid_ip                No         Fails if the supplied IP is not valid.        valid_ip[ipv6]
                                        Accepts an optional parameter of ‘ipv4’ or
                                        ‘ipv6’ to specify an IP format.
    -valid_url               No         Fails if field does not contain a valid URL.
    +valid_url               No         Fails if field does not contain (loosely) a
    +                                   URL. Includes simple strings that could be
    +                                   hostnames, like "codeigniter".
    +valid_url_strict        Yes        Fails if field does not contain a valid URL.  valid_url_strict[http,https]
    +                                   Roughly equivalent to a "fail anything that
    +                                   would not be a clickable link." You can
    +                                   optionally specify a list of valid schemas.
    +                                   If not specified,
    +                                   ``http,https,mailto,tel,sms`` are valid.
     valid_date              No         Fails if field does not contain a valid date. valid_date[d/m/Y]
                                        Accepts an optional parameter to matches
                                        a date format.
    
    From 10b3de20a43759dc38c501948fa742936fd0967a Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 14 Oct 2021 20:41:45 +0900
    Subject: [PATCH 0582/2325] docs: make @return strict
    
    ---
     system/Database/BaseBuilder.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 886ce928e132..b26c98189d20 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1944,7 +1944,7 @@ protected function validateUpdate(): bool
          *
          * @throws DatabaseException
          *
    -     * @return mixed Number of rows affected, SQL string, or FALSE on failure
    +     * @return false|int|string[] Number of rows affected or FALSE on failure, SQL array when testMode
          */
         public function updateBatch(?array $set = null, ?string $index = null, int $batchSize = 100)
         {
    
    From 0f3088c2786c5bc66f39b1857659ca99c47bcdd0 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Thu, 14 Oct 2021 20:46:01 +0900
    Subject: [PATCH 0583/2325] fix: make the return type of insertBatch() the same
     as updateBatch()
    
    ---
     system/Database/BaseBuilder.php | 7 ++++---
     1 file changed, 4 insertions(+), 3 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index b26c98189d20..da826824d18d 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1590,7 +1590,7 @@ public function getWhere($where = null, ?int $limit = null, ?int $offset = 0, bo
          *
          * @throws DatabaseException
          *
    -     * @return false|int Number of rows inserted or FALSE on failure
    +     * @return false|int|string[] Number of rows inserted or FALSE on failure, SQL array when testMode
          */
         public function insertBatch(?array $set = null, ?bool $escape = null, int $batchSize = 100)
         {
    @@ -1617,12 +1617,13 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
             $table = $this->QBFrom[0];
     
             $affectedRows = 0;
    +        $savedSQL     = [];
     
             for ($i = 0, $total = count($this->QBSet); $i < $total; $i += $batchSize) {
                 $sql = $this->_insertBatch($this->db->protectIdentifiers($table, true, null, false), $this->QBKeys, array_slice($this->QBSet, $i, $batchSize));
     
                 if ($this->testMode) {
    -                $affectedRows++;
    +                $savedSQL[] = $sql;
                 } else {
                     $this->db->query($sql, $this->binds, false);
                     $affectedRows += $this->db->affectedRows();
    @@ -1633,7 +1634,7 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
                 $this->resetWrite();
             }
     
    -        return $affectedRows;
    +        return $this->testMode ? $savedSQL : $affectedRows;
         }
     
         /**
    
    From c18c70ef655ecc0e48149dcf3c510149e27b1d65 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 15 Oct 2021 10:42:13 +0900
    Subject: [PATCH 0584/2325] refactor: do not use $this->binds when
     insertBatch()
    
    To reduce memory consumption.
    ---
     system/Database/BaseBuilder.php | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index da826824d18d..96127360c3fa 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1625,7 +1625,7 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
                 if ($this->testMode) {
                     $savedSQL[] = $sql;
                 } else {
    -                $this->db->query($sql, $this->binds, false);
    +                $this->db->query($sql, null, false);
                     $affectedRows += $this->db->affectedRows();
                 }
             }
    @@ -1679,7 +1679,7 @@ public function setInsertBatch($key, string $value = '', ?bool $escape = null)
                 $clean = [];
     
                 foreach ($row as $k => $rowValue) {
    -                $clean[] = ':' . $this->setBind($k, $rowValue, $escape) . ':';
    +                $clean[] = $escape ? $this->db->escape($rowValue) : $rowValue;
                 }
     
                 $row = $clean;
    
    From acd566de40d61b78f3a96a86ca711b016cec2832 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 15 Oct 2021 10:59:08 +0900
    Subject: [PATCH 0585/2325] refactor: reduce memory useage when insertBatch()
     with $set is not null
    
    ---
     system/Database/BaseBuilder.php | 22 ++++++++++++++++++----
     1 file changed, 18 insertions(+), 4 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 96127360c3fa..d28cabb570f4 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1610,17 +1610,27 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
     
                     return false; // @codeCoverageIgnore
                 }
    -
    -            $this->setInsertBatch($set, '', $escape);
             }
     
    +        $hasQBSet = ($set === null);
    +
             $table = $this->QBFrom[0];
     
             $affectedRows = 0;
             $savedSQL     = [];
     
    -        for ($i = 0, $total = count($this->QBSet); $i < $total; $i += $batchSize) {
    -            $sql = $this->_insertBatch($this->db->protectIdentifiers($table, true, null, false), $this->QBKeys, array_slice($this->QBSet, $i, $batchSize));
    +        if ($hasQBSet) {
    +            $set = $this->QBSet;
    +        }
    +
    +        for ($i = 0, $total = count($set); $i < $total; $i += $batchSize) {
    +            if ($hasQBSet) {
    +                $QBSet = array_slice($this->QBSet, $i, $batchSize);
    +            } else {
    +                $this->setInsertBatch(array_slice($set, $i, $batchSize), '', $escape);
    +                $QBSet = $this->QBSet;
    +            }
    +            $sql = $this->_insertBatch($this->db->protectIdentifiers($table, true, null, false), $this->QBKeys, $QBSet);
     
                 if ($this->testMode) {
                     $savedSQL[] = $sql;
    @@ -1628,6 +1638,10 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
                     $this->db->query($sql, null, false);
                     $affectedRows += $this->db->affectedRows();
                 }
    +
    +            if (! $hasQBSet) {
    +                $this->resetWrite();
    +            }
             }
     
             if (! $this->testMode) {
    
    From bc36f0ca3ffa38693e1df49e775a726f4af02467 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 15 Oct 2021 11:10:10 +0900
    Subject: [PATCH 0586/2325] refactor: resetWrite() when testMode
    
    No need to keep write values even if testMode.
    ---
     system/Database/BaseBuilder.php | 4 +---
     1 file changed, 1 insertion(+), 3 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index d28cabb570f4..73d9a69b7196 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1644,9 +1644,7 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
                 }
             }
     
    -        if (! $this->testMode) {
    -            $this->resetWrite();
    -        }
    +        $this->resetWrite();
     
             return $this->testMode ? $savedSQL : $affectedRows;
         }
    
    From adbdd7034293528273905bd8711bbf5c755386ed Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 15 Oct 2021 11:29:28 +0900
    Subject: [PATCH 0587/2325] refactor: vendor/bin/rector process
    
    ---
     system/Database/BaseBuilder.php | 14 ++++++--------
     1 file changed, 6 insertions(+), 8 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 73d9a69b7196..9f0d4888b271 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1602,14 +1602,12 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
     
                     return false; // @codeCoverageIgnore
                 }
    -        } else {
    -            if (empty($set)) {
    -                if (CI_DEBUG) {
    -                    throw new DatabaseException('insertBatch() called with no data');
    -                }
    -
    -                return false; // @codeCoverageIgnore
    +        } elseif (empty($set)) {
    +            if (CI_DEBUG) {
    +                throw new DatabaseException('insertBatch() called with no data');
                 }
    +
    +            return false; // @codeCoverageIgnore
             }
     
             $hasQBSet = ($set === null);
    @@ -1690,7 +1688,7 @@ public function setInsertBatch($key, string $value = '', ?bool $escape = null)
     
                 $clean = [];
     
    -            foreach ($row as $k => $rowValue) {
    +            foreach ($row as $rowValue) {
                     $clean[] = $escape ? $this->db->escape($rowValue) : $rowValue;
                 }
     
    
    From 8ce784756b39222e1a62faf06304b955a54f5ded Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 15 Oct 2021 11:38:12 +0900
    Subject: [PATCH 0588/2325] test: remove tests for getOriginalQuery()
    
    Now do not use binds to reduce memory useage.
    ---
     tests/system/Database/Builder/InsertTest.php | 9 ---------
     1 file changed, 9 deletions(-)
    
    diff --git a/tests/system/Database/Builder/InsertTest.php b/tests/system/Database/Builder/InsertTest.php
    index d9c0c79e11e6..2905fe222613 100644
    --- a/tests/system/Database/Builder/InsertTest.php
    +++ b/tests/system/Database/Builder/InsertTest.php
    @@ -91,9 +91,6 @@ public function testInsertBatch()
             $query = $this->db->getLastQuery();
             $this->assertInstanceOf(Query::class, $query);
     
    -        $raw = 'INSERT INTO "jobs" ("description", "id", "name") VALUES (:description:,:id:,:name:), (:description.1:,:id.1:,:name.1:)';
    -        $this->assertSame($raw, str_replace("\n", ' ', $query->getOriginalQuery()));
    -
             $expected = "INSERT INTO \"jobs\" (\"description\", \"id\", \"name\") VALUES ('There''s something in your teeth',2,'Commedian'), ('I am yellow',3,'Cab Driver')";
             $this->assertSame($expected, str_replace("\n", ' ', $query->getQuery()));
         }
    @@ -121,9 +118,6 @@ public function testInsertBatchWithoutEscape()
             $query = $this->db->getLastQuery();
             $this->assertInstanceOf(Query::class, $query);
     
    -        $raw = 'INSERT INTO "jobs" ("description", "id", "name") VALUES (:description:,:id:,:name:), (:description.1:,:id.1:,:name.1:)';
    -        $this->assertSame($raw, str_replace("\n", ' ', $query->getOriginalQuery()));
    -
             $expected = 'INSERT INTO "jobs" ("description", "id", "name") VALUES (1 + 2,2,1 + 1), (2 + 2,3,2 + 1)';
             $this->assertSame($expected, str_replace("\n", ' ', $query->getQuery()));
         }
    @@ -148,9 +142,6 @@ public function testInsertBatchWithFieldsEndingInNumbers()
             $query = $this->db->getLastQuery();
             $this->assertInstanceOf(Query::class, $query);
     
    -        $raw = 'INSERT INTO "ip_table" ("ip", "ip2") VALUES (:ip:,:ip2:), (:ip.1:,:ip2.1:), (:ip.2:,:ip2.2:), (:ip.3:,:ip2.3:)';
    -        $this->assertSame($raw, str_replace("\n", ' ', $query->getOriginalQuery()));
    -
             $expected = "INSERT INTO \"ip_table\" (\"ip\", \"ip2\") VALUES ('1.1.1.0','1.1.1.2'), ('2.2.2.0','2.2.2.2'), ('3.3.3.0','3.3.3.2'), ('4.4.4.0','4.4.4.2')";
             $this->assertSame($expected, str_replace("\n", ' ', $query->getQuery()));
         }
    
    From 516555059753240a1035a77cb88e7cc9f186e9ce Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Fri, 15 Oct 2021 11:41:52 +0900
    Subject: [PATCH 0589/2325] refactor: do not use $this->binds when
     updateBatch()
    
    To reduce memory consumption.
    ---
     system/Database/BaseBuilder.php              |  5 ++--
     tests/system/Database/Builder/UpdateTest.php | 26 --------------------
     2 files changed, 2 insertions(+), 29 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 9f0d4888b271..58459c37cd4c 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -2076,9 +2076,8 @@ public function setUpdateBatch($key, string $index = '', ?bool $escape = null)
                         $indexSet = true;
                     }
     
    -                $bind = $this->setBind($k2, $v2, $escape);
    -
    -                $clean[$this->db->protectIdentifiers($k2, false)] = ":{$bind}:";
    +                $clean[$this->db->protectIdentifiers($k2, false)]
    +                    = $escape ? $this->db->escape($v2) : $v2;
                 }
     
                 if ($indexSet === false) {
    diff --git a/tests/system/Database/Builder/UpdateTest.php b/tests/system/Database/Builder/UpdateTest.php
    index 1bf36ffe7b3e..bda9ae49915d 100644
    --- a/tests/system/Database/Builder/UpdateTest.php
    +++ b/tests/system/Database/Builder/UpdateTest.php
    @@ -208,19 +208,6 @@ public function testUpdateBatch()
     
             $space = ' ';
     
    -        $expected = <<assertSame($expected, $query->getOriginalQuery());
    -
             $expected = <<assertSame($expected, $query->getOriginalQuery());
    -
             $expected = <<
    Date: Fri, 15 Oct 2021 11:51:49 +0900
    Subject: [PATCH 0590/2325] refactor: reduce memory useage when updateBatch()
     with $set is not null
    
    ---
     system/Database/BaseBuilder.php | 33 +++++++++++++++++++++++----------
     1 file changed, 23 insertions(+), 10 deletions(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index 58459c37cd4c..b20c4779de34 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1975,28 +1975,37 @@ public function updateBatch(?array $set = null, ?string $index = null, int $batc
     
                     return false; // @codeCoverageIgnore
                 }
    -        } else {
    -            if (empty($set)) {
    -                if (CI_DEBUG) {
    -                    throw new DatabaseException('updateBatch() called with no data');
    -                }
    -
    -                return false; // @codeCoverageIgnore
    +        } elseif (empty($set)) {
    +            if (CI_DEBUG) {
    +                throw new DatabaseException('updateBatch() called with no data');
                 }
     
    -            $this->setUpdateBatch($set, $index);
    +            return false; // @codeCoverageIgnore
             }
     
    +        $hasQBSet = ($set === null);
    +
             $table = $this->QBFrom[0];
     
             $affectedRows = 0;
             $savedSQL     = [];
             $savedQBWhere = $this->QBWhere;
     
    -        for ($i = 0, $total = count($this->QBSet); $i < $total; $i += $batchSize) {
    +        if ($hasQBSet) {
    +            $set = $this->QBSet;
    +        }
    +
    +        for ($i = 0, $total = count($set); $i < $total; $i += $batchSize) {
    +            if ($hasQBSet) {
    +                $QBSet = array_slice($this->QBSet, $i, $batchSize);
    +            } else {
    +                $this->setUpdateBatch(array_slice($set, $i, $batchSize), $index);
    +                $QBSet = $this->QBSet;
    +            }
    +
                 $sql = $this->_updateBatch(
                     $table,
    -                array_slice($this->QBSet, $i, $batchSize),
    +                $QBSet,
                     $this->db->protectIdentifiers($index)
                 );
     
    @@ -2007,6 +2016,10 @@ public function updateBatch(?array $set = null, ?string $index = null, int $batc
                     $affectedRows += $this->db->affectedRows();
                 }
     
    +            if (! $hasQBSet) {
    +                $this->resetWrite();
    +            }
    +
                 $this->QBWhere = $savedQBWhere;
             }
     
    
    From 1b7bc3d63d000deca412d737172349e1eb2ffa91 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 18:42:59 +0900
    Subject: [PATCH 0591/2325] refactor: remove ()
    
    Co-authored-by: Abdul Malik Ikhsan 
    ---
     system/Database/BaseBuilder.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index b20c4779de34..fd71a4afd624 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1983,7 +1983,7 @@ public function updateBatch(?array $set = null, ?string $index = null, int $batc
                 return false; // @codeCoverageIgnore
             }
     
    -        $hasQBSet = ($set === null);
    +        $hasQBSet = $set === null;
     
             $table = $this->QBFrom[0];
     
    
    From 94eaf09a80edaaa04960971c014bf75ad6a87d2b Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 19:00:14 +0900
    Subject: [PATCH 0592/2325] test: add test for getOriginalQuery()
    
    ---
     tests/system/Database/Builder/InsertTest.php | 5 +++++
     1 file changed, 5 insertions(+)
    
    diff --git a/tests/system/Database/Builder/InsertTest.php b/tests/system/Database/Builder/InsertTest.php
    index 2905fe222613..5235a3bdbf58 100644
    --- a/tests/system/Database/Builder/InsertTest.php
    +++ b/tests/system/Database/Builder/InsertTest.php
    @@ -91,6 +91,11 @@ public function testInsertBatch()
             $query = $this->db->getLastQuery();
             $this->assertInstanceOf(Query::class, $query);
     
    +        $raw = <<<'SQL'
    +            INSERT INTO "jobs" ("description", "id", "name") VALUES ('There''s something in your teeth',2,'Commedian'), ('I am yellow',3,'Cab Driver')
    +            SQL;
    +        $this->assertSame($raw, str_replace("\n", ' ', $query->getOriginalQuery()));
    +
             $expected = "INSERT INTO \"jobs\" (\"description\", \"id\", \"name\") VALUES ('There''s something in your teeth',2,'Commedian'), ('I am yellow',3,'Cab Driver')";
             $this->assertSame($expected, str_replace("\n", ' ', $query->getQuery()));
         }
    
    From 5ad421a92ed93aff24470411626a4667c13ca7f2 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 19:01:14 +0900
    Subject: [PATCH 0593/2325] docs: add breaking changes to changelog
    
    ---
     user_guide_src/source/changelogs/v4.1.5.rst | 2 ++
     1 file changed, 2 insertions(+)
    
    diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst
    index f763123fbd85..b97885f2a3b0 100644
    --- a/user_guide_src/source/changelogs/v4.1.5.rst
    +++ b/user_guide_src/source/changelogs/v4.1.5.rst
    @@ -14,6 +14,8 @@ BREAKING
     
     - Fixed `a bug `_ on CSRF protection. Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied. If you use such requests, you need to send CSRF token.
     - In the previous version, if you didn't provide your own headers, ``CURLRequest`` would send the request-headers from the browser, due to a bug. As of this version, it does not send them.
    +- Fixed ``BaseBuilder::insertBatch()`` return value. Now it returns SQL string array instead of wrong affected row number when testMode.
    +- Because of the optimization, when ``BaseBuilder::insertBatch()`` and ``BaseBuilder::updateBatch()`` are used, the return value of ``$query->getOriginalQuery()`` changed.
     
     Enhancements
     ============
    
    From 6e1194f2ee520b88bd90f2e154b9e195ec117e04 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 19:04:43 +0900
    Subject: [PATCH 0594/2325] refactor: remove ()
    
    Co-authored-by: Abdul Malik Ikhsan 
    ---
     system/Database/BaseBuilder.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php
    index fd71a4afd624..74b9dffad0e4 100644
    --- a/system/Database/BaseBuilder.php
    +++ b/system/Database/BaseBuilder.php
    @@ -1610,7 +1610,7 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch
                 return false; // @codeCoverageIgnore
             }
     
    -        $hasQBSet = ($set === null);
    +        $hasQBSet = $set === null;
     
             $table = $this->QBFrom[0];
     
    
    From cc5b1d0b6e2319857b1a18e25dd1566d5265ea50 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Mon, 1 Nov 2021 19:52:52 +0900
    Subject: [PATCH 0595/2325] docs: add breaking changes to upgrade note
    
    ---
     user_guide_src/source/installation/upgrade_415.rst | 8 ++++++++
     1 file changed, 8 insertions(+)
    
    diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst
    index 7a8c51f985ae..b6a4007a518b 100644
    --- a/user_guide_src/source/installation/upgrade_415.rst
    +++ b/user_guide_src/source/installation/upgrade_415.rst
    @@ -61,6 +61,14 @@ The bug was fixed. If your requests depend on the headers, your requests might f
     In this case, add the necessary headers manually.
     See `CURLRequest Class <../libraries/curlrequest.html#headers>`_ for how to add.
     
    +Query Builder changes
    +---------------------
    +
    +For optimization and a bug fix, the following behaviors, mostly used in testing, have been changed.
    +
    +- When you use ``insertBatch()`` and ``updateBatch()``, the return value of ``$query->getOriginalQuery()`` changed.
    +- If ``testMode`` is ``true``, ``insertBatch()`` will return an SQL string array instead of the number of affected rows that were wrong.
    +
     Breaking Enhancements
     =====================
     
    
    From 2165b114ada16045106c327bae48407a5043e90b Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Mon, 1 Nov 2021 23:45:26 +0800
    Subject: [PATCH 0596/2325] Enclose the PR template's notes as comments
    
    ---
     .github/PULL_REQUEST_TEMPLATE.md | 4 +++-
     1 file changed, 3 insertions(+), 1 deletion(-)
    
    diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
    index 6204913fd437..5b48f145ee3a 100644
    --- a/.github/PULL_REQUEST_TEMPLATE.md
    +++ b/.github/PULL_REQUEST_TEMPLATE.md
    @@ -10,7 +10,7 @@ Explain what you have changed, and why.
     - [ ] User guide updated
     - [ ] Conforms to style guide
     
    ----------Remove from here down in your description----------
    +
    
    From b8c1939cf41652caffa8ef17892938ae1bfab44d Mon Sep 17 00:00:00 2001
    From: "John Paul E. Balandan, CPA"
     <51850998+paulbalandan@users.noreply.github.com>
    Date: Mon, 1 Nov 2021 23:45:54 +0800
    Subject: [PATCH 0597/2325] Simplify logic of `number_to_roman` function
    
    ---
     system/Helpers/number_helper.php | 91 +++++++++-----------------------
     1 file changed, 24 insertions(+), 67 deletions(-)
    
    diff --git a/system/Helpers/number_helper.php b/system/Helpers/number_helper.php
    index d7f49c15f852..b3d7c80c6006 100644
    --- a/system/Helpers/number_helper.php
    +++ b/system/Helpers/number_helper.php
    @@ -182,79 +182,36 @@ function format_number(float $num, int $precision = 1, ?string $locale = null, a
          */
         function number_to_roman(string $num): ?string
         {
    +        static $map = [
    +            'M'  => 1000,
    +            'CM' => 900,
    +            'D'  => 500,
    +            'CD' => 400,
    +            'C'  => 100,
    +            'XC' => 90,
    +            'L'  => 50,
    +            'XL' => 40,
    +            'X'  => 10,
    +            'IX' => 9,
    +            'V'  => 5,
    +            'IV' => 4,
    +            'I'  => 1,
    +        ];
    +
             $num = (int) $num;
    +
             if ($num < 1 || $num > 3999) {
                 return null;
             }
     
    -        $_number_to_roman = static function ($num, $th) use (&$_number_to_roman) {
    -            $return = '';
    -            $key1   = null;
    -            $key2   = null;
    -
    -            switch ($th) {
    -                case 1:
    -                    $key1 = 'I';
    -                    $key2 = 'V';
    -                    $keyF = 'X';
    -                    break;
    -
    -                case 2:
    -                    $key1 = 'X';
    -                    $key2 = 'L';
    -                    $keyF = 'C';
    -                    break;
    -
    -                case 3:
    -                    $key1 = 'C';
    -                    $key2 = 'D';
    -                    $keyF = 'M';
    -                    break;
    -
    -                case 4:
    -                    $key1 = 'M';
    -                    break;
    -            }
    -            $n = $num % 10;
    -
    -            switch ($n) {
    -                case 1:
    -                case 2:
    -                case 3:
    -                    $return = str_repeat($key1, $n);
    -                    break;
    +        $result = '';
     
    -                case 4:
    -                    $return = $key1 . $key2;
    -                    break;
    -
    -                case 5:
    -                    $return = $key2;
    -                    break;
    -
    -                case 6:
    -                case 7:
    -                case 8:
    -                    $return = $key2 . str_repeat($key1, $n - 5);
    -                    break;
    -
    -                case 9:
    -                    $return = $key1 . $keyF; // @phpstan-ignore-line
    -                    break;
    -            }
    -
    -            switch ($num) {
    -                case 10:
    -                    $return = $keyF; // @phpstan-ignore-line
    -                    break;
    -            }
    -            if ($num > 10) {
    -                $return = $_number_to_roman($num / 10, ++$th) . $return;
    -            }
    -
    -            return $return;
    -        };
    +        foreach ($map as $roman => $arabic) {
    +            $repeat = (int) floor($num / $arabic);
    +            $result .= str_repeat($roman, $repeat);
    +            $num %= $arabic;
    +        }
     
    -        return $_number_to_roman($num, 1);
    +        return $result;
         }
     }
    
    From 056846458554549bd665750fcc7389b75ee9a48c Mon Sep 17 00:00:00 2001
    From: Abdul Malik Ikhsan 
    Date: Mon, 1 Nov 2021 23:10:46 +0700
    Subject: [PATCH 0598/2325] [Rector] Refactor
     UnderscoreToCamelCaseVariableNameRector so no longer require
     symplify/package-builder
    
    ---
     composer.json                                 |  3 +-
     rector.php                                    |  2 -
     ...nderscoreToCamelCaseVariableNameRector.php | 48 +++++++------------
     3 files changed, 19 insertions(+), 34 deletions(-)
    
    diff --git a/composer.json b/composer.json
    index d914b452e528..b7b3176e055f 100644
    --- a/composer.json
    +++ b/composer.json
    @@ -24,8 +24,7 @@
             "phpstan/phpstan": "^0.12.91",
             "phpunit/phpunit": "^9.1",
             "predis/predis": "^1.1",
    -        "rector/rector": "0.11.60",
    -        "symplify/package-builder": "^9.3"
    +        "rector/rector": "0.11.60"
         },
         "suggest": {
             "ext-fileinfo": "Improves mime type detection for files"
    diff --git a/rector.php b/rector.php
    index 04e761cbf89e..77f8124c7d6f 100644
    --- a/rector.php
    +++ b/rector.php
    @@ -117,8 +117,6 @@
         $parameters->set(Option::PHP_VERSION_FEATURES, PhpVersion::PHP_73);
     
         $services = $containerConfigurator->services();
    -    $services->load('Symplify\\PackageBuilder\\', __DIR__ . '/vendor/symplify/package-builder/src');
    -
         $services->set(UnderscoreToCamelCaseVariableNameRector::class);
         $services->set(SimplifyUselessVariableRector::class);
         $services->set(RemoveAlwaysElseRector::class);
    diff --git a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php
    index 005355bb7fd6..f87956f758e4 100644
    --- a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php
    +++ b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php
    @@ -13,7 +13,6 @@
     
     namespace Utils\Rector;
     
    -use Nette\Utils\Strings;
     use PhpParser\Comment\Doc;
     use PhpParser\Node;
     use PhpParser\Node\Expr\Variable;
    @@ -21,8 +20,7 @@
     use PhpParser\Node\Stmt\Function_;
     use Rector\Core\Php\ReservedKeywordAnalyzer;
     use Rector\Core\Rector\AbstractRector;
    -use Rector\NodeTypeResolver\Node\AttributeKey;
    -use Symplify\PackageBuilder\Strings\StringFormatConverter;
    +use Rector\NodeNestingScope\ParentFinder;
     use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
     use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
     
    @@ -43,16 +41,16 @@ final class UnderscoreToCamelCaseVariableNameRector extends AbstractRector
         private $reservedKeywordAnalyzer;
     
         /**
    -     * @var StringFormatConverter
    +     * @var ParentFinder
          */
    -    private $stringFormatConverter;
    +    private $parentFinder;
     
         public function __construct(
             ReservedKeywordAnalyzer $reservedKeywordAnalyzer,
    -        StringFormatConverter $stringFormatConverter
    +        ParentFinder $parentFinder
         ) {
             $this->reservedKeywordAnalyzer = $reservedKeywordAnalyzer;
    -        $this->stringFormatConverter   = $stringFormatConverter;
    +        $this->parentFinder            = $parentFinder;
         }
     
         public function getRuleDefinition(): RuleDefinition
    @@ -100,19 +98,20 @@ public function refactor(Node $node): ?Node
                 return null;
             }
     
    -        if (! Strings::contains($nodeName, '_')) {
    -            return null;
    -        }
    -
             if ($this->reservedKeywordAnalyzer->isNativeVariable($nodeName)) {
                 return null;
             }
     
    -        if ($nodeName[0] === '_') {
    +        $underscorePosition = strpos($nodeName, '_');
    +        // underscore not found, or in the first char, skip
    +        if ($underscorePosition === false || $underscorePosition === 0) {
                 return null;
             }
     
    -        $camelCaseName = $this->stringFormatConverter->underscoreAndHyphenToCamelCase($nodeName);
    +        $replaceUnderscoreToSpace = str_replace('_', ' ', $nodeName);
    +        $uppercaseFirstChar       = ucwords($replaceUnderscoreToSpace);
    +        $camelCaseName            = lcfirst(str_replace(' ', '', $uppercaseFirstChar));
    +
             if ($camelCaseName === 'this') {
                 return null;
             }
    @@ -125,24 +124,13 @@ public function refactor(Node $node): ?Node
     
         private function updateDocblock(Variable $variable, string $variableName, string $camelCaseName): void
         {
    -        $parentNode = $variable->getAttribute(AttributeKey::PARENT_NODE);
    -
    -        while ($parentNode) {
    -            /**
    -             * @var ClassMethod|Function_ $parentNode
    -             */
    -            $parentNode = $parentNode->getAttribute(AttributeKey::PARENT_NODE);
    -
    -            if ($parentNode instanceof ClassMethod || $parentNode instanceof Function_) {
    -                break;
    -            }
    -        }
    +        $parentClassMethodOrFunction = $this->parentFinder->findByTypes($variable, [ClassMethod::class, Function_::class]);
     
    -        if ($parentNode === null) {
    +        if ($parentClassMethodOrFunction === null) {
                 return;
             }
     
    -        $docComment = $parentNode->getDocComment();
    +        $docComment = $parentClassMethodOrFunction->getDocComment();
             if ($docComment === null) {
                 return;
             }
    @@ -152,11 +140,11 @@ private function updateDocblock(Variable $variable, string $variableName, string
                 return;
             }
     
    -        if (! Strings::match($docCommentText, sprintf(self::PARAM_NAME_REGEX, $variableName))) {
    +        if (! preg_match(sprintf(self::PARAM_NAME_REGEX, $variableName), $docCommentText)) {
                 return;
             }
     
    -        $phpDocInfo         = $this->phpDocInfoFactory->createFromNodeOrEmpty($parentNode);
    +        $phpDocInfo         = $this->phpDocInfoFactory->createFromNodeOrEmpty($parentClassMethodOrFunction);
             $paramTagValueNodes = $phpDocInfo->getParamTagValueNodes();
     
             foreach ($paramTagValueNodes as $paramTagValueNode) {
    @@ -166,6 +154,6 @@ private function updateDocblock(Variable $variable, string $variableName, string
                 }
             }
     
    -        $parentNode->setDocComment(new Doc($phpDocInfo->getPhpDocNode()->__toString()));
    +        $parentClassMethodOrFunction->setDocComment(new Doc($phpDocInfo->getPhpDocNode()->__toString()));
         }
     }
    
    From efb3b4dd288052061019f44d49bedfc37cb43b3e Mon Sep 17 00:00:00 2001
    From: Abdul Malik Ikhsan 
    Date: Mon, 1 Nov 2021 23:48:11 +0700
    Subject: [PATCH 0599/2325] cast to int for strpos result
    
    Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com>
    ---
     utils/Rector/UnderscoreToCamelCaseVariableNameRector.php | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php
    index f87956f758e4..f87222bb2d5d 100644
    --- a/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php
    +++ b/utils/Rector/UnderscoreToCamelCaseVariableNameRector.php
    @@ -104,7 +104,7 @@ public function refactor(Node $node): ?Node
     
             $underscorePosition = strpos($nodeName, '_');
             // underscore not found, or in the first char, skip
    -        if ($underscorePosition === false || $underscorePosition === 0) {
    +        if ((int) $underscorePosition === 0) {
                 return null;
             }
     
    
    From 9c5f5ccd930fbba7c308837dd6c34ef05e00ca6a Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 08:18:01 +0900
    Subject: [PATCH 0600/2325] docs: make the description more precise
    
    Co-authored-by: Michal Sniatala 
    ---
     user_guide_src/source/installation/upgrade_415.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/installation/upgrade_415.rst b/user_guide_src/source/installation/upgrade_415.rst
    index b6a4007a518b..ac3cdb529d74 100644
    --- a/user_guide_src/source/installation/upgrade_415.rst
    +++ b/user_guide_src/source/installation/upgrade_415.rst
    @@ -66,7 +66,7 @@ Query Builder changes
     
     For optimization and a bug fix, the following behaviors, mostly used in testing, have been changed.
     
    -- When you use ``insertBatch()`` and ``updateBatch()``, the return value of ``$query->getOriginalQuery()`` changed.
    +- When you use ``insertBatch()`` and ``updateBatch()``, the return value of ``$query->getOriginalQuery()`` has changed. It no longer returns the query with the binded parameters, but the actual query that was run.
     - If ``testMode`` is ``true``, ``insertBatch()`` will return an SQL string array instead of the number of affected rows that were wrong.
     
     Breaking Enhancements
    
    From e08bc930685837000a615b4dd40b67b89d677fae Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 08:20:03 +0900
    Subject: [PATCH 0601/2325] docs: make the description more specific
    
    Co-authored-by: Michal Sniatala 
    ---
     user_guide_src/source/changelogs/v4.1.5.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/changelogs/v4.1.5.rst b/user_guide_src/source/changelogs/v4.1.5.rst
    index b97885f2a3b0..34eb8937baf4 100644
    --- a/user_guide_src/source/changelogs/v4.1.5.rst
    +++ b/user_guide_src/source/changelogs/v4.1.5.rst
    @@ -15,7 +15,7 @@ BREAKING
     - Fixed `a bug `_ on CSRF protection. Now CSRF protection works on PUT/PATCH/DELETE requests when CSRF filter is applied. If you use such requests, you need to send CSRF token.
     - In the previous version, if you didn't provide your own headers, ``CURLRequest`` would send the request-headers from the browser, due to a bug. As of this version, it does not send them.
     - Fixed ``BaseBuilder::insertBatch()`` return value. Now it returns SQL string array instead of wrong affected row number when testMode.
    -- Because of the optimization, when ``BaseBuilder::insertBatch()`` and ``BaseBuilder::updateBatch()`` are used, the return value of ``$query->getOriginalQuery()`` changed.
    +- Major optimizations have been made to the way data is processed in ``BaseBuilder::insertBatch()`` and ``BaseBuilder::updateBatch()`` methods. This resulted in reduced memory usage and faster query processing. As a trade-off, the result generated by the ``$query->getOriginalQuery()`` method was changed. It no longer returns the query with the binded parameters, but the actual query that was run.
     
     Enhancements
     ============
    
    From 019ea5acadf7993c0ddaf72c605ac220b709bf88 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 08:36:12 +0900
    Subject: [PATCH 0602/2325] refactor: remove if statements
    
    ---
     system/Validation/FormatRules.php | 22 +++++++++-------------
     1 file changed, 9 insertions(+), 13 deletions(-)
    
    diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php
    index 482765212f0b..5f6289b41c4c 100644
    --- a/system/Validation/FormatRules.php
    +++ b/system/Validation/FormatRules.php
    @@ -305,19 +305,15 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu
                 return false;
             }
     
    -        if ($validSchemes === null) {
    -            $validSchemes = 'http,https,mailto,tel,sms';
    -        }
    -
    -        $scheme           = strtolower(parse_url($str, PHP_URL_SCHEME));
    -        $validSchemes     = strtolower($validSchemes);
    -        $validSchemeArray = explode(',', $validSchemes);
    -
    -        if (! in_array(($scheme), $validSchemeArray, true)) {
    -            return false;
    -        }
    -
    -        return filter_var($str, FILTER_VALIDATE_URL) !== false;
    +        $scheme       = strtolower(parse_url($str, PHP_URL_SCHEME));
    +        $validSchemes = explode(
    +            ',',
    +            strtolower($validSchemes ?? 'http,https,mailto,tel,sms')
    +        );
    +
    +        return ! in_array($scheme, $validSchemes, true)
    +            ? false
    +            : filter_var($str, FILTER_VALIDATE_URL) !== false;
         }
     
         /**
    
    From 5b91b08731b90d907a859d3578a1e173a029ffca Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 09:02:55 +0900
    Subject: [PATCH 0603/2325] docs: add how to fix code with Rector
    
    ---
     contributing/pull_request.md | 4 ++++
     1 file changed, 4 insertions(+)
    
    diff --git a/contributing/pull_request.md b/contributing/pull_request.md
    index d08bbd2e035c..e08a5c110558 100644
    --- a/contributing/pull_request.md
    +++ b/contributing/pull_request.md
    @@ -199,6 +199,10 @@ Rector, on the other hand, can be run on the specific files you modified or adde
     
     	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
    +
     [1]: https://github.com/phpstan/phpstan-src
     [2]: https://github.com/rector/rector
     
    
    From 1b0850e422568f4527b6c70247e697d83817cea2 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 09:11:04 +0900
    Subject: [PATCH 0604/2325] refactor: simplify return statement
    
    ---
     system/Validation/FormatRules.php | 5 ++---
     1 file changed, 2 insertions(+), 3 deletions(-)
    
    diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php
    index 5f6289b41c4c..daf5061c80f6 100644
    --- a/system/Validation/FormatRules.php
    +++ b/system/Validation/FormatRules.php
    @@ -311,9 +311,8 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu
                 strtolower($validSchemes ?? 'http,https,mailto,tel,sms')
             );
     
    -        return ! in_array($scheme, $validSchemes, true)
    -            ? false
    -            : filter_var($str, FILTER_VALIDATE_URL) !== false;
    +        return in_array($scheme, $validSchemes, true)
    +            && filter_var($str, FILTER_VALIDATE_URL) !== false;
         }
     
         /**
    
    From fe2c565a5128672b33c7c143de0de721046683ea Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 11:16:17 +0900
    Subject: [PATCH 0605/2325] fix: remove incorrect processing of CLI params
    
    Fixes #5266
    ---
     system/HTTP/CLIRequest.php           |  6 +++---
     tests/system/HTTP/CLIRequestTest.php | 24 ++++++++++++++++++++++++
     2 files changed, 27 insertions(+), 3 deletions(-)
    
    diff --git a/system/HTTP/CLIRequest.php b/system/HTTP/CLIRequest.php
    index fcc2a51389d2..b10d41884733 100644
    --- a/system/HTTP/CLIRequest.php
    +++ b/system/HTTP/CLIRequest.php
    @@ -170,17 +170,17 @@ protected function parseCommand()
                     if ($optionValue) {
                         $optionValue = false;
                     } else {
    -                    $this->segments[] = esc(strip_tags($arg));
    +                    $this->segments[] = $arg;
                     }
     
                     continue;
                 }
     
    -            $arg   = esc(strip_tags(ltrim($arg, '-')));
    +            $arg   = ltrim($arg, '-');
                 $value = null;
     
                 if (isset($args[$i + 1]) && mb_strpos($args[$i + 1], '-') !== 0) {
    -                $value       = esc(strip_tags($args[$i + 1]));
    +                $value       = $args[$i + 1];
                     $optionValue = true;
                 }
     
    diff --git a/tests/system/HTTP/CLIRequestTest.php b/tests/system/HTTP/CLIRequestTest.php
    index c31bace6b554..1c7c23c1c21e 100644
    --- a/tests/system/HTTP/CLIRequestTest.php
    +++ b/tests/system/HTTP/CLIRequestTest.php
    @@ -61,6 +61,30 @@ public function testParsingSegments()
             $this->assertSame($segments, $this->request->getSegments());
         }
     
    +    public function testParsingSegmentsWithHTMLMetaChars()
    +    {
    +        $_SERVER['argv'] = [
    +            'index.php',
    +            'users',
    +            '21',
    +            'abc < def',
    +            "McDonald's",
    +            'aaa',
    +        ];
    +
    +        // reinstantiate it to force parsing
    +        $this->request = new CLIRequest(new App());
    +
    +        $segments = [
    +            'users',
    +            '21',
    +            'abc < def',
    +            "McDonald's",
    +            'aaa',
    +        ];
    +        $this->assertSame($segments, $this->request->getSegments());
    +    }
    +
         public function testParsingOptions()
         {
             $_SERVER['argv'] = [
    
    From eeaa4db60a2fd7fdb7daa7bcfb1fe73446e6e200 Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 15:37:45 +0900
    Subject: [PATCH 0606/2325] docs: move CSRF Protection Methods section up
    
    This is a basic config item, so it is better to have it at the beginning.
    ---
     user_guide_src/source/libraries/security.rst | 31 ++++++++++----------
     1 file changed, 15 insertions(+), 16 deletions(-)
    
    diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst
    index 48b97baf1f61..a7ee6e141f78 100644
    --- a/user_guide_src/source/libraries/security.rst
    +++ b/user_guide_src/source/libraries/security.rst
    @@ -26,6 +26,21 @@ Cross-site request forgery (CSRF)
     .. warning:: The CSRF Protection is only available for **POST/PUT/PATCH/DELETE** requests.
         Requests for other methods are not protected.
     
    +CSRF Protection Methods
    +=======================
    +
    +By default, the Cookie based CSRF Protection is used. It is
    +`Double Submit Cookie `_
    +on OWASP Cross-Site Request Forgery Prevention Cheat Sheet.
    +
    +You can also use Session based CSRF Protection. It is
    +`Synchronizer Token Pattern `_.
    +
    +You can set to use the Session based CSRF protection by editing the following config parameter value in
    +**app/Config/Security.php**::
    +
    +    public $csrfProtection = 'session';
    +
     Enable CSRF Protection
     ======================
     
    @@ -130,22 +145,6 @@ than simply crashing. This can be turned off by editing the following config par
     
     Even when the redirect value is ``true``, AJAX calls will not redirect, but will throw an error.
     
    -=======================
    -CSRF Protection Methods
    -=======================
    -
    -By default, the Cookie based CSRF Protection is used. It is
    -`Double Submit Cookie `_
    -on OWASP Cross-Site Request Forgery Prevention Cheat Sheet.
    -
    -You can also use Session based CSRF Protection. It is
    -`Synchronizer Token Pattern `_.
    -
    -You can set to use the Session based CSRF protection by editing the following config parameter value in
    -**app/Config/Security.php**::
    -
    -    public $csrfProtection = 'session';
    -
     *********************
     Other Helpful Methods
     *********************
    
    From 8ffd0ad3895b4d16f77817f25ba79f4e943549fc Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 15:44:35 +0900
    Subject: [PATCH 0607/2325] docs: fix sample code format
    
    ---
     user_guide_src/source/helpers/html_helper.rst | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst
    index a477b9cbd311..a7ad04914831 100755
    --- a/user_guide_src/source/helpers/html_helper.rst
    +++ b/user_guide_src/source/helpers/html_helper.rst
    @@ -79,7 +79,7 @@ The following functions are available:
             echo img($src);
     
         There is an optional second parameter to specify the MIME type, otherwise the
    -    function will use your Mimes config to guess.
    +    function will use your Mimes config to guess::
     
             $src = img_data('path/img_without_extension', 'image/png'); // data:image/png;base64,HT5A822...
     
    
    From 0705c535247a13a0ede50b53cea53d545464123e Mon Sep 17 00:00:00 2001
    From: kenjis 
    Date: Tue, 2 Nov 2021 15:47:50 +0900
    Subject: [PATCH 0608/2325] docs: decorate HTML tags with '``'
    
    ---
     user_guide_src/source/helpers/html_helper.rst | 20 +++++++++----------
     1 file changed, 10 insertions(+), 10 deletions(-)
    
    diff --git a/user_guide_src/source/helpers/html_helper.rst b/user_guide_src/source/helpers/html_helper.rst
    index a7ad04914831..8eb55fb649d0 100755
    --- a/user_guide_src/source/helpers/html_helper.rst
    +++ b/user_guide_src/source/helpers/html_helper.rst
    @@ -32,7 +32,7 @@ The following functions are available:
         :returns:   HTML image tag
         :rtype: string
     
    -    Lets you create HTML  tags. The first parameter contains the
    +    Lets you create HTML ```` tags. The first parameter contains the
         image source. Example::
     
             echo img('images/picture.jpg');
    @@ -99,7 +99,7 @@ The following functions are available:
         :returns:   HTML link tag
         :rtype: string
     
    -    Lets you create HTML  tags. This is useful for stylesheet links,
    +    Lets you create HTML ```` tags. This is useful for stylesheet links,
         as well as other links. The parameters are *href*, with optional *rel*,
         *type*, *title*, *media* and *indexPage*.
     
    @@ -139,7 +139,7 @@ The following functions are available:
         :returns:   HTML script tag
         :rtype: string
     
    -    Lets you create HTML  tags. The parameters is *src*, with optional *indexPage*.
    +    Lets you create HTML ```` tags. The parameters is *src*, with optional *indexPage*.
     
         *indexPage* is a boolean value that specifies if the *src* should have
         the page specified by ``$config['indexPage']`` added to the address it creates.
    @@ -284,8 +284,8 @@ The following functions are available:
         :returns:   HTML-formatted ordered list
         :rtype: string
     
    -    Identical to :php:func:`ul()`, only it produces the 
      tag for - ordered lists instead of
        . + Identical to :php:func:`ul()`, only it produces the ``
          `` tag for + ordered lists instead of ``
            ``. .. php:function:: video($src[, $unsupportedMessage = ''[, $attributes = ''[, $tracks = [][, $indexPage = false]]]]) @@ -359,7 +359,7 @@ The following functions are available: :returns: HTML-formatted audio element :rtype: string - Identical to :php:func:`video()`, only it produces the
    {duration} {! sql !}{trace-file}:{trace-line}
    Pathuri) ?>getUri()) ?>
    HTTP Method
    ', - - 'thead_open' => '', - 'thead_close' => '', - - 'heading_row_start' => '', - 'heading_row_end' => '', - 'heading_cell_start' => '', - - 'tfoot_open' => '', - 'tfoot_close' => '', - - 'footing_row_start' => '', - 'footing_row_end' => '', - 'footing_cell_start' => '', - - 'tbody_open' => '', - 'tbody_close' => '', - - 'row_start' => '', - 'row_end' => '', - 'cell_start' => '', - - 'row_alt_start' => '', - 'row_alt_end' => '', - 'cell_alt_start' => '', - - 'table_close' => '
    ', - 'heading_cell_end' => '
    ', - 'footing_cell_end' => '
    ', - 'cell_end' => '
    ', - 'cell_alt_end' => '
    ' - ]; +specify the design of your layout. Here is the template prototype: - $table->setTemplate($template); +.. literalinclude:: table/006.php + :lines: 2- .. note:: You'll notice there are two sets of "row" blocks in the template. These permit you to create alternating row colors or design @@ -130,23 +68,16 @@ specify the design of your layout. Here is the template prototype:: You are NOT required to submit a complete template. If you only need to change parts of the layout you can simply submit those elements. In this -example, only the table opening tag is being changed:: +example, only the table opening tag is being changed: - $template = [ - 'table_open' => '' - ]; - - $table->setTemplate($template); +.. literalinclude:: table/007.php + :lines: 2- You can also set defaults for these by passing an array of template settings -to the Table constructor.:: - - $customSettings = [ - 'table_open' => '
    ' - ]; - - $table = new \CodeIgniter\View\Table($customSettings); +to the Table constructor.: +.. literalinclude:: table/008.php + :lines: 2- *************** Class Reference @@ -157,15 +88,9 @@ Class Reference .. attribute:: $function = null Allows you to specify a native PHP function or a valid function array object to be applied to all cell data. - :: - - $table = new \CodeIgniter\View\Table(); - - $table->setHeading('Name', 'Color', 'Size'); - $table->addRow('Fred', 'Blue', 'Small'); - $table->function = 'htmlspecialchars'; - echo $table->generate(); + .. literalinclude:: table/009.php + :lines: 2- In the above example, all cell data would be run through PHP's :php:func:`htmlspecialchars()` function, resulting in:: @@ -186,9 +111,9 @@ Class Reference :rtype: Table Permits you to add a caption to the table. - :: - $table->setCaption('Colors'); + .. literalinclude:: table/010.php + :lines: 2- .. php:method:: setHeading([$args = [] [, ...]]) @@ -196,11 +121,10 @@ Class Reference :returns: Table instance (method chaining) :rtype: Table - Permits you to set the table heading. You can submit an array or discrete params:: + Permits you to set the table heading. You can submit an array or discrete params: - $table->setHeading('Name', 'Color', 'Size'); // or - - $table->setHeading(['Name', 'Color', 'Size']); + .. literalinclude:: table/011.php + :lines: 2- .. php:method:: setFooting([$args = [] [, ...]]) @@ -208,11 +132,10 @@ Class Reference :returns: Table instance (method chaining) :rtype: Table - Permits you to set the table footing. You can submit an array or discrete params:: - - $table->setFooting('Subtotal', $subtotal, $notes); // or + Permits you to set the table footing. You can submit an array or discrete params: - $table->setFooting(['Subtotal', $subtotal, $notes]); + .. literalinclude:: table/012.php + :lines: 2- .. php:method:: addRow([$args = [] [, ...]]) @@ -220,20 +143,16 @@ Class Reference :returns: Table instance (method chaining) :rtype: Table - Permits you to add a row to your table. You can submit an array or discrete params:: - - $table->addRow('Blue', 'Red', 'Green'); // or + Permits you to add a row to your table. You can submit an array or discrete params: - $table->addRow(['Blue', 'Red', 'Green']); + .. literalinclude:: table/013.php + :lines: 2- If you would like to set an individual cell's tag attributes, you can use an associative array for that cell. - The associative key **data** defines the cell's data. Any other key => val pairs are added as key='val' attributes to the tag:: + The associative key **data** defines the cell's data. Any other key => val pairs are added as key='val' attributes to the tag: - $cell = ['data' => 'Blue', 'class' => 'highlight', 'colspan' => 2]; - $table->addRow($cell, 'Red', 'Green'); - - // generates - // + .. literalinclude:: table/014.php + :lines: 2- .. php:method:: makeColumns([$array = [] [, $columnLimit = 0]]) @@ -243,27 +162,10 @@ Class Reference :rtype: array This method takes a one-dimensional array as input and creates a multi-dimensional array with a depth equal to the number of columns desired. - This allows a single array with many elements to be displayed in a table that has a fixed column count. Consider this example:: - - $list = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve']; - - $newList = $table->makeColumns($list, 3); - - $table->generate($newList); - - // Generates a table with this prototype - -
    BlueRedGreen
    - - - - - - - - -
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    + This allows a single array with many elements to be displayed in a table that has a fixed column count. Consider this example: + .. literalinclude:: table/015.php + :lines: 2- .. php:method:: setTemplate($template) @@ -272,13 +174,9 @@ Class Reference :rtype: bool Permits you to set your template. You can submit a full or partial template. - :: - - $template = [ - 'table_open' => '' - ]; - $table->setTemplate($template); + .. literalinclude:: table/016.php + :lines: 2- .. php:method:: setEmpty($value) @@ -287,9 +185,10 @@ Class Reference :rtype: Table Lets you set a default value for use in any table cells that are empty. - You might, for example, set a non-breaking space:: + You might, for example, set a non-breaking space: - $table->setEmpty(" "); + .. literalinclude:: table/017.php + :lines: 2- .. php:method:: clear() @@ -301,24 +200,7 @@ Class Reference should to call this method after each table has been generated to clear the previous table information. - Example :: - - $table = new \CodeIgniter\View\Table(); - - $table->setCaption('Preferences') - ->setHeading('Name', 'Color', 'Size') - ->addRow('Fred', 'Blue', 'Small') - ->addRow('Mary', 'Red', 'Large') - ->addRow('John', 'Green', 'Medium'); - - echo $table->generate(); - - $table->clear(); - - $table->setCaption('Shipping') - ->setHeading('Name', 'Day', 'Delivery') - ->addRow('Fred', 'Wednesday', 'Express') - ->addRow('Mary', 'Monday', 'Air') - ->addRow('John', 'Saturday', 'Overnight'); + Example - echo $table->generate(); + .. literalinclude:: table/018.php + :lines: 2- diff --git a/user_guide_src/source/outgoing/table/001.php b/user_guide_src/source/outgoing/table/001.php new file mode 100644 index 000000000000..dbd5ba323335 --- /dev/null +++ b/user_guide_src/source/outgoing/table/001.php @@ -0,0 +1,3 @@ +generate($data); diff --git a/user_guide_src/source/outgoing/table/003.php b/user_guide_src/source/outgoing/table/003.php new file mode 100644 index 000000000000..91218de3f143 --- /dev/null +++ b/user_guide_src/source/outgoing/table/003.php @@ -0,0 +1,7 @@ +query('SELECT * FROM my_table'); + +echo $table->generate($query); diff --git a/user_guide_src/source/outgoing/table/004.php b/user_guide_src/source/outgoing/table/004.php new file mode 100644 index 000000000000..0d0679305409 --- /dev/null +++ b/user_guide_src/source/outgoing/table/004.php @@ -0,0 +1,11 @@ +setHeading('Name', 'Color', 'Size'); + +$table->addRow('Fred', 'Blue', 'Small'); +$table->addRow('Mary', 'Red', 'Large'); +$table->addRow('John', 'Green', 'Medium'); + +echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/005.php b/user_guide_src/source/outgoing/table/005.php new file mode 100644 index 000000000000..06eaf75d9f8d --- /dev/null +++ b/user_guide_src/source/outgoing/table/005.php @@ -0,0 +1,11 @@ +setHeading(array('Name', 'Color', 'Size')); + +$table->addRow(['Fred', 'Blue', 'Small']); +$table->addRow(['Mary', 'Red', 'Large']); +$table->addRow(['John', 'Green', 'Medium']); + +echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/006.php b/user_guide_src/source/outgoing/table/006.php new file mode 100644 index 000000000000..2bc38b546950 --- /dev/null +++ b/user_guide_src/source/outgoing/table/006.php @@ -0,0 +1,38 @@ + '
    ', + + 'thead_open' => '', + 'thead_close' => '', + + 'heading_row_start' => '', + 'heading_row_end' => '', + 'heading_cell_start' => '', + + 'tfoot_open' => '', + 'tfoot_close' => '', + + 'footing_row_start' => '', + 'footing_row_end' => '', + 'footing_cell_start' => '', + + 'tbody_open' => '', + 'tbody_close' => '', + + 'row_start' => '', + 'row_end' => '', + 'cell_start' => '', + + 'row_alt_start' => '', + 'row_alt_end' => '', + 'cell_alt_start' => '', + + 'table_close' => '
    ', + 'heading_cell_end' => '
    ', + 'footing_cell_end' => '
    ', + 'cell_end' => '
    ', + 'cell_alt_end' => '
    ' +]; + +$table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/007.php b/user_guide_src/source/outgoing/table/007.php new file mode 100644 index 000000000000..307d2e9a6c26 --- /dev/null +++ b/user_guide_src/source/outgoing/table/007.php @@ -0,0 +1,7 @@ + '' +]; + +$table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/008.php b/user_guide_src/source/outgoing/table/008.php new file mode 100644 index 000000000000..9d6dbddd40c6 --- /dev/null +++ b/user_guide_src/source/outgoing/table/008.php @@ -0,0 +1,7 @@ + '
    ' +]; + +$table = new \CodeIgniter\View\Table($customSettings); diff --git a/user_guide_src/source/outgoing/table/009.php b/user_guide_src/source/outgoing/table/009.php new file mode 100644 index 000000000000..c08af5b1fa9a --- /dev/null +++ b/user_guide_src/source/outgoing/table/009.php @@ -0,0 +1,9 @@ +setHeading('Name', 'Color', 'Size'); +$table->addRow('Fred', 'Blue', 'Small'); + +$table->function = 'htmlspecialchars'; +echo $table->generate(); diff --git a/user_guide_src/source/outgoing/table/010.php b/user_guide_src/source/outgoing/table/010.php new file mode 100644 index 000000000000..0c6a74ea5b35 --- /dev/null +++ b/user_guide_src/source/outgoing/table/010.php @@ -0,0 +1,3 @@ +setCaption('Colors'); diff --git a/user_guide_src/source/outgoing/table/011.php b/user_guide_src/source/outgoing/table/011.php new file mode 100644 index 000000000000..a6657c8690e4 --- /dev/null +++ b/user_guide_src/source/outgoing/table/011.php @@ -0,0 +1,5 @@ +setHeading('Name', 'Color', 'Size'); // or + +$table->setHeading(['Name', 'Color', 'Size']); diff --git a/user_guide_src/source/outgoing/table/012.php b/user_guide_src/source/outgoing/table/012.php new file mode 100644 index 000000000000..01a26b237908 --- /dev/null +++ b/user_guide_src/source/outgoing/table/012.php @@ -0,0 +1,5 @@ +setFooting('Subtotal', $subtotal, $notes); // or + +$table->setFooting(['Subtotal', $subtotal, $notes]); diff --git a/user_guide_src/source/outgoing/table/013.php b/user_guide_src/source/outgoing/table/013.php new file mode 100644 index 000000000000..1229bd01d7cd --- /dev/null +++ b/user_guide_src/source/outgoing/table/013.php @@ -0,0 +1,5 @@ +addRow('Blue', 'Red', 'Green'); // or + +$table->addRow(['Blue', 'Red', 'Green']); diff --git a/user_guide_src/source/outgoing/table/014.php b/user_guide_src/source/outgoing/table/014.php new file mode 100644 index 000000000000..eb2e3d729a8c --- /dev/null +++ b/user_guide_src/source/outgoing/table/014.php @@ -0,0 +1,7 @@ + 'Blue', 'class' => 'highlight', 'colspan' => 2]; +$table->addRow($cell, 'Red', 'Green'); + +// generates +// diff --git a/user_guide_src/source/outgoing/table/015.php b/user_guide_src/source/outgoing/table/015.php new file mode 100644 index 000000000000..4f4349ec66b4 --- /dev/null +++ b/user_guide_src/source/outgoing/table/015.php @@ -0,0 +1,20 @@ +makeColumns($list, 3); + +$table->generate($newList); + +// Generates a table with this prototype + +
    BlueRedGreen
    + + + + + + + + +
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    diff --git a/user_guide_src/source/outgoing/table/016.php b/user_guide_src/source/outgoing/table/016.php new file mode 100644 index 000000000000..307d2e9a6c26 --- /dev/null +++ b/user_guide_src/source/outgoing/table/016.php @@ -0,0 +1,7 @@ + '' +]; + +$table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/017.php b/user_guide_src/source/outgoing/table/017.php new file mode 100644 index 000000000000..41ecff5926c7 --- /dev/null +++ b/user_guide_src/source/outgoing/table/017.php @@ -0,0 +1,3 @@ +setEmpty(" "); diff --git a/user_guide_src/source/outgoing/table/018.php b/user_guide_src/source/outgoing/table/018.php new file mode 100644 index 000000000000..c67c746bde9b --- /dev/null +++ b/user_guide_src/source/outgoing/table/018.php @@ -0,0 +1,21 @@ +setCaption('Preferences') + ->setHeading('Name', 'Color', 'Size') + ->addRow('Fred', 'Blue', 'Small') + ->addRow('Mary', 'Red', 'Large') + ->addRow('John', 'Green', 'Medium'); + +echo $table->generate(); + +$table->clear(); + +$table->setCaption('Shipping') + ->setHeading('Name', 'Day', 'Delivery') + ->addRow('Fred', 'Wednesday', 'Express') + ->addRow('Mary', 'Monday', 'Air') + ->addRow('John', 'Saturday', 'Overnight'); + +echo $table->generate(); diff --git a/user_guide_src/source/outgoing/view_decorators.rst b/user_guide_src/source/outgoing/view_decorators.rst index 513e9c1a3f0a..1620446785b0 100644 --- a/user_guide_src/source/outgoing/view_decorators.rst +++ b/user_guide_src/source/outgoing/view_decorators.rst @@ -13,29 +13,12 @@ Creating your own view decorators requires creating a new class that implements This requires a single method that takes the generated HTML string, performs any modifications on it, and returns the resulting HTML. -:: +.. literalinclude:: view_decorators/001.php - endSection() ?> endSection() ?> - ****************** Rendering the View ****************** -Rendering the view and it's layout is done exactly as any other view would be displayed within a controller:: +Rendering the view and it's layout is done exactly as any other view would be displayed within a controller: - public function index() - { - echo view('some_view'); - } +.. literalinclude:: view_layouts/001.php + :lines: 2- It renders the View **app/Views/some_view.php** and if it extends ``default``, the Layout **app/Views/default.php** is also used automatically. diff --git a/user_guide_src/source/outgoing/view_layouts/001.php b/user_guide_src/source/outgoing/view_layouts/001.php new file mode 100644 index 000000000000..5c6136bfe9ee --- /dev/null +++ b/user_guide_src/source/outgoing/view_layouts/001.php @@ -0,0 +1,6 @@ + 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - ]; - - echo $parser->setData($data) - ->render('blog_template'); +.. literalinclude:: view_parser/003.php + :lines: 2- View parameters are passed to ``setData()`` as an associative array of data to be replaced in the template. In the above example, the @@ -116,12 +113,8 @@ Several options can be passed to the ``render()`` or ``renderString()`` methods. - ``cascadeData`` - true if pseudo-variable settings should be passed on to nested substitutions; default is **true** -:: - - echo $parser->render('blog_template', [ - 'cache' => HOUR, - 'cache_name' => 'something_unique', - ]); +.. literalinclude:: view_parser/004.php + :lines: 2- *********************** Substitution Variations @@ -132,14 +125,10 @@ Substitutions are performed in the same sequence that pseudo-variables were adde The **simple substitution** performed by the parser is a one-to-one replacement of pseudo-variables where the corresponding data parameter -has either a scalar or string value, as in this example:: - - $template = '{blog_title}'; - $data = ['blog_title' => 'My ramblings']; - - echo $parser->setData($data)->renderString($template); +has either a scalar or string value, as in this example: - // Result: My ramblings +.. literalinclude:: view_parser/005.php + :lines: 2- The ``Parser`` takes substitution a lot further with "variable pairs", used for nested substitutions or looping, and with some advanced @@ -184,22 +173,10 @@ the number of rows in the "blog_entries" element of the parameters array. Parsing variable pairs is done using the identical code shown above to parse single variables, except, you will add a multi-dimensional array -corresponding to your variable pair data. Consider this example:: +corresponding to your variable pair data. Consider this example: - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => [ - ['title' => 'Title 1', 'body' => 'Body 1'], - ['title' => 'Title 2', 'body' => 'Body 2'], - ['title' => 'Title 3', 'body' => 'Body 3'], - ['title' => 'Title 4', 'body' => 'Body 4'], - ['title' => 'Title 5', 'body' => 'Body 5'], - ], - ]; - - echo $parser->setData($data) - ->render('blog_template'); +.. literalinclude:: view_parser/006.php + :lines: 2- The value for the pseudo-variable ``blog_entries`` is a sequential array of associative arrays. The outer level does not have keys associated @@ -207,18 +184,10 @@ with each of the nested "rows". If your "pair" data is coming from a database result, which is already a multi-dimensional array, you can simply use the database ``getResultArray()`` -method:: - - $query = $db->query("SELECT * FROM blog"); - - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entries' => $query->getResultArray(), - ]; +method: - echo $parser->setData($data) - ->render('blog_template'); +.. literalinclude:: view_parser/007.php + :lines: 2- If the array you are trying to loop over contains objects instead of arrays, the parser will first look for an ``asArray()`` method on the object. If it exists, @@ -234,19 +203,10 @@ Nested Substitutions ==================== A nested substitution happens when the value for a pseudo-variable is -an associative array of values, like a record from a database:: - - $data = [ - 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading', - 'blog_entry' => [ - 'title' => 'Title 1', - 'body' => 'Body 1', - ], - ]; +an associative array of values, like a record from a database: - echo $parser->setData($data) - ->render('blog_template'); +.. literalinclude:: view_parser/008.php + :lines: 2- The value for the pseudo-variable ``blog_entry`` is an associative array. The key/value pairs defined inside it will be exposed inside @@ -287,32 +247,15 @@ Cascading Data With both a nested and a loop substitution, you have the option of cascading data pairs into the inner substitution. -The following example is not impacted by cascading:: - - $template = '{name} lives in {location}{city} on {planet}{/location}.'; - - $data = [ - 'name' => 'George', - 'location' => ['city' => 'Red City', 'planet' => 'Mars'], - ]; - - echo $parser->setData($data)->renderString($template); - // Result: George lives in Red City on Mars. - -This example gives different results, depending on cascading:: - - $template = '{location}{name} lives in {city} on {planet}{/location}.'; +The following example is not impacted by cascading: - $data = [ - 'name' => 'George', - 'location' => ['city' => 'Red City', 'planet' => 'Mars'], - ]; +.. literalinclude:: view_parser/009.php + :lines: 2- - echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]); - // Result: {name} lives in Red City on Mars. +This example gives different results, depending on cascading: - echo $parser->setData($data)->renderString($template, ['cascadeData'=>true]); - // Result: George lives in Red City on Mars. +.. literalinclude:: view_parser/010.php + :lines: 2- Preventing Parsing ================== @@ -336,11 +279,9 @@ blocks must be closed with an ``endif`` tag::

    Welcome, Admin!

    {endif} -This simple block is converted to the following during parsing:: +This simple block is converted to the following during parsing: - -

    Welcome, Admin!

    - +.. literalinclude:: view_parser/010-2.php All variables used within if statements must have been previously set with the same name. Other than that, it is treated exactly like a standard PHP conditional, and all standard PHP rules would apply here. You can use any @@ -470,23 +411,20 @@ Custom Filters You can easily create your own filters by editing **app/Config/View.php** and adding new entries to the ``$filters`` array. Each key is the name of the filter is called by in the view, and its value is any valid PHP -callable:: +callable: - public $filters = [ - 'abs' => '\CodeIgniter\View\Filters::abs', - 'capitalize' => '\CodeIgniter\View\Filters::capitalize', - ]; +.. literalinclude:: view_parser/011.php + :lines: 2- PHP Native functions as Filters ------------------------------- You can use native php function as filters by editing **app/Config/View.php** and adding new entries to the ``$filters`` array.Each key is the name of the native PHP function is called by in the view, and its value is any valid native PHP -function prefixed with:: +function prefixed with: - public $filters = [ - 'str_repeat' => '\str_repeat', - ]; +.. literalinclude:: view_parser/012.php + :lines: 2- Parser Plugins ============== @@ -541,100 +479,50 @@ Registering a Plugin At its simplest, all you need to do to register a new plugin and make it ready for use is to add it to the **app/Config/View.php**, under the **$plugins** array. The key is the name of the plugin that is -used within the template file. The value is any valid PHP callable, including static class methods, and closures:: - - public $plugins = [ - 'foo' => '\Some\Class::methodName', - 'bar' => function ($str, array $params=[]) { - return $str; - }, - ]; - -Any closures that are being used must be defined in the config file's constructor:: +used within the template file. The value is any valid PHP callable, including static class methods, and closures: - class View extends \CodeIgniter\Config\View - { - public $plugins = []; +.. literalinclude:: view_parser/013.php + :lines: 2- - public function __construct() - { - $this->plugins['bar'] = function (array $params=[]) { - return $params[0] ?? ''; - }; +Any closures that are being used must be defined in the config file's constructor: - parent::__construct(); - } - } +.. literalinclude:: view_parser/014.php + :lines: 2- If the callable is on its own, it is treated as a single tag, not a open/close one. It will be replaced by -the return value from the plugin:: +the return value from the plugin: - public $plugins = [ - 'foo' => '\Some\Class::methodName' - ]; - - // Tag is replaced by the return value of Some\Class::methodName static function. - {+ foo +} +.. literalinclude:: view_parser/015.php + :lines: 2- If the callable is wrapped in an array, it is treated as an open/close tag pair that can operate on any of -the content between its tags:: - - public $plugins = [ - 'foo' => ['\Some\Class::methodName'] - ]; +the content between its tags: - {+ foo +} inner content {+ /foo +} +.. literalinclude:: view_parser/016.php + :lines: 2- *********** Usage Notes *********** If you include substitution parameters that are not referenced in your -template, they are ignored:: - - $template = 'Hello, {firstname} {lastname}'; - $data = [ - 'title' => 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe' - ]; - echo $parser->setData($data) - ->renderString($template); +template, they are ignored: - // Result: Hello, John Doe +.. literalinclude:: view_parser/017.php + :lines: 2- If you do not include a substitution parameter that is referenced in your -template, the original pseudo-variable is shown in the result:: +template, the original pseudo-variable is shown in the result: - $template = 'Hello, {firstname} {initials} {lastname}'; - $data = [ - 'title' => 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', - ]; - echo $parser->setData($data) - ->renderString($template); - - // Result: Hello, John {initials} Doe +.. literalinclude:: view_parser/018.php + :lines: 2- If you provide a string substitution parameter when an array is expected, i.e., for a variable pair, the substitution is done for the opening variable -pair tag, but the closing variable pair tag is not rendered properly:: +pair tag, but the closing variable pair tag is not rendered properly: - $template = 'Hello, {firstname} {lastname} ({degrees}{degree} {/degrees})'; - $data = [ - 'degrees' => 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe', - 'titles' => [ - ['degree' => 'BSc'], - ['degree' => 'PhD'], - ], - ]; - echo $parser->setData($data) - ->renderString($template); - - // Result: Hello, John Doe (Mr{degree} {/degrees}) +.. literalinclude:: view_parser/019.php + :lines: 2- View Fragments ============== @@ -667,25 +555,10 @@ Result:: An example with the iteration controlled in the controller, -using a view fragment:: - - $temp = ''; - $template1 = '
  • {title}
  • '; - $data1 = [ - ['title' => 'First Link', 'link' => '/first'], - ['title' => 'Second Link', 'link' => '/second'], - ]; - - foreach ($data1 as $menuItem),{ - $temp .= $parser->setData($menuItem)->renderString($template1); - } +using a view fragment: - $template2 = '
      {menuitems}
    '; - $data = [ - 'menuitems' => $temp, - ]; - echo $parser->setData($data) - ->renderString($template2); +.. literalinclude:: view_parser/020.php + :lines: 2- Result:: @@ -708,9 +581,10 @@ Class Reference :returns: The rendered text for the chosen view :rtype: string - Builds the output based upon a file name and any data that has already been set:: + Builds the output based upon a file name and any data that has already been set: - echo $parser->render('myview'); + .. literalinclude:: view_parser/021.php + :lines: 2- Options supported: @@ -732,9 +606,10 @@ Class Reference :returns: The rendered text for the chosen view :rtype: string - Builds the output based upon a provided template source and any data that has already been set:: + Builds the output based upon a provided template source and any data that has already been set: - echo $parser->render('myview'); + .. literalinclude:: view_parser/021.php + :lines: 2- Options supported, and behavior, as above. @@ -745,9 +620,10 @@ Class Reference :returns: The Renderer, for method chaining :rtype: CodeIgniter\\View\\RendererInterface. - Sets several pieces of view data at once:: + Sets several pieces of view data at once: - $renderer->setData(['name' => 'George', 'position' => 'Boss']); + .. literalinclude:: view_parser/023.php + :lines: 2- Supported escape contexts: html, css, js, url, or attr or raw. If 'raw', no escaping will happen. @@ -760,9 +636,10 @@ Class Reference :returns: The Renderer, for method chaining :rtype: CodeIgniter\\View\\RendererInterface. - Sets a single piece of view data:: + Sets a single piece of view data: - $renderer->setVar('name','Joe','html'); + .. literalinclude:: view_parser/024.php + :lines: 2- Supported escape contexts: html, css, js, url, attr or raw. If 'raw', no escaping will happen. @@ -774,6 +651,7 @@ Class Reference :returns: The Renderer, for method chaining :rtype: CodeIgniter\\View\\RendererInterface. - Override the substitution field delimiters:: + Override the substitution field delimiters: - $renderer->setDelimiters('[',']'); + .. literalinclude:: view_parser/025.php + :lines: 2- diff --git a/user_guide_src/source/outgoing/view_parser/001.php b/user_guide_src/source/outgoing/view_parser/001.php new file mode 100644 index 000000000000..56f7f51e4a07 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/001.php @@ -0,0 +1,3 @@ + 'My Blog Title', + 'blog_heading' => 'My Blog Heading', +]; + +echo $parser->setData($data) + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/004.php b/user_guide_src/source/outgoing/view_parser/004.php new file mode 100644 index 000000000000..70862b585adc --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/004.php @@ -0,0 +1,6 @@ +render('blog_template', [ + 'cache' => HOUR, + 'cache_name' => 'something_unique', +]); diff --git a/user_guide_src/source/outgoing/view_parser/005.php b/user_guide_src/source/outgoing/view_parser/005.php new file mode 100644 index 000000000000..6681b588d74e --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/005.php @@ -0,0 +1,8 @@ +{blog_title}'; +$data = ['blog_title' => 'My ramblings']; + +echo $parser->setData($data)->renderString($template); + +// Result: My ramblings diff --git a/user_guide_src/source/outgoing/view_parser/006.php b/user_guide_src/source/outgoing/view_parser/006.php new file mode 100644 index 000000000000..1bedecc07c0a --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/006.php @@ -0,0 +1,16 @@ + 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + 'blog_entries' => [ + ['title' => 'Title 1', 'body' => 'Body 1'], + ['title' => 'Title 2', 'body' => 'Body 2'], + ['title' => 'Title 3', 'body' => 'Body 3'], + ['title' => 'Title 4', 'body' => 'Body 4'], + ['title' => 'Title 5', 'body' => 'Body 5'], + ], +]; + +echo $parser->setData($data) + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/007.php b/user_guide_src/source/outgoing/view_parser/007.php new file mode 100644 index 000000000000..8932712a7835 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/007.php @@ -0,0 +1,12 @@ +query("SELECT * FROM blog"); + +$data = [ + 'blog_title' => 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + 'blog_entries' => $query->getResultArray(), +]; + +echo $parser->setData($data) + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/008.php b/user_guide_src/source/outgoing/view_parser/008.php new file mode 100644 index 000000000000..ef502cf5e3af --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/008.php @@ -0,0 +1,13 @@ + 'My Blog Title', + 'blog_heading' => 'My Blog Heading', + 'blog_entry' => [ + 'title' => 'Title 1', + 'body' => 'Body 1', + ], +]; + +echo $parser->setData($data) + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/009.php b/user_guide_src/source/outgoing/view_parser/009.php new file mode 100644 index 000000000000..6b112fdd6829 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/009.php @@ -0,0 +1,11 @@ + 'George', + 'location' => ['city' => 'Red City', 'planet' => 'Mars'], +]; + +echo $parser->setData($data)->renderString($template); +// Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/010-2.php b/user_guide_src/source/outgoing/view_parser/010-2.php new file mode 100644 index 000000000000..8030f44e8883 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/010-2.php @@ -0,0 +1,3 @@ + +

    Welcome, Admin!

    + diff --git a/user_guide_src/source/outgoing/view_parser/010.php b/user_guide_src/source/outgoing/view_parser/010.php new file mode 100644 index 000000000000..33439f861407 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/010.php @@ -0,0 +1,14 @@ + 'George', + 'location' => ['city' => 'Red City', 'planet' => 'Mars'], +]; + +echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]); +// Result: {name} lives in Red City on Mars. + +echo $parser->setData($data)->renderString($template, ['cascadeData'=>true]); +// Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/011.php b/user_guide_src/source/outgoing/view_parser/011.php new file mode 100644 index 000000000000..39eae3da0177 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/011.php @@ -0,0 +1,6 @@ + '\CodeIgniter\View\Filters::abs', + 'capitalize' => '\CodeIgniter\View\Filters::capitalize', +]; diff --git a/user_guide_src/source/outgoing/view_parser/012.php b/user_guide_src/source/outgoing/view_parser/012.php new file mode 100644 index 000000000000..dbb096b416fb --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/012.php @@ -0,0 +1,5 @@ + '\str_repeat', +]; diff --git a/user_guide_src/source/outgoing/view_parser/013.php b/user_guide_src/source/outgoing/view_parser/013.php new file mode 100644 index 000000000000..d959d153d415 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/013.php @@ -0,0 +1,8 @@ + '\Some\Class::methodName', + 'bar' => function ($str, array $params=[]) { + return $str; + }, +]; diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php new file mode 100644 index 000000000000..bac6137888f1 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -0,0 +1,15 @@ +plugins['bar'] = function (array $params=[]) { + return $params[0] ?? ''; + }; + + parent::__construct(); + } +} diff --git a/user_guide_src/source/outgoing/view_parser/015.php b/user_guide_src/source/outgoing/view_parser/015.php new file mode 100644 index 000000000000..74a18943365c --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/015.php @@ -0,0 +1,8 @@ + '\Some\Class::methodName' +]; + +// Tag is replaced by the return value of Some\Class::methodName static function. +{+ foo +} diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php new file mode 100644 index 000000000000..30d72b247059 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -0,0 +1,7 @@ + ['\Some\Class::methodName'] +]; + +{+ foo +} inner content {+ /foo +} diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php new file mode 100644 index 000000000000..cd9ca09109b9 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/017.php @@ -0,0 +1,12 @@ + 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe' +]; +echo $parser->setData($data) + ->renderString($template); + +// Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php new file mode 100644 index 000000000000..dfce0c26ccb4 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/018.php @@ -0,0 +1,12 @@ + 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe', +]; +echo $parser->setData($data) + ->renderString($template); + +// Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php new file mode 100644 index 000000000000..371fa9a21f14 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/019.php @@ -0,0 +1,16 @@ + 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe', + 'titles' => [ + ['degree' => 'BSc'], + ['degree' => 'PhD'], + ], +]; +echo $parser->setData($data) + ->renderString($template); + +// Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php new file mode 100644 index 000000000000..cf7b31fa7e30 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/020.php @@ -0,0 +1,19 @@ +{title}'; +$data1 = [ + ['title' => 'First Link', 'link' => '/first'], + ['title' => 'Second Link', 'link' => '/second'], +]; + +foreach ($data1 as $menuItem),{ + $temp .= $parser->setData($menuItem)->renderString($template1); +} + +$template2 = '
      {menuitems}
    '; +$data = [ + 'menuitems' => $temp, +]; +echo $parser->setData($data) + ->renderString($template2); diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php new file mode 100644 index 000000000000..022450bb6fd6 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/021.php @@ -0,0 +1,3 @@ +render('myview'); diff --git a/user_guide_src/source/outgoing/view_parser/022.php b/user_guide_src/source/outgoing/view_parser/022.php new file mode 100644 index 000000000000..022450bb6fd6 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/022.php @@ -0,0 +1,3 @@ +render('myview'); diff --git a/user_guide_src/source/outgoing/view_parser/023.php b/user_guide_src/source/outgoing/view_parser/023.php new file mode 100644 index 000000000000..42ddfa949331 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/023.php @@ -0,0 +1,3 @@ +setData(['name' => 'George', 'position' => 'Boss']); diff --git a/user_guide_src/source/outgoing/view_parser/024.php b/user_guide_src/source/outgoing/view_parser/024.php new file mode 100644 index 000000000000..76ba0b537f96 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/024.php @@ -0,0 +1,3 @@ +setVar('name','Joe','html'); diff --git a/user_guide_src/source/outgoing/view_parser/025.php b/user_guide_src/source/outgoing/view_parser/025.php new file mode 100644 index 000000000000..a8633d5717c7 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/025.php @@ -0,0 +1,3 @@ +setDelimiters('[',']'); diff --git a/user_guide_src/source/outgoing/view_renderer.rst b/user_guide_src/source/outgoing/view_renderer.rst index 7da85b6f9546..bf1570cede9c 100644 --- a/user_guide_src/source/outgoing/view_renderer.rst +++ b/user_guide_src/source/outgoing/view_renderer.rst @@ -12,14 +12,16 @@ Using the View Renderer The ``view()`` function is a convenience function that grabs an instance of the ``renderer`` service, sets the data, and renders the view. While this is often exactly what you want, you may find times where you want to work with it more directly. -In that case you can access the View service directly:: +In that case you can access the View service directly: - $view = \Config\Services::renderer(); +.. literalinclude:: view_renderer/001.php + :lines: 2- Alternately, if you are not using the ``View`` class as your default renderer, you -can instantiate it directly:: +can instantiate it directly: - $view = new \CodeIgniter\View\View(); +.. literalinclude:: view_renderer/002.php + :lines: 2- .. important:: You should create services only within controllers. If you need access to the View class from a library, you should set that as a dependency @@ -49,11 +51,10 @@ Method Chaining =============== The ``setVar()`` and ``setData()`` methods are chainable, allowing you to combine a -number of different calls together in a chain:: +number of different calls together in a chain: - $view->setVar('one', $one) - ->setVar('two', $two) - ->render('myView'); +.. literalinclude:: view_renderer/003.php + :lines: 2- Escaping Data ============= @@ -62,9 +63,10 @@ When you pass data to the ``setVar()`` and ``setData()`` functions you have the against cross-site scripting attacks. As the last parameter in either method, you can pass the desired context to escape the data for. See below for context descriptions. -If you don't want the data to be escaped, you can pass ``null`` or ``'raw'`` as the final parameter to each function:: +If you don't want the data to be escaped, you can pass ``null`` or ``'raw'`` as the final parameter to each function: - $view->setVar('one', $one, 'raw'); +.. literalinclude:: view_renderer/004.php + :lines: 2- If you choose not to escape data, or you are passing in an object instance, you can manually escape the data within the view with the ``esc()`` function. The first parameter is the string to escape. The second parameter is the @@ -118,9 +120,10 @@ Class Reference :returns: The rendered text for the chosen view :rtype: string - Builds the output based upon a file name and any data that has already been set:: + Builds the output based upon a file name and any data that has already been set: - echo $view->render('myview'); + .. literalinclude:: view_renderer/005.php + :lines: 2- .. php:method:: renderString($view[, $options[, $saveData = false]]) :noindex: @@ -131,9 +134,10 @@ Class Reference :returns: The rendered text for the chosen view :rtype: string - Builds the output based upon a view fragment and any data that has already been set:: + Builds the output based upon a view fragment and any data that has already been set: - echo $view->renderString('
    My Sharona
    '); + .. literalinclude:: view_renderer/006.php + :lines: 2- .. warning:: This could be used for displaying content that might have been stored in a database, but you need to be aware that this is a potential security vulnerability, @@ -148,9 +152,10 @@ Class Reference :returns: The Renderer, for method chaining :rtype: CodeIgniter\\View\\RendererInterface. - Sets several pieces of view data at once:: + Sets several pieces of view data at once: - $view->setData(['name'=>'George', 'position'=>'Boss']); + .. literalinclude:: view_renderer/007.php + :lines: 2- Supported escape contexts: ``html``, ``css``, ``js``, ``url``, or ``attr`` or ``raw``. If ``'raw'``, no escaping will happen. @@ -167,9 +172,10 @@ Class Reference :returns: The Renderer, for method chaining :rtype: CodeIgniter\\View\\RendererInterface. - Sets a single piece of view data:: + Sets a single piece of view data: - $view->setVar('name','Joe','html'); + .. literalinclude:: view_renderer/008.php + :lines: 2- Supported escape contexts: ``html``, ``css``, ``js``, ``url``, ``attr`` or ``raw``. If ``'raw'``, no escaping will happen. diff --git a/user_guide_src/source/outgoing/view_renderer/001.php b/user_guide_src/source/outgoing/view_renderer/001.php new file mode 100644 index 000000000000..2772e22cad0d --- /dev/null +++ b/user_guide_src/source/outgoing/view_renderer/001.php @@ -0,0 +1,3 @@ +setVar('one', $one) + ->setVar('two', $two) + ->render('myView'); diff --git a/user_guide_src/source/outgoing/view_renderer/004.php b/user_guide_src/source/outgoing/view_renderer/004.php new file mode 100644 index 000000000000..b690f3478c82 --- /dev/null +++ b/user_guide_src/source/outgoing/view_renderer/004.php @@ -0,0 +1,3 @@ +setVar('one', $one, 'raw'); diff --git a/user_guide_src/source/outgoing/view_renderer/005.php b/user_guide_src/source/outgoing/view_renderer/005.php new file mode 100644 index 000000000000..9bb35502f352 --- /dev/null +++ b/user_guide_src/source/outgoing/view_renderer/005.php @@ -0,0 +1,3 @@ +render('myview'); diff --git a/user_guide_src/source/outgoing/view_renderer/006.php b/user_guide_src/source/outgoing/view_renderer/006.php new file mode 100644 index 000000000000..8f3c21abd99d --- /dev/null +++ b/user_guide_src/source/outgoing/view_renderer/006.php @@ -0,0 +1,3 @@ +renderString('
    My Sharona
    '); diff --git a/user_guide_src/source/outgoing/view_renderer/007.php b/user_guide_src/source/outgoing/view_renderer/007.php new file mode 100644 index 000000000000..1b45fef3dca5 --- /dev/null +++ b/user_guide_src/source/outgoing/view_renderer/007.php @@ -0,0 +1,3 @@ +setData(['name'=>'George', 'position'=>'Boss']); diff --git a/user_guide_src/source/outgoing/view_renderer/008.php b/user_guide_src/source/outgoing/view_renderer/008.php new file mode 100644 index 000000000000..284b58caf6be --- /dev/null +++ b/user_guide_src/source/outgoing/view_renderer/008.php @@ -0,0 +1,3 @@ +setVar('name','Joe','html'); diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 96e350216ce7..9c386f3feb7c 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -35,27 +35,18 @@ Then save the file in your **app/Views** directory. Displaying a View ================= -To load and display a particular view file you will use the following function:: +To load and display a particular view file you will use the following function: - echo view('name'); +.. literalinclude:: views/001.php + :lines: 2- Where *name* is the name of your view file. .. important:: If the file extension is omitted, then the views are expected to end with the .php extension. -Now, open the controller file you made earlier called ``Blog.php``, and replace the echo statement with the view function:: +Now, open the controller file you made earlier called ``Blog.php``, and replace the echo statement with the view function: - 'Your title', - ]; +content view, and a footer view. That might look something like this: - echo view('header'); - echo view('menu'); - echo view('content', $data); - echo view('footer'); - } - } +.. literalinclude:: views/003.php In the example above, we are using "dynamically added data", which you will see below. @@ -96,9 +70,10 @@ Storing Views within Sub-directories ==================================== Your view files can also be stored within sub-directories if you prefer that type of organization. -When doing so you will need to include the directory name loading the view. Example:: +When doing so you will need to include the directory name loading the view. Example: - echo view('directory_name/file_name'); +.. literalinclude:: views/004.php + :lines: 2- Namespaced Views ================ @@ -109,9 +84,10 @@ to package your views together in a module-like fashion for easy re-use or distr If you have ``example/blog`` directory that has a PSR-4 mapping set up in the :doc:`Autoloader ` living under the namespace ``Example\Blog``, you could retrieve view files as if they were namespaced also. Following this -example, you could load the **blog_view.php** file from **example/blog/Views** by prepending the namespace to the view name:: +example, you could load the **blog_view.php** file from **example/blog/Views** by prepending the namespace to the view name: - echo view('Example\Blog\Views\blog_view'); +.. literalinclude:: views/005.php + :lines: 2- .. _caching-views: @@ -119,47 +95,29 @@ Caching Views ============= You can cache a view with the ``view`` command by passing a ``cache`` option with the number of seconds to cache -the view for, in the third parameter:: +the view for, in the third parameter: - // Cache the view for 60 seconds - echo view('file_name', $data, ['cache' => 60]); +.. literalinclude:: views/006.php + :lines: 2- By default, the view will be cached using the same name as the view file itself. You can customize this by passing -along ``cache_name`` and the cache ID you wish to use:: +along ``cache_name`` and the cache ID you wish to use: - // Cache the view for 60 seconds - echo view('file_name', $data, ['cache' => 60, 'cache_name' => 'my_cached_view']); +.. literalinclude:: views/007.php + :lines: 2- Adding Dynamic Data to the View =============================== Data is passed from the controller to the view by way of an array in the second parameter of the view function. -Here's an example:: +Here's an example: - $data = [ - 'title' => 'My title', - 'heading' => 'My Heading', - 'message' => 'My Message', - ]; +.. literalinclude:: views/008.php + :lines: 2- - echo view('blog_view', $data); +Let's try it with your controller file. Open it and add this code: -Let's try it with your controller file. Open it and add this code:: - - 'My title', - 'heading' => 'My Heading', - 'message' => 'My Message', - ]; - echo view('blog_view', $data, ['saveData' => true]); +.. literalinclude:: views/010.php + :lines: 2- Additionally, if you would like the default functionality of the view function to be that it does save the data between calls, you can set ``$saveData`` to **true** in **app/Config/Views.php**. @@ -198,44 +150,10 @@ The data array you pass to your view files is not limited to simple variables. Y arrays, which can be looped to generate multiple rows. For example, if you pull data from your database it will typically be in the form of a multi-dimensional array. -Here’s a simple example. Add this to your controller:: +Here’s a simple example. Add this to your controller: - ['Clean House', 'Call Mom', 'Run Errands'], - 'title' => 'My Real Title', - 'heading' => 'My Real Heading', - ]; - - echo view('blog_view', $data); - } - } - -Now open your view file and create a loop:: - - - - <?= esc($title) ?> - - -

    - -

    My Todo List

    - -
      - - -
    • - - -
    - - - +.. literalinclude:: views/012.php diff --git a/user_guide_src/source/outgoing/views/001.php b/user_guide_src/source/outgoing/views/001.php new file mode 100644 index 000000000000..90c817235bf5 --- /dev/null +++ b/user_guide_src/source/outgoing/views/001.php @@ -0,0 +1,3 @@ + 'Your title', + ]; + + echo view('header'); + echo view('menu'); + echo view('content', $data); + echo view('footer'); + } +} diff --git a/user_guide_src/source/outgoing/views/004.php b/user_guide_src/source/outgoing/views/004.php new file mode 100644 index 000000000000..d77e328657f3 --- /dev/null +++ b/user_guide_src/source/outgoing/views/004.php @@ -0,0 +1,3 @@ + 60]); diff --git a/user_guide_src/source/outgoing/views/007.php b/user_guide_src/source/outgoing/views/007.php new file mode 100644 index 000000000000..b1d22eb55260 --- /dev/null +++ b/user_guide_src/source/outgoing/views/007.php @@ -0,0 +1,4 @@ + 60, 'cache_name' => 'my_cached_view']); diff --git a/user_guide_src/source/outgoing/views/008.php b/user_guide_src/source/outgoing/views/008.php new file mode 100644 index 000000000000..c9b2ab2f5bbd --- /dev/null +++ b/user_guide_src/source/outgoing/views/008.php @@ -0,0 +1,9 @@ + 'My title', + 'heading' => 'My Heading', + 'message' => 'My Message', +]; + +echo view('blog_view', $data); diff --git a/user_guide_src/source/outgoing/views/009.php b/user_guide_src/source/outgoing/views/009.php new file mode 100644 index 000000000000..02ce288dd6c8 --- /dev/null +++ b/user_guide_src/source/outgoing/views/009.php @@ -0,0 +1,14 @@ + 'My title', + 'heading' => 'My Heading', + 'message' => 'My Message', +]; + +echo view('blog_view', $data, ['saveData' => true]); diff --git a/user_guide_src/source/outgoing/views/011.php b/user_guide_src/source/outgoing/views/011.php new file mode 100644 index 000000000000..2f3cb13c2989 --- /dev/null +++ b/user_guide_src/source/outgoing/views/011.php @@ -0,0 +1,17 @@ + ['Clean House', 'Call Mom', 'Run Errands'], + 'title' => 'My Real Title', + 'heading' => 'My Real Heading', + ]; + + echo view('blog_view', $data); + } +} diff --git a/user_guide_src/source/outgoing/views/012.php b/user_guide_src/source/outgoing/views/012.php new file mode 100644 index 000000000000..5a3781fe6720 --- /dev/null +++ b/user_guide_src/source/outgoing/views/012.php @@ -0,0 +1,19 @@ + + + <?= esc($title) ?> + + +

    + +

    My Todo List

    + +
      + + +
    • + + +
    + + + diff --git a/user_guide_src/source/testing/benchmark.rst b/user_guide_src/source/testing/benchmark.rst index 780dcfe8ac08..33fe7c200be9 100644 --- a/user_guide_src/source/testing/benchmark.rst +++ b/user_guide_src/source/testing/benchmark.rst @@ -23,48 +23,39 @@ it simple to measure the performance of different aspects of your application. A the ``start()`` and ``stop()`` methods. The ``start()`` methods takes a single parameter: the name of this timer. You can use any string as the name -of the timer. It is only used for you to reference later to know which measurement is which:: +of the timer. It is only used for you to reference later to know which measurement is which: - $benchmark = \Config\Services::timer(); - $benchmark->start('render view'); +.. literalinclude:: benchmark/001.php + :lines: 2- -The ``stop()`` method takes the name of the timer that you want to stop as the only parameter, also:: +The ``stop()`` method takes the name of the timer that you want to stop as the only parameter, also: - $benchmark->stop('render view'); +.. literalinclude:: benchmark/002.php + :lines: 2- The name is not case-sensitive, but otherwise must match the name you gave it when you started the timer. Alternatively, you can use the :doc:`global function ` ``timer()`` to start -and stop timers:: +and stop timers: - // Start the timer - timer('render view'); - // Stop a running timer, - // if one of this name has been started - timer('render view'); +.. literalinclude:: benchmark/003.php + :lines: 2- Viewing Your Benchmark Points ============================= When your application runs, all of the timers that you have set are collected by the Timer class. It does not automatically display them, though. You can retrieve all of your timers by calling the ``getTimers()`` method. -This returns an array of benchmark information, including start, end, and duration:: +This returns an array of benchmark information, including start, end, and duration: - $timers = $benchmark->getTimers(); - - // Timers = - [ - 'render view' => [ - 'start' => 1234567890, - 'end' => 1345678920, - 'duration' => 15.4315, // number of seconds - ] - ] +.. literalinclude:: benchmark/004.php + :lines: 2- You can change the precision of the calculated duration by passing in the number of decimal places you want to be shown as -the only parameter. The default value is 4 numbers behind the decimal point:: +the only parameter. The default value is 4 numbers behind the decimal point: - $timers = $benchmark->getTimers(6); +.. literalinclude:: benchmark/005.php + :lines: 2- The timers are automatically displayed in the :doc:`Debub Toolbar `. @@ -73,10 +64,10 @@ Displaying Execution Time While the ``getTimers()`` method will give you the raw data for all of the timers in your project, you can retrieve the duration of a single timer, in seconds, with the `getElapsedTime()` method. The first parameter is the name of -the timer to display. The second is the number of decimal places to display. This defaults to 4:: +the timer to display. The second is the number of decimal places to display. This defaults to 4: - echo timer()->getElapsedTime('render view'); - // Displays: 0.0234 +.. literalinclude:: benchmark/006.php + :lines: 2- ================== Using the Iterator @@ -92,32 +83,23 @@ Creating Tasks To Run Tasks are defined within Closures. Any output the task creates will be discarded automatically. They are added to the Iterator class through the `add()` method. The first parameter is a name you want to refer to -this test by. The second parameter is the Closure, itself:: - - $iterator = new \CodeIgniter\Benchmark\Iterator(); - - // Add a new task - $iterator->add('single_concat', function () { - $str = 'Some basic'.'little'.'string concatenation test.'; - }); +this test by. The second parameter is the Closure, itself: - // Add another task - $iterator->add('double', function ($a = 'little') { - $str = "Some basic {$little} string test."; - }); +.. literalinclude:: benchmark/007.php + :lines: 2- Running the Tasks ================= Once you've added the tasks to run, you can use the ``run()`` method to loop over the tasks many times. By default, it will run each task 1000 times. This is probably sufficient for most simple tests. If you need -to run the tests more times than that, you can pass the number as the first parameter:: +to run the tests more times than that, you can pass the number as the first parameter: - // Run the tests 3000 times. - $iterator->run(3000); +.. literalinclude:: benchmark/008.php + :lines: 2- Once it has run, it will return an HTML table with the results of the test. If you don't want the results -displayed, you can pass in `false` as the second parameter:: +displayed, you can pass in `false` as the second parameter: - // Don't display the results. - $iterator->run(1000, false); +.. literalinclude:: benchmark/009.php + :lines: 2- diff --git a/user_guide_src/source/testing/benchmark/001.php b/user_guide_src/source/testing/benchmark/001.php new file mode 100644 index 000000000000..ce3bd09ac87f --- /dev/null +++ b/user_guide_src/source/testing/benchmark/001.php @@ -0,0 +1,4 @@ +start('render view'); diff --git a/user_guide_src/source/testing/benchmark/002.php b/user_guide_src/source/testing/benchmark/002.php new file mode 100644 index 000000000000..003d1cc18cf7 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/002.php @@ -0,0 +1,3 @@ +stop('render view'); diff --git a/user_guide_src/source/testing/benchmark/003.php b/user_guide_src/source/testing/benchmark/003.php new file mode 100644 index 000000000000..861dbd8232a5 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/003.php @@ -0,0 +1,7 @@ +getTimers(); + +// Timers = +[ + 'render view' => [ + 'start' => 1234567890, + 'end' => 1345678920, + 'duration' => 15.4315, // number of seconds + ] +] diff --git a/user_guide_src/source/testing/benchmark/005.php b/user_guide_src/source/testing/benchmark/005.php new file mode 100644 index 000000000000..309c02f92a9b --- /dev/null +++ b/user_guide_src/source/testing/benchmark/005.php @@ -0,0 +1,3 @@ +getTimers(6); diff --git a/user_guide_src/source/testing/benchmark/006.php b/user_guide_src/source/testing/benchmark/006.php new file mode 100644 index 000000000000..a5f93a20fbf9 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/006.php @@ -0,0 +1,4 @@ +getElapsedTime('render view'); +// Displays: 0.0234 diff --git a/user_guide_src/source/testing/benchmark/007.php b/user_guide_src/source/testing/benchmark/007.php new file mode 100644 index 000000000000..c126ed4a9670 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/007.php @@ -0,0 +1,13 @@ +add('single_concat', function () { + $str = 'Some basic'.'little'.'string concatenation test.'; +}); + +// Add another task +$iterator->add('double', function ($a = 'little') { + $str = "Some basic {$little} string test."; +}); diff --git a/user_guide_src/source/testing/benchmark/008.php b/user_guide_src/source/testing/benchmark/008.php new file mode 100644 index 000000000000..da0f6a83b5fa --- /dev/null +++ b/user_guide_src/source/testing/benchmark/008.php @@ -0,0 +1,4 @@ +run(3000); diff --git a/user_guide_src/source/testing/benchmark/009.php b/user_guide_src/source/testing/benchmark/009.php new file mode 100644 index 000000000000..1f30692559b2 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/009.php @@ -0,0 +1,4 @@ +run(1000, false); diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst index d5dd2d379b8b..590e491ed687 100644 --- a/user_guide_src/source/testing/controllers.rst +++ b/user_guide_src/source/testing/controllers.rst @@ -17,47 +17,16 @@ case you need it. The Helper Trait ================ -To enable Controller Testing you need to use the ``ControllerTestTrait`` trait within your tests:: +To enable Controller Testing you need to use the ``ControllerTestTrait`` trait within your tests: - withURI('http://example.com/categories') - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); - - $this->assertTrue($result->isOK()); - } - } +.. literalinclude:: controllers/002.php Helper Methods ============== @@ -65,16 +34,17 @@ Helper Methods **controller($class)** Specifies the class name of the controller to test. The first parameter must be a fully qualified class name -(i.e., include the namespace):: +(i.e., include the namespace): - $this->controller(\App\Controllers\ForumController::class); +.. literalinclude:: controllers/003.php + :lines: 2- **execute(string $method, ...$params)** -Executes the specified method within the controller. The first parameter is the name of the method to run:: +Executes the specified method within the controller. The first parameter is the name of the method to run: - $results = $this->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/004.php + :lines: 2- By specifying the second and subsequent parameters, you can pass them to the controller method. @@ -83,54 +53,39 @@ for details. **withConfig($config)** -Allows you to pass in a modified version of **Config\App.php** to test with different settings:: +Allows you to pass in a modified version of **Config\App.php** to test with different settings: - $config = new Config\App(); - $config->appTimezone = 'America/Chicago'; - - $results = $this->withConfig($config) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/005.php + :lines: 2- If you do not provide one, the application's App config file will be used. **withRequest($request)** -Allows you to provide an **IncomingRequest** instance tailored to your testing needs:: - - $request = new \CodeIgniter\HTTP\IncomingRequest(new \Config\App(), new URI('http://example.com')); - $request->setLocale($locale); +Allows you to provide an **IncomingRequest** instance tailored to your testing needs: - $results = $this->withRequest($request) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/006.php + :lines: 2- If you do not provide one, a new IncomingRequest instance with the default application values will be passed into your controller. **withResponse($response)** -Allows you to provide a **Response** instance:: +Allows you to provide a **Response** instance: - $response = new \CodeIgniter\HTTP\Response(new \Config\App()); - - $results = $this->withResponse($response) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/007.php + :lines: 2- If you do not provide one, a new Response instance with the default application values will be passed into your controller. **withLogger($logger)** -Allows you to provide a **Logger** instance:: - - $logger = new \CodeIgniter\Log\Handlers\FileHandler(); +Allows you to provide a **Logger** instance: - $results = $this->withResponse($response) - ->withLogger($logger) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/008.php + :lines: 2- If you do not provide one, a new Logger instance with the default configuration values will be passed into your controller. @@ -139,24 +94,20 @@ into your controller. Allows you to provide a new URI that simulates the URL the client was visiting when this controller was run. This is helpful if you need to check URI segments within your controller. The only parameter is a string -representing a valid URI:: +representing a valid URI: - $results = $this->withURI('http://example.com/forums/categories') - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/009.php + :lines: 2- It is a good practice to always provide the URI during testing to avoid surprises. **withBody($body)** Allows you to provide a custom body for the request. This can be helpful when testing API controllers where -you need to set a JSON value as the body. The only parameter is a string that represents the body of the request:: - - $body = json_encode(['foo' => 'bar']); +you need to set a JSON value as the body. The only parameter is a string that represents the body of the request: - $results = $this->withBody($body) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); +.. literalinclude:: controllers/010.php + :lines: 2- Checking the Response ===================== @@ -174,19 +125,9 @@ The Helper Trait ---------------- Just like with the Controller Tester you need to include the ``FilterTestTrait`` in your test -cases to enable these features:: - - filtersConfig->globals['before'] = ['admin-only-filter']; - - $this->assertHasFilters('unfiltered/route', 'before'); - } - ... +.. literalinclude:: controllers/012.php + :lines: 2- Checking Routes --------------- @@ -234,9 +166,10 @@ a large performance advantage over Controller and HTTP Testing. :returns: Aliases for each filter that would have run :rtype: string[] - Usage example:: + Usage example: - $result = $this->getFiltersForRoute('/', 'after'); // ['toolbar'] + .. literalinclude:: controllers/013.php + :lines: 2- Calling Filter Methods ---------------------- @@ -252,15 +185,10 @@ method using these properties to test your Filter code safely and check the resu :returns: A callable method to run the simulated Filter event :rtype: Closure - Usage example:: - - protected function testUnauthorizedAccessRedirects() - { - $caller = $this->getFilterCaller('permission', 'before'); - $result = $caller('MayEditWidgets'); + Usage example: - $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); - } + .. literalinclude:: controllers/014.php + :lines: 2- Notice how the ``Closure`` can take input parameters which are passed to your filter method. @@ -270,22 +198,22 @@ Assertions In addition to the helper methods above ``FilterTestTrait`` also comes with some assertions to streamline your test methods. -The **assertFilter()** method checks that the given route at position uses the filter (by its alias):: +The **assertFilter()** method checks that the given route at position uses the filter (by its alias): - // Make sure users are logged in before checking their account - $this->assertFilter('users/account', 'before', 'login'); +.. literalinclude:: controllers/015.php + :lines: 2- -The **assertNotFilter()** method checks that the given route at position does not use the filter (by its alias):: +The **assertNotFilter()** method checks that the given route at position does not use the filter (by its alias): - // Make sure API calls do not try to use the Debug Toolbar - $this->assertNotFilter('api/v1/widgets', 'after', 'toolbar'); +.. literalinclude:: controllers/016.php + :lines: 2- -The **assertHasFilters()** method checks that the given route at position has at least one filter set:: +The **assertHasFilters()** method checks that the given route at position has at least one filter set: - // Make sure that filters are enabled - $this->assertHasFilters('filtered/route', 'after'); +.. literalinclude:: controllers/017.php + :lines: 2- -The **assertNotHasFilters()** method checks that the given route at position has no filters set:: +The **assertNotHasFilters()** method checks that the given route at position has no filters set: - // Make sure no filters run for our static pages - $this->assertNotHasFilters('about/contact', 'before'); +.. literalinclude:: controllers/018.php + :lines: 2- diff --git a/user_guide_src/source/testing/controllers/001.php b/user_guide_src/source/testing/controllers/001.php new file mode 100644 index 000000000000..9c31d5b62d00 --- /dev/null +++ b/user_guide_src/source/testing/controllers/001.php @@ -0,0 +1,12 @@ +withURI('http://example.com/categories') + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); + + $this->assertTrue($result->isOK()); + } +} diff --git a/user_guide_src/source/testing/controllers/003.php b/user_guide_src/source/testing/controllers/003.php new file mode 100644 index 000000000000..51e810538e87 --- /dev/null +++ b/user_guide_src/source/testing/controllers/003.php @@ -0,0 +1,3 @@ +controller(\App\Controllers\ForumController::class); diff --git a/user_guide_src/source/testing/controllers/004.php b/user_guide_src/source/testing/controllers/004.php new file mode 100644 index 000000000000..d06bb51768c3 --- /dev/null +++ b/user_guide_src/source/testing/controllers/004.php @@ -0,0 +1,4 @@ +controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/005.php b/user_guide_src/source/testing/controllers/005.php new file mode 100644 index 000000000000..bffc4c9c8f95 --- /dev/null +++ b/user_guide_src/source/testing/controllers/005.php @@ -0,0 +1,8 @@ +appTimezone = 'America/Chicago'; + +$results = $this->withConfig($config) + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/006.php b/user_guide_src/source/testing/controllers/006.php new file mode 100644 index 000000000000..aef7e41e071e --- /dev/null +++ b/user_guide_src/source/testing/controllers/006.php @@ -0,0 +1,8 @@ +setLocale($locale); + +$results = $this->withRequest($request) + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/007.php b/user_guide_src/source/testing/controllers/007.php new file mode 100644 index 000000000000..73b1d4e122c2 --- /dev/null +++ b/user_guide_src/source/testing/controllers/007.php @@ -0,0 +1,7 @@ +withResponse($response) + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/008.php b/user_guide_src/source/testing/controllers/008.php new file mode 100644 index 000000000000..4ea1c84dee20 --- /dev/null +++ b/user_guide_src/source/testing/controllers/008.php @@ -0,0 +1,8 @@ +withResponse($response) + ->withLogger($logger) + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/009.php b/user_guide_src/source/testing/controllers/009.php new file mode 100644 index 000000000000..4559dd8f4711 --- /dev/null +++ b/user_guide_src/source/testing/controllers/009.php @@ -0,0 +1,5 @@ +withURI('http://example.com/forums/categories') + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/010.php b/user_guide_src/source/testing/controllers/010.php new file mode 100644 index 000000000000..2cf6d9919c31 --- /dev/null +++ b/user_guide_src/source/testing/controllers/010.php @@ -0,0 +1,7 @@ + 'bar']); + +$results = $this->withBody($body) + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/011.php b/user_guide_src/source/testing/controllers/011.php new file mode 100644 index 000000000000..f2ab558b8da2 --- /dev/null +++ b/user_guide_src/source/testing/controllers/011.php @@ -0,0 +1,11 @@ +filtersConfig->globals['before'] = ['admin-only-filter']; + + $this->assertHasFilters('unfiltered/route', 'before'); + } +... diff --git a/user_guide_src/source/testing/controllers/013.php b/user_guide_src/source/testing/controllers/013.php new file mode 100644 index 000000000000..e205f0f4ea54 --- /dev/null +++ b/user_guide_src/source/testing/controllers/013.php @@ -0,0 +1,3 @@ +getFiltersForRoute('/', 'after'); // ['toolbar'] diff --git a/user_guide_src/source/testing/controllers/014.php b/user_guide_src/source/testing/controllers/014.php new file mode 100644 index 000000000000..19f2310392fa --- /dev/null +++ b/user_guide_src/source/testing/controllers/014.php @@ -0,0 +1,9 @@ +getFilterCaller('permission', 'before'); + $result = $caller('MayEditWidgets'); + + $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); +} diff --git a/user_guide_src/source/testing/controllers/015.php b/user_guide_src/source/testing/controllers/015.php new file mode 100644 index 000000000000..866d2e80ce43 --- /dev/null +++ b/user_guide_src/source/testing/controllers/015.php @@ -0,0 +1,4 @@ +assertFilter('users/account', 'before', 'login'); diff --git a/user_guide_src/source/testing/controllers/016.php b/user_guide_src/source/testing/controllers/016.php new file mode 100644 index 000000000000..cdbf08ccc36b --- /dev/null +++ b/user_guide_src/source/testing/controllers/016.php @@ -0,0 +1,4 @@ +assertNotFilter('api/v1/widgets', 'after', 'toolbar'); diff --git a/user_guide_src/source/testing/controllers/017.php b/user_guide_src/source/testing/controllers/017.php new file mode 100644 index 000000000000..15db694e5419 --- /dev/null +++ b/user_guide_src/source/testing/controllers/017.php @@ -0,0 +1,4 @@ +assertHasFilters('filtered/route', 'after'); diff --git a/user_guide_src/source/testing/controllers/018.php b/user_guide_src/source/testing/controllers/018.php new file mode 100644 index 000000000000..33606c0e122e --- /dev/null +++ b/user_guide_src/source/testing/controllers/018.php @@ -0,0 +1,4 @@ +assertNotHasFilters('about/contact', 'before'); diff --git a/user_guide_src/source/testing/database.rst b/user_guide_src/source/testing/database.rst index 86b91537917e..614099449e29 100644 --- a/user_guide_src/source/testing/database.rst +++ b/user_guide_src/source/testing/database.rst @@ -10,51 +10,15 @@ The Test Class ============== In order to take advantage of the built-in database tools that CodeIgniter provides for testing, your -tests must extend ``CIUnitTestCase`` and use the ``DatabaseTestTrait``:: +tests must extend ``CIUnitTestCase`` and use the ``DatabaseTestTrait``: - 'joe@example.com', - 'active' => 1, - ]; - $this->dontSeeInDatabase('users', $criteria); +.. literalinclude:: database/004.php + :lines: 2- **seeInDatabase($table, $criteria)** Asserts that a row with criteria matching the key/value pairs in ``$criteria`` DOES exist in the database. -:: - $criteria = [ - 'email' => 'joe@example.com', - 'active' => 1, - ]; - $this->seeInDatabase('users', $criteria); +.. literalinclude:: database/005.php + :lines: 2- **grabFromDatabase($table, $column, $criteria)** Returns the value of ``$column`` from the specified table where the row matches ``$criteria``. If more than one row is found, it will only test against the first one. -:: - $username = $this->grabFromDatabase('users', 'username', ['email' => 'joe@example.com']); +.. literalinclude:: database/006.php + :lines: 2- **hasInDatabase($table, $data)** Inserts a new row into the database. This row is removed after the current test runs. ``$data`` is an associative array with the data to insert into the table. -:: - $data = [ - 'email' => 'joe@example.com', - 'name' => 'Joe Cool', - ]; - $this->hasInDatabase('users', $data); +.. literalinclude:: database/007.php + :lines: 2- **seeNumRecords($expected, $table, $criteria)** Asserts that a number of matching rows are found in the database that match ``$criteria``. -:: - $criteria = [ - 'active' => 1, - ]; - $this->seeNumRecords(2, 'users', $criteria); +.. literalinclude:: database/008.php + :lines: 2- diff --git a/user_guide_src/source/testing/database/001.php b/user_guide_src/source/testing/database/001.php new file mode 100644 index 000000000000..809cd59d8c0f --- /dev/null +++ b/user_guide_src/source/testing/database/001.php @@ -0,0 +1,13 @@ + 'joe@example.com', + 'active' => 1, +]; +$this->dontSeeInDatabase('users', $criteria); diff --git a/user_guide_src/source/testing/database/005.php b/user_guide_src/source/testing/database/005.php new file mode 100644 index 000000000000..960ba5e5b91e --- /dev/null +++ b/user_guide_src/source/testing/database/005.php @@ -0,0 +1,7 @@ + 'joe@example.com', + 'active' => 1, +]; +$this->seeInDatabase('users', $criteria); diff --git a/user_guide_src/source/testing/database/006.php b/user_guide_src/source/testing/database/006.php new file mode 100644 index 000000000000..951736b95611 --- /dev/null +++ b/user_guide_src/source/testing/database/006.php @@ -0,0 +1,3 @@ +grabFromDatabase('users', 'username', ['email' => 'joe@example.com']); diff --git a/user_guide_src/source/testing/database/007.php b/user_guide_src/source/testing/database/007.php new file mode 100644 index 000000000000..46ebb8fbe695 --- /dev/null +++ b/user_guide_src/source/testing/database/007.php @@ -0,0 +1,7 @@ + 'joe@example.com', + 'name' => 'Joe Cool', +]; +$this->hasInDatabase('users', $data); diff --git a/user_guide_src/source/testing/database/008.php b/user_guide_src/source/testing/database/008.php new file mode 100644 index 000000000000..9a60e154d331 --- /dev/null +++ b/user_guide_src/source/testing/database/008.php @@ -0,0 +1,6 @@ + 1, +]; +$this->seeNumRecords(2, 'users', $criteria); diff --git a/user_guide_src/source/testing/debugging.rst b/user_guide_src/source/testing/debugging.rst index 22c77141e116..0b841517846e 100644 --- a/user_guide_src/source/testing/debugging.rst +++ b/user_guide_src/source/testing/debugging.rst @@ -29,9 +29,10 @@ Using Kint **d()** The ``d()`` method dumps all of the data it knows about the contents passed as the only parameter to the screen, and -allows the script to continue executing:: +allows the script to continue executing: - d($_SERVER); +.. literalinclude:: debugging/001.php + :lines: 2- **dd()** @@ -39,9 +40,10 @@ This method is identical to ``d()``, except that it also ``dies()`` and no furth **trace()** -This provides a backtrace to the current execution point, with Kint's own unique spin:: +This provides a backtrace to the current execution point, with Kint's own unique spin: - trace(); +.. literalinclude:: debugging/002.php + :lines: 2- For more information, see `Kint's page `_. @@ -74,18 +76,10 @@ Choosing What to Show CodeIgniter ships with several Collectors that, as the name implies, collect data to display on the toolbar. You can easily make your own to customize the toolbar. To determine which collectors are shown, again head over to -the **app/Config/Toolbar.php** configuration file:: - - public $collectors = [ - \CodeIgniter\Debug\Toolbar\Collectors\Timers::class, - \CodeIgniter\Debug\Toolbar\Collectors\Database::class, - \CodeIgniter\Debug\Toolbar\Collectors\Logs::class, - \CodeIgniter\Debug\Toolbar\Collectors\Views::class, - \CodeIgniter\Debug\Toolbar\Collectors\Cache::class, - \CodeIgniter\Debug\Toolbar\Collectors\Files::class, - \CodeIgniter\Debug\Toolbar\Collectors\Routes::class, - \CodeIgniter\Debug\Toolbar\Collectors\Events::class, - ]; +the **app/Config/Toolbar.php** configuration file: + +.. literalinclude:: debugging/003.php + :lines: 2- Comment out any collectors that you do not want to show. Add custom Collectors here by providing the fully-qualified class name. The exact collectors that appear here will affect which tabs are shown, as well as what information is @@ -119,24 +113,8 @@ Creating custom collectors is a straightforward task. You create a new class, fu can locate it, that extends ``CodeIgniter\Debug\Toolbar\Collectors\BaseCollector``. This provides a number of methods that you can override, and has four required class properties that you must correctly set depending on how you want the Collector to work -:: - - '', // Name displayed on the left of the timeline - 'component' => '', // Name of the Component listed in the middle of timeline - 'start' => 0.00, // start time, like microtime(true) - 'duration' => 0.00, // duration, like mircrotime(true) - microtime(true) - ]; +.. literalinclude:: debugging/005.php + :lines: 2- Providing Vars -------------- @@ -196,15 +170,7 @@ To add data to the Vars tab you must: 2. Implement ``getVarData()`` method. The ``getVarData()`` method should return an array containing arrays of key/value pairs to display. The name of the -outer array's key is the name of the section on the Vars tab:: - - $data = [ - 'section 1' => [ - 'foo' => 'bar', - 'bar' => 'baz', - ], - 'section 2' => [ - 'foo' => 'bar', - 'bar' => 'baz', - ], - ]; +outer array's key is the name of the section on the Vars tab: + +.. literalinclude:: debugging/006.php + :lines: 2- diff --git a/user_guide_src/source/testing/debugging/001.php b/user_guide_src/source/testing/debugging/001.php new file mode 100644 index 000000000000..f54b4701f98e --- /dev/null +++ b/user_guide_src/source/testing/debugging/001.php @@ -0,0 +1,3 @@ + '', // Name displayed on the left of the timeline + 'component' => '', // Name of the Component listed in the middle of timeline + 'start' => 0.00, // start time, like microtime(true) + 'duration' => 0.00, // duration, like mircrotime(true) - microtime(true) +]; diff --git a/user_guide_src/source/testing/debugging/006.php b/user_guide_src/source/testing/debugging/006.php new file mode 100644 index 000000000000..3140ea7e4a81 --- /dev/null +++ b/user_guide_src/source/testing/debugging/006.php @@ -0,0 +1,12 @@ + [ + 'foo' => 'bar', + 'bar' => 'baz', + ], + 'section 2' => [ + 'foo' => 'bar', + 'bar' => 'baz', + ], + ]; diff --git a/user_guide_src/source/testing/fabricator.rst b/user_guide_src/source/testing/fabricator.rst index abd68d8af86b..3e419353ef07 100644 --- a/user_guide_src/source/testing/fabricator.rst +++ b/user_guide_src/source/testing/fabricator.rst @@ -14,27 +14,25 @@ Supported Models ================ ``Fabricator`` supports any model that extends the framework's core model, ``CodeIgniter\Model``. -You may use your own custom models by ensuring they implement ``CodeIgniter\Test\Interfaces\FabricatorModel``:: +You may use your own custom models by ensuring they implement ``CodeIgniter\Test\Interfaces\FabricatorModel``: - class MyModel implements CodeIgniter\Test\Interfaces\FabricatorModel +.. literalinclude:: fabricator/001.php + :lines: 2- .. note:: In addition to methods, the interface outlines some necessary properties for the target model. Please see the interface code for details. Loading Fabricators =================== -At its most basic a fabricator takes the model to act on:: +At its most basic a fabricator takes the model to act on: - use App\Models\UserModel; - use CodeIgniter\Test\Fabricator; +.. literalinclude:: fabricator/002.php + :lines: 2- - $fabricator = new Fabricator(UserModel::class); +The parameter can be a string specifying the name of the model, or an instance of the model itself: -The parameter can be a string specifying the name of the model, or an instance of the model itself:: - - $model = new UserModel($testDbConnection); - - $fabricator = new Fabricator($model); +.. literalinclude:: fabricator/003.php + :lines: 2- Defining Formatters =================== @@ -43,16 +41,10 @@ Faker generates data by requesting it from a formatter. With no formatters defin attempt to guess at the most appropriate fit based on the field name and properties of the model it represents, falling back on ``$fabricator->defaultFormatter``. This may be fine if your field names correspond with common formatters, or if you don't care much about the content of the fields, but most -of the time you will want to specify the formatters to use as the second parameter to the constructor:: - - $formatters = [ - 'first' => 'firstName', - 'email' => 'email', - 'phone' => 'phoneNumber', - 'avatar' => 'imageUrl', - ]; +of the time you will want to specify the formatters to use as the second parameter to the constructor: - $fabricator = new Fabricator(UserModel::class, $formatters); +.. literalinclude:: fabricator/004.php + :lines: 2- You can also change the formatters after a fabricator is initialized by using the ``setFormatters()`` method. @@ -60,41 +52,28 @@ You can also change the formatters after a fabricator is initialized by using th Sometimes the default return of a formatter is not enough. Faker providers allow parameters to most formatters to further limit the scope of random data. A fabricator will check its representative model for the ``fake()`` -method where you can define exactly what the faked data should look like:: - - class UserModel - { - public function fake(Generator &$faker) - { - return [ - 'first' => $faker->firstName, - 'email' => $faker->email, - 'phone' => $faker->phoneNumber, - 'avatar' => Faker\Provider\Image::imageUrl(800, 400), - 'login' => config('Auth')->allowRemembering ? date('Y-m-d') : null, - ]; - } +method where you can define exactly what the faked data should look like: + +.. literalinclude:: fabricator/005.php + :lines: 2- Notice in this example how the first three values are equivalent to the formatters from before. However for ``avatar`` we have requested an image size other than the default and ``login`` uses a conditional based on app configuration, neither of which are possible using the ``$formatters`` parameter. You may want to keep your test data separate from your production models, so it is a good practice to define -a child class in your test support folder:: - - namespace Tests\Support\Models; +a child class in your test support folder: - class UserFabricator extends \App\Models\UserModel - { - public function fake(&$faker) - { +.. literalinclude:: fabricator/006.php + :lines: 2- Localization ============ Faker supports a lot of different locales. Check their documentation to determine which providers -support your locale. Specify a locale in the third parameter while initiating a fabricator:: +support your locale. Specify a locale in the third parameter while initiating a fabricator: - $fabricator = new Fabricator(UserModel::class, null, 'fr_FR'); +.. literalinclude:: fabricator/007.php + :lines: 2- If no locale is specified it will use the one defined in **app/Config/App.php** as ``defaultLocale``. You can check the locale of an existing fabricator using its ``getLocale()`` method. @@ -102,114 +81,72 @@ You can check the locale of an existing fabricator using its ``getLocale()`` met Faking the Data =============== -Once you have a properly-initialized fabricator it is easy to generate test data with the ``make()`` command:: +Once you have a properly-initialized fabricator it is easy to generate test data with the ``make()`` command: - $fabricator = new Fabricator(UserFabricator::class); - $testUser = $fabricator->make(); - print_r($testUser); +.. literalinclude:: fabricator/008.php + :lines: 2- -You might get back something like this:: +You might get back something like this: - array( - 'first' => "Maynard", - 'email' => "king.alford@example.org", - 'phone' => "201-886-0269 x3767", - 'avatar' => "http://lorempixel.com/800/400/", - 'login' => null, - ) +.. literalinclude:: fabricator/009.php + :lines: 2- -You can also get a lot of them back by supplying a count:: +You can also get a lot of them back by supplying a count: - $users = $fabricator->make(10); +.. literalinclude:: fabricator/010.php + :lines: 2- The return type of ``make()`` mimics what is defined in the representative model, but you can -force a type using the methods directly:: +force a type using the methods directly: - $userArray = $fabricator->makeArray(); - $userObject = $fabricator->makeObject(); - $userEntity = $fabricator->makeObject('App\Entities\User'); +.. literalinclude:: fabricator/011.php + :lines: 2- The return from ``make()`` is ready to be used in tests or inserted into the database. Alternatively ``Fabricator`` includes the ``create()`` command to insert it for you, and return the result. Due to model callbacks, database formatting, and special keys like primary and timestamps the return -from ``create()`` can differ from ``make()``. You might get back something like this:: +from ``create()`` can differ from ``make()``. You might get back something like this: - array( - 'id' => 1, - 'first' => "Rachel", - 'email' => "bradley72@gmail.com", - 'phone' => "741-241-2356", - 'avatar' => "http://lorempixel.com/800/400/", - 'login' => null, - 'created_at' => "2020-05-08 14:52:10", - 'updated_at' => "2020-05-08 14:52:10", - ) +.. literalinclude:: fabricator/012.php + :lines: 2- -Similar to ``make()`` you can supply a count to insert and return an array of objects:: +Similar to ``make()`` you can supply a count to insert and return an array of objects: - $users = $fabricator->create(100); +.. literalinclude:: fabricator/013.php + :lines: 2- Finally, there may be times you want to test with the full database object but you are not actually using a database. ``create()`` takes a second parameter to allowing mocking the object, returning -the object with extra database fields above without actually touching the database:: - - $user = $fabricator(null, true); +the object with extra database fields above without actually touching the database: - $this->assertIsNumeric($user->id); - $this->dontSeeInDatabase('user', ['id' => $user->id]); +.. literalinclude:: fabricator/014.php + :lines: 2- Specifying Test Data ==================== Generated data is great, but sometimes you may want to supply a specific field for a test without compromising your formatters configuration. Rather then creating a new fabricator for each variant -you can use ``setOverrides()`` to specify the value for any fields:: +you can use ``setOverrides()`` to specify the value for any fields: - $fabricator->setOverrides(['first' => 'Bobby']); - $bobbyUser = $fabricator->make(); +.. literalinclude:: fabricator/015.php + :lines: 2- -Now any data generated with ``make()`` or ``create()`` will always use "Bobby" for the ``first`` field:: +Now any data generated with ``make()`` or ``create()`` will always use "Bobby" for the ``first`` field: - array( - 'first' => "Bobby", - 'email' => "latta.kindel@company.org", - 'phone' => "251-806-2169", - 'avatar' => "http://lorempixel.com/800/400/", - 'login' => null, - ) - - array( - 'first' => "Bobby", - 'email' => "melissa.strike@fabricon.us", - 'phone' => "525-214-2656 x23546", - 'avatar' => "http://lorempixel.com/800/400/", - 'login' => null, - ) +.. literalinclude:: fabricator/016.php + :lines: 2- ``setOverrides()`` can take a second parameter to indicate whether this should be a persistent -override or only for a single action:: - - $fabricator->setOverrides(['first' => 'Bobby'], $persist = false); - $bobbyUser = $fabricator->make(); - $bobbyUser = $fabricator->make(); - -Notice after the first return the fabricator stops using the overrides:: - - array( - 'first' => "Bobby", - 'email' => "belingadon142@example.org", - 'phone' => "741-857-1933 x1351", - 'avatar' => "http://lorempixel.com/800/400/", - 'login' => null, - ) - - array( - 'first' => "Hans", - 'email' => "hoppifur@metraxalon.com", - 'phone' => "487-235-7006", - 'avatar' => "http://lorempixel.com/800/400/", - 'login' => null, - ) +override or only for a single action: + +.. literalinclude:: fabricator/017.php + :lines: 2- + +Notice after the first return the fabricator stops using the overrides: + +.. literalinclude:: fabricator/018.php + :lines: 2- If no second parameter is supplied then passed values will persist by default. @@ -217,16 +154,15 @@ Test Helper =========== Often all you will need is a one-and-done fake object for testing. The Test Helper provides -the ``fake($model, $overrides, $persist = true)`` function to do just this:: +the ``fake($model, $overrides, $persist = true)`` function to do just this: - helper('test'); - $user = fake('App\Models\UserModel', ['name' => 'Gerry']); +.. literalinclude:: fabricator/019.php + :lines: 2- -This is equivalent to:: +This is equivalent to: - $fabricator = new Fabricator('App\Models\UserModel'); - $fabricator->setOverrides(['name' => 'Gerry']); - $user = $fabricator->create(); +.. literalinclude:: fabricator/020.php + :lines: 2- If you just need a fake object without saving it to the database you can pass false into the persist parameter. @@ -240,20 +176,10 @@ example: Your project has users and groups. In your test case you want to create various scenarios with groups of different sizes, so you use ``Fabricator`` to create a bunch of groups. Now you want to create fake users but don't want to assign them to a non-existant group ID. -Your model's fake method could look like this:: - - class UserModel - { - protected $table = 'users'; - - public function fake(Generator &$faker) - { - return [ - 'first' => $faker->firstName, - 'email' => $faker->email, - 'group_id' => rand(1, Fabricator::getCount('groups')), - ]; - } +Your model's fake method could look like this: + +.. literalinclude:: fabricator/021.php + :lines: 2- Now creating a new user will ensure it is a part of a valid group: ``$user = fake(UserModel::class);`` diff --git a/user_guide_src/source/testing/fabricator/001.php b/user_guide_src/source/testing/fabricator/001.php new file mode 100644 index 000000000000..f5f2e33ff455 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/001.php @@ -0,0 +1,3 @@ + 'firstName', + 'email' => 'email', + 'phone' => 'phoneNumber', + 'avatar' => 'imageUrl', +]; + +$fabricator = new Fabricator(UserModel::class, $formatters); diff --git a/user_guide_src/source/testing/fabricator/005.php b/user_guide_src/source/testing/fabricator/005.php new file mode 100644 index 000000000000..d5dc3ab38932 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/005.php @@ -0,0 +1,14 @@ + $faker->firstName, + 'email' => $faker->email, + 'phone' => $faker->phoneNumber, + 'avatar' => Faker\Provider\Image::imageUrl(800, 400), + 'login' => config('Auth')->allowRemembering ? date('Y-m-d') : null, + ]; + } diff --git a/user_guide_src/source/testing/fabricator/006.php b/user_guide_src/source/testing/fabricator/006.php new file mode 100644 index 000000000000..587a0697d1fa --- /dev/null +++ b/user_guide_src/source/testing/fabricator/006.php @@ -0,0 +1,8 @@ +make(); +print_r($testUser); diff --git a/user_guide_src/source/testing/fabricator/009.php b/user_guide_src/source/testing/fabricator/009.php new file mode 100644 index 000000000000..3a7507430265 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/009.php @@ -0,0 +1,9 @@ + "Maynard", + 'email' => "king.alford@example.org", + 'phone' => "201-886-0269 x3767", + 'avatar' => "http://lorempixel.com/800/400/", + 'login' => null, +) diff --git a/user_guide_src/source/testing/fabricator/010.php b/user_guide_src/source/testing/fabricator/010.php new file mode 100644 index 000000000000..54b795ee2f72 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/010.php @@ -0,0 +1,3 @@ +make(10); diff --git a/user_guide_src/source/testing/fabricator/011.php b/user_guide_src/source/testing/fabricator/011.php new file mode 100644 index 000000000000..9b9f62fd84ee --- /dev/null +++ b/user_guide_src/source/testing/fabricator/011.php @@ -0,0 +1,5 @@ +makeArray(); +$userObject = $fabricator->makeObject(); +$userEntity = $fabricator->makeObject('App\Entities\User'); diff --git a/user_guide_src/source/testing/fabricator/012.php b/user_guide_src/source/testing/fabricator/012.php new file mode 100644 index 000000000000..782c58f8917f --- /dev/null +++ b/user_guide_src/source/testing/fabricator/012.php @@ -0,0 +1,12 @@ + 1, + 'first' => "Rachel", + 'email' => "bradley72@gmail.com", + 'phone' => "741-241-2356", + 'avatar' => "http://lorempixel.com/800/400/", + 'login' => null, + 'created_at' => "2020-05-08 14:52:10", + 'updated_at' => "2020-05-08 14:52:10", +) diff --git a/user_guide_src/source/testing/fabricator/013.php b/user_guide_src/source/testing/fabricator/013.php new file mode 100644 index 000000000000..6e89dd774eb9 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/013.php @@ -0,0 +1,3 @@ +create(100); diff --git a/user_guide_src/source/testing/fabricator/014.php b/user_guide_src/source/testing/fabricator/014.php new file mode 100644 index 000000000000..60f0161b795f --- /dev/null +++ b/user_guide_src/source/testing/fabricator/014.php @@ -0,0 +1,6 @@ +assertIsNumeric($user->id); +$this->dontSeeInDatabase('user', ['id' => $user->id]); diff --git a/user_guide_src/source/testing/fabricator/015.php b/user_guide_src/source/testing/fabricator/015.php new file mode 100644 index 000000000000..277c32fa370b --- /dev/null +++ b/user_guide_src/source/testing/fabricator/015.php @@ -0,0 +1,4 @@ +setOverrides(['first' => 'Bobby']); +$bobbyUser = $fabricator->make(); diff --git a/user_guide_src/source/testing/fabricator/016.php b/user_guide_src/source/testing/fabricator/016.php new file mode 100644 index 000000000000..72f2b946366e --- /dev/null +++ b/user_guide_src/source/testing/fabricator/016.php @@ -0,0 +1,17 @@ + "Bobby", + 'email' => "latta.kindel@company.org", + 'phone' => "251-806-2169", + 'avatar' => "http://lorempixel.com/800/400/", + 'login' => null, +) + +array( + 'first' => "Bobby", + 'email' => "melissa.strike@fabricon.us", + 'phone' => "525-214-2656 x23546", + 'avatar' => "http://lorempixel.com/800/400/", + 'login' => null, +) diff --git a/user_guide_src/source/testing/fabricator/017.php b/user_guide_src/source/testing/fabricator/017.php new file mode 100644 index 000000000000..ee79ea6f8d03 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/017.php @@ -0,0 +1,5 @@ +setOverrides(['first' => 'Bobby'], $persist = false); +$bobbyUser = $fabricator->make(); +$bobbyUser = $fabricator->make(); diff --git a/user_guide_src/source/testing/fabricator/018.php b/user_guide_src/source/testing/fabricator/018.php new file mode 100644 index 000000000000..73a3b932052e --- /dev/null +++ b/user_guide_src/source/testing/fabricator/018.php @@ -0,0 +1,17 @@ + "Bobby", + 'email' => "belingadon142@example.org", + 'phone' => "741-857-1933 x1351", + 'avatar' => "http://lorempixel.com/800/400/", + 'login' => null, +) + +array( + 'first' => "Hans", + 'email' => "hoppifur@metraxalon.com", + 'phone' => "487-235-7006", + 'avatar' => "http://lorempixel.com/800/400/", + 'login' => null, +) diff --git a/user_guide_src/source/testing/fabricator/019.php b/user_guide_src/source/testing/fabricator/019.php new file mode 100644 index 000000000000..4c1de5f23dd2 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/019.php @@ -0,0 +1,4 @@ + 'Gerry']); diff --git a/user_guide_src/source/testing/fabricator/020.php b/user_guide_src/source/testing/fabricator/020.php new file mode 100644 index 000000000000..385646b2ea2c --- /dev/null +++ b/user_guide_src/source/testing/fabricator/020.php @@ -0,0 +1,5 @@ +setOverrides(['name' => 'Gerry']); +$user = $fabricator->create(); diff --git a/user_guide_src/source/testing/fabricator/021.php b/user_guide_src/source/testing/fabricator/021.php new file mode 100644 index 000000000000..a1b0111e0903 --- /dev/null +++ b/user_guide_src/source/testing/fabricator/021.php @@ -0,0 +1,14 @@ + $faker->firstName, + 'email' => $faker->email, + 'group_id' => rand(1, Fabricator::getCount('groups')), + ]; + } diff --git a/user_guide_src/source/testing/feature.rst b/user_guide_src/source/testing/feature.rst index 2a9eb96a348a..54cb6035a804 100644 --- a/user_guide_src/source/testing/feature.rst +++ b/user_guide_src/source/testing/feature.rst @@ -18,33 +18,8 @@ Feature testing requires that all of your test classes use the ``CodeIgniter\Tes and ``CodeIgniter\Test\FeatureTestTrait`` traits. Since these testing tools rely on proper database staging you must always ensure that ``parent::setUp()`` and ``parent::tearDown()`` are called if you implement your own methods. -:: - myClassMethod(); - } - - protected function tearDown(): void - { - parent::tearDown(); - - $this->anotherClassMethod(); - } - } +.. literalinclude:: feature/001.php Requesting A Page ================= @@ -54,25 +29,14 @@ to do this, you use the ``call()`` method. The first parameter is the HTTP metho The second parameter is the path on your site to test. The third parameter accepts an array that is used to populate the superglobal variables for the HTTP verb you are using. So, a method of **GET** would have the **$_GET** variable populated, while a **post** request would have the **$_POST** array populated. -:: - - // Get a simple page - $result = $this->call('get', '/'); - // Submit a form - $result = $this->call('post', 'contact'), [ - 'name' => 'Fred Flintstone', - 'email' => 'flintyfred@example.com' - ]); +.. literalinclude:: feature/002.php + :lines: 2- -Shorthand methods for each of the HTTP verbs exist to ease typing and make things clearer:: +Shorthand methods for each of the HTTP verbs exist to ease typing and make things clearer: - $this->get($path, $params); - $this->post($path, $params); - $this->put($path, $params); - $this->patch($path, $params); - $this->delete($path, $params); - $this->options($path, $params); +.. literalinclude:: feature/003.php + :lines: 2- .. note:: The ``$params`` array does not make sense for every HTTP verb, but is included for consistency. @@ -80,57 +44,41 @@ Setting Different Routes ------------------------ You can use a custom collection of routes by passing an array of "routes" into the ``withRoutes()`` method. This will -override any existing routes in the system:: +override any existing routes in the system: - $routes = [ - ['get', 'users', 'UserController::list'], - ]; - - $result = $this->withRoutes($routes)->get('users'); +.. literalinclude:: feature/004.php + :lines: 2- Each of the "routes" is a 3 element array containing the HTTP verb (or "add" for all), the URI to match, and the routing destination. - Setting Session Values ---------------------- You can set custom session values to use during a single test with the ``withSession()`` method. This takes an array of key/value pairs that should exist within the ``$_SESSION`` variable when this request is made, or ``null`` to indicate that the current values of ``$_SESSION`` should be used. This is handy for testing authentication and more. -:: - - $values = [ - 'logged_in' => 123, - ]; - - $result = $this->withSession($values)->get('admin'); - // Or... - - $_SESSION['logged_in'] = 123; - - $result = $this->withSession()->get('admin'); +.. literalinclude:: feature/005.php + :lines: 2- Setting Headers --------------- You can set header values with the ``withHeaders()`` method. This takes an array of key/value pairs that would be -passed as a header into the call.:: +passed as a header into the call.: - $headers = [ - 'CONTENT_TYPE' => 'application/json', - ]; - - $result = $this->withHeaders($headers)->post('users'); +.. literalinclude:: feature/006.php + :lines: 2- Bypassing Events ---------------- Events are handy to use in your application, but can be problematic during testing. Especially events that are used -to send out emails. You can tell the system to skip any event handling with the ``skipEvents()`` method:: +to send out emails. You can tell the system to skip any event handling with the ``skipEvents()`` method: - $result = $this->skipEvents()->post('users', $userInfo); +.. literalinclude:: feature/007.php + :lines: 2- Formatting The Request ----------------------- @@ -139,13 +87,9 @@ You can set the format of your request's body using the ``withBodyFormat()`` met `json` or `xml`. This will take the parameters passed into ``call()``, ``post()``, ``get()``... and assign them to the body of the request in the given format. This will also set the `Content-Type` header for your request accordingly. This is useful when testing JSON or XML API's so that you can set the request in the form that the controller will expect. -:: - - // If your feature test contains this: - $result = $this->withBodyFormat('json')->post('users', $userInfo); - // Your controller can then get the parameters passed in with: - $userInfo = $this->request->getJson(); +.. literalinclude:: feature/008.php + :lines: 2- Setting the Body ---------------- diff --git a/user_guide_src/source/testing/feature/001.php b/user_guide_src/source/testing/feature/001.php new file mode 100644 index 000000000000..5449332fe266 --- /dev/null +++ b/user_guide_src/source/testing/feature/001.php @@ -0,0 +1,25 @@ +myClassMethod(); + } + + protected function tearDown(): void + { + parent::tearDown(); + + $this->anotherClassMethod(); + } +} diff --git a/user_guide_src/source/testing/feature/002.php b/user_guide_src/source/testing/feature/002.php new file mode 100644 index 000000000000..c5f67f42b36c --- /dev/null +++ b/user_guide_src/source/testing/feature/002.php @@ -0,0 +1,10 @@ +call('get', '/'); + +// Submit a form +$result = $this->call('post', 'contact'), [ + 'name' => 'Fred Flintstone', + 'email' => 'flintyfred@example.com' +]); diff --git a/user_guide_src/source/testing/feature/003.php b/user_guide_src/source/testing/feature/003.php new file mode 100644 index 000000000000..1905a2dcf110 --- /dev/null +++ b/user_guide_src/source/testing/feature/003.php @@ -0,0 +1,8 @@ +get($path, $params); +$this->post($path, $params); +$this->put($path, $params); +$this->patch($path, $params); +$this->delete($path, $params); +$this->options($path, $params); diff --git a/user_guide_src/source/testing/feature/004.php b/user_guide_src/source/testing/feature/004.php new file mode 100644 index 000000000000..4f98ced2f8d6 --- /dev/null +++ b/user_guide_src/source/testing/feature/004.php @@ -0,0 +1,7 @@ +withRoutes($routes)->get('users'); diff --git a/user_guide_src/source/testing/feature/005.php b/user_guide_src/source/testing/feature/005.php new file mode 100644 index 000000000000..448e68800a4e --- /dev/null +++ b/user_guide_src/source/testing/feature/005.php @@ -0,0 +1,13 @@ + 123, +]; + +$result = $this->withSession($values)->get('admin'); + +// Or... + +$_SESSION['logged_in'] = 123; + +$result = $this->withSession()->get('admin'); diff --git a/user_guide_src/source/testing/feature/006.php b/user_guide_src/source/testing/feature/006.php new file mode 100644 index 000000000000..e3cf72b69b47 --- /dev/null +++ b/user_guide_src/source/testing/feature/006.php @@ -0,0 +1,7 @@ + 'application/json', +]; + +$result = $this->withHeaders($headers)->post('users'); diff --git a/user_guide_src/source/testing/feature/007.php b/user_guide_src/source/testing/feature/007.php new file mode 100644 index 000000000000..f44369c79865 --- /dev/null +++ b/user_guide_src/source/testing/feature/007.php @@ -0,0 +1,3 @@ +skipEvents()->post('users', $userInfo); diff --git a/user_guide_src/source/testing/feature/008.php b/user_guide_src/source/testing/feature/008.php new file mode 100644 index 000000000000..f5118ea42091 --- /dev/null +++ b/user_guide_src/source/testing/feature/008.php @@ -0,0 +1,7 @@ +withBodyFormat('json')->post('users', $userInfo); + +// Your controller can then get the parameters passed in with: +$userInfo = $this->request->getJson(); diff --git a/user_guide_src/source/testing/mocking.rst b/user_guide_src/source/testing/mocking.rst index 972ad1a40f96..8c4b8b54d222 100644 --- a/user_guide_src/source/testing/mocking.rst +++ b/user_guide_src/source/testing/mocking.rst @@ -15,9 +15,9 @@ Cache ===== You can mock the cache with the ``mock()`` method, using the ``CacheFactory`` as its only parameter. -:: - $mock = mock(\CodeIgniter\Cache\CacheFactory::class); +.. literalinclude:: mocking/001.php + :lines: 2- While this returns an instance of ``CodeIgniter\Test\Mock\MockCache`` that you can use directly, it also inserts the mock into the Service class, so any calls within your code to ``service('cache')`` or ``Config\Services::cache()`` will @@ -31,23 +31,14 @@ Additional Methods You can instruct the mocked cache handler to never do any caching with the ``bypass()`` method. This will emulate using the dummy handler and ensures that your test does not rely on cached data for your tests. -:: - $mock = mock(\CodeIgniter\Cache\CacheFactory::class); - // Never cache any items during this test. - $mock->bypass(); +.. literalinclude:: mocking/002.php + :lines: 2- Available Assertions -------------------- The following new assertions are available on the mocked class for using during testing: -:: - $mock = mock(\CodeIgniter\Cache\CacheFactory::class); - - // Assert that a cached item named $key exists - $mock->assertHas($key); - // Assert that a cached item named $key exists with a value of $value - $mock->assertHasValue($key, $value); - // Assert that a cached item named $key does NOT exist - $mock->assertMissing($key); +.. literalinclude:: mocking/003.php + :lines: 2- diff --git a/user_guide_src/source/testing/mocking/001.php b/user_guide_src/source/testing/mocking/001.php new file mode 100644 index 000000000000..69e69239049d --- /dev/null +++ b/user_guide_src/source/testing/mocking/001.php @@ -0,0 +1,3 @@ +bypass(); diff --git a/user_guide_src/source/testing/mocking/003.php b/user_guide_src/source/testing/mocking/003.php new file mode 100644 index 000000000000..4a3babddaf54 --- /dev/null +++ b/user_guide_src/source/testing/mocking/003.php @@ -0,0 +1,10 @@ +assertHas($key); +// Assert that a cached item named $key exists with a value of $value +$mock->assertHasValue($key, $value); +// Assert that a cached item named $key does NOT exist +$mock->assertMissing($key); diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 4b4cdce7beed..9c3fec194ab4 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -43,7 +43,6 @@ Phar The other option is to download the .phar file from the `PHPUnit `__ site. This is a standalone file that should be placed within your project root. - ************************ Testing Your Application ************************ @@ -64,38 +63,13 @@ The Test Class In order to take advantage of the additional tools provided, your tests must extend ``CIUnitTestCase``. All tests are expected to be located in the **tests/app** directory by default. -To test a new library, **Foo**, you would create a new file at **tests/app/Libraries/FooTest.php**:: - - model->purgeDeleted() - } +.. literalinclude:: overview/006.php + :lines: 2- Traits ------ @@ -157,22 +114,10 @@ A common way to enhance your tests is by using traits to consolidate staging acr 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 of your test cases you could create an authentication trait with a set up method to fake a -logged in user:: - - trait AuthTrait - { - protected setUpAuthTrait() - { - $user = $this->createFakeUser(); - $this->logInUser($user); - } - ... - - class AuthenticationFeatureTest - { - use AuthTrait; - ... +logged in user: +.. literalinclude:: overview/007.php + :lines: 2- Additional Assertions --------------------- @@ -181,54 +126,34 @@ Additional Assertions **assertLogged($level, $expectedMessage)** -Ensure that something you expected to be logged actually was:: +Ensure that something you expected to be logged actually was: - $config = new LoggerConfig(); - $logger = new Logger($config); - - ... do something that you expect a log entry from - $logger->log('error', "That's no moon"); - - $this->assertLogged('error', "That's no moon"); +.. literalinclude:: overview/008.php + :lines: 2- **assertEventTriggered($eventName)** -Ensure that an event you expected to be triggered actually was:: - - Events::on('foo', function ($arg) use(&$result) { - $result = $arg; - }); - - Events::trigger('foo', 'bar'); +Ensure that an event you expected to be triggered actually was: - $this->assertEventTriggered('foo'); +.. literalinclude:: overview/009.php + :lines: 2- **assertHeaderEmitted($header, $ignoreCase = false)** -Ensure that a header or cookie was actually emitted:: +Ensure that a header or cookie was actually emitted: - $response->setCookie('foo', 'bar'); - - ob_start(); - $this->response->send(); - $output = ob_get_clean(); // in case you want to check the actual body - - $this->assertHeaderEmitted("Set-Cookie: foo=bar"); +.. literalinclude:: overview/010.php + :lines: 2- Note: the test case with this should be `run as a separate process in PHPunit `_. **assertHeaderNotEmitted($header, $ignoreCase = false)** -Ensure that a header or cookie was not emitted:: - - $response->setCookie('foo', 'bar'); - - ob_start(); - $this->response->send(); - $output = ob_get_clean(); // in case you want to check the actual body +Ensure that a header or cookie was not emitted: - $this->assertHeaderNotEmitted("Set-Cookie: banana"); +.. literalinclude:: overview/011.php + :lines: 2- Note: the test case with this should be `run as a separate process in PHPunit `_. @@ -236,26 +161,23 @@ in PHPunit start('longjohn', strtotime('-11 minutes')); - $this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn')); +.. literalinclude:: overview/012.php + :lines: 2- The above test will allow the actual time to be either 660 or 661 seconds. **assertCloseEnoughString($expected, $actual, $message = '', $tolerance = 1)** For extended execution time testing, tests that the absolute difference -between expected and actual time, formatted as strings, is within the prescribed tolerance.:: +between expected and actual time, formatted as strings, is within the prescribed tolerance.: - $timer = new Timer(); - $timer->start('longjohn', strtotime('-11 minutes')); - $this->assertCloseEnoughString(11 * 60, $timer->getElapsedTime('longjohn')); +.. literalinclude:: overview/013.php + :lines: 2- The above test will allow the actual time to be either 660 or 661 seconds. - Accessing Protected/Private Properties -------------------------------------- @@ -267,42 +189,24 @@ properties in the classes that you are testing. Enables you to call private methods from outside the class. This returns a function that can be called. The first parameter is an instance of the class to test. The second parameter is the name of the method you want to call. -:: - - // Create an instance of the class to test - $obj = new Foo(); - - // Get the invoker for the 'privateMethod' method. - $method = $this->getPrivateMethodInvoker($obj, 'privateMethod'); - - // Test the results - $this->assertEquals('bar', $method('param1', 'param2')); +.. literalinclude:: overview/014.php + :lines: 2- **getPrivateProperty($instance, $property)** Retrieves the value of a private/protected class property from an instance of a class. The first parameter is an instance of the class to test. The second parameter is the name of the property. -:: - - // Create an instance of the class to test - $obj = new Foo(); - - // Test the value - $this->assertEquals('bar', $this->getPrivateProperty($obj, 'baz')); +.. literalinclude:: overview/015.php + :lines: 2- **setPrivateProperty($instance, $property, $value)** Set a protected value within a class instance. The first parameter is an instance of the class to test. The second -parameter is the name of the property to set the value of. The third parameter is the value to set it to:: - - // Create an instance of the class to test - $obj = new Foo(); - - // Set the value - $this->setPrivateProperty($obj, 'baz', 'oops!'); +parameter is the name of the property to set the value of. The third parameter is the value to set it to: - // Do normal testing... +.. literalinclude:: overview/016.php + :lines: 2- Mocking Services ================ @@ -316,17 +220,9 @@ to simplify this. This method allows you to define the exact instance that will be returned by the Services class. You can use this to set properties of a service so that it behaves in a certain way, or replace a service with a mocked class. -:: - public function testSomething() - { - $curlrequest = $this->getMockBuilder('CodeIgniter\HTTP\CURLRequest') - ->setMethods(['request']) - ->getMock(); - Services::injectMock('curlrequest', $curlrequest); - - // Do normal testing here.... - } +.. literalinclude:: overview/017.php + :lines: 2- The first parameter is the service that you are replacing. The name must match the function name in the Services class exactly. The second parameter is the instance to replace it with. @@ -347,15 +243,10 @@ Mocking Factory Instances Similar to Services, you may find yourself needing to supply a pre-configured class instance during testing that will be used with ``Factories``. Use the same ``injectMock()`` and ``reset()`` static methods like **Services**, but they take an additional preceding parameter for the -component name:: - - protected function setUp() - { - parent::setUp(); +component name: - $model = new MockUserModel(); - Factories::injectMock('models', 'App\Models\UserModel', $model); - } +.. literalinclude:: overview/018.php + :lines: 2- .. note:: All component Factories are reset by default between each test. Modify your test case's ``$setUpMethods`` if you need instances to persist. @@ -367,22 +258,7 @@ Stream Filters You may need to test things that are difficult to test. Sometimes, capturing a stream, like PHP's own STDOUT, or STDERR, might be helpful. The ``CITestStreamFilter`` helps you capture the output from the stream of your choice. -An example demonstrating this inside one of your test cases:: - - public function setUp() - { - CITestStreamFilter::$buffer = ''; - $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - } - - public function tearDown() - { - stream_filter_remove($this->stream_filter); - } - - public function testSomeOutput() - { - CLI::write('first.'); - $expected = "first.\n"; - $this->assertSame($expected, CITestStreamFilter::$buffer); - } +An example demonstrating this inside one of your test cases: + +.. literalinclude:: overview/019.php + :lines: 2- diff --git a/user_guide_src/source/testing/overview/001.php b/user_guide_src/source/testing/overview/001.php new file mode 100644 index 000000000000..6dac95d2b671 --- /dev/null +++ b/user_guide_src/source/testing/overview/001.php @@ -0,0 +1,13 @@ +model->purgeDeleted() + } diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php new file mode 100644 index 000000000000..74bbb533de38 --- /dev/null +++ b/user_guide_src/source/testing/overview/007.php @@ -0,0 +1,15 @@ +createFakeUser(); + $this->logInUser($user); + } +... + +class AuthenticationFeatureTest +{ + use AuthTrait; +... diff --git a/user_guide_src/source/testing/overview/008.php b/user_guide_src/source/testing/overview/008.php new file mode 100644 index 000000000000..9d84f888c1d4 --- /dev/null +++ b/user_guide_src/source/testing/overview/008.php @@ -0,0 +1,9 @@ +log('error', "That's no moon"); + +$this->assertLogged('error', "That's no moon"); diff --git a/user_guide_src/source/testing/overview/009.php b/user_guide_src/source/testing/overview/009.php new file mode 100644 index 000000000000..115cf6bda9e4 --- /dev/null +++ b/user_guide_src/source/testing/overview/009.php @@ -0,0 +1,9 @@ +assertEventTriggered('foo'); diff --git a/user_guide_src/source/testing/overview/010.php b/user_guide_src/source/testing/overview/010.php new file mode 100644 index 000000000000..4884f9a4a9f2 --- /dev/null +++ b/user_guide_src/source/testing/overview/010.php @@ -0,0 +1,9 @@ +setCookie('foo', 'bar'); + +ob_start(); +$this->response->send(); +$output = ob_get_clean(); // in case you want to check the actual body + +$this->assertHeaderEmitted("Set-Cookie: foo=bar"); diff --git a/user_guide_src/source/testing/overview/011.php b/user_guide_src/source/testing/overview/011.php new file mode 100644 index 000000000000..a2aa11c7bb64 --- /dev/null +++ b/user_guide_src/source/testing/overview/011.php @@ -0,0 +1,9 @@ +setCookie('foo', 'bar'); + +ob_start(); +$this->response->send(); +$output = ob_get_clean(); // in case you want to check the actual body + +$this->assertHeaderNotEmitted("Set-Cookie: banana"); diff --git a/user_guide_src/source/testing/overview/012.php b/user_guide_src/source/testing/overview/012.php new file mode 100644 index 000000000000..c9b85aef7f87 --- /dev/null +++ b/user_guide_src/source/testing/overview/012.php @@ -0,0 +1,5 @@ +start('longjohn', strtotime('-11 minutes')); +$this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn')); diff --git a/user_guide_src/source/testing/overview/013.php b/user_guide_src/source/testing/overview/013.php new file mode 100644 index 000000000000..1c03733868e4 --- /dev/null +++ b/user_guide_src/source/testing/overview/013.php @@ -0,0 +1,5 @@ +start('longjohn', strtotime('-11 minutes')); +$this->assertCloseEnoughString(11 * 60, $timer->getElapsedTime('longjohn')); diff --git a/user_guide_src/source/testing/overview/014.php b/user_guide_src/source/testing/overview/014.php new file mode 100644 index 000000000000..f228dcf28963 --- /dev/null +++ b/user_guide_src/source/testing/overview/014.php @@ -0,0 +1,10 @@ +getPrivateMethodInvoker($obj, 'privateMethod'); + +// Test the results +$this->assertEquals('bar', $method('param1', 'param2')); diff --git a/user_guide_src/source/testing/overview/015.php b/user_guide_src/source/testing/overview/015.php new file mode 100644 index 000000000000..1befb710253e --- /dev/null +++ b/user_guide_src/source/testing/overview/015.php @@ -0,0 +1,7 @@ +assertEquals('bar', $this->getPrivateProperty($obj, 'baz')); diff --git a/user_guide_src/source/testing/overview/016.php b/user_guide_src/source/testing/overview/016.php new file mode 100644 index 000000000000..c2e815953dd9 --- /dev/null +++ b/user_guide_src/source/testing/overview/016.php @@ -0,0 +1,9 @@ +setPrivateProperty($obj, 'baz', 'oops!'); + +// Do normal testing... diff --git a/user_guide_src/source/testing/overview/017.php b/user_guide_src/source/testing/overview/017.php new file mode 100644 index 000000000000..653c7d0947ba --- /dev/null +++ b/user_guide_src/source/testing/overview/017.php @@ -0,0 +1,11 @@ +getMockBuilder('CodeIgniter\HTTP\CURLRequest') + ->setMethods(['request']) + ->getMock(); + Services::injectMock('curlrequest', $curlrequest); + + // Do normal testing here.... +} diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php new file mode 100644 index 000000000000..743074117d9e --- /dev/null +++ b/user_guide_src/source/testing/overview/018.php @@ -0,0 +1,9 @@ +stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); +} + +public function tearDown() +{ + stream_filter_remove($this->stream_filter); +} + +public function testSomeOutput() +{ + CLI::write('first.'); + $expected = "first.\n"; + $this->assertSame($expected, CITestStreamFilter::$buffer); +} diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index 6c22e7e9cbdb..e695064825fe 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -5,10 +5,10 @@ Testing Responses The ``TestResponse`` class provides a number of helpful functions for parsing and testing responses from your test cases. Usually a ``TestResponse`` will be provided for you as a result of your :doc:`Controller Tests ` or :doc:`HTTP Feature Tests `, but you can always -create your own directly using any ``ResponseInterface``:: +create your own directly using any ``ResponseInterface``: - $result = new \CodeIgniter\Test\TestResponse($response); - $result->assertOK(); +.. literalinclude:: response/001.php + :lines: 2- .. contents:: :local: @@ -25,15 +25,17 @@ Accessing Request/Response **request()** -You can access directly the Request object, if it was set during testing:: +You can access directly the Request object, if it was set during testing: - $request = $results->request(); +.. literalinclude:: response/002.php + :lines: 2- **response()** -This allows you direct access to the response object:: +This allows you direct access to the response object: - $response = $results->response(); +.. literalinclude:: response/003.php + :lines: 2- Checking Response Status ------------------------ @@ -42,58 +44,52 @@ Checking Response Status Returns a boolean true/false based on whether the response is perceived to be "ok". This is primarily determined by a response status code in the 200 or 300's. An empty body is not considered valid, unless in redirects. -:: - if ($result->isOK()) { - ... - } +.. literalinclude:: response/004.php + :lines: 2- **assertOK()** This assertion simply uses the **isOK()** method to test a response. **assertNotOK** is the inverse of this assertion. -:: - $result->assertOK(); +.. literalinclude:: response/005.php + :lines: 2- **isRedirect()** Returns a boolean true/false based on whether the response is a redirected response. -:: - if ($result->isRedirect()) { - ... - } +.. literalinclude:: response/006.php + :lines: 2- **assertRedirect()** Asserts that the Response is an instance of RedirectResponse. **assertNotRedirect** is the inverse of this assertion. -:: - $result->assertRedirect(); +.. literalinclude:: response/007.php + :lines: 2- **assertRedirectTo()** Asserts that the Response is an instance of RedirectResponse and the destination matches the uri given. -:: - $result->assertRedirectTo('foo/bar'); +.. literalinclude:: response/008.php + :lines: 2- **getRedirectUrl()** Returns the URL set for a RedirectResponse, or null for failure. -:: - $url = $result->getRedirectUrl(); - $this->assertEquals(site_url('foo/bar'), $url); +.. literalinclude:: response/009.php + :lines: 2- **assertStatus(int $code)** Asserts that the HTTP status code returned matches $code. -:: - - $result->assertStatus(403); +.. literalinclude:: response/010.php + :lines: 2- Session Assertions ------------------ @@ -102,17 +98,16 @@ Session Assertions Asserts that a value exists in the resulting session. If $value is passed, will also assert that the variable's value matches what was specified. -:: - $result->assertSessionHas('logged_in', 123); +.. literalinclude:: response/011.php + :lines: 2- **assertSessionMissing(string $key)** Asserts that the resulting session does not include the specified $key. -:: - - $result->assertSessionMissin('logged_in'); +.. literalinclude:: response/012.php + :lines: 2- Header Assertions ----------------- @@ -121,17 +116,16 @@ Header Assertions Asserts that a header named **$key** exists in the response. If **$value** is not empty, will also assert that the values match. -:: - $result->assertHeader('Content-Type', 'text/html'); +.. literalinclude:: response/013.php + :lines: 2- **assertHeaderMissing(string $key)** Asserts that a header name **$key** does not exist in the response. -:: - - $result->assertHeader('Accepts'); +.. literalinclude:: response/014.php + :lines: 2- Cookie Assertions ----------------- @@ -140,24 +134,24 @@ Cookie Assertions Asserts that a cookie named **$key** exists in the response. If **$value** is not empty, will also assert that the values match. You can set the cookie prefix, if needed, by passing it in as the third parameter. -:: - $result->assertCookie('foo', 'bar'); +.. literalinclude:: response/015.php + :lines: 2- **assertCookieMissing(string $key)** Asserts that a cookie named **$key** does not exist in the response. -:: - $result->assertCookieMissing('ci_session'); +.. literalinclude:: response/016.php + :lines: 2- **assertCookieExpired(string $key, string $prefix = '')** Asserts that a cookie named **$key** exists, but has expired. You can set the cookie prefix, if needed, by passing it in as the second parameter. -:: - $result->assertCookieExpired('foo'); +.. literalinclude:: response/017.php + :lines: 2- DOM Helpers ----------- @@ -166,54 +160,36 @@ The response you get back contains a number of helper methods to inspect the HTM are useful for using within assertions in your tests. The **see()** method checks the text on the page to see if it exists either by itself, or more specifically within -a tag, as specified by type, class, or id:: +a tag, as specified by type, class, or id: - // Check that "Hello World" is on the page - $results->see('Hello World'); - // Check that "Hello World" is within an h1 tag - $results->see('Hello World', 'h1'); - // Check that "Hello World" is within an element with the "notice" class - $results->see('Hello World', '.notice'); - // Check that "Hello World" is within an element with id of "title" - $results->see('Hellow World', '#title'); +.. literalinclude:: response/018.php + :lines: 2- -The **dontSee()** method is the exact opposite:: +The **dontSee()** method is the exact opposite: - // Checks that "Hello World" does NOT exist on the page - $results->dontSee('Hello World'); - // Checks that "Hellow World" does NOT exist within any h1 tag - $results->dontSee('Hello World', 'h1'); +.. literalinclude:: response/019.php + :lines: 2- The **seeElement()** and **dontSeeElement()** are very similar to the previous methods, but do not look at the -values of the elements. Instead, they simply check that the elements exist on the page:: +values of the elements. Instead, they simply check that the elements exist on the page: - // Check that an element with class 'notice' exists - $results->seeElement('.notice'); - // Check that an element with id 'title' exists - $results->seeElement('#title') - // Verify that an element with id 'title' does NOT exist - $results->dontSeeElement('#title'); +.. literalinclude:: response/020.php + :lines: 2- -You can use **seeLink()** to ensure that a link appears on the page with the specified text:: +You can use **seeLink()** to ensure that a link appears on the page with the specified text: - // Check that a link exists with 'Upgrade Account' as the text:: - $results->seeLink('Upgrade Account'); - // Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' - $results->seeLink('Upgrade Account', '.upsell'); +.. literalinclude:: response/021.php + :lines: 2- -The **seeInField()** method checks for any input tags exist with the name and value:: +The **seeInField()** method checks for any input tags exist with the name and value: - // Check that an input exists named 'user' with the value 'John Snow' - $results->seeInField('user', 'John Snow'); - // Check a multi-dimensional input - $results->seeInField('user[name]', 'John Snow'); +.. literalinclude:: response/022.php + :lines: 2- -Finally, you can check if a checkbox exists and is checked with the **seeCheckboxIsChecked()** method:: +Finally, you can check if a checkbox exists and is checked with the **seeCheckboxIsChecked()** method: - // Check if checkbox is checked with class of 'foo' - $results->seeCheckboxIsChecked('.foo'); - // Check if checkbox with id of 'bar' is checked - $results->seeCheckboxIsChecked('#bar'); +.. literalinclude:: response/023.php + :lines: 2- DOM Assertions -------------- @@ -224,62 +200,46 @@ assertions. **assertSee(string $search = null, string $element = null)** Asserts that text/HTML is on the page, either by itself or - more specifically - within -a tag, as specified by type, class, or id:: - - // Check that "Hello World" is on the page - $result->assertSee('Hello World'); - // Check that "Hello World" is within an h1 tag - $result->assertSee('Hello World', 'h1'); - // Check that "Hello World" is within an element with the "notice" class - $result->assertSee('Hello World', '.notice'); - // Check that "Hello World" is within an element with id of "title" - $result->assertSee('Hellow World', '#title'); +a tag, as specified by type, class, or id: +.. literalinclude:: response/024.php + :lines: 2- **assertDontSee(string $search = null, string $element = null)** -Asserts the exact opposite of the **assertSee()** method:: +Asserts the exact opposite of the **assertSee()** method: - // Checks that "Hello World" does NOT exist on the page - $results->dontSee('Hello World'); - // Checks that "Hello World" does NOT exist within any h1 tag - $results->dontSee('Hello World', 'h1'); +.. literalinclude:: response/025.php + :lines: 2- **assertSeeElement(string $search)** -Similar to **assertSee()**, however this only checks for an existing element. It does not check for specific text:: +Similar to **assertSee()**, however this only checks for an existing element. It does not check for specific text: - // Check that an element with class 'notice' exists - $results->seeElement('.notice'); - // Check that an element with id 'title' exists - $results->seeElement('#title') +.. literalinclude:: response/026.php + :lines: 2- **assertDontSeeElement(string $search)** Similar to **assertSee()**, however this only checks for an existing element that is missing. It does not check for -specific text:: +specific text: - // Verify that an element with id 'title' does NOT exist - $results->dontSeeElement('#title'); +.. literalinclude:: response/027.php + :lines: 2- **assertSeeLink(string $text, string $details=null)** -Asserts that an anchor tag is found with matching **$text** as the body of the tag:: +Asserts that an anchor tag is found with matching **$text** as the body of the tag: - // Check that a link exists with 'Upgrade Account' as the text:: - $results->seeLink('Upgrade Account'); - // Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' - $results->seeLink('Upgrade Account', '.upsell'); +.. literalinclude:: response/021.php + :lines: 2- **assertSeeInField(string $field, string $value=null)** -Asserts that an input tag exists with the name and value:: - - // Check that an input exists named 'user' with the value 'John Snow' - $results->assertSeeInField('user', 'John Snow'); - // Check a multi-dimensional input - $results->assertSeeInField('user[name]', 'John Snow'); +Asserts that an input tag exists with the name and value: +.. literalinclude:: response/029.php + :lines: 2- Working With JSON ----------------- @@ -289,22 +249,15 @@ can help to test the responses. **getJSON()** -This method will return the body of the response as a JSON string:: +This method will return the body of the response as a JSON string: - // Response body is this: - ['foo' => 'bar'] +.. literalinclude:: response/030.php + :lines: 2- - $json = $result->getJSON(); +You can use this method to determine if ``$response`` actually holds JSON content: - // $json is this: - { - "foo": "bar" - } - -You can use this method to determine if ``$response`` actually holds JSON content:: - - // Verify the response is JSON - $this->assertTrue($result->getJSON() !== false) +.. literalinclude:: response/031.php + :lines: 2- .. note:: Be aware that the JSON string will be pretty-printed in the result. @@ -312,21 +265,13 @@ You can use this method to determine if ``$response`` actually holds JSON conten Asserts that $fragment is found within the JSON response. It does not need to match the entire JSON value. -:: - - // Response body is this: - [ - 'config' => ['key-a', 'key-b'], - ] - - // Is true - $result->assertJSONFragment(['config' => ['key-a']]); +.. literalinclude:: response/032.php + :lines: 2- **assertJSONExact($test)** Similar to **assertJSONFragment()**, but checks the entire JSON response to ensure exact matches. - Working With XML ---------------- diff --git a/user_guide_src/source/testing/response/001.php b/user_guide_src/source/testing/response/001.php new file mode 100644 index 000000000000..0e37cfec37ba --- /dev/null +++ b/user_guide_src/source/testing/response/001.php @@ -0,0 +1,4 @@ +assertOK(); diff --git a/user_guide_src/source/testing/response/002.php b/user_guide_src/source/testing/response/002.php new file mode 100644 index 000000000000..a835659904db --- /dev/null +++ b/user_guide_src/source/testing/response/002.php @@ -0,0 +1,3 @@ +request(); diff --git a/user_guide_src/source/testing/response/003.php b/user_guide_src/source/testing/response/003.php new file mode 100644 index 000000000000..c0cb73899f30 --- /dev/null +++ b/user_guide_src/source/testing/response/003.php @@ -0,0 +1,3 @@ +response(); diff --git a/user_guide_src/source/testing/response/004.php b/user_guide_src/source/testing/response/004.php new file mode 100644 index 000000000000..3cb56ea74b8f --- /dev/null +++ b/user_guide_src/source/testing/response/004.php @@ -0,0 +1,5 @@ +isOK()) { + ... +} diff --git a/user_guide_src/source/testing/response/005.php b/user_guide_src/source/testing/response/005.php new file mode 100644 index 000000000000..9c01964bc050 --- /dev/null +++ b/user_guide_src/source/testing/response/005.php @@ -0,0 +1,3 @@ +assertOK(); diff --git a/user_guide_src/source/testing/response/006.php b/user_guide_src/source/testing/response/006.php new file mode 100644 index 000000000000..90da5662c383 --- /dev/null +++ b/user_guide_src/source/testing/response/006.php @@ -0,0 +1,5 @@ +isRedirect()) { + ... +} diff --git a/user_guide_src/source/testing/response/007.php b/user_guide_src/source/testing/response/007.php new file mode 100644 index 000000000000..38b43a99b200 --- /dev/null +++ b/user_guide_src/source/testing/response/007.php @@ -0,0 +1,3 @@ +assertRedirect(); diff --git a/user_guide_src/source/testing/response/008.php b/user_guide_src/source/testing/response/008.php new file mode 100644 index 000000000000..62b8da3db6af --- /dev/null +++ b/user_guide_src/source/testing/response/008.php @@ -0,0 +1,3 @@ +assertRedirectTo('foo/bar'); diff --git a/user_guide_src/source/testing/response/009.php b/user_guide_src/source/testing/response/009.php new file mode 100644 index 000000000000..ba58bc23bb9e --- /dev/null +++ b/user_guide_src/source/testing/response/009.php @@ -0,0 +1,4 @@ +getRedirectUrl(); +$this->assertEquals(site_url('foo/bar'), $url); diff --git a/user_guide_src/source/testing/response/010.php b/user_guide_src/source/testing/response/010.php new file mode 100644 index 000000000000..70faf34078e1 --- /dev/null +++ b/user_guide_src/source/testing/response/010.php @@ -0,0 +1,3 @@ +assertStatus(403); diff --git a/user_guide_src/source/testing/response/011.php b/user_guide_src/source/testing/response/011.php new file mode 100644 index 000000000000..e9fccd725002 --- /dev/null +++ b/user_guide_src/source/testing/response/011.php @@ -0,0 +1,3 @@ +assertSessionHas('logged_in', 123); diff --git a/user_guide_src/source/testing/response/012.php b/user_guide_src/source/testing/response/012.php new file mode 100644 index 000000000000..671330ac32a4 --- /dev/null +++ b/user_guide_src/source/testing/response/012.php @@ -0,0 +1,3 @@ +assertSessionMissin('logged_in'); diff --git a/user_guide_src/source/testing/response/013.php b/user_guide_src/source/testing/response/013.php new file mode 100644 index 000000000000..761b39943842 --- /dev/null +++ b/user_guide_src/source/testing/response/013.php @@ -0,0 +1,3 @@ +assertHeader('Content-Type', 'text/html'); diff --git a/user_guide_src/source/testing/response/014.php b/user_guide_src/source/testing/response/014.php new file mode 100644 index 000000000000..109ce46d1097 --- /dev/null +++ b/user_guide_src/source/testing/response/014.php @@ -0,0 +1,3 @@ +assertHeader('Accepts'); diff --git a/user_guide_src/source/testing/response/015.php b/user_guide_src/source/testing/response/015.php new file mode 100644 index 000000000000..ded077e66a9b --- /dev/null +++ b/user_guide_src/source/testing/response/015.php @@ -0,0 +1,3 @@ +assertCookie('foo', 'bar'); diff --git a/user_guide_src/source/testing/response/016.php b/user_guide_src/source/testing/response/016.php new file mode 100644 index 000000000000..3aa73f14899a --- /dev/null +++ b/user_guide_src/source/testing/response/016.php @@ -0,0 +1,3 @@ +assertCookieMissing('ci_session'); diff --git a/user_guide_src/source/testing/response/017.php b/user_guide_src/source/testing/response/017.php new file mode 100644 index 000000000000..5ce2b3e2ab9f --- /dev/null +++ b/user_guide_src/source/testing/response/017.php @@ -0,0 +1,3 @@ +assertCookieExpired('foo'); diff --git a/user_guide_src/source/testing/response/018.php b/user_guide_src/source/testing/response/018.php new file mode 100644 index 000000000000..e6860f412e08 --- /dev/null +++ b/user_guide_src/source/testing/response/018.php @@ -0,0 +1,10 @@ +see('Hello World'); +// Check that "Hello World" is within an h1 tag +$results->see('Hello World', 'h1'); +// Check that "Hello World" is within an element with the "notice" class +$results->see('Hello World', '.notice'); +// Check that "Hello World" is within an element with id of "title" +$results->see('Hellow World', '#title'); diff --git a/user_guide_src/source/testing/response/019.php b/user_guide_src/source/testing/response/019.php new file mode 100644 index 000000000000..f96493b52e91 --- /dev/null +++ b/user_guide_src/source/testing/response/019.php @@ -0,0 +1,6 @@ +dontSee('Hello World'); +// Checks that "Hellow World" does NOT exist within any h1 tag +$results->dontSee('Hello World', 'h1'); diff --git a/user_guide_src/source/testing/response/020.php b/user_guide_src/source/testing/response/020.php new file mode 100644 index 000000000000..cb490d8a98ff --- /dev/null +++ b/user_guide_src/source/testing/response/020.php @@ -0,0 +1,8 @@ +seeElement('.notice'); +// Check that an element with id 'title' exists +$results->seeElement('#title') +// Verify that an element with id 'title' does NOT exist +$results->dontSeeElement('#title'); diff --git a/user_guide_src/source/testing/response/021.php b/user_guide_src/source/testing/response/021.php new file mode 100644 index 000000000000..bc74e3ad9124 --- /dev/null +++ b/user_guide_src/source/testing/response/021.php @@ -0,0 +1,6 @@ +seeLink('Upgrade Account'); +// Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' +$results->seeLink('Upgrade Account', '.upsell'); diff --git a/user_guide_src/source/testing/response/022.php b/user_guide_src/source/testing/response/022.php new file mode 100644 index 000000000000..9bb549c9db5f --- /dev/null +++ b/user_guide_src/source/testing/response/022.php @@ -0,0 +1,6 @@ +seeInField('user', 'John Snow'); +// Check a multi-dimensional input +$results->seeInField('user[name]', 'John Snow'); diff --git a/user_guide_src/source/testing/response/023.php b/user_guide_src/source/testing/response/023.php new file mode 100644 index 000000000000..3378144f6eb7 --- /dev/null +++ b/user_guide_src/source/testing/response/023.php @@ -0,0 +1,6 @@ +seeCheckboxIsChecked('.foo'); +// Check if checkbox with id of 'bar' is checked +$results->seeCheckboxIsChecked('#bar'); diff --git a/user_guide_src/source/testing/response/024.php b/user_guide_src/source/testing/response/024.php new file mode 100644 index 000000000000..021910b4e3f7 --- /dev/null +++ b/user_guide_src/source/testing/response/024.php @@ -0,0 +1,10 @@ +assertSee('Hello World'); +// Check that "Hello World" is within an h1 tag +$result->assertSee('Hello World', 'h1'); +// Check that "Hello World" is within an element with the "notice" class +$result->assertSee('Hello World', '.notice'); +// Check that "Hello World" is within an element with id of "title" +$result->assertSee('Hellow World', '#title'); diff --git a/user_guide_src/source/testing/response/025.php b/user_guide_src/source/testing/response/025.php new file mode 100644 index 000000000000..b255f4155ac5 --- /dev/null +++ b/user_guide_src/source/testing/response/025.php @@ -0,0 +1,6 @@ +dontSee('Hello World'); +// Checks that "Hello World" does NOT exist within any h1 tag +$results->dontSee('Hello World', 'h1'); diff --git a/user_guide_src/source/testing/response/026.php b/user_guide_src/source/testing/response/026.php new file mode 100644 index 000000000000..773b7dd04833 --- /dev/null +++ b/user_guide_src/source/testing/response/026.php @@ -0,0 +1,6 @@ +seeElement('.notice'); +// Check that an element with id 'title' exists +$results->seeElement('#title') diff --git a/user_guide_src/source/testing/response/027.php b/user_guide_src/source/testing/response/027.php new file mode 100644 index 000000000000..9780489133ee --- /dev/null +++ b/user_guide_src/source/testing/response/027.php @@ -0,0 +1,4 @@ +dontSeeElement('#title'); diff --git a/user_guide_src/source/testing/response/028.php b/user_guide_src/source/testing/response/028.php new file mode 100644 index 000000000000..bc74e3ad9124 --- /dev/null +++ b/user_guide_src/source/testing/response/028.php @@ -0,0 +1,6 @@ +seeLink('Upgrade Account'); +// Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' +$results->seeLink('Upgrade Account', '.upsell'); diff --git a/user_guide_src/source/testing/response/029.php b/user_guide_src/source/testing/response/029.php new file mode 100644 index 000000000000..1ae7910e9776 --- /dev/null +++ b/user_guide_src/source/testing/response/029.php @@ -0,0 +1,6 @@ +assertSeeInField('user', 'John Snow'); +// Check a multi-dimensional input +$results->assertSeeInField('user[name]', 'John Snow'); diff --git a/user_guide_src/source/testing/response/030.php b/user_guide_src/source/testing/response/030.php new file mode 100644 index 000000000000..e6417035e73f --- /dev/null +++ b/user_guide_src/source/testing/response/030.php @@ -0,0 +1,11 @@ + 'bar'] + +$json = $result->getJSON(); + +// $json is this: +{ + "foo": "bar" +} diff --git a/user_guide_src/source/testing/response/031.php b/user_guide_src/source/testing/response/031.php new file mode 100644 index 000000000000..0c9ded88a7f5 --- /dev/null +++ b/user_guide_src/source/testing/response/031.php @@ -0,0 +1,4 @@ +assertTrue($result->getJSON() !== false) diff --git a/user_guide_src/source/testing/response/032.php b/user_guide_src/source/testing/response/032.php new file mode 100644 index 000000000000..e808ca1a43dd --- /dev/null +++ b/user_guide_src/source/testing/response/032.php @@ -0,0 +1,9 @@ + ['key-a', 'key-b'], +] + +// Is true +$result->assertJSONFragment(['config' => ['key-a']]); diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 81a84e71f927..acf04e52d0f6 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -11,11 +11,10 @@ Enable CSRF Filter Before creating a form, let's enable the CSRF protection. -Open the **app/Config/Filters.php** file and update the ``$methods`` property like the following:: +Open the **app/Config/Filters.php** file and update the ``$methods`` property like the following: - public $methods = [ - 'post' => ['csrf'], - ]; +.. literalinclude:: create_news_items/001.php + :lines: 2- It configures the CSRF filter to be enabled for all **POST** requests. You can read more about the CSRF protection in :doc:`Security ` library. @@ -67,29 +66,8 @@ check whether the form was submitted and whether the submitted data passed the validation rules. You'll use the :doc:`form validation <../libraries/validation>` library to do this. -:: - - public function create() - { - $model = model(NewsModel::class); - - if ($this->request->getMethod() === 'post' && $this->validate([ - 'title' => 'required|min_length[3]|max_length[255]', - 'body' => 'required', - ])) { - $model->save([ - 'title' => $this->request->getPost('title'), - 'slug' => url_title($this->request->getPost('title'), '-', true), - 'body' => $this->request->getPost('body'), - ]); - - echo view('news/success'); - } else { - echo view('templates/header', ['title' => 'Create a news item']); - echo view('news/create'); - echo view('templates/footer'); - } - } +.. literalinclude:: create_news_items/002.php + :lines: 2- The code above adds a lot of functionality. First we load the NewsModel. After that, we check if we deal with the **POST** request and then @@ -134,20 +112,7 @@ not actually save any data because it doesn't know what fields are safe to be updated. Edit the **NewsModel** to provide it a list of updatable fields in the ``$allowedFields`` property. -:: - - `. -:: - - $routes->match(['get', 'post'], 'news/create', 'News::create'); - $routes->get('news/(:segment)', 'News::view/$1'); - $routes->get('news', 'News::index'); - $routes->get('(:any)', 'Pages::view/$1'); +.. literalinclude:: create_news_items/004.php + :lines: 2- Now point your browser to your local development environment where you installed CodeIgniter and add ``/news/create`` to the URL. diff --git a/user_guide_src/source/tutorial/create_news_items/001.php b/user_guide_src/source/tutorial/create_news_items/001.php new file mode 100644 index 000000000000..80d86db34633 --- /dev/null +++ b/user_guide_src/source/tutorial/create_news_items/001.php @@ -0,0 +1,5 @@ + ['csrf'], +]; diff --git a/user_guide_src/source/tutorial/create_news_items/002.php b/user_guide_src/source/tutorial/create_news_items/002.php new file mode 100644 index 000000000000..2dc230c3a720 --- /dev/null +++ b/user_guide_src/source/tutorial/create_news_items/002.php @@ -0,0 +1,23 @@ +request->getMethod() === 'post' && $this->validate([ + 'title' => 'required|min_length[3]|max_length[255]', + 'body' => 'required', + ])) { + $model->save([ + 'title' => $this->request->getPost('title'), + 'slug' => url_title($this->request->getPost('title'), '-', true), + 'body' => $this->request->getPost('body'), + ]); + + echo view('news/success'); + } else { + echo view('templates/header', ['title' => 'Create a news item']); + echo view('news/create'); + echo view('templates/footer'); + } +} diff --git a/user_guide_src/source/tutorial/create_news_items/003.php b/user_guide_src/source/tutorial/create_news_items/003.php new file mode 100644 index 000000000000..83e03f18eb2b --- /dev/null +++ b/user_guide_src/source/tutorial/create_news_items/003.php @@ -0,0 +1,12 @@ +match(['get', 'post'], 'news/create', 'News::create'); +$routes->get('news/(:segment)', 'News::view/$1'); +$routes->get('news', 'News::index'); +$routes->get('(:any)', 'Pages::view/$1'); diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst index 798341a6ce96..35cb5ba9ba7f 100644 --- a/user_guide_src/source/tutorial/index.rst +++ b/user_guide_src/source/tutorial/index.rst @@ -84,7 +84,6 @@ command line from the root of your project:: > php spark serve - The Welcome Page **************** @@ -127,6 +126,5 @@ There are a couple of things to note here: Everything else should be clear when you see it. - Now that we know how to get started and how to debug a little, let's get started building this small news application. diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index 396c74255962..3e5c7b0dd631 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -75,18 +75,7 @@ You can read more about it :doc:`here `. Open up the **app/Models/** directory and create a new file called **NewsModel.php** and add the following code. -:: - - findAll(); - } - - return $this->where(['slug' => $slug])->first(); - } +.. literalinclude:: news_section/002.php + :lines: 2- With this code, you can perform two different queries. You can get all news records, or get a news item by its slug. You might have @@ -135,30 +116,7 @@ in our ``Pages`` controller created earlier, but for the sake of clarity, a new ``News`` controller is defined. Create the new controller at **app/Controllers/News.php**. -:: - - getNews(); - } - - public function view($slug = null) - { - $model = model(NewsModel::class); - - $data['news'] = $model->getNews($slug); - } - } +.. literalinclude:: news_section/003.php Looking at the code, you may see some similarity with the files we created earlier. First, it extends a core CodeIgniter class, ``Controller``, @@ -179,21 +137,10 @@ news item to be returned. Now the data is retrieved by the controller through our model, but nothing is displayed yet. The next thing to do is, passing this data to -the views. Modify the ``index()`` method to look like this:: - - public function index() - { - $model = model(NewsModel::class); - - $data = [ - 'news' => $model->getNews(), - 'title' => 'News archive', - ]; +the views. Modify the ``index()`` method to look like this: - echo view('templates/header', $data); - echo view('news/overview', $data); - echo view('templates/footer', $data); - } +.. literalinclude:: news_section/004.php + :lines: 2- The code above gets all news records from the model and assigns it to a variable. The value for the title is also assigned to the ``$data['title']`` @@ -201,31 +148,7 @@ element and all data is passed to the views. You now need to create a view to render the news items. Create **app/Views/news/overview.php** and add the next piece of code. -:: - -

    - - - - - -

    - -
    - -
    -

    View article

    - - - - - -

    No News

    - -

    Unable to find any news for you.

    - - - +.. literalinclude:: news_section/005.php .. note:: We are again using using ``esc()`` to help prevent XSS attacks. But this time we also passed "url" as a second parameter. That's because @@ -243,34 +166,15 @@ a way that it can easily be used for this functionality. You only need to add some code to the controller and create a new view. Go back to the ``News`` controller and update the ``view()`` method with the following: -:: - - public function view($slug = null) - { - $model = model(NewsModel::class); - - $data['news'] = $model->getNews($slug); - - if (empty($data['news'])) { - throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug); - } - - $data['title'] = $data['news']['title']; - - echo view('templates/header', $data); - echo view('news/view', $data); - echo view('templates/footer', $data); - } +.. literalinclude:: news_section/006.php + :lines: 2- Instead of calling the ``getNews()`` method without a parameter, the ``$slug`` variable is passed, so it will return the specific news item. The only thing left to do is create the corresponding view at **app/Views/news/view.php**. Put the following code in this file. -:: - -

    -

    +.. literalinclude:: news_section/007.php Routing ------------------------------------------------------- @@ -282,11 +186,8 @@ This makes sure the requests reach the ``News`` controller instead of going directly to the ``Pages`` controller. The first line routes URI's with a slug to the ``view()`` method in the ``News`` controller. -:: - - $routes->get('news/(:segment)', 'News::view/$1'); - $routes->get('news', 'News::index'); - $routes->get('(:any)', 'Pages::view/$1'); +.. literalinclude:: news_section/008.php + :lines: 2- Point your browser to your "news" page, i.e., ``localhost:8080/news``, you should see a list of the news items, each of which has a link diff --git a/user_guide_src/source/tutorial/news_section/001.php b/user_guide_src/source/tutorial/news_section/001.php new file mode 100644 index 000000000000..b565d4a82f25 --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/001.php @@ -0,0 +1,10 @@ +findAll(); + } + + return $this->where(['slug' => $slug])->first(); +} diff --git a/user_guide_src/source/tutorial/news_section/003.php b/user_guide_src/source/tutorial/news_section/003.php new file mode 100644 index 000000000000..13c3b7263db6 --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/003.php @@ -0,0 +1,22 @@ +getNews(); + } + + public function view($slug = null) + { + $model = model(NewsModel::class); + + $data['news'] = $model->getNews($slug); + } +} diff --git a/user_guide_src/source/tutorial/news_section/004.php b/user_guide_src/source/tutorial/news_section/004.php new file mode 100644 index 000000000000..0fac31909775 --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/004.php @@ -0,0 +1,15 @@ + $model->getNews(), + 'title' => 'News archive', + ]; + + echo view('templates/header', $data); + echo view('news/overview', $data); + echo view('templates/footer', $data); +} diff --git a/user_guide_src/source/tutorial/news_section/005.php b/user_guide_src/source/tutorial/news_section/005.php new file mode 100644 index 000000000000..39db0a4319f7 --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/005.php @@ -0,0 +1,22 @@ +

    + + + + + +

    + +
    + +
    +

    View article

    + + + + + +

    No News

    + +

    Unable to find any news for you.

    + + diff --git a/user_guide_src/source/tutorial/news_section/006.php b/user_guide_src/source/tutorial/news_section/006.php new file mode 100644 index 000000000000..ea7331dbf77f --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/006.php @@ -0,0 +1,18 @@ +getNews($slug); + + if (empty($data['news'])) { + throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug); + } + + $data['title'] = $data['news']['title']; + + echo view('templates/header', $data); + echo view('news/view', $data); + echo view('templates/footer', $data); +} diff --git a/user_guide_src/source/tutorial/news_section/007.php b/user_guide_src/source/tutorial/news_section/007.php new file mode 100644 index 000000000000..9975baad0cbb --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/007.php @@ -0,0 +1,2 @@ +

    +

    diff --git a/user_guide_src/source/tutorial/news_section/008.php b/user_guide_src/source/tutorial/news_section/008.php new file mode 100644 index 000000000000..8943925258bd --- /dev/null +++ b/user_guide_src/source/tutorial/news_section/008.php @@ -0,0 +1,5 @@ +get('news/(:segment)', 'News::view/$1'); +$routes->get('news', 'News::index'); +$routes->get('(:any)', 'Pages::view/$1'); diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index ecf6e87e03c5..0b64ca40baba 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -33,25 +33,7 @@ Let's make our first controller Create a file at **app/Controllers/Pages.php** with the following code. -:: - - @@ -95,9 +75,7 @@ The header contains the basic HTML code that you'll want to display before loading the main view, together with a heading. It will also output the ``$title`` variable, which we'll define later in the controller. Now, create a footer at **app/Views/templates/footer.php** that -includes the following code: - -:: +includes the following code:: © 2021 @@ -123,21 +101,8 @@ In order to load those pages, you'll have to check whether the requested page actually exists. This will be the body of the ``view()`` method in the ``Pages`` controller created above: -:: - - public function view($page = 'home') - { - if (! is_file(APPPATH . 'Views/pages/' . $page . '.php')) { - // Whoops, we don't have a page for that! - throw new \CodeIgniter\Exceptions\PageNotFoundException($page); - } - - $data['title'] = ucfirst($page); // Capitalize the first letter - - echo view('templates/header', $data); - echo view('pages/' . $page, $data); - echo view('templates/footer', $data); - } +.. literalinclude:: static_pages/002.php + :lines: 2- Now, when the requested page does exist, it is loaded, including the header and footer, and displayed to the user. If the requested page doesn't exist, a "404 @@ -212,7 +177,6 @@ controller you made above produces... | | `app/Views/pages/shop.php` | +---------------------------------+-----------------------------------------------------------------+ - Routing ------------------------------------------------------- @@ -231,18 +195,16 @@ section of the configuration file. The only uncommented line there to start with should be: -:: - - $routes->get('/', 'Home::index'); +.. literalinclude:: static_pages/003.php + :lines: 2- This directive says that any incoming request without any content specified should be handled by the ``index()`` method inside the ``Home`` controller. Add the following line, **after** the route directive for '/'. -:: - - $routes->get('(:any)', 'Pages::view/$1'); +.. literalinclude:: static_pages/004.php + :lines: 2- CodeIgniter reads its routing rules from top to bottom and routes the request to the first matching rule. Each rule is a regular expression diff --git a/user_guide_src/source/tutorial/static_pages/001.php b/user_guide_src/source/tutorial/static_pages/001.php new file mode 100644 index 000000000000..0cedb8e44906 --- /dev/null +++ b/user_guide_src/source/tutorial/static_pages/001.php @@ -0,0 +1,16 @@ +get('/', 'Home::index'); diff --git a/user_guide_src/source/tutorial/static_pages/004.php b/user_guide_src/source/tutorial/static_pages/004.php new file mode 100644 index 000000000000..f998b89762fd --- /dev/null +++ b/user_guide_src/source/tutorial/static_pages/004.php @@ -0,0 +1,3 @@ +get('(:any)', 'Pages::view/$1'); From c18c392c01d009a6fb068871e4f8fdf714ad42f1 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Sun, 20 Feb 2022 00:04:17 +0100 Subject: [PATCH 1600/2325] Segregate duplicates. --- user_guide_src/source/libraries/publisher.rst | 2 +- user_guide_src/source/libraries/sessions.rst | 4 ++-- user_guide_src/source/libraries/sessions/005-1.php | 3 +++ user_guide_src/source/libraries/sessions/005-2.php | 3 +++ user_guide_src/source/outgoing/view_parser.rst | 2 +- user_guide_src/source/outgoing/view_parser/021-1.php | 3 +++ user_guide_src/source/testing/response.rst | 2 +- user_guide_src/source/testing/response/021-2.php | 6 ++++++ 8 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 user_guide_src/source/libraries/sessions/005-1.php create mode 100644 user_guide_src/source/libraries/sessions/005-2.php create mode 100644 user_guide_src/source/outgoing/view_parser/021-1.php create mode 100644 user_guide_src/source/testing/response/021-2.php diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 3657a124317c..ebe0716d2bcb 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -39,7 +39,7 @@ On Demand Access ``Publisher`` directly by instantiating a new instance of the class: -.. literalinclude:: publisher/001.php +.. literalinclude:: publisher/002.php :lines: 2- By default the source and destination will be set to ``ROOTPATH`` and ``FCPATH`` respectively, giving ``Publisher`` diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 889ad559d8bb..fcab322aa3d9 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -119,7 +119,7 @@ Retrieving Session Data Any piece of information from the session array is available through the ``$_SESSION`` superglobal: -.. literalinclude:: sessions/005.php +.. literalinclude:: sessions/005-2.php :lines: 2- Or through the conventional accessor method: @@ -335,7 +335,7 @@ You can also pass an array to ``setTempdata()``: To read a tempdata variable, again you can just access it through the ``$_SESSION`` superglobal array: -.. literalinclude:: sessions/005.php +.. literalinclude:: sessions/005-1.php :lines: 2- .. important:: The ``get()`` method WILL return tempdata items when diff --git a/user_guide_src/source/libraries/sessions/005-1.php b/user_guide_src/source/libraries/sessions/005-1.php new file mode 100644 index 000000000000..4f09358d5fc8 --- /dev/null +++ b/user_guide_src/source/libraries/sessions/005-1.php @@ -0,0 +1,3 @@ +render('myview'); diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index e695064825fe..ae6eb2deb97e 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -178,7 +178,7 @@ values of the elements. Instead, they simply check that the elements exist on th You can use **seeLink()** to ensure that a link appears on the page with the specified text: -.. literalinclude:: response/021.php +.. literalinclude:: response/021-2.php :lines: 2- The **seeInField()** method checks for any input tags exist with the name and value: diff --git a/user_guide_src/source/testing/response/021-2.php b/user_guide_src/source/testing/response/021-2.php new file mode 100644 index 000000000000..bc74e3ad9124 --- /dev/null +++ b/user_guide_src/source/testing/response/021-2.php @@ -0,0 +1,6 @@ +seeLink('Upgrade Account'); +// Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' +$results->seeLink('Upgrade Account', '.upsell'); From a85a2e843ef01971af68e9068c27e1c8c60676db Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Sun, 20 Feb 2022 09:04:37 +0100 Subject: [PATCH 1601/2325] Renumerate examples. --- user_guide_src/source/helpers/url_helper.rst | 44 ++++----- .../source/helpers/url_helper/002-2.php | 3 - .../source/helpers/url_helper/002-3.php | 3 - .../source/helpers/url_helper/002-4.php | 3 - .../source/helpers/url_helper/003.php | 2 +- .../source/helpers/url_helper/004.php | 2 +- .../source/helpers/url_helper/005.php | 9 +- .../source/helpers/url_helper/006.php | 13 +-- .../source/helpers/url_helper/007.php | 2 +- .../source/helpers/url_helper/008.php | 9 +- .../source/helpers/url_helper/009.php | 14 ++- .../source/helpers/url_helper/010.php | 2 +- .../source/helpers/url_helper/011.php | 2 +- .../source/helpers/url_helper/012.php | 3 +- .../source/helpers/url_helper/013.php | 2 +- .../source/helpers/url_helper/014.php | 4 +- .../source/helpers/url_helper/015.php | 4 +- .../source/helpers/url_helper/016.php | 4 +- .../source/helpers/url_helper/017.php | 4 +- .../source/helpers/url_helper/018.php | 4 +- .../source/helpers/url_helper/019.php | 4 +- .../source/helpers/url_helper/020.php | 2 +- .../source/helpers/url_helper/021.php | 2 +- .../source/helpers/url_helper/022.php | 3 + .../source/helpers/url_helper/023.php | 3 + .../source/helpers/url_helper/024.php | 3 + user_guide_src/source/incoming/routing.rst | 96 +++++++++---------- .../source/incoming/routing/000.php | 3 - .../source/incoming/routing/001.php | 6 +- .../source/incoming/routing/002.php | 6 +- .../source/incoming/routing/003.php | 4 +- .../source/incoming/routing/004.php | 2 +- .../source/incoming/routing/005.php | 2 +- .../source/incoming/routing/006.php | 2 +- .../source/incoming/routing/007.php | 2 +- .../source/incoming/routing/008.php | 6 +- .../source/incoming/routing/009.php | 2 +- .../source/incoming/routing/010.php | 3 +- .../source/incoming/routing/011.php | 6 +- .../source/incoming/routing/012.php | 2 +- .../source/incoming/routing/013.php | 7 +- .../source/incoming/routing/014.php | 7 +- .../source/incoming/routing/015.php | 7 +- .../source/incoming/routing/016.php | 7 +- .../source/incoming/routing/017.php | 9 +- .../source/incoming/routing/018.php | 9 +- .../source/incoming/routing/019.php | 5 +- .../source/incoming/routing/020.php | 6 +- .../source/incoming/routing/021.php | 4 +- .../source/incoming/routing/022.php | 11 +-- .../source/incoming/routing/023-2.php | 3 - .../source/incoming/routing/023.php | 11 +-- .../source/incoming/routing/024.php | 6 +- .../source/incoming/routing/025.php | 7 +- .../source/incoming/routing/026.php | 7 +- .../source/incoming/routing/027.php | 13 +-- .../source/incoming/routing/028.php | 2 +- .../source/incoming/routing/029.php | 13 ++- .../source/incoming/routing/030.php | 2 +- .../source/incoming/routing/031.php | 2 +- .../source/incoming/routing/032.php | 3 +- .../source/incoming/routing/033.php | 2 +- .../source/incoming/routing/034.php | 4 +- .../source/incoming/routing/035.php | 3 +- .../source/incoming/routing/036.php | 6 +- .../source/incoming/routing/037.php | 12 +-- .../source/incoming/routing/038.php | 5 +- .../source/incoming/routing/039.php | 13 ++- .../source/incoming/routing/040.php | 8 +- .../source/incoming/routing/041.php | 9 +- .../source/incoming/routing/042.php | 8 +- .../source/incoming/routing/043.php | 3 +- .../source/incoming/routing/044.php | 2 +- .../source/incoming/routing/045.php | 9 +- .../source/incoming/routing/046.php | 6 +- .../source/incoming/routing/047.php | 10 ++ .../source/incoming/routing/048.php | 7 ++ user_guide_src/source/libraries/sessions.rst | 6 +- .../source/libraries/sessions/005-1.php | 3 - .../source/libraries/sessions/005-2.php | 3 - .../source/libraries/uploaded_files.rst | 46 ++++----- .../source/libraries/uploaded_files/000.php | 23 ----- .../source/libraries/uploaded_files/001.php | 57 ++++------- .../source/libraries/uploaded_files/002.php | 47 ++++++++- .../source/libraries/uploaded_files/003.php | 4 +- .../source/libraries/uploaded_files/004.php | 6 +- .../source/libraries/uploaded_files/005.php | 4 +- .../source/libraries/uploaded_files/006.php | 10 +- .../source/libraries/uploaded_files/007.php | 2 +- .../source/libraries/uploaded_files/008.php | 9 +- .../source/libraries/uploaded_files/009.php | 10 +- .../source/libraries/uploaded_files/010.php | 3 +- .../source/libraries/uploaded_files/011.php | 3 +- .../source/libraries/uploaded_files/012.php | 5 +- .../source/libraries/uploaded_files/013.php | 4 +- .../source/libraries/uploaded_files/014.php | 2 +- .../source/libraries/uploaded_files/015.php | 2 +- .../source/libraries/uploaded_files/016.php | 2 +- .../source/libraries/uploaded_files/017.php | 4 +- .../source/libraries/uploaded_files/018.php | 4 +- .../source/libraries/uploaded_files/019.php | 3 +- .../source/libraries/uploaded_files/020.php | 5 +- .../source/libraries/uploaded_files/021.php | 4 +- .../source/libraries/uploaded_files/022.php | 2 +- .../source/libraries/uploaded_files/023.php | 3 + .../source/libraries/validation.rst | 18 ++-- .../source/libraries/validation/029-2.php | 7 -- .../source/libraries/validation/030.php | 13 +-- .../source/libraries/validation/031.php | 7 +- .../source/libraries/validation/032.php | 14 +-- .../source/libraries/validation/033.php | 18 ++-- .../source/libraries/validation/034.php | 11 +-- .../source/libraries/validation/035.php | 13 ++- .../source/libraries/validation/036.php | 35 +------ .../source/libraries/validation/037.php | 40 ++++++-- .../source/libraries/validation/038.php | 10 ++ .../source/outgoing/view_parser.rst | 32 +++---- .../source/outgoing/view_parser/010-2.php | 3 - .../source/outgoing/view_parser/011.php | 9 +- .../source/outgoing/view_parser/012.php | 3 +- .../source/outgoing/view_parser/013.php | 7 +- .../source/outgoing/view_parser/014.php | 19 ++-- .../source/outgoing/view_parser/015.php | 17 +++- .../source/outgoing/view_parser/016.php | 5 +- .../source/outgoing/view_parser/017.php | 11 +-- .../source/outgoing/view_parser/018.php | 6 +- .../source/outgoing/view_parser/019.php | 10 +- .../source/outgoing/view_parser/020.php | 25 +++-- .../source/outgoing/view_parser/021-1.php | 3 - .../source/outgoing/view_parser/021.php | 18 +++- .../source/outgoing/view_parser/023.php | 2 +- .../source/outgoing/view_parser/024.php | 2 +- .../source/outgoing/view_parser/025.php | 2 +- .../source/outgoing/view_parser/026.php | 3 + user_guide_src/source/testing/response.rst | 4 +- .../source/testing/response/021-2.php | 6 -- 136 files changed, 587 insertions(+), 602 deletions(-) delete mode 100644 user_guide_src/source/helpers/url_helper/002-2.php delete mode 100644 user_guide_src/source/helpers/url_helper/002-3.php delete mode 100644 user_guide_src/source/helpers/url_helper/002-4.php create mode 100644 user_guide_src/source/helpers/url_helper/022.php create mode 100644 user_guide_src/source/helpers/url_helper/023.php create mode 100644 user_guide_src/source/helpers/url_helper/024.php delete mode 100644 user_guide_src/source/incoming/routing/000.php delete mode 100644 user_guide_src/source/incoming/routing/023-2.php create mode 100644 user_guide_src/source/incoming/routing/047.php create mode 100644 user_guide_src/source/incoming/routing/048.php delete mode 100644 user_guide_src/source/libraries/sessions/005-1.php delete mode 100644 user_guide_src/source/libraries/sessions/005-2.php delete mode 100644 user_guide_src/source/libraries/uploaded_files/000.php create mode 100644 user_guide_src/source/libraries/uploaded_files/023.php delete mode 100644 user_guide_src/source/libraries/validation/029-2.php create mode 100644 user_guide_src/source/libraries/validation/038.php delete mode 100644 user_guide_src/source/outgoing/view_parser/010-2.php delete mode 100644 user_guide_src/source/outgoing/view_parser/021-1.php create mode 100644 user_guide_src/source/outgoing/view_parser/026.php delete mode 100644 user_guide_src/source/testing/response/021-2.php diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst index 5ce922578e45..0713a770b5f7 100644 --- a/user_guide_src/source/helpers/url_helper.rst +++ b/user_guide_src/source/helpers/url_helper.rst @@ -62,7 +62,7 @@ The following functions are available: Returns your site base URL, as specified in your config file. Example: - .. literalinclude:: url_helper/002-2.php + .. literalinclude:: url_helper/003.php :lines: 2- This function returns the same thing as :php:func:`site_url()`, without @@ -71,7 +71,7 @@ The following functions are available: Also like :php:func:`site_url()`, you can supply segments as a string or an array. Here is a string example: - .. literalinclude:: url_helper/002-3.php + .. literalinclude:: url_helper/004.php :lines: 2- The above example would return something like: @@ -80,7 +80,7 @@ The following functions are available: This is useful because unlike :php:func:`site_url()`, you can supply a string to a file, such as an image or stylesheet. For example: - .. literalinclude:: url_helper/002-4.php + .. literalinclude:: url_helper/005.php :lines: 2- This would give you something like: @@ -98,7 +98,7 @@ The following functions are available: .. note:: Calling this function is the same as doing this: - .. literalinclude:: url_helper/003.php + .. literalinclude:: url_helper/006.php :lines: 2- .. important:: Prior to **4.1.2** this function had a bug causing it to ignore the configuration on ``App::$indexPage``. @@ -147,7 +147,7 @@ The following functions are available: Returns your site **indexPage**, as specified in your config file. Example: - .. literalinclude:: url_helper/004.php + .. literalinclude:: url_helper/007.php :lines: 2- As with :php:func:`site_url()`, you may specify an alternate configuration. @@ -184,7 +184,7 @@ The following functions are available: Here are some examples: - .. literalinclude:: url_helper/005.php + .. literalinclude:: url_helper/008.php :lines: 2- As above, you may specify an alternate configuration. @@ -211,7 +211,7 @@ The following functions are available: Here is an example with attributes: - .. literalinclude:: url_helper/006.php + .. literalinclude:: url_helper/009.php :lines: 2- As above, you may specify an alternate configuration. @@ -224,7 +224,7 @@ The following functions are available: function to use all of its defaults simply pass an empty array in the third parameter: - .. literalinclude:: url_helper/007.php + .. literalinclude:: url_helper/010.php :lines: 2- .. note:: The **window_name** is not really an attribute, but an argument to @@ -246,13 +246,13 @@ The following functions are available: Creates a standard HTML e-mail link. Usage example: - .. literalinclude:: url_helper/008.php + .. literalinclude:: url_helper/011.php :lines: 2- As with the :php:func:`anchor()` tab above, you can set attributes using the third parameter: - .. literalinclude:: url_helper/009.php + .. literalinclude:: url_helper/012.php :lines: 2- .. note:: Attributes passed into the mailto function are automatically escaped to protected against XSS attacks. @@ -280,7 +280,7 @@ The following functions are available: Automatically turns URLs and e-mail addresses contained in a string into links. Example: - .. literalinclude:: url_helper/010.php + .. literalinclude:: url_helper/013.php :lines: 2- The second parameter determines whether URLs and e-mails are converted or @@ -290,18 +290,18 @@ The following functions are available: Converts only URLs: - .. literalinclude:: url_helper/011.php + .. literalinclude:: url_helper/014.php :lines: 2- Converts only e-mail addresses: - .. literalinclude:: url_helper/012.php + .. literalinclude:: url_helper/015.php :lines: 2- The third parameter determines whether links are shown in a new window. The value can be true or false (boolean): - .. literalinclude:: url_helper/013.php + .. literalinclude:: url_helper/016.php :lines: 2- .. note:: The only URLs recognized are those that start with "www." or with "://". @@ -318,7 +318,7 @@ The following functions are available: useful if, for example, you have a blog in which you'd like to use the title of your entries in the URL. Example: - .. literalinclude:: url_helper/014.php + .. literalinclude:: url_helper/017.php :lines: 2- The second parameter determines the word delimiter. By default dashes @@ -326,7 +326,7 @@ The following functions are available: Example: - .. literalinclude:: url_helper/015.php + .. literalinclude:: url_helper/018.php :lines: 2- The third parameter determines whether or not lowercase characters are @@ -334,7 +334,7 @@ The following functions are available: Example: - .. literalinclude:: url_helper/016.php + .. literalinclude:: url_helper/019.php :lines: 2- .. php:function:: mb_url_title($str[, $separator = '-'[, $lowercase = false]]) @@ -360,7 +360,7 @@ The following functions are available: Pass the URL string to the function like this: - .. literalinclude:: url_helper/017.php + .. literalinclude:: url_helper/020.php :lines: 2- .. php:function:: url_to($controller[, ...$args]) @@ -372,13 +372,13 @@ The following functions are available: Builds an absolute URL to a controller method in your app. Example: - .. literalinclude:: url_helper/018.php + .. literalinclude:: url_helper/021.php :lines: 2- You can also add arguments to the route. Here is an example: - .. literalinclude:: url_helper/019.php + .. literalinclude:: url_helper/022.php :lines: 2- The above example would return something like: @@ -394,13 +394,13 @@ The following functions are available: Compares the current URL's path against the given path to see if they match. Example: - .. literalinclude:: url_helper/020.php + .. literalinclude:: url_helper/023.php :lines: 2- This would match ``http://example.com/admin``. You can use the ``*`` wildcard to match any other applicable characters in the URL: - .. literalinclude:: url_helper/021.php + .. literalinclude:: url_helper/024.php :lines: 2- This would match any of the following: diff --git a/user_guide_src/source/helpers/url_helper/002-2.php b/user_guide_src/source/helpers/url_helper/002-2.php deleted file mode 100644 index fc388607fec6..000000000000 --- a/user_guide_src/source/helpers/url_helper/002-2.php +++ /dev/null @@ -1,3 +0,0 @@ -My News - -echo anchor('news/local/123', 'My News', ['title' => 'The best news!']); -// Prints: My News - -echo anchor('', 'Click here'); -// Prints: Click here +echo base_url('images/icons/edit.png'); diff --git a/user_guide_src/source/helpers/url_helper/006.php b/user_guide_src/source/helpers/url_helper/006.php index 960bc6f0430e..e6bd1a239fcd 100644 --- a/user_guide_src/source/helpers/url_helper/006.php +++ b/user_guide_src/source/helpers/url_helper/006.php @@ -1,14 +1,3 @@ 800, - 'height' => 600, - 'scrollbars' => 'yes', - 'status'      => 'yes', - 'resizable'   => 'yes', - 'screenx' => 0, - 'screeny' => 0, - 'window_name' => '_blank', -]; - -echo anchor_popup('news/local/123', 'Click Me!', $atts); +site_url(uri_string()); diff --git a/user_guide_src/source/helpers/url_helper/007.php b/user_guide_src/source/helpers/url_helper/007.php index cb1e202af757..35ae47978306 100644 --- a/user_guide_src/source/helpers/url_helper/007.php +++ b/user_guide_src/source/helpers/url_helper/007.php @@ -1,3 +1,3 @@ My News + +echo anchor('news/local/123', 'My News', ['title' => 'The best news!']); +// Prints: My News + +echo anchor('', 'Click here'); +// Prints: Click here diff --git a/user_guide_src/source/helpers/url_helper/009.php b/user_guide_src/source/helpers/url_helper/009.php index dcd65cd2bfcf..960bc6f0430e 100644 --- a/user_guide_src/source/helpers/url_helper/009.php +++ b/user_guide_src/source/helpers/url_helper/009.php @@ -1,4 +1,14 @@ 'Mail me']; -echo mailto('me@my-site.com', 'Contact Me', $attributes); +$atts = [ + 'width' => 800, + 'height' => 600, + 'scrollbars' => 'yes', + 'status'      => 'yes', + 'resizable'   => 'yes', + 'screenx' => 0, + 'screeny' => 0, + 'window_name' => '_blank', +]; + +echo anchor_popup('news/local/123', 'Click Me!', $atts); diff --git a/user_guide_src/source/helpers/url_helper/010.php b/user_guide_src/source/helpers/url_helper/010.php index 65bf083b99cf..cb1e202af757 100644 --- a/user_guide_src/source/helpers/url_helper/010.php +++ b/user_guide_src/source/helpers/url_helper/010.php @@ -1,3 +1,3 @@ 'Mail me']; +echo mailto('me@my-site.com', 'Contact Me', $attributes); diff --git a/user_guide_src/source/helpers/url_helper/013.php b/user_guide_src/source/helpers/url_helper/013.php index 4ee151df4b12..65bf083b99cf 100644 --- a/user_guide_src/source/helpers/url_helper/013.php +++ b/user_guide_src/source/helpers/url_helper/013.php @@ -1,3 +1,3 @@ ` for a group of routes. This will always run the filter before or after the controller. This is especially handy during authentication or api logging: -.. literalinclude:: routing/018.php +.. literalinclude:: routing/021.php :lines: 2- The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. It is possible to nest groups within groups for finer organization if you need it: -.. literalinclude:: routing/019.php +.. literalinclude:: routing/022.php :lines: 2- This would handle the URL at **admin/users/list**. @@ -275,7 +275,7 @@ config options like namespace, subdomain, etc. Without necessarily needing to ad an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the given route config options: -.. literalinclude:: routing/020.php +.. literalinclude:: routing/023.php :lines: 2- Environment Restrictions @@ -286,7 +286,7 @@ tools that only the developer can use on their local machines that are not reach This can be done with the ``environment()`` method. The first parameter is the name of the environment. Any routes defined within this closure are only accessible from the given environment: -.. literalinclude:: routing/021.php +.. literalinclude:: routing/024.php :lines: 2- Reverse Routing @@ -301,7 +301,7 @@ function to get the current route that should be used. The first parameter is th separated by a double colon (``::``), much like you would use when writing the initial route itself. Any parameters that should be passed to the route are passed in next: -.. literalinclude:: routing/022.php +.. literalinclude:: routing/025.php :lines: 2- Using Named Routes @@ -312,7 +312,7 @@ later, and even if the route definition changes, all of the links in your applic will still work without you having to make any changes. A route is named by passing in the ``as`` option with the name of the route: -.. literalinclude:: routing/023.php +.. literalinclude:: routing/026.php :lines: 2- This has the added benefit of making the views more readable, too. @@ -323,7 +323,7 @@ Routes with any HTTP verbs It is possible to define a route with any HTTP verbs. You can use the ``add()`` method: -.. literalinclude:: routing/023-2.php +.. literalinclude:: routing/027.php :lines: 2- .. warning:: While the ``add()`` method seems to be convenient, it is recommended to always use the HTTP-verb-based @@ -343,7 +343,7 @@ You can create routes that work only from the command-line, and are inaccessible route methods will also be inaccessible from the CLI, but routes created by the ``add()`` method will still be available from the command line: -.. literalinclude:: routing/026.php +.. literalinclude:: routing/028.php :lines: 2- Global Options @@ -352,7 +352,7 @@ Global Options All of the methods for creating a route (add, get, post, :doc:`resource ` etc) can take an array of options that can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter: -.. literalinclude:: routing/027.php +.. literalinclude:: routing/029.php :lines: 2- .. _applying-filters: @@ -379,19 +379,19 @@ See :doc:`Controller filters ` for more information on setting up filte You specify an alias defined in **app/Config/Filters.php** for the filter value: -.. literalinclude:: routing/028.php +.. literalinclude:: routing/030.php :lines: 2- You may also supply arguments to be passed to the alias filter's ``before()`` and ``after()`` methods: -.. literalinclude:: routing/029.php +.. literalinclude:: routing/031.php :lines: 2- **Classname filter** You specify a filter classname for the filter value: -.. literalinclude:: routing/030.php +.. literalinclude:: routing/032.php :lines: 2- **Multiple filters** @@ -400,7 +400,7 @@ You specify a filter classname for the filter value: You specify an array for the filter value: -.. literalinclude:: routing/031.php +.. literalinclude:: routing/033.php :lines: 2- .. _assigning-namespace: @@ -412,7 +412,7 @@ While a default namespace will be prepended to the generated controllers (see be a different namespace to be used in any options array, with the ``namespace`` option. The value should be the namespace you want modified: -.. literalinclude:: routing/032.php +.. literalinclude:: routing/034.php :lines: 2- The new namespace is only applied during that call for any methods that create a single route, like get, post, etc. @@ -425,7 +425,7 @@ Limit to Hostname You can restrict groups of routes to function only in certain domain or sub-domains of your application by passing the "hostname" option along with the desired domain to allow it on as part of the options array: -.. literalinclude:: routing/033.php +.. literalinclude:: routing/035.php :lines: 2- This example would only allow the specified hosts to work if the domain exactly matched **accounts.example.com**. @@ -437,13 +437,13 @@ Limit to Subdomains When the ``subdomain`` option is present, the system will restrict the routes to only be available on that sub-domain. The route will only be matched if the subdomain is the one the application is being viewed through: -.. literalinclude:: routing/034.php +.. literalinclude:: routing/036.php :lines: 2- You can restrict it to any subdomain by setting the value to an asterisk, (``*``). If you are viewing from a URL that does not have any subdomain present, this will not be matched: -.. literalinclude:: routing/035.php +.. literalinclude:: routing/037.php :lines: 2- .. important:: The system is not perfect and should be tested for your specific domain before being used in production. @@ -459,7 +459,7 @@ value being the number of segments to offset. This can be beneficial when developing API's with the first URI segment being the version number. It can also be used when the first parameter is a language string: -.. literalinclude:: routing/036.php +.. literalinclude:: routing/038.php :lines: 2- .. _routing-priority: @@ -473,12 +473,12 @@ You can solve this problem by lowering the priority of route processing using th accepts positive integers and zero. The higher the number specified in the ``priority``, the lower route priority in the processing queue: -.. literalinclude:: routing/037.php +.. literalinclude:: routing/039.php :lines: 2- To disable this functionality, you must call the method with the parameter ``false``: -.. literalinclude:: routing/038.php +.. literalinclude:: routing/040.php :lines: 2- .. note:: By default, all routes have a priority of 0. @@ -502,13 +502,13 @@ specified by the route. By default, this value is ``App\Controllers``. If you set the value empty string (``''``), it leaves each route to specify the fully namespaced controller: -.. literalinclude:: routing/039.php +.. literalinclude:: routing/041.php :lines: 2- If your controllers are not explicitly namespaced, there is no need to change this. If you namespace your controllers, then you can change this value to save typing: -.. literalinclude:: routing/040.php +.. literalinclude:: routing/042.php :lines: 2- Default Controller @@ -518,7 +518,7 @@ When a user visits the root of your site (i.e., example.com) the controller to u the ``setDefaultController()`` method, unless a route exists for it explicitly. The default value for this is ``Home`` which matches the controller at **app/Controllers/Home.php**: -.. literalinclude:: routing/041.php +.. literalinclude:: routing/043.php :lines: 2- The default controller is also used when no matching route has been found, and the URI would point to a directory @@ -535,7 +535,7 @@ when a controller is found that matches the URI, but no segment exists for the m In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the ``Products::listAll()`` method would be executed: -.. literalinclude:: routing/042.php +.. literalinclude:: routing/044.php :lines: 2- Translate URI Dashes @@ -545,7 +545,7 @@ This option enables you to automatically replace dashes (``-``) with underscores URI segments, thus saving you additional route entries if you need to do that. This is required because the dash isn’t a valid class or method name character and would cause a fatal error if you try to use it: -.. literalinclude:: routing/043.php +.. literalinclude:: routing/045.php :lines: 2- .. _use-defined-routes-only: @@ -557,7 +557,7 @@ When no defined route is found that matches the URI, the system will attempt to controllers and methods as described above. You can disable this automatic matching, and restrict routes to only those defined by you, by setting the ``setAutoRoute()`` option to false: -.. literalinclude:: routing/044.php +.. literalinclude:: routing/046.php :lines: 2- .. warning:: If you use the :doc:`CSRF protection `, it does not protect **GET** @@ -570,7 +570,7 @@ When a page is not found that matches the current URI, the system will show a ge what happens by specifying an action to happen with the ``set404Override()`` method. The value can be either a valid class/method pair, just like you would show in any route, or a Closure: -.. literalinclude:: routing/045.php +.. literalinclude:: routing/047.php :lines: 2- Route processing by priority @@ -580,7 +580,7 @@ Enables or disables processing of the routes queue by priority. Lowering the pri Disabled by default. This functionality affects all routes. For an example use of lowering the priority see :ref:`routing-priority`: -.. literalinclude:: routing/046.php +.. literalinclude:: routing/048.php :lines: 2- ***************** diff --git a/user_guide_src/source/incoming/routing/000.php b/user_guide_src/source/incoming/routing/000.php deleted file mode 100644 index d799d1cf0fb5..000000000000 --- a/user_guide_src/source/incoming/routing/000.php +++ /dev/null @@ -1,3 +0,0 @@ -get('/', 'Home::index'); diff --git a/user_guide_src/source/incoming/routing/001.php b/user_guide_src/source/incoming/routing/001.php index 4ddfd31abaed..d799d1cf0fb5 100644 --- a/user_guide_src/source/incoming/routing/001.php +++ b/user_guide_src/source/incoming/routing/001.php @@ -1,7 +1,3 @@ list() -$routes->get('users', 'Users::list'); - -// Calls $Users->list(1, 23) -$routes->get('users/1/23', 'Users::list/1/23'); \ No newline at end of file +$routes->get('/', 'Home::index'); diff --git a/user_guide_src/source/incoming/routing/002.php b/user_guide_src/source/incoming/routing/002.php index ba4d8d98a28a..4ddfd31abaed 100644 --- a/user_guide_src/source/incoming/routing/002.php +++ b/user_guide_src/source/incoming/routing/002.php @@ -1,3 +1,7 @@ get('product/(:num)', 'Catalog::productLookup'); +// Calls $Users->list() +$routes->get('users', 'Users::list'); + +// Calls $Users->list(1, 23) +$routes->get('users/1/23', 'Users::list/1/23'); \ No newline at end of file diff --git a/user_guide_src/source/incoming/routing/003.php b/user_guide_src/source/incoming/routing/003.php index 7a9075b57b2f..7351142dea77 100644 --- a/user_guide_src/source/incoming/routing/003.php +++ b/user_guide_src/source/incoming/routing/003.php @@ -1,3 +1,5 @@ get('journals', 'Blogs'); +$routes->post('products', 'Product::feature'); +$routes->put('products/1', 'Product::feature'); +$routes->delete('products/1', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/004.php b/user_guide_src/source/incoming/routing/004.php index 4ee87c0af53a..a071f75cd156 100644 --- a/user_guide_src/source/incoming/routing/004.php +++ b/user_guide_src/source/incoming/routing/004.php @@ -1,3 +1,3 @@ get('blog/joe', 'Blogs::users/34'); +$routes->match(['get', 'put'], 'products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/005.php b/user_guide_src/source/incoming/routing/005.php index d840165c7809..ba4d8d98a28a 100644 --- a/user_guide_src/source/incoming/routing/005.php +++ b/user_guide_src/source/incoming/routing/005.php @@ -1,3 +1,3 @@ get('product/(:any)', 'Catalog::productLookup'); +$routes->get('product/(:num)', 'Catalog::productLookup'); diff --git a/user_guide_src/source/incoming/routing/006.php b/user_guide_src/source/incoming/routing/006.php index 638ed4492220..7a9075b57b2f 100644 --- a/user_guide_src/source/incoming/routing/006.php +++ b/user_guide_src/source/incoming/routing/006.php @@ -1,3 +1,3 @@ get('product/(:num)', 'Catalog::productLookupByID/$1'); +$routes->get('journals', 'Blogs'); diff --git a/user_guide_src/source/incoming/routing/007.php b/user_guide_src/source/incoming/routing/007.php index c88bc65573a3..4ee87c0af53a 100644 --- a/user_guide_src/source/incoming/routing/007.php +++ b/user_guide_src/source/incoming/routing/007.php @@ -1,3 +1,3 @@ get('product/(:any)', 'Catalog::productLookup/$1'); +$routes->get('blog/joe', 'Blogs::users/34'); diff --git a/user_guide_src/source/incoming/routing/008.php b/user_guide_src/source/incoming/routing/008.php index 11437a5881c2..d840165c7809 100644 --- a/user_guide_src/source/incoming/routing/008.php +++ b/user_guide_src/source/incoming/routing/008.php @@ -1,7 +1,3 @@ get('product/(:any)', 'Catalog::productLookup'); diff --git a/user_guide_src/source/incoming/routing/009.php b/user_guide_src/source/incoming/routing/009.php index cee3785eb0d8..638ed4492220 100644 --- a/user_guide_src/source/incoming/routing/009.php +++ b/user_guide_src/source/incoming/routing/009.php @@ -1,3 +1,3 @@ get('product/(:segment)', 'Catalog::productLookup/$1'); +$routes->get('product/(:num)', 'Catalog::productLookupByID/$1'); diff --git a/user_guide_src/source/incoming/routing/010.php b/user_guide_src/source/incoming/routing/010.php index cb1cdda7c78c..c88bc65573a3 100644 --- a/user_guide_src/source/incoming/routing/010.php +++ b/user_guide_src/source/incoming/routing/010.php @@ -1,4 +1,3 @@ addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); -$routes->get('users/(:uuid)', 'Users::show/$1'); +$routes->get('product/(:any)', 'Catalog::productLookup/$1'); diff --git a/user_guide_src/source/incoming/routing/011.php b/user_guide_src/source/incoming/routing/011.php index a1619a4bf080..11437a5881c2 100644 --- a/user_guide_src/source/incoming/routing/011.php +++ b/user_guide_src/source/incoming/routing/011.php @@ -1,3 +1,7 @@ get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); +public function productLookup($seg1 = false, $seg2 = false, $seg3 = false) { + echo $seg1; // Will be 123 in all examples + echo $seg2; // false in first, 456 in second and third example + echo $seg3; // false in first and second, 789 in third +} diff --git a/user_guide_src/source/incoming/routing/012.php b/user_guide_src/source/incoming/routing/012.php index c9ddfae73610..cee3785eb0d8 100644 --- a/user_guide_src/source/incoming/routing/012.php +++ b/user_guide_src/source/incoming/routing/012.php @@ -1,3 +1,3 @@ get('login/(.+)', 'Auth::login/$1'); +$routes->get('product/(:segment)', 'Catalog::productLookup/$1'); diff --git a/user_guide_src/source/incoming/routing/013.php b/user_guide_src/source/incoming/routing/013.php index 2d0f48cb284e..cb1cdda7c78c 100644 --- a/user_guide_src/source/incoming/routing/013.php +++ b/user_guide_src/source/incoming/routing/013.php @@ -1,7 +1,4 @@ get('feed', function () { - $rss = new RSSFeeder(); - - return $rss->feed('general'); -}); +$routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); +$routes->get('users/(:uuid)', 'Users::show/$1'); diff --git a/user_guide_src/source/incoming/routing/014.php b/user_guide_src/source/incoming/routing/014.php index 8ebc27e3f9f5..a1619a4bf080 100644 --- a/user_guide_src/source/incoming/routing/014.php +++ b/user_guide_src/source/incoming/routing/014.php @@ -1,8 +1,3 @@ 'Catalog::productLookupById', - 'product/(:alphanum)' => 'Catalog::productLookupByName', -]; - -$routes->map($multipleRoutes); +$routes->get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); diff --git a/user_guide_src/source/incoming/routing/015.php b/user_guide_src/source/incoming/routing/015.php index d92d9934db5a..c9ddfae73610 100644 --- a/user_guide_src/source/incoming/routing/015.php +++ b/user_guide_src/source/incoming/routing/015.php @@ -1,8 +1,3 @@ get('users/profile', 'Users::profile', ['as' => 'profile']); - -// Redirect to a named route -$routes->addRedirect('users/about', 'profile'); -// Redirect to a URI -$routes->addRedirect('users/about', 'users/profile'); +$routes->get('login/(.+)', 'Auth::login/$1'); diff --git a/user_guide_src/source/incoming/routing/016.php b/user_guide_src/source/incoming/routing/016.php index 8c770fd05f24..2d0f48cb284e 100644 --- a/user_guide_src/source/incoming/routing/016.php +++ b/user_guide_src/source/incoming/routing/016.php @@ -1,6 +1,7 @@ group('admin', function ($routes) { - $routes->get('users', 'Admin\Users::index'); - $routes->get('blog', 'Admin\Blog::index'); +$routes->get('feed', function () { + $rss = new RSSFeeder(); + + return $rss->feed('general'); }); diff --git a/user_guide_src/source/incoming/routing/017.php b/user_guide_src/source/incoming/routing/017.php index 678e90700e74..8ebc27e3f9f5 100644 --- a/user_guide_src/source/incoming/routing/017.php +++ b/user_guide_src/source/incoming/routing/017.php @@ -1,5 +1,8 @@ group('api', ['namespace' => 'App\API\v1'], function ($routes) { - $routes->resource('users'); -}); +$multipleRoutes = [ + 'product/(:num)' => 'Catalog::productLookupById', + 'product/(:alphanum)' => 'Catalog::productLookupByName', +]; + +$routes->map($multipleRoutes); diff --git a/user_guide_src/source/incoming/routing/018.php b/user_guide_src/source/incoming/routing/018.php index 395ddfe6c8c8..d92d9934db5a 100644 --- a/user_guide_src/source/incoming/routing/018.php +++ b/user_guide_src/source/incoming/routing/018.php @@ -1,5 +1,8 @@ group('api', ['filter' => 'api-auth'], function ($routes) { - $routes->resource('users'); -}); +$routes->get('users/profile', 'Users::profile', ['as' => 'profile']); + +// Redirect to a named route +$routes->addRedirect('users/about', 'profile'); +// Redirect to a URI +$routes->addRedirect('users/about', 'users/profile'); diff --git a/user_guide_src/source/incoming/routing/019.php b/user_guide_src/source/incoming/routing/019.php index 08169acec275..8c770fd05f24 100644 --- a/user_guide_src/source/incoming/routing/019.php +++ b/user_guide_src/source/incoming/routing/019.php @@ -1,7 +1,6 @@ group('admin', function ($routes) { - $routes->group('users', function ($routes) { - $routes->get('list', 'Admin\Users::list'); - }); + $routes->get('users', 'Admin\Users::index'); + $routes->get('blog', 'Admin\Blog::index'); }); diff --git a/user_guide_src/source/incoming/routing/020.php b/user_guide_src/source/incoming/routing/020.php index d7624ddc6d5c..678e90700e74 100644 --- a/user_guide_src/source/incoming/routing/020.php +++ b/user_guide_src/source/incoming/routing/020.php @@ -1,7 +1,5 @@ group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { - $routes->get('login', 'AuthController::login', ['as' => 'login']); - $routes->post('login', 'AuthController::attemptLogin'); - $routes->get('logout', 'AuthController::logout'); +$routes->group('api', ['namespace' => 'App\API\v1'], function ($routes) { + $routes->resource('users'); }); diff --git a/user_guide_src/source/incoming/routing/021.php b/user_guide_src/source/incoming/routing/021.php index 69a4c184ab36..395ddfe6c8c8 100644 --- a/user_guide_src/source/incoming/routing/021.php +++ b/user_guide_src/source/incoming/routing/021.php @@ -1,5 +1,5 @@ environment('development', function ($routes) { - $routes->get('builder', 'Tools\Builder::index'); +$routes->group('api', ['filter' => 'api-auth'], function ($routes) { + $routes->resource('users'); }); diff --git a/user_guide_src/source/incoming/routing/022.php b/user_guide_src/source/incoming/routing/022.php index 0af87a58c3b5..08169acec275 100644 --- a/user_guide_src/source/incoming/routing/022.php +++ b/user_guide_src/source/incoming/routing/022.php @@ -1,8 +1,7 @@ get('users/(:num)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2'); - -// Generate the relative URL to link to user ID 15, gallery 12 -// Generates: /users/15/gallery/12 -View Gallery +$routes->group('admin', function ($routes) { + $routes->group('users', function ($routes) { + $routes->get('list', 'Admin\Users::list'); + }); +}); diff --git a/user_guide_src/source/incoming/routing/023-2.php b/user_guide_src/source/incoming/routing/023-2.php deleted file mode 100644 index e2a3784f335f..000000000000 --- a/user_guide_src/source/incoming/routing/023-2.php +++ /dev/null @@ -1,3 +0,0 @@ -add('products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/023.php b/user_guide_src/source/incoming/routing/023.php index 5469c79db91a..d7624ddc6d5c 100644 --- a/user_guide_src/source/incoming/routing/023.php +++ b/user_guide_src/source/incoming/routing/023.php @@ -1,8 +1,7 @@ get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); - -// Generate the relative URL to link to user ID 15, gallery 12 -// Generates: /users/15/gallery/12 -View Gallery +$routes->group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { + $routes->get('login', 'AuthController::login', ['as' => 'login']); + $routes->post('login', 'AuthController::attemptLogin'); + $routes->get('logout', 'AuthController::logout'); +}); diff --git a/user_guide_src/source/incoming/routing/024.php b/user_guide_src/source/incoming/routing/024.php index 7351142dea77..69a4c184ab36 100644 --- a/user_guide_src/source/incoming/routing/024.php +++ b/user_guide_src/source/incoming/routing/024.php @@ -1,5 +1,5 @@ post('products', 'Product::feature'); -$routes->put('products/1', 'Product::feature'); -$routes->delete('products/1', 'Product::feature'); +$routes->environment('development', function ($routes) { + $routes->get('builder', 'Tools\Builder::index'); +}); diff --git a/user_guide_src/source/incoming/routing/025.php b/user_guide_src/source/incoming/routing/025.php index a071f75cd156..0af87a58c3b5 100644 --- a/user_guide_src/source/incoming/routing/025.php +++ b/user_guide_src/source/incoming/routing/025.php @@ -1,3 +1,8 @@ match(['get', 'put'], 'products', 'Product::feature'); +// The route is defined as: +$routes->get('users/(:num)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2'); + +// Generate the relative URL to link to user ID 15, gallery 12 +// Generates: /users/15/gallery/12 +View Gallery diff --git a/user_guide_src/source/incoming/routing/026.php b/user_guide_src/source/incoming/routing/026.php index a82d57ebc5c7..5469c79db91a 100644 --- a/user_guide_src/source/incoming/routing/026.php +++ b/user_guide_src/source/incoming/routing/026.php @@ -1,3 +1,8 @@ cli('migrate', 'App\Database::migrate'); +// The route is defined as: +$routes->get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); + +// Generate the relative URL to link to user ID 15, gallery 12 +// Generates: /users/15/gallery/12 +View Gallery diff --git a/user_guide_src/source/incoming/routing/027.php b/user_guide_src/source/incoming/routing/027.php index 31c1dda07a70..e2a3784f335f 100644 --- a/user_guide_src/source/incoming/routing/027.php +++ b/user_guide_src/source/incoming/routing/027.php @@ -1,14 +1,3 @@ add('from', 'to', $options); -$routes->get('from', 'to', $options); -$routes->post('from', 'to', $options); -$routes->put('from', 'to', $options); -$routes->head('from', 'to', $options); -$routes->options('from', 'to', $options); -$routes->delete('from', 'to', $options); -$routes->patch('from', 'to', $options); -$routes->match(['get', 'put'], 'from', 'to', $options); -$routes->resource('photos', $options); -$routes->map($array, $options); -$routes->group('name', $options, function ()); +$routes->add('products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/028.php b/user_guide_src/source/incoming/routing/028.php index ca1121e0786d..a82d57ebc5c7 100644 --- a/user_guide_src/source/incoming/routing/028.php +++ b/user_guide_src/source/incoming/routing/028.php @@ -1,3 +1,3 @@ get('admin',' AdminController::index', ['filter' => 'admin-auth']); +$routes->cli('migrate', 'App\Database::migrate'); diff --git a/user_guide_src/source/incoming/routing/029.php b/user_guide_src/source/incoming/routing/029.php index b50db49bd962..31c1dda07a70 100644 --- a/user_guide_src/source/incoming/routing/029.php +++ b/user_guide_src/source/incoming/routing/029.php @@ -1,3 +1,14 @@ post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); +$routes->add('from', 'to', $options); +$routes->get('from', 'to', $options); +$routes->post('from', 'to', $options); +$routes->put('from', 'to', $options); +$routes->head('from', 'to', $options); +$routes->options('from', 'to', $options); +$routes->delete('from', 'to', $options); +$routes->patch('from', 'to', $options); +$routes->match(['get', 'put'], 'from', 'to', $options); +$routes->resource('photos', $options); +$routes->map($array, $options); +$routes->group('name', $options, function ()); diff --git a/user_guide_src/source/incoming/routing/030.php b/user_guide_src/source/incoming/routing/030.php index 14d5142de2f0..ca1121e0786d 100644 --- a/user_guide_src/source/incoming/routing/030.php +++ b/user_guide_src/source/incoming/routing/030.php @@ -1,3 +1,3 @@ get('admin',' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); +$routes->get('admin',' AdminController::index', ['filter' => 'admin-auth']); diff --git a/user_guide_src/source/incoming/routing/031.php b/user_guide_src/source/incoming/routing/031.php index 24cf6c5dbc2d..b50db49bd962 100644 --- a/user_guide_src/source/incoming/routing/031.php +++ b/user_guide_src/source/incoming/routing/031.php @@ -1,3 +1,3 @@ get('admin',' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); +$routes->post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); diff --git a/user_guide_src/source/incoming/routing/032.php b/user_guide_src/source/incoming/routing/032.php index b992deb96ecf..14d5142de2f0 100644 --- a/user_guide_src/source/incoming/routing/032.php +++ b/user_guide_src/source/incoming/routing/032.php @@ -1,4 +1,3 @@ get('admin/users', 'Users::index', ['namespace' => 'Admin']); +$routes->get('admin',' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); diff --git a/user_guide_src/source/incoming/routing/033.php b/user_guide_src/source/incoming/routing/033.php index 5b415a50138b..24cf6c5dbc2d 100644 --- a/user_guide_src/source/incoming/routing/033.php +++ b/user_guide_src/source/incoming/routing/033.php @@ -1,3 +1,3 @@ get('from', 'to', ['hostname' => 'accounts.example.com']); +$routes->get('admin',' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); diff --git a/user_guide_src/source/incoming/routing/034.php b/user_guide_src/source/incoming/routing/034.php index 32a74934eb3a..b992deb96ecf 100644 --- a/user_guide_src/source/incoming/routing/034.php +++ b/user_guide_src/source/incoming/routing/034.php @@ -1,4 +1,4 @@ get('from', 'to', ['subdomain' => 'media']); +// Routes to \Admin\Users::index() +$routes->get('admin/users', 'Users::index', ['namespace' => 'Admin']); diff --git a/user_guide_src/source/incoming/routing/035.php b/user_guide_src/source/incoming/routing/035.php index 0d0fd0e67fb4..5b415a50138b 100644 --- a/user_guide_src/source/incoming/routing/035.php +++ b/user_guide_src/source/incoming/routing/035.php @@ -1,4 +1,3 @@ get('from', 'to', ['subdomain' => '*']); +$routes->get('from', 'to', ['hostname' => 'accounts.example.com']); diff --git a/user_guide_src/source/incoming/routing/036.php b/user_guide_src/source/incoming/routing/036.php index ec7fa680f65e..32a74934eb3a 100644 --- a/user_guide_src/source/incoming/routing/036.php +++ b/user_guide_src/source/incoming/routing/036.php @@ -1,6 +1,4 @@ get('users/(:num)', 'users/show/$1', ['offset' => 1]); - -// Creates: -$routes['users/(:num)'] = 'users/show/$2'; +// Limit to media.example.com +$routes->get('from', 'to', ['subdomain' => 'media']); diff --git a/user_guide_src/source/incoming/routing/037.php b/user_guide_src/source/incoming/routing/037.php index 29fc83e59f17..0d0fd0e67fb4 100644 --- a/user_guide_src/source/incoming/routing/037.php +++ b/user_guide_src/source/incoming/routing/037.php @@ -1,12 +1,4 @@ setPrioritize(); - -// App\Config\Routes -$routes->get('(.*)', 'Posts::index', ['priority' => 1]); - -// Modules\Acme\Config\Routes -$routes->get('admin', 'Admin::index'); - -// The "admin" route will now be processed before the wildcard router. +// Limit to any sub-domain +$routes->get('from', 'to', ['subdomain' => '*']); diff --git a/user_guide_src/source/incoming/routing/038.php b/user_guide_src/source/incoming/routing/038.php index 9465f4147e2c..ec7fa680f65e 100644 --- a/user_guide_src/source/incoming/routing/038.php +++ b/user_guide_src/source/incoming/routing/038.php @@ -1,3 +1,6 @@ setPrioritize(false); +$routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]); + +// Creates: +$routes['users/(:num)'] = 'users/show/$2'; diff --git a/user_guide_src/source/incoming/routing/039.php b/user_guide_src/source/incoming/routing/039.php index 98aef9276f9d..29fc83e59f17 100644 --- a/user_guide_src/source/incoming/routing/039.php +++ b/user_guide_src/source/incoming/routing/039.php @@ -1,9 +1,12 @@ setDefaultNamespace(''); +// First you need to enable sorting. +$routes->setPrioritize(); -// Controller is \Users -$routes->get('users', 'Users::index'); +// App\Config\Routes +$routes->get('(.*)', 'Posts::index', ['priority' => 1]); -// Controller is \Admin\Users -$routes->get('users', 'Admin\Users::index'); +// Modules\Acme\Config\Routes +$routes->get('admin', 'Admin::index'); + +// The "admin" route will now be processed before the wildcard router. diff --git a/user_guide_src/source/incoming/routing/040.php b/user_guide_src/source/incoming/routing/040.php index fbbbee2300df..9465f4147e2c 100644 --- a/user_guide_src/source/incoming/routing/040.php +++ b/user_guide_src/source/incoming/routing/040.php @@ -1,9 +1,3 @@ setDefaultNamespace('App'); - -// Controller is \App\Users -$routes->get('users', 'Users::index'); - -// Controller is \App\Admin\Users -$routes->get('users', 'Admin\Users::index'); +$routes->setPrioritize(false); diff --git a/user_guide_src/source/incoming/routing/041.php b/user_guide_src/source/incoming/routing/041.php index 5d17df8130d4..98aef9276f9d 100644 --- a/user_guide_src/source/incoming/routing/041.php +++ b/user_guide_src/source/incoming/routing/041.php @@ -1,4 +1,9 @@ setDefaultController('Welcome'); +$routes->setDefaultNamespace(''); + +// Controller is \Users +$routes->get('users', 'Users::index'); + +// Controller is \Admin\Users +$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/042.php b/user_guide_src/source/incoming/routing/042.php index e926e651287d..fbbbee2300df 100644 --- a/user_guide_src/source/incoming/routing/042.php +++ b/user_guide_src/source/incoming/routing/042.php @@ -1,3 +1,9 @@ setDefaultMethod('listAll'); +$routes->setDefaultNamespace('App'); + +// Controller is \App\Users +$routes->get('users', 'Users::index'); + +// Controller is \App\Admin\Users +$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/043.php b/user_guide_src/source/incoming/routing/043.php index 31d49508ab86..5d17df8130d4 100644 --- a/user_guide_src/source/incoming/routing/043.php +++ b/user_guide_src/source/incoming/routing/043.php @@ -1,3 +1,4 @@ setTranslateURIDashes(true); +// example.com routes to app/Controllers/Welcome.php +$routes->setDefaultController('Welcome'); diff --git a/user_guide_src/source/incoming/routing/044.php b/user_guide_src/source/incoming/routing/044.php index c331102cd9f4..e926e651287d 100644 --- a/user_guide_src/source/incoming/routing/044.php +++ b/user_guide_src/source/incoming/routing/044.php @@ -1,3 +1,3 @@ setAutoRoute(false); +$routes->setDefaultMethod('listAll'); diff --git a/user_guide_src/source/incoming/routing/045.php b/user_guide_src/source/incoming/routing/045.php index 1f3758e244d4..31d49508ab86 100644 --- a/user_guide_src/source/incoming/routing/045.php +++ b/user_guide_src/source/incoming/routing/045.php @@ -1,10 +1,3 @@ set404Override('App\Errors::show404'); - -// Will display a custom view -$routes->set404Override(function () -{ - echo view('my_errors/not_found.html'); -}); +$routes->setTranslateURIDashes(true); diff --git a/user_guide_src/source/incoming/routing/046.php b/user_guide_src/source/incoming/routing/046.php index e3dd9f60c989..c331102cd9f4 100644 --- a/user_guide_src/source/incoming/routing/046.php +++ b/user_guide_src/source/incoming/routing/046.php @@ -1,7 +1,3 @@ setPrioritize(); - -// to disable -$routes->setPrioritize(false); +$routes->setAutoRoute(false); diff --git a/user_guide_src/source/incoming/routing/047.php b/user_guide_src/source/incoming/routing/047.php new file mode 100644 index 000000000000..1f3758e244d4 --- /dev/null +++ b/user_guide_src/source/incoming/routing/047.php @@ -0,0 +1,10 @@ +set404Override('App\Errors::show404'); + +// Will display a custom view +$routes->set404Override(function () +{ + echo view('my_errors/not_found.html'); +}); diff --git a/user_guide_src/source/incoming/routing/048.php b/user_guide_src/source/incoming/routing/048.php new file mode 100644 index 000000000000..e3dd9f60c989 --- /dev/null +++ b/user_guide_src/source/incoming/routing/048.php @@ -0,0 +1,7 @@ +setPrioritize(); + +// to disable +$routes->setPrioritize(false); diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index fcab322aa3d9..ad45f9fea4f3 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -119,7 +119,7 @@ Retrieving Session Data Any piece of information from the session array is available through the ``$_SESSION`` superglobal: -.. literalinclude:: sessions/005-2.php +.. literalinclude:: sessions/005.php :lines: 2- Or through the conventional accessor method: @@ -264,7 +264,7 @@ You can also pass an array to ``setFlashdata()``, in the same manner as Reading flashdata variables is the same as reading regular session data through ``$_SESSION``: -.. literalinclude:: sessions/005.php +.. literalinclude:: sessions/024.php :lines: 2- .. important:: The ``get()`` method WILL return flashdata items when @@ -335,7 +335,7 @@ You can also pass an array to ``setTempdata()``: To read a tempdata variable, again you can just access it through the ``$_SESSION`` superglobal array: -.. literalinclude:: sessions/005-1.php +.. literalinclude:: sessions/033.php :lines: 2- .. important:: The ``get()`` method WILL return tempdata items when diff --git a/user_guide_src/source/libraries/sessions/005-1.php b/user_guide_src/source/libraries/sessions/005-1.php deleted file mode 100644 index 4f09358d5fc8..000000000000 --- a/user_guide_src/source/libraries/sessions/005-1.php +++ /dev/null @@ -1,3 +0,0 @@ - - - - Upload Form - - - - -
  • - - - - - - -

    - - - - - - - diff --git a/user_guide_src/source/libraries/uploaded_files/001.php b/user_guide_src/source/libraries/uploaded_files/001.php index f186d517fd96..d58b7664d28b 100644 --- a/user_guide_src/source/libraries/uploaded_files/001.php +++ b/user_guide_src/source/libraries/uploaded_files/001.php @@ -1,48 +1,23 @@ - + + + Upload Form + + -namespace App\Controllers; + +
  • + -use CodeIgniter\Files\File; + -class Upload extends BaseController -{ - protected $helpers = ['form']; + - public function index() - { - return view('upload_form', ['errors' => []]); - } +

    - public function upload() - { - $validationRule = [ - 'userfile' => [ - 'label' => 'Image File', - 'rules' => 'uploaded[userfile]' - . '|is_image[userfile]' - . '|mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]' - . '|max_size[userfile,100]' - . '|max_dims[userfile,1024,768]', - ], - ]; - if (! $this->validate($validationRule)) { - $data = ['errors' => $this->validator->getErrors()]; + - return view('upload_form', $data); - } + - $img = $this->request->getFile('userfile'); - - if (! $img->hasMoved()) { - $filepath = WRITEPATH . 'uploads/' . $img->store(); - - $data = ['uploaded_flleinfo' => new File($filepath)]; - - return view('upload_success', $data); - } else { - $data = ['errors' => 'The file has already been moved.']; - - return view('upload_form', $data); - } - } -} + + diff --git a/user_guide_src/source/libraries/uploaded_files/002.php b/user_guide_src/source/libraries/uploaded_files/002.php index 17141efbdde8..f186d517fd96 100644 --- a/user_guide_src/source/libraries/uploaded_files/002.php +++ b/user_guide_src/source/libraries/uploaded_files/002.php @@ -1,3 +1,48 @@ request->getFiles(); +namespace App\Controllers; + +use CodeIgniter\Files\File; + +class Upload extends BaseController +{ + protected $helpers = ['form']; + + public function index() + { + return view('upload_form', ['errors' => []]); + } + + public function upload() + { + $validationRule = [ + 'userfile' => [ + 'label' => 'Image File', + 'rules' => 'uploaded[userfile]' + . '|is_image[userfile]' + . '|mime_in[userfile,image/jpg,image/jpeg,image/gif,image/png,image/webp]' + . '|max_size[userfile,100]' + . '|max_dims[userfile,1024,768]', + ], + ]; + if (! $this->validate($validationRule)) { + $data = ['errors' => $this->validator->getErrors()]; + + return view('upload_form', $data); + } + + $img = $this->request->getFile('userfile'); + + if (! $img->hasMoved()) { + $filepath = WRITEPATH . 'uploads/' . $img->store(); + + $data = ['uploaded_flleinfo' => new File($filepath)]; + + return view('upload_success', $data); + } else { + $data = ['errors' => 'The file has already been moved.']; + + return view('upload_form', $data); + } + } +} diff --git a/user_guide_src/source/libraries/uploaded_files/003.php b/user_guide_src/source/libraries/uploaded_files/003.php index 368facf4f7ab..17141efbdde8 100644 --- a/user_guide_src/source/libraries/uploaded_files/003.php +++ b/user_guide_src/source/libraries/uploaded_files/003.php @@ -1,5 +1,3 @@ // UploadedFile instance -] +$files = $this->request->getFiles(); diff --git a/user_guide_src/source/libraries/uploaded_files/004.php b/user_guide_src/source/libraries/uploaded_files/004.php index bf31373e57bd..368facf4f7ab 100644 --- a/user_guide_src/source/libraries/uploaded_files/004.php +++ b/user_guide_src/source/libraries/uploaded_files/004.php @@ -1,9 +1,5 @@ [ - 'details' => [ - 'avatar' => // UploadedFile instance - ] - ] + 'avatar' => // UploadedFile instance ] diff --git a/user_guide_src/source/libraries/uploaded_files/005.php b/user_guide_src/source/libraries/uploaded_files/005.php index c53d82a298fc..bf31373e57bd 100644 --- a/user_guide_src/source/libraries/uploaded_files/005.php +++ b/user_guide_src/source/libraries/uploaded_files/005.php @@ -3,9 +3,7 @@ [ 'my-form' => [ 'details' => [ - 'avatar' => [ - 0 => /* UploadedFile instance */, - 1 => /* UploadedFile instance */ + 'avatar' => // UploadedFile instance ] ] ] diff --git a/user_guide_src/source/libraries/uploaded_files/006.php b/user_guide_src/source/libraries/uploaded_files/006.php index e5f6440d96fb..c53d82a298fc 100644 --- a/user_guide_src/source/libraries/uploaded_files/006.php +++ b/user_guide_src/source/libraries/uploaded_files/006.php @@ -1,3 +1,11 @@ request->getFile('userfile'); +[ + 'my-form' => [ + 'details' => [ + 'avatar' => [ + 0 => /* UploadedFile instance */, + 1 => /* UploadedFile instance */ + ] + ] +] diff --git a/user_guide_src/source/libraries/uploaded_files/007.php b/user_guide_src/source/libraries/uploaded_files/007.php index ad71bd5575fb..e5f6440d96fb 100644 --- a/user_guide_src/source/libraries/uploaded_files/007.php +++ b/user_guide_src/source/libraries/uploaded_files/007.php @@ -1,3 +1,3 @@ request->getFile('my-form.details.avatar'); +$file = $this->request->getFile('userfile'); diff --git a/user_guide_src/source/libraries/uploaded_files/008.php b/user_guide_src/source/libraries/uploaded_files/008.php index f37491c04821..ad71bd5575fb 100644 --- a/user_guide_src/source/libraries/uploaded_files/008.php +++ b/user_guide_src/source/libraries/uploaded_files/008.php @@ -1,10 +1,3 @@ request->getFiles()) { - foreach($imagefile['images'] as $img) { - if ($img->isValid() && ! $img->hasMoved()) { - $newName = $img->getRandomName(); - $img->move(WRITEPATH . 'uploads', $newName); - } - } -} +$file = $this->request->getFile('my-form.details.avatar'); diff --git a/user_guide_src/source/libraries/uploaded_files/009.php b/user_guide_src/source/libraries/uploaded_files/009.php index da51d17dbd15..f37491c04821 100644 --- a/user_guide_src/source/libraries/uploaded_files/009.php +++ b/user_guide_src/source/libraries/uploaded_files/009.php @@ -1,4 +1,10 @@ request->getFile('images.0'); -$file2 = $this->request->getFile('images.1'); +if ($imagefile = $this->request->getFiles()) { + foreach($imagefile['images'] as $img) { + if ($img->isValid() && ! $img->hasMoved()) { + $newName = $img->getRandomName(); + $img->move(WRITEPATH . 'uploads', $newName); + } + } +} diff --git a/user_guide_src/source/libraries/uploaded_files/010.php b/user_guide_src/source/libraries/uploaded_files/010.php index 646e6bb0b8b9..da51d17dbd15 100644 --- a/user_guide_src/source/libraries/uploaded_files/010.php +++ b/user_guide_src/source/libraries/uploaded_files/010.php @@ -1,3 +1,4 @@ request->getFileMultiple('images'); +$file1 = $this->request->getFile('images.0'); +$file2 = $this->request->getFile('images.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/011.php b/user_guide_src/source/libraries/uploaded_files/011.php index d18a755ba234..646e6bb0b8b9 100644 --- a/user_guide_src/source/libraries/uploaded_files/011.php +++ b/user_guide_src/source/libraries/uploaded_files/011.php @@ -1,4 +1,3 @@ request->getFile('my-form.details.avatars.0'); -$file2 = $this->request->getFile('my-form.details.avatars.1'); +$files = $this->request->getFileMultiple('images'); diff --git a/user_guide_src/source/libraries/uploaded_files/012.php b/user_guide_src/source/libraries/uploaded_files/012.php index 094ea73c1064..d18a755ba234 100644 --- a/user_guide_src/source/libraries/uploaded_files/012.php +++ b/user_guide_src/source/libraries/uploaded_files/012.php @@ -1,5 +1,4 @@ isValid()) { - throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); -} +$file1 = $this->request->getFile('my-form.details.avatars.0'); +$file2 = $this->request->getFile('my-form.details.avatars.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/013.php b/user_guide_src/source/libraries/uploaded_files/013.php index 057a56b3e9a0..094ea73c1064 100644 --- a/user_guide_src/source/libraries/uploaded_files/013.php +++ b/user_guide_src/source/libraries/uploaded_files/013.php @@ -1,3 +1,5 @@ getName(); +if (! $file->isValid()) { + throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); +} diff --git a/user_guide_src/source/libraries/uploaded_files/014.php b/user_guide_src/source/libraries/uploaded_files/014.php index 4fb0cae0ad12..057a56b3e9a0 100644 --- a/user_guide_src/source/libraries/uploaded_files/014.php +++ b/user_guide_src/source/libraries/uploaded_files/014.php @@ -1,3 +1,3 @@ getClientName(); +$name = $file->getName(); diff --git a/user_guide_src/source/libraries/uploaded_files/015.php b/user_guide_src/source/libraries/uploaded_files/015.php index c9e4774a4bbf..4fb0cae0ad12 100644 --- a/user_guide_src/source/libraries/uploaded_files/015.php +++ b/user_guide_src/source/libraries/uploaded_files/015.php @@ -1,3 +1,3 @@ getTempName(); +$originalName = $file->getClientName(); diff --git a/user_guide_src/source/libraries/uploaded_files/016.php b/user_guide_src/source/libraries/uploaded_files/016.php index 867877238c76..c9e4774a4bbf 100644 --- a/user_guide_src/source/libraries/uploaded_files/016.php +++ b/user_guide_src/source/libraries/uploaded_files/016.php @@ -1,3 +1,3 @@ getClientExtension(); +$tempfile = $file->getTempName(); diff --git a/user_guide_src/source/libraries/uploaded_files/017.php b/user_guide_src/source/libraries/uploaded_files/017.php index dd1288e441c3..867877238c76 100644 --- a/user_guide_src/source/libraries/uploaded_files/017.php +++ b/user_guide_src/source/libraries/uploaded_files/017.php @@ -1,5 +1,3 @@ getClientMimeType(); - -echo $type; // image/png +$ext = $file->getClientExtension(); diff --git a/user_guide_src/source/libraries/uploaded_files/018.php b/user_guide_src/source/libraries/uploaded_files/018.php index 12499a3ca1ba..dd1288e441c3 100644 --- a/user_guide_src/source/libraries/uploaded_files/018.php +++ b/user_guide_src/source/libraries/uploaded_files/018.php @@ -1,3 +1,5 @@ move(WRITEPATH . 'uploads'); +$type = $file->getClientMimeType(); + +echo $type; // image/png diff --git a/user_guide_src/source/libraries/uploaded_files/019.php b/user_guide_src/source/libraries/uploaded_files/019.php index 2e6b39645a4b..12499a3ca1ba 100644 --- a/user_guide_src/source/libraries/uploaded_files/019.php +++ b/user_guide_src/source/libraries/uploaded_files/019.php @@ -1,4 +1,3 @@ getRandomName(); -$file->move(WRITEPATH . 'uploads', $newName); +$file->move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/uploaded_files/020.php b/user_guide_src/source/libraries/uploaded_files/020.php index 7f49d1f5232e..2e6b39645a4b 100644 --- a/user_guide_src/source/libraries/uploaded_files/020.php +++ b/user_guide_src/source/libraries/uploaded_files/020.php @@ -1,5 +1,4 @@ isValid() && ! $file->hasMoved()) { - $file->move($path); -} +$newName = $file->getRandomName(); +$file->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/uploaded_files/021.php b/user_guide_src/source/libraries/uploaded_files/021.php index 90f9495eaf7b..7f49d1f5232e 100644 --- a/user_guide_src/source/libraries/uploaded_files/021.php +++ b/user_guide_src/source/libraries/uploaded_files/021.php @@ -1,3 +1,5 @@ request->getFile('userfile')->store(); +if ($file->isValid() && ! $file->hasMoved()) { + $file->move($path); +} diff --git a/user_guide_src/source/libraries/uploaded_files/022.php b/user_guide_src/source/libraries/uploaded_files/022.php index 0e552f417d52..90f9495eaf7b 100644 --- a/user_guide_src/source/libraries/uploaded_files/022.php +++ b/user_guide_src/source/libraries/uploaded_files/022.php @@ -1,3 +1,3 @@ request->getFile('userfile')->store('head_img/', 'user_name.jpg'); +$path = $this->request->getFile('userfile')->store(); diff --git a/user_guide_src/source/libraries/uploaded_files/023.php b/user_guide_src/source/libraries/uploaded_files/023.php new file mode 100644 index 000000000000..0e552f417d52 --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/023.php @@ -0,0 +1,3 @@ +request->getFile('userfile')->store('head_img/', 'user_name.jpg'); diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 0f43f911a506..a74bca7904d8 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -534,12 +534,12 @@ The first step is to create custom views. These can be placed anywhere that the which means the standard View directory, or any namespaced View folder will work. For example, you could create a new view at **/app/Views/_errors_list.php**: -.. literalinclude:: validation/029-2.php +.. literalinclude:: validation/030.php An array named ``$errors`` is available within the view that contains a list of the errors, where the key is the name of the field that had the error, and the value is the error message, like this: -.. literalinclude:: validation/030.php +.. literalinclude:: validation/031.php :lines: 2- There are actually two types of views that you can create. The first has an array of all of the errors, and is what @@ -555,7 +555,7 @@ Once you have your views created, you need to let the Validation library know ab Inside, you'll find the ``$templates`` property where you can list as many custom views as you want, and provide an short alias they can be referenced by. If we were to add our example file from above, it would look something like: -.. literalinclude:: validation/031.php +.. literalinclude:: validation/032.php :lines: 2- Specifying the Template @@ -577,7 +577,7 @@ Rules are stored within simple, namespaced classes. They can be stored any locat autoloader can find it. These files are called RuleSets. To add a new RuleSet, edit **Config/Validation.php** and add the new file to the ``$ruleSets`` array: -.. literalinclude:: validation/032.php +.. literalinclude:: validation/033.php :lines: 2- You can add it as either a simple string with the fully qualified class name, or using the ``::class`` suffix as @@ -586,19 +586,19 @@ shown above. The primary benefit here is that it provides some extra navigation Within the file itself, each method is a rule and must accept a string as the first parameter, and must return a boolean true or false value signifying true if it passed the test or false if it did not: -.. literalinclude:: validation/033.php +.. literalinclude:: validation/034.php :lines: 2- By default, the system will look within ``CodeIgniter\Language\en\Validation.php`` for the language strings used within errors. In custom rules, you may provide error messages by accepting a ``$error`` variable by reference in the second parameter: -.. literalinclude:: validation/034.php +.. literalinclude:: validation/035.php :lines: 2- Your new custom rule could now be used just like any other rule: -.. literalinclude:: validation/035.php +.. literalinclude:: validation/036.php :lines: 2- Allowing Parameters @@ -608,7 +608,7 @@ If your method needs to work with parameters, the function will need a minimum o the parameter string, and an array with all of the data that was submitted the form. The ``$data`` array is especially handy for rules like ``require_with`` that needs to check the value of another submitted field to base its result on: -.. literalinclude:: validation/036.php +.. literalinclude:: validation/037.php :lines: 2- Custom errors can be returned as the fourth parameter, just as described above. @@ -621,7 +621,7 @@ The following is a list of all the native rules that are available to use: .. note:: Rule is a string; there must be **no spaces** between the parameters, especially the ``is_unique`` rule. There can be no spaces before and after ``ignore_value``. -.. literalinclude:: validation/037.php +.. literalinclude:: validation/038.php :lines: 2- ======================= ========== ============================================= =================================================== diff --git a/user_guide_src/source/libraries/validation/029-2.php b/user_guide_src/source/libraries/validation/029-2.php deleted file mode 100644 index f7c69eb42e99..000000000000 --- a/user_guide_src/source/libraries/validation/029-2.php +++ /dev/null @@ -1,7 +0,0 @@ - diff --git a/user_guide_src/source/libraries/validation/030.php b/user_guide_src/source/libraries/validation/030.php index 0da86ca2d054..f7c69eb42e99 100644 --- a/user_guide_src/source/libraries/validation/030.php +++ b/user_guide_src/source/libraries/validation/030.php @@ -1,6 +1,7 @@ - 'The username field must be unique.', - 'email' => 'You must provide a valid email address.' -]; + diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php index 110b159a41cc..0da86ca2d054 100644 --- a/user_guide_src/source/libraries/validation/031.php +++ b/user_guide_src/source/libraries/validation/031.php @@ -1,7 +1,6 @@ 'CodeIgniter\Validation\Views\list', - 'single' => 'CodeIgniter\Validation\Views\single', - 'my_list' => '_errors_list', +$errors = [ + 'username' => 'The username field must be unique.', + 'email' => 'You must provide a valid email address.' ]; diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php index ccee27b08ad7..110b159a41cc 100644 --- a/user_guide_src/source/libraries/validation/032.php +++ b/user_guide_src/source/libraries/validation/032.php @@ -1,13 +1,7 @@ 'CodeIgniter\Validation\Views\list', + 'single' => 'CodeIgniter\Validation\Views\single', + 'my_list' => '_errors_list', ]; diff --git a/user_guide_src/source/libraries/validation/033.php b/user_guide_src/source/libraries/validation/033.php index d7a10b5071cd..ccee27b08ad7 100644 --- a/user_guide_src/source/libraries/validation/033.php +++ b/user_guide_src/source/libraries/validation/033.php @@ -1,9 +1,13 @@ validate($request, [ - 'foo' => 'required|even', -]); +public function even(string $str, string &$error = null): bool +{ + if ((int) $str % 2 !== 0) { + $error = lang('myerrors.evenError'); + + return false; + } + + return true; +} diff --git a/user_guide_src/source/libraries/validation/036.php b/user_guide_src/source/libraries/validation/036.php index 9511380c04f5..99db5f30eae4 100644 --- a/user_guide_src/source/libraries/validation/036.php +++ b/user_guide_src/source/libraries/validation/036.php @@ -1,34 +1,5 @@ required($str ?? ''); - - if ($present) { - return true; - } - - // Still here? Then we fail this test if - // any of the fields are present in $data - // as $fields is the lis - $requiredFields = []; - - foreach ($fields as $field) { - if (array_key_exists($field, $data)) { - $requiredFields[] = $field; - } - } - - // Remove any keys with empty values since, that means they - // weren't truly there, as far as this is concerned. - $requiredFields = array_filter($requiredFields, function ($item) use ($data) { - return ! empty($data[$item]); - }); - - return empty($requiredFields); -} +$this->validate($request, [ + 'foo' => 'required|even', +]); diff --git a/user_guide_src/source/libraries/validation/037.php b/user_guide_src/source/libraries/validation/037.php index 089b0eeaf465..9511380c04f5 100644 --- a/user_guide_src/source/libraries/validation/037.php +++ b/user_guide_src/source/libraries/validation/037.php @@ -1,10 +1,34 @@ setRules([ - 'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok - 'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok - 'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok - 'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders" -]); +public function required_with($str, string $fields, array $data): bool +{ + $fields = explode(',', $fields); + + // If the field is present we can safely assume that + // the field is here, no matter whether the corresponding + // search field is present or not. + $present = $this->required($str ?? ''); + + if ($present) { + return true; + } + + // Still here? Then we fail this test if + // any of the fields are present in $data + // as $fields is the lis + $requiredFields = []; + + foreach ($fields as $field) { + if (array_key_exists($field, $data)) { + $requiredFields[] = $field; + } + } + + // Remove any keys with empty values since, that means they + // weren't truly there, as far as this is concerned. + $requiredFields = array_filter($requiredFields, function ($item) use ($data) { + return ! empty($data[$item]); + }); + + return empty($requiredFields); +} diff --git a/user_guide_src/source/libraries/validation/038.php b/user_guide_src/source/libraries/validation/038.php new file mode 100644 index 000000000000..089b0eeaf465 --- /dev/null +++ b/user_guide_src/source/libraries/validation/038.php @@ -0,0 +1,10 @@ +setRules([ + 'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok + 'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok + 'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok + 'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders" +]); diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 4681711398d0..ef17f8d7fa6e 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -281,7 +281,7 @@ blocks must be closed with an ``endif`` tag:: This simple block is converted to the following during parsing: -.. literalinclude:: view_parser/010-2.php +.. literalinclude:: view_parser/011.php All variables used within if statements must have been previously set with the same name. Other than that, it is treated exactly like a standard PHP conditional, and all standard PHP rules would apply here. You can use any @@ -413,7 +413,7 @@ You can easily create your own filters by editing **app/Config/View.php** and ad ``$filters`` array. Each key is the name of the filter is called by in the view, and its value is any valid PHP callable: -.. literalinclude:: view_parser/011.php +.. literalinclude:: view_parser/012.php :lines: 2- PHP Native functions as Filters @@ -423,7 +423,7 @@ You can use native php function as filters by editing **app/Config/View.php** an ``$filters`` array.Each key is the name of the native PHP function is called by in the view, and its value is any valid native PHP function prefixed with: -.. literalinclude:: view_parser/012.php +.. literalinclude:: view_parser/013.php :lines: 2- Parser Plugins @@ -481,24 +481,24 @@ At its simplest, all you need to do to register a new plugin and make it ready f **app/Config/View.php**, under the **$plugins** array. The key is the name of the plugin that is used within the template file. The value is any valid PHP callable, including static class methods, and closures: -.. literalinclude:: view_parser/013.php +.. literalinclude:: view_parser/014.php :lines: 2- Any closures that are being used must be defined in the config file's constructor: -.. literalinclude:: view_parser/014.php +.. literalinclude:: view_parser/015.php :lines: 2- If the callable is on its own, it is treated as a single tag, not a open/close one. It will be replaced by the return value from the plugin: -.. literalinclude:: view_parser/015.php +.. literalinclude:: view_parser/016.php :lines: 2- If the callable is wrapped in an array, it is treated as an open/close tag pair that can operate on any of the content between its tags: -.. literalinclude:: view_parser/016.php +.. literalinclude:: view_parser/017.php :lines: 2- *********** @@ -508,20 +508,20 @@ Usage Notes If you include substitution parameters that are not referenced in your template, they are ignored: -.. literalinclude:: view_parser/017.php +.. literalinclude:: view_parser/018.php :lines: 2- If you do not include a substitution parameter that is referenced in your template, the original pseudo-variable is shown in the result: -.. literalinclude:: view_parser/018.php +.. literalinclude:: view_parser/019.php :lines: 2- If you provide a string substitution parameter when an array is expected, i.e., for a variable pair, the substitution is done for the opening variable pair tag, but the closing variable pair tag is not rendered properly: -.. literalinclude:: view_parser/019.php +.. literalinclude:: view_parser/020.php :lines: 2- View Fragments @@ -557,7 +557,7 @@ Result:: An example with the iteration controlled in the controller, using a view fragment: -.. literalinclude:: view_parser/020.php +.. literalinclude:: view_parser/021.php :lines: 2- Result:: @@ -583,7 +583,7 @@ Class Reference Builds the output based upon a file name and any data that has already been set: - .. literalinclude:: view_parser/021.php + .. literalinclude:: view_parser/022.php :lines: 2- Options supported: @@ -608,7 +608,7 @@ Class Reference Builds the output based upon a provided template source and any data that has already been set: - .. literalinclude:: view_parser/021-1.php + .. literalinclude:: view_parser/023.php :lines: 2- Options supported, and behavior, as above. @@ -622,7 +622,7 @@ Class Reference Sets several pieces of view data at once: - .. literalinclude:: view_parser/023.php + .. literalinclude:: view_parser/024.php :lines: 2- Supported escape contexts: html, css, js, url, or attr or raw. @@ -638,7 +638,7 @@ Class Reference Sets a single piece of view data: - .. literalinclude:: view_parser/024.php + .. literalinclude:: view_parser/025.php :lines: 2- Supported escape contexts: html, css, js, url, attr or raw. @@ -653,5 +653,5 @@ Class Reference Override the substitution field delimiters: - .. literalinclude:: view_parser/025.php + .. literalinclude:: view_parser/026.php :lines: 2- diff --git a/user_guide_src/source/outgoing/view_parser/010-2.php b/user_guide_src/source/outgoing/view_parser/010-2.php deleted file mode 100644 index 8030f44e8883..000000000000 --- a/user_guide_src/source/outgoing/view_parser/010-2.php +++ /dev/null @@ -1,3 +0,0 @@ - -

    Welcome, Admin!

    - diff --git a/user_guide_src/source/outgoing/view_parser/011.php b/user_guide_src/source/outgoing/view_parser/011.php index 39eae3da0177..8030f44e8883 100644 --- a/user_guide_src/source/outgoing/view_parser/011.php +++ b/user_guide_src/source/outgoing/view_parser/011.php @@ -1,6 +1,3 @@ - '\CodeIgniter\View\Filters::abs', - 'capitalize' => '\CodeIgniter\View\Filters::capitalize', -]; + +

    Welcome, Admin!

    + diff --git a/user_guide_src/source/outgoing/view_parser/012.php b/user_guide_src/source/outgoing/view_parser/012.php index dbb096b416fb..39eae3da0177 100644 --- a/user_guide_src/source/outgoing/view_parser/012.php +++ b/user_guide_src/source/outgoing/view_parser/012.php @@ -1,5 +1,6 @@ '\str_repeat', + 'abs' => '\CodeIgniter\View\Filters::abs', + 'capitalize' => '\CodeIgniter\View\Filters::capitalize', ]; diff --git a/user_guide_src/source/outgoing/view_parser/013.php b/user_guide_src/source/outgoing/view_parser/013.php index d959d153d415..dbb096b416fb 100644 --- a/user_guide_src/source/outgoing/view_parser/013.php +++ b/user_guide_src/source/outgoing/view_parser/013.php @@ -1,8 +1,5 @@ '\Some\Class::methodName', - 'bar' => function ($str, array $params=[]) { - return $str; - }, +public $filters = [ + 'str_repeat' => '\str_repeat', ]; diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php index bac6137888f1..d959d153d415 100644 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -1,15 +1,8 @@ plugins['bar'] = function (array $params=[]) { - return $params[0] ?? ''; - }; - - parent::__construct(); - } -} +public $plugins = [ + 'foo' => '\Some\Class::methodName', + 'bar' => function ($str, array $params=[]) { + return $str; + }, +]; diff --git a/user_guide_src/source/outgoing/view_parser/015.php b/user_guide_src/source/outgoing/view_parser/015.php index 74a18943365c..bac6137888f1 100644 --- a/user_guide_src/source/outgoing/view_parser/015.php +++ b/user_guide_src/source/outgoing/view_parser/015.php @@ -1,8 +1,15 @@ '\Some\Class::methodName' -]; +class View extends \CodeIgniter\Config\View +{ + public $plugins = []; -// Tag is replaced by the return value of Some\Class::methodName static function. -{+ foo +} + public function __construct() + { + $this->plugins['bar'] = function (array $params=[]) { + return $params[0] ?? ''; + }; + + parent::__construct(); + } +} diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index 30d72b247059..74a18943365c 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -1,7 +1,8 @@ ['\Some\Class::methodName'] + 'foo' => '\Some\Class::methodName' ]; -{+ foo +} inner content {+ /foo +} +// Tag is replaced by the return value of Some\Class::methodName static function. +{+ foo +} diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php index cd9ca09109b9..30d72b247059 100644 --- a/user_guide_src/source/outgoing/view_parser/017.php +++ b/user_guide_src/source/outgoing/view_parser/017.php @@ -1,12 +1,7 @@ 'Mr', - 'firstname' => 'John', - 'lastname' => 'Doe' +public $plugins = [ + 'foo' => ['\Some\Class::methodName'] ]; -echo $parser->setData($data) - ->renderString($template); -// Result: Hello, John Doe +{+ foo +} inner content {+ /foo +} diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php index dfce0c26ccb4..cd9ca09109b9 100644 --- a/user_guide_src/source/outgoing/view_parser/018.php +++ b/user_guide_src/source/outgoing/view_parser/018.php @@ -1,12 +1,12 @@ 'Mr', 'firstname' => 'John', - 'lastname' => 'Doe', + 'lastname' => 'Doe' ]; echo $parser->setData($data) ->renderString($template); -// Result: Hello, John {initials} Doe +// Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php index 371fa9a21f14..dfce0c26ccb4 100644 --- a/user_guide_src/source/outgoing/view_parser/019.php +++ b/user_guide_src/source/outgoing/view_parser/019.php @@ -1,16 +1,12 @@ 'Mr', + 'title' => 'Mr', 'firstname' => 'John', 'lastname' => 'Doe', - 'titles' => [ - ['degree' => 'BSc'], - ['degree' => 'PhD'], - ], ]; echo $parser->setData($data) ->renderString($template); -// Result: Hello, John Doe (Mr{degree} {/degrees}) +// Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php index cf7b31fa7e30..371fa9a21f14 100644 --- a/user_guide_src/source/outgoing/view_parser/020.php +++ b/user_guide_src/source/outgoing/view_parser/020.php @@ -1,19 +1,16 @@ {title}'; -$data1 = [ - ['title' => 'First Link', 'link' => '/first'], - ['title' => 'Second Link', 'link' => '/second'], -]; - -foreach ($data1 as $menuItem),{ - $temp .= $parser->setData($menuItem)->renderString($template1); -} - -$template2 = '
      {menuitems}
    '; +$template = 'Hello, {firstname} {lastname} ({degrees}{degree} {/degrees})'; $data = [ - 'menuitems' => $temp, + 'degrees' => 'Mr', + 'firstname' => 'John', + 'lastname' => 'Doe', + 'titles' => [ + ['degree' => 'BSc'], + ['degree' => 'PhD'], + ], ]; echo $parser->setData($data) - ->renderString($template2); + ->renderString($template); + +// Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/outgoing/view_parser/021-1.php b/user_guide_src/source/outgoing/view_parser/021-1.php deleted file mode 100644 index 022450bb6fd6..000000000000 --- a/user_guide_src/source/outgoing/view_parser/021-1.php +++ /dev/null @@ -1,3 +0,0 @@ -render('myview'); diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php index 022450bb6fd6..cf7b31fa7e30 100644 --- a/user_guide_src/source/outgoing/view_parser/021.php +++ b/user_guide_src/source/outgoing/view_parser/021.php @@ -1,3 +1,19 @@ render('myview'); +$temp = ''; +$template1 = '
  • {title}
  • '; +$data1 = [ + ['title' => 'First Link', 'link' => '/first'], + ['title' => 'Second Link', 'link' => '/second'], +]; + +foreach ($data1 as $menuItem),{ + $temp .= $parser->setData($menuItem)->renderString($template1); +} + +$template2 = '
      {menuitems}
    '; +$data = [ + 'menuitems' => $temp, +]; +echo $parser->setData($data) + ->renderString($template2); diff --git a/user_guide_src/source/outgoing/view_parser/023.php b/user_guide_src/source/outgoing/view_parser/023.php index 42ddfa949331..022450bb6fd6 100644 --- a/user_guide_src/source/outgoing/view_parser/023.php +++ b/user_guide_src/source/outgoing/view_parser/023.php @@ -1,3 +1,3 @@ setData(['name' => 'George', 'position' => 'Boss']); +echo $parser->render('myview'); diff --git a/user_guide_src/source/outgoing/view_parser/024.php b/user_guide_src/source/outgoing/view_parser/024.php index 76ba0b537f96..42ddfa949331 100644 --- a/user_guide_src/source/outgoing/view_parser/024.php +++ b/user_guide_src/source/outgoing/view_parser/024.php @@ -1,3 +1,3 @@ setVar('name','Joe','html'); +$renderer->setData(['name' => 'George', 'position' => 'Boss']); diff --git a/user_guide_src/source/outgoing/view_parser/025.php b/user_guide_src/source/outgoing/view_parser/025.php index a8633d5717c7..76ba0b537f96 100644 --- a/user_guide_src/source/outgoing/view_parser/025.php +++ b/user_guide_src/source/outgoing/view_parser/025.php @@ -1,3 +1,3 @@ setDelimiters('[',']'); +$renderer->setVar('name','Joe','html'); diff --git a/user_guide_src/source/outgoing/view_parser/026.php b/user_guide_src/source/outgoing/view_parser/026.php new file mode 100644 index 000000000000..a8633d5717c7 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/026.php @@ -0,0 +1,3 @@ +setDelimiters('[',']'); diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index ae6eb2deb97e..e39df524affc 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -178,7 +178,7 @@ values of the elements. Instead, they simply check that the elements exist on th You can use **seeLink()** to ensure that a link appears on the page with the specified text: -.. literalinclude:: response/021-2.php +.. literalinclude:: response/021.php :lines: 2- The **seeInField()** method checks for any input tags exist with the name and value: @@ -231,7 +231,7 @@ specific text: Asserts that an anchor tag is found with matching **$text** as the body of the tag: -.. literalinclude:: response/021.php +.. literalinclude:: response/028.php :lines: 2- **assertSeeInField(string $field, string $value=null)** diff --git a/user_guide_src/source/testing/response/021-2.php b/user_guide_src/source/testing/response/021-2.php deleted file mode 100644 index bc74e3ad9124..000000000000 --- a/user_guide_src/source/testing/response/021-2.php +++ /dev/null @@ -1,6 +0,0 @@ -seeLink('Upgrade Account'); -// Check that a link exists with 'Upgrade Account' as the text, AND a class of 'upsell' -$results->seeLink('Upgrade Account', '.upsell'); From 5b84072e32e7dc70a143accdd4f6d4f80b7c784b Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Sun, 20 Feb 2022 09:57:37 +0100 Subject: [PATCH 1602/2325] Fix merge conflicts. --- .../source/incoming/incomingrequest.rst | 282 +++++++----------- .../source/incoming/incomingrequest/006.php | 4 - .../source/incoming/incomingrequest/024.php | 18 -- .../incomingrequest/{001.php => 1.php} | 0 .../incomingrequest/{011.php => 10.php} | 0 .../incomingrequest/{012.php => 11.php} | 0 .../incomingrequest/{013.php => 12.php} | 0 .../incomingrequest/{014.php => 13.php} | 0 .../incomingrequest/{015.php => 14.php} | 0 .../incomingrequest/{016.php => 15.php} | 0 .../incomingrequest/{017.php => 16.php} | 0 .../incomingrequest/{018.php => 17.php} | 0 .../incomingrequest/{019.php => 18.php} | 0 .../incomingrequest/{020.php => 19.php} | 0 .../incomingrequest/{002.php => 2.php} | 0 .../incomingrequest/{021.php => 20.php} | 0 .../incomingrequest/{022.php => 21.php} | 0 .../incomingrequest/{023.php => 22.php} | 0 .../source/incoming/incomingrequest/23.php | 3 + .../incomingrequest/{025.php => 24.php} | 0 .../incomingrequest/{026.php => 25.php} | 0 .../incomingrequest/{027.php => 26.php} | 0 .../incomingrequest/{028.php => 27.php} | 0 .../incomingrequest/{029.php => 28.php} | 0 .../incomingrequest/{030.php => 29.php} | 0 .../incomingrequest/{003.php => 3.php} | 0 .../incomingrequest/{031.php => 30.php} | 0 .../incomingrequest/{032.php => 31.php} | 0 .../incomingrequest/{033.php => 32.php} | 0 .../incomingrequest/{034.php => 33.php} | 0 .../incomingrequest/{035.php => 34.php} | 0 .../incomingrequest/{036.php => 35.php} | 0 .../incomingrequest/{037.php => 36.php} | 0 .../incomingrequest/{038.php => 37.php} | 0 .../incomingrequest/{039.php => 38.php} | 0 .../incomingrequest/{004.php => 4.php} | 0 .../incomingrequest/{005.php => 5.php} | 0 .../incomingrequest/{007.php => 6.php} | 0 .../incomingrequest/{008.php => 7.php} | 0 .../incomingrequest/{009.php => 8.php} | 0 .../incomingrequest/{010.php => 9.php} | 0 41 files changed, 111 insertions(+), 196 deletions(-) delete mode 100644 user_guide_src/source/incoming/incomingrequest/006.php delete mode 100644 user_guide_src/source/incoming/incomingrequest/024.php rename user_guide_src/source/incoming/incomingrequest/{001.php => 1.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{011.php => 10.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{012.php => 11.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{013.php => 12.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{014.php => 13.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{015.php => 14.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{016.php => 15.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{017.php => 16.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{018.php => 17.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{019.php => 18.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{020.php => 19.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{002.php => 2.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{021.php => 20.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{022.php => 21.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{023.php => 22.php} (100%) create mode 100644 user_guide_src/source/incoming/incomingrequest/23.php rename user_guide_src/source/incoming/incomingrequest/{025.php => 24.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{026.php => 25.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{027.php => 26.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{028.php => 27.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{029.php => 28.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{030.php => 29.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{003.php => 3.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{031.php => 30.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{032.php => 31.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{033.php => 32.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{034.php => 33.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{035.php => 34.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{036.php => 35.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{037.php => 36.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{038.php => 37.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{039.php => 38.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{004.php => 4.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{005.php => 5.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{007.php => 6.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{008.php => 7.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{009.php => 8.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{010.php => 9.php} (100%) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 5e77e9253804..70692d1aa4c4 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -13,72 +13,38 @@ Accessing the Request --------------------- An instance of the request class already populated for you if the current class is a descendant of -``CodeIgniter\Controller`` and can be accessed as a class property:: +``CodeIgniter\Controller`` and can be accessed as a class property: - request->isAJAX()) { - // ... - } - } - } +.. literalinclude:: incomingrequest/1.php If you are not within a controller, but still need access to the application's Request object, you can -get a copy of it through the :doc:`Services class `:: +get a copy of it through the :doc:`Services class `: - $request = \Config\Services::request(); +.. literalinclude:: incomingrequest/2.php + :lines: 2- It's preferable, though, to pass the request in as a dependency if the class is anything other than -the controller, where you can save it as a class property:: - - request = $request; - } - } +the controller, where you can save it as a class property: - $someClass = new SomeClass(\Config\Services::request()); +.. literalinclude:: incomingrequest/3.php Determining Request Type ------------------------ A request could be of several types, including an AJAX request or a request from the command line. This can -be checked with the ``isAJAX()`` and ``isCLI()`` methods:: +be checked with the ``isAJAX()`` and ``isCLI()`` methods: - // Check for AJAX request. - if ($request->isAJAX()) { - // ... - } - - // Check for CLI Request - if ($request->isCLI()) { - // ... - } +.. literalinclude:: incomingrequest/4.php + :lines: 2- .. note:: The ``isAJAX()`` method depends on the ``X-Requested-With`` header, which in some cases is not sent by default in XHR requests via JavaScript (i.e., fetch). See the :doc:`AJAX Requests ` section on how to avoid this problem. -You can check the HTTP method that this request represents with the ``method()`` method:: +You can check the HTTP method that this request represents with the ``method()`` method: - // Returns 'post' - $method = $request->getMethod(); +.. literalinclude:: incomingrequest/5.php + :lines: 2- By default, the method is returned as a lower-case string (i.e., 'get', 'post', etc). You can get an uppercase version by wrapping the call in ``str_to_upper()``:: @@ -86,11 +52,10 @@ uppercase version by wrapping the call in ``str_to_upper()``:: // Returns 'GET' $method = str_to_upper($request->getMethod()); -You can also check if the request was made through and HTTPS connection with the ``isSecure()`` method:: +You can also check if the request was made through and HTTPS connection with the ``isSecure()`` method: - if (! $request->isSecure()) { - force_https(); - } +.. literalinclude:: incomingrequest/6.php + :lines: 2- Retrieving Input ---------------- @@ -100,13 +65,15 @@ The data is not automatically filtered and returns the raw input data as passed advantages to using these methods instead of accessing them directly ($_POST['something']), is that they will return null if the item doesn't exist, and you can have the data filtered. This lets you conveniently use data without having to test whether an item exists first. In other words, normally you might do something -like this:: +like this: - $something = isset($_POST['foo']) ? $_POST['foo'] : null; +.. literalinclude:: incomingrequest/7.php + :lines: 2- -With CodeIgniter’s built in methods you can simply do this:: +With CodeIgniter’s built in methods you can simply do this: - $something = $request->getVar('foo'); +.. literalinclude:: incomingrequest/8.php + :lines: 2- The ``getVar()`` method will pull from $_REQUEST, so will return any data from $_GET, $POST, or $_COOKIE. While this is convenient, you will often need to use a more specific method, like: @@ -129,9 +96,9 @@ You can grab the contents of php://input as a JSON stream with ``getJSON()``. .. note:: This has no way of checking if the incoming data is valid JSON or not, you should only use this method if you know that you're expecting JSON. -:: - $json = $request->getJSON(); +.. literalinclude:: incomingrequest/9.php + :lines: 2- By default, this will return any objects in the JSON data as objects. If you want that converted to associative arrays, pass in ``true`` as the first parameter. @@ -147,51 +114,32 @@ the JSON stream. Using ``getVar()`` in this way will always return an object. You can get a specific piece of data from a JSON stream by passing a variable name into ``getVar()`` for the data that you want or you can use "dot" notation to dig into the JSON to get data that is not on the root level. -:: - - // With a request body of: - { - "foo": "bar", - "fizz": { - "buzz": "baz" - } - } - $data = $request->getVar('foo'); - // $data = "bar" - $data = $request->getVar('fizz.buzz'); - // $data = "baz" +.. literalinclude:: incomingrequest/10.php + :lines: 2- If you want the result to be an associative array instead of an object, you can use ``getJsonVar()`` instead and pass true in the second parameter. This function can also be used if you can't guarantee that the incoming request will have the correct ``CONTENT_TYPE`` header. -:: - // With the same request as above - $data = $request->getJsonVar('fizz'); - // $data->buzz = "baz" - - $data = $request->getJsonVar('fizz', true); - // $data = ["buzz" => "baz"] +.. literalinclude:: incomingrequest/11.php + :lines: 2- .. note:: See the documentation for ``dot_array_search()`` in the ``Array`` helper for more information on "dot" notation. **Retrieving Raw data (PUT, PATCH, DELETE)** -Finally, you can grab the contents of php://input as a raw stream with ``getRawInput()``:: - - $data = $request->getRawInput(); +Finally, you can grab the contents of php://input as a raw stream with ``getRawInput()``: -This will retrieve data and convert it to an array. Like this:: +.. literalinclude:: incomingrequest/12.php + :lines: 2- - var_dump($request->getRawInput()); +This will retrieve data and convert it to an array. Like this: - [ - 'Param1' => 'Value1', - 'Param2' => 'Value2' - ] +.. literalinclude:: incomingrequest/13.php + :lines: 2- **Filtering Input Data** @@ -200,9 +148,10 @@ pass the type of filter to use as the second parameter of any of these methods. function is used for the filtering. Head over to the PHP manual for a list of `valid filter types `_. -Filtering a POST variable would look like this:: +Filtering a POST variable would look like this: - $email = $request->getVar('email', FILTER_SANITIZE_EMAIL); +.. literalinclude:: incomingrequest/14.php + :lines: 2- All of the methods mentioned above support the filter type passed in as the second parameter, with the exception of ``getJSON()``. @@ -212,75 +161,52 @@ Retrieving Headers You can get access to any header that was sent with the request with the ``headers()`` method, which returns an array of all headers, with the key as the name of the header, and the value is an instance of -``CodeIgniter\HTTP\Header``:: +``CodeIgniter\HTTP\Header``: - var_dump($request->headers()); - - [ - 'Host' => CodeIgniter\HTTP\Header, - 'Cache-Control' => CodeIgniter\HTTP\Header, - 'Accept' => CodeIgniter\HTTP\Header, - ] +.. literalinclude:: incomingrequest/15.php + :lines: 2- If you only need a single header, you can pass the name into the ``header()`` method. This will grab the -specified header object in a case-insensitive manner if it exists. If not, then it will return ``null``:: +specified header object in a case-insensitive manner if it exists. If not, then it will return ``null``: - // these are all equivalent - $host = $request->header('host'); - $host = $request->header('Host'); - $host = $request->header('HOST'); +.. literalinclude:: incomingrequest/16.php + :lines: 2- -You can always use ``hasHeader()`` to see if the header existed in this request:: +You can always use ``hasHeader()`` to see if the header existed in this request: - if ($request->hasHeader('DNT')) { - // Don't track something... - } +.. literalinclude:: incomingrequest/17.php + :lines: 2- -If you need the value of header as a string with all values on one line, you can use the ``getHeaderLine()`` method:: +If you need the value of header as a string with all values on one line, you can use the ``getHeaderLine()`` method: - // Accept-Encoding: gzip, deflate, sdch - echo 'Accept-Encoding: '.$request->getHeaderLine('accept-encoding'); +.. literalinclude:: incomingrequest/18.php + :lines: 2- -If you need the entire header, with the name and values in a single string, simply cast the header as a string:: +If you need the entire header, with the name and values in a single string, simply cast the header as a string: - echo (string)$header; +.. literalinclude:: incomingrequest/19.php + :lines: 2- The Request URL --------------- You can retrieve a :doc:`URI ` object that represents the current URI for this request through the -``$request->getUri()`` method. You can cast this object as a string to get a full URL for the current request:: - - $uri = (string) $request->getUri(); +``$request->getUri()`` method. You can cast this object as a string to get a full URL for the current request: -The object gives you full abilities to grab any part of the request on it's own:: +.. literalinclude:: incomingrequest/20.php + :lines: 2- - $uri = $request->getUri(); +The object gives you full abilities to grab any part of the request on it's own: - echo $uri->getScheme(); // http - echo $uri->getAuthority(); // snoopy:password@example.com:88 - echo $uri->getUserInfo(); // snoopy:password - echo $uri->getHost(); // example.com - echo $uri->getPort(); // 88 - echo $uri->getPath(); // /path/to/page - echo $uri->getQuery(); // foo=bar&bar=baz - echo $uri->getSegments(); // ['path', 'to', 'page'] - echo $uri->getSegment(1); // 'path' - echo $uri->getTotalSegments(); // 3 +.. literalinclude:: incomingrequest/21.php + :lines: 2- You can work with the current URI string (the path relative to your baseURL) using the ``getPath()`` and ``setPath()`` methods. Note that this relative path on the shared instance of ``IncomingRequest`` is what the :doc:`URL Helper ` -functions use, so this is a helpful way to "spoof" an incoming request for testing:: - - class MyMenuTest extends CIUnitTestCase - { - public function testActiveLinkUsesCurrentUrl() - { - service('request')->setPath('users/list'); - $menu = new MyMenu(); - $this->assertTrue('users/list', $menu->getActiveLink()); - } - } +functions use, so this is a helpful way to "spoof" an incoming request for testing: + +.. literalinclude:: incomingrequest/22.php + :lines: 2- Uploaded Files -------------- @@ -288,33 +214,32 @@ Uploaded Files Information about all uploaded files can be retrieved through ``$request->getFiles()``, which returns an array of ``CodeIgniter\HTTP\Files\UploadedFile`` instance. This helps to ease the pain of working with uploaded files, and uses best practices to minimize any security risks. -:: - $files = $request->getFiles(); +.. literalinclude:: incomingrequest/23.php + :lines: 2- See :ref:`Working with Uploaded Files ` for the details. -You can retrieve a single file uploaded on its own, based on the filename given in the HTML file input:: +You can retrieve a single file uploaded on its own, based on the filename given in the HTML file input: - $file = $request->getFile('userfile'); +.. literalinclude:: incomingrequest/24.php + :lines: 2- You can retrieve an array of same-named files uploaded as part of a -multi-file upload, based on the filename given in the HTML file input:: +multi-file upload, based on the filename given in the HTML file input: - $files = $request->getFileMultiple('userfile'); +.. literalinclude:: incomingrequest/25.php + :lines: 2- .. note:: The files here correspond to ``$_FILES``. Even if a user just clicks submit button of a form and does not upload any file, the file will still exist. You can check that the file was actually uploaded by the ``isValid()`` method in UploadedFile. See :ref:`verify-a-file` for more details. Content Negotiation ------------------- -You can easily negotiate content types with the request through the ``negotiate()`` method:: +You can easily negotiate content types with the request through the ``negotiate()`` method: - $language = $request->negotiate('language', ['en-US', 'en-GB', 'fr', 'es-mx']); - $imageType = $request->negotiate('media', ['image/png', 'image/jpg']); - $charset = $request->negotiate('charset', ['UTF-8', 'UTF-16']); - $contentType = $request->negotiate('media', ['text/html', 'text/xml']); - $encoding = $request->negotiate('encoding', ['gzip', 'compress']); +.. literalinclude:: incomingrequest/26.php + :lines: 2- See the :doc:`Content Negotiation ` page for more details. @@ -376,35 +301,39 @@ The methods provided by the parent classes that are available are: :returns: $_REQUEST if no parameters supplied, otherwise the REQUEST value if found, or null if not :rtype: mixed|null - The first parameter will contain the name of the REQUEST item you are looking for:: + The first parameter will contain the name of the REQUEST item you are looking for: - $request->getVar('some_data'); + .. literalinclude:: incomingrequest/27.php + :lines: 2- The method returns null if the item you are attempting to retrieve does not exist. The second optional parameter lets you run the data through the PHP's - filters. Pass in the desired filter type as the second parameter:: + filters. Pass in the desired filter type as the second parameter: - $request->getVar('some_data', FILTER_SANITIZE_FULL_SPECIAL_CHARS); + .. literalinclude:: incomingrequest/28.php + :lines: 2- To return an array of all POST items call without any parameters. To return all POST items and pass them through the filter, set the first parameter to null while setting the second parameter to the filter - you want to use:: + you want to use: - $request->getVar(null, FILTER_SANITIZE_FULL_SPECIAL_CHARS); - // returns all POST items with string sanitation + .. literalinclude:: incomingrequest/29.php + :lines: 2- - To return an array of multiple POST parameters, pass all the required keys as an array:: + To return an array of multiple POST parameters, pass all the required keys as an array: - $request->getVar(['field1', 'field2']); + .. literalinclude:: incomingrequest/30.php + :lines: 2- Same rule applied here, to retrieve the parameters with filtering, set the second parameter to - the filter type to apply:: + the filter type to apply: - $request->getVar(['field1', 'field2'], FILTER_SANITIZE_FULL_SPECIAL_CHARS); + .. literalinclude:: incomingrequest/31.php + :lines: 2- .. php:method:: getGet([$index = null[, $filter = null[, $flags = null]]]) @@ -442,9 +371,10 @@ The methods provided by the parent classes that are available are: This method works pretty much the same way as ``getPost()`` and ``getGet()``, only combined. It will search through both POST and GET streams for data, looking first in POST, and - then in GET:: + then in GET: - $request->getPostGet('field1'); + .. literalinclude:: incomingrequest/32.php + :lines: 2- .. php:method:: getGetPost([$index = null[, $filter = null[, $flags = null]]]) @@ -458,9 +388,10 @@ The methods provided by the parent classes that are available are: This method works pretty much the same way as ``getPost()`` and ``getGet()``, only combined. It will search through both POST and GET streams for data, looking first in GET, and - then in POST:: + then in POST: - $request->getGetPost('field1'); + .. literalinclude:: incomingrequest/33.php + :lines: 2- .. php:method:: getCookie([$index = null[, $filter = null[, $flags = null]]]) :noindex: @@ -473,14 +404,15 @@ The methods provided by the parent classes that are available are: :returns: $_COOKIE if no parameters supplied, otherwise the COOKIE value if found or null if not :rtype: mixed - This method is identical to ``getPost()`` and ``getGet()``, only it fetches cookie data:: + This method is identical to ``getPost()`` and ``getGet()``, only it fetches cookie data: - $request->getCookie('some_cookie'); - $request->getCookie('some_cookie', FILTER_SANITIZE_FULL_SPECIAL_CHARS); // with filter + .. literalinclude:: incomingrequest/34.php + :lines: 2- - To return an array of multiple cookie values, pass all the required keys as an array:: + To return an array of multiple cookie values, pass all the required keys as an array: - $request->getCookie(['some_cookie', 'some_cookie2']); + .. literalinclude:: incomingrequest/35.php + :lines: 2- .. note:: Unlike the :doc:`Cookie Helper <../helpers/cookie_helper>` function :php:func:`get_cookie()`, this method does NOT prepend @@ -498,15 +430,16 @@ The methods provided by the parent classes that are available are: :rtype: mixed This method is identical to the ``getPost()``, ``getGet()`` and ``getCookie()`` - methods, only it fetches getServer data (``$_SERVER``):: + methods, only it fetches getServer data (``$_SERVER``): - $request->getServer('some_data'); + .. literalinclude:: incomingrequest/36.php + :lines: 2- To return an array of multiple ``$_SERVER`` values, pass all the required keys as an array. - :: - $request->getServer(['SERVER_PROTOCOL', 'REQUEST_URI']); + .. literalinclude:: incomingrequest/37.php + :lines: 2- .. php:method:: getUserAgent([$filter = null]) @@ -515,9 +448,10 @@ The methods provided by the parent classes that are available are: :returns: The User Agent string, as found in the SERVER data, or null if not found. :rtype: mixed - This method returns the User Agent string from the SERVER data:: + This method returns the User Agent string from the SERVER data: - $request->getUserAgent(); + .. literalinclude:: incomingrequest/38.php + :lines: 2- .. php:method:: getPath() diff --git a/user_guide_src/source/incoming/incomingrequest/006.php b/user_guide_src/source/incoming/incomingrequest/006.php deleted file mode 100644 index 99e269157152..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/006.php +++ /dev/null @@ -1,4 +0,0 @@ -getMethod()); diff --git a/user_guide_src/source/incoming/incomingrequest/024.php b/user_guide_src/source/incoming/incomingrequest/024.php deleted file mode 100644 index e29f87b9f419..000000000000 --- a/user_guide_src/source/incoming/incomingrequest/024.php +++ /dev/null @@ -1,18 +0,0 @@ -getFiles(); - -// Grab the file by name given in HTML form -if ($files->hasFile('userfile')) { - $file = $files->getFile('userfile'); - - // Generate a new secure name - $name = $file->getRandomName(); - - // Move the file to it's new home - $file->move('/path/to/dir', $name); - - echo $file->getSize('mb'); // 1.23 - echo $file->getExtension(); // jpg - echo $file->getType(); // image/jpg -} diff --git a/user_guide_src/source/incoming/incomingrequest/001.php b/user_guide_src/source/incoming/incomingrequest/1.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/001.php rename to user_guide_src/source/incoming/incomingrequest/1.php diff --git a/user_guide_src/source/incoming/incomingrequest/011.php b/user_guide_src/source/incoming/incomingrequest/10.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/011.php rename to user_guide_src/source/incoming/incomingrequest/10.php diff --git a/user_guide_src/source/incoming/incomingrequest/012.php b/user_guide_src/source/incoming/incomingrequest/11.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/012.php rename to user_guide_src/source/incoming/incomingrequest/11.php diff --git a/user_guide_src/source/incoming/incomingrequest/013.php b/user_guide_src/source/incoming/incomingrequest/12.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/013.php rename to user_guide_src/source/incoming/incomingrequest/12.php diff --git a/user_guide_src/source/incoming/incomingrequest/014.php b/user_guide_src/source/incoming/incomingrequest/13.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/014.php rename to user_guide_src/source/incoming/incomingrequest/13.php diff --git a/user_guide_src/source/incoming/incomingrequest/015.php b/user_guide_src/source/incoming/incomingrequest/14.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/015.php rename to user_guide_src/source/incoming/incomingrequest/14.php diff --git a/user_guide_src/source/incoming/incomingrequest/016.php b/user_guide_src/source/incoming/incomingrequest/15.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/016.php rename to user_guide_src/source/incoming/incomingrequest/15.php diff --git a/user_guide_src/source/incoming/incomingrequest/017.php b/user_guide_src/source/incoming/incomingrequest/16.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/017.php rename to user_guide_src/source/incoming/incomingrequest/16.php diff --git a/user_guide_src/source/incoming/incomingrequest/018.php b/user_guide_src/source/incoming/incomingrequest/17.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/018.php rename to user_guide_src/source/incoming/incomingrequest/17.php diff --git a/user_guide_src/source/incoming/incomingrequest/019.php b/user_guide_src/source/incoming/incomingrequest/18.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/019.php rename to user_guide_src/source/incoming/incomingrequest/18.php diff --git a/user_guide_src/source/incoming/incomingrequest/020.php b/user_guide_src/source/incoming/incomingrequest/19.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/020.php rename to user_guide_src/source/incoming/incomingrequest/19.php diff --git a/user_guide_src/source/incoming/incomingrequest/002.php b/user_guide_src/source/incoming/incomingrequest/2.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/002.php rename to user_guide_src/source/incoming/incomingrequest/2.php diff --git a/user_guide_src/source/incoming/incomingrequest/021.php b/user_guide_src/source/incoming/incomingrequest/20.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/021.php rename to user_guide_src/source/incoming/incomingrequest/20.php diff --git a/user_guide_src/source/incoming/incomingrequest/022.php b/user_guide_src/source/incoming/incomingrequest/21.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/022.php rename to user_guide_src/source/incoming/incomingrequest/21.php diff --git a/user_guide_src/source/incoming/incomingrequest/023.php b/user_guide_src/source/incoming/incomingrequest/22.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/023.php rename to user_guide_src/source/incoming/incomingrequest/22.php diff --git a/user_guide_src/source/incoming/incomingrequest/23.php b/user_guide_src/source/incoming/incomingrequest/23.php new file mode 100644 index 000000000000..de3c1601647d --- /dev/null +++ b/user_guide_src/source/incoming/incomingrequest/23.php @@ -0,0 +1,3 @@ +getFiles(); diff --git a/user_guide_src/source/incoming/incomingrequest/025.php b/user_guide_src/source/incoming/incomingrequest/24.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/025.php rename to user_guide_src/source/incoming/incomingrequest/24.php diff --git a/user_guide_src/source/incoming/incomingrequest/026.php b/user_guide_src/source/incoming/incomingrequest/25.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/026.php rename to user_guide_src/source/incoming/incomingrequest/25.php diff --git a/user_guide_src/source/incoming/incomingrequest/027.php b/user_guide_src/source/incoming/incomingrequest/26.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/027.php rename to user_guide_src/source/incoming/incomingrequest/26.php diff --git a/user_guide_src/source/incoming/incomingrequest/028.php b/user_guide_src/source/incoming/incomingrequest/27.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/028.php rename to user_guide_src/source/incoming/incomingrequest/27.php diff --git a/user_guide_src/source/incoming/incomingrequest/029.php b/user_guide_src/source/incoming/incomingrequest/28.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/029.php rename to user_guide_src/source/incoming/incomingrequest/28.php diff --git a/user_guide_src/source/incoming/incomingrequest/030.php b/user_guide_src/source/incoming/incomingrequest/29.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/030.php rename to user_guide_src/source/incoming/incomingrequest/29.php diff --git a/user_guide_src/source/incoming/incomingrequest/003.php b/user_guide_src/source/incoming/incomingrequest/3.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/003.php rename to user_guide_src/source/incoming/incomingrequest/3.php diff --git a/user_guide_src/source/incoming/incomingrequest/031.php b/user_guide_src/source/incoming/incomingrequest/30.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/031.php rename to user_guide_src/source/incoming/incomingrequest/30.php diff --git a/user_guide_src/source/incoming/incomingrequest/032.php b/user_guide_src/source/incoming/incomingrequest/31.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/032.php rename to user_guide_src/source/incoming/incomingrequest/31.php diff --git a/user_guide_src/source/incoming/incomingrequest/033.php b/user_guide_src/source/incoming/incomingrequest/32.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/033.php rename to user_guide_src/source/incoming/incomingrequest/32.php diff --git a/user_guide_src/source/incoming/incomingrequest/034.php b/user_guide_src/source/incoming/incomingrequest/33.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/034.php rename to user_guide_src/source/incoming/incomingrequest/33.php diff --git a/user_guide_src/source/incoming/incomingrequest/035.php b/user_guide_src/source/incoming/incomingrequest/34.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/035.php rename to user_guide_src/source/incoming/incomingrequest/34.php diff --git a/user_guide_src/source/incoming/incomingrequest/036.php b/user_guide_src/source/incoming/incomingrequest/35.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/036.php rename to user_guide_src/source/incoming/incomingrequest/35.php diff --git a/user_guide_src/source/incoming/incomingrequest/037.php b/user_guide_src/source/incoming/incomingrequest/36.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/037.php rename to user_guide_src/source/incoming/incomingrequest/36.php diff --git a/user_guide_src/source/incoming/incomingrequest/038.php b/user_guide_src/source/incoming/incomingrequest/37.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/038.php rename to user_guide_src/source/incoming/incomingrequest/37.php diff --git a/user_guide_src/source/incoming/incomingrequest/039.php b/user_guide_src/source/incoming/incomingrequest/38.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/039.php rename to user_guide_src/source/incoming/incomingrequest/38.php diff --git a/user_guide_src/source/incoming/incomingrequest/004.php b/user_guide_src/source/incoming/incomingrequest/4.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/004.php rename to user_guide_src/source/incoming/incomingrequest/4.php diff --git a/user_guide_src/source/incoming/incomingrequest/005.php b/user_guide_src/source/incoming/incomingrequest/5.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/005.php rename to user_guide_src/source/incoming/incomingrequest/5.php diff --git a/user_guide_src/source/incoming/incomingrequest/007.php b/user_guide_src/source/incoming/incomingrequest/6.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/007.php rename to user_guide_src/source/incoming/incomingrequest/6.php diff --git a/user_guide_src/source/incoming/incomingrequest/008.php b/user_guide_src/source/incoming/incomingrequest/7.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/008.php rename to user_guide_src/source/incoming/incomingrequest/7.php diff --git a/user_guide_src/source/incoming/incomingrequest/009.php b/user_guide_src/source/incoming/incomingrequest/8.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/009.php rename to user_guide_src/source/incoming/incomingrequest/8.php diff --git a/user_guide_src/source/incoming/incomingrequest/010.php b/user_guide_src/source/incoming/incomingrequest/9.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/010.php rename to user_guide_src/source/incoming/incomingrequest/9.php From b135145df6ddb40ecae45926be50cbac9373f1ce Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Sun, 20 Feb 2022 09:04:22 +0100 Subject: [PATCH 1603/2325] Add script for automatic renumeration of examples. --- .php-cs-fixer.dist.php | 1 + user_guide_src/renumerate.php | 98 +++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 user_guide_src/renumerate.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 3c9e05fe3b74..ec0ceaeb0172 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -32,6 +32,7 @@ __DIR__ . '/.no-header.php-cs-fixer.dist.php', __DIR__ . '/rector.php', __DIR__ . '/spark', + __DIR__ . '/user_guide_src/renumerate.php', ]); $overrides = []; diff --git a/user_guide_src/renumerate.php b/user_guide_src/renumerate.php new file mode 100644 index 000000000000..ca885551d168 --- /dev/null +++ b/user_guide_src/renumerate.php @@ -0,0 +1,98 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +$srcFolder = __DIR__ . '/source'; + +// Exclude static folders +$excludes = ['_static', 'images']; + +// Safety prefix +$prefix = 'old_'; + +// Begin user info +echo 'The following sections were renumerated:', PHP_EOL; + +// Loop source directory +$srcIterator = new DirectoryIterator($srcFolder); + +foreach ($srcIterator as $chapterInfo) { + if (! $chapterInfo->isDot() && $chapterInfo->isDir() && ! in_array($chapterInfo->getFilename(), $excludes, true)) { + $chapterName = $chapterInfo->getFilename(); + + // Iterate the working directory + $chapterIterator = new DirectoryIterator($chapterInfo->getPathname()); + + foreach ($chapterIterator as $sectionInfo) { + if (! $sectionInfo->isDot() && $sectionInfo->isFile() && $sectionInfo->getExtension() === 'rst') { + $sectionName = $sectionInfo->getBasename('.rst'); + $sectionFolder = $sectionInfo->getPath() . '/' . $sectionName; + + // Read the section file + $sectionContent = file_get_contents($sectionInfo->getPathname()); + + // Match all includes + preg_match_all("~\\.\\. literalinclude:: {$sectionName}\\/(.+)\\.php(\n[ ]*:lines: 2\\-)?~", $sectionContent, $matches); + $includeStrings = $matches[0]; + $exampleNames = $matches[1]; + + // Exit early if no matches + if (count($exampleNames) === 0) { + continue; + } + + // Check if examples are consecutive + $consecutive = true; + + foreach ($exampleNames as $exampleIndex => $exampleName) { + if (str_pad($exampleIndex + 1, 3, '0', STR_PAD_LEFT) !== $exampleName) { + $consecutive = false; + break; + } + } + + // Exit if examples are already consecutive + if ($consecutive) { + continue; + } + + // Rename all example files to avoid conflicts + $exampleIterator = new DirectoryIterator($sectionFolder); + + foreach ($exampleIterator as $exampleInfo) { + if (! $exampleInfo->isDot() && $exampleInfo->isFile() && $exampleInfo->getExtension() === 'php') { + rename($exampleInfo->getPathname(), $exampleInfo->getPath() . '/' . $prefix . $exampleInfo->getFilename()); + } + } + $sectionContent = preg_replace("~\\.\\. literalinclude:: {$sectionName}\\/(.+)\\.php~", ".. literalinclude:: {$sectionName}/{$prefix}$1.php", $sectionContent); + + // Renumerate examples + foreach ($exampleNames as $exampleIndex => $exampleName) { + $newName = str_pad($exampleIndex + 1, 3, '0', STR_PAD_LEFT); + + // Rename example file + rename($sectionFolder . '/' . $prefix . $exampleName . '.php', $sectionFolder . '/' . $newName . '.php'); + + // Fix include link + $sectionContent = preg_replace(preg_quote(str_replace($exampleName, $prefix . $exampleName, $includeStrings[$exampleIndex]), '~'), str_replace($exampleName, $newName, $includeStrings[$exampleIndex]), $sectionContent, 1, $count); + } + + // Write new content to rst + file_put_contents($sectionInfo->getPathname(), $sectionContent); + + // User info + echo $chapterName, '/', $sectionName, PHP_EOL; + } + } + } +} + +// End user info +echo 'Renumerating finished.', PHP_EOL; From dfce69826845d1b0eba58461004051de61d61c47 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 21 Feb 2022 10:22:16 +0900 Subject: [PATCH 1604/2325] docs: add comment about RecursiveIteratorIterator::hasChildren() --- system/HTTP/Files/FileCollection.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index 10e58c2eb824..bff2e5d609b4 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -220,6 +220,10 @@ protected function fixFilesArray(array $data): array $pointer = &$stack[count($stack) - 1]; $pointer = &$pointer[$key]; $stack[] = &$pointer; + + // RecursiveIteratorIterator::hasChildren() can be used. RecursiveIteratorIterator + // forwards all unknown method calls to the underlying RecursiveIterator internally. + // See https://github.com/php/doc-en/issues/787#issuecomment-881446121 if (! $iterator->hasChildren()) { $pointer[$field] = $val; } From 2c525a49f983c87151817e1e922e9e8bbfb41d87 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 21 Feb 2022 10:22:58 +0900 Subject: [PATCH 1605/2325] docs: fix typo --- system/HTTP/Files/FileCollection.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/Files/FileCollection.php b/system/HTTP/Files/FileCollection.php index bff2e5d609b4..87f31ee511ea 100644 --- a/system/HTTP/Files/FileCollection.php +++ b/system/HTTP/Files/FileCollection.php @@ -235,7 +235,7 @@ protected function fixFilesArray(array $data): array } /** - * Navigate through a array looking for a particular index + * Navigate through an array looking for a particular index * * @param array $index The index sequence we are navigating down * @param array $value The portion of the array to process From bb7dc422dbffbcdae6f6023a2d50e98d6f1e8962 Mon Sep 17 00:00:00 2001 From: Nudasoft <30935025+Nudasoft@users.noreply.github.com> Date: Mon, 21 Feb 2022 11:28:40 +0530 Subject: [PATCH 1606/2325] Fix alignment issues on few buttons in debug toobar and few cosmetic tweaks. --- system/Debug/Toolbar/Views/toolbar.css | 32 ++++++++------------------ 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index ed4230be0988..47e74d9a4f1b 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -39,16 +39,9 @@ font-size: 16px; font-weight: 400; } #debug-bar h1 { - bottom: 0; - display: inline-block; - font-size: 14px; + display: flex; font-weight: normal; - margin: 0 16px 0 0; - padding: 0; - position: absolute; - right: 30px; - text-align: left; - top: 0; } + margin: 0 0 0 auto; } #debug-bar h1 svg { width: 16px; margin-right: 5px; } @@ -135,15 +128,8 @@ #debug-bar #toolbar-theme a:hover { text-decoration: none; } #debug-bar #debug-bar-link { - bottom: 0; - display: inline-block; - font-size: 16px; - line-height: 36px; padding: 6px; - position: absolute; - right: 10px; - top: 0; - width: 24px; } + display: flex; } #debug-bar .ci-label { display: inline-flex; font-size: 14px; } @@ -329,7 +315,7 @@ #debug-bar .ci-label:hover { background-color: #DFDFDF; } #debug-bar .ci-label .badge { - background-color: #5BC0DE; + background-color: #DD7359; color: #FFFFFF; } #debug-bar .tab { background-color: #FFFFFF; @@ -420,8 +406,8 @@ #debug-bar .ci-label:hover { background-color: #252525; } #debug-bar .ci-label .badge { - background-color: #5BC0DE; - color: #DFDFDF; } + background-color: #DD7359; + color: #FFFFFF; } #debug-bar .tab { background-color: #252525; box-shadow: 0 -1px 4px #434343; @@ -509,8 +495,8 @@ #toolbarContainer.dark #debug-bar .ci-label:hover { background-color: #252525; } #toolbarContainer.dark #debug-bar .ci-label .badge { - background-color: #5BC0DE; - color: #DFDFDF; } + background-color: #DD7359; + color: #FFFFFF; } #toolbarContainer.dark #debug-bar .tab { background-color: #252525; box-shadow: 0 -1px 4px #434343; @@ -602,7 +588,7 @@ #toolbarContainer.light #debug-bar .ci-label:hover { background-color: #DFDFDF; } #toolbarContainer.light #debug-bar .ci-label .badge { - background-color: #5BC0DE; + background-color: #DD7359; color: #FFFFFF; } #toolbarContainer.light #debug-bar .tab { background-color: #FFFFFF; From 2c52bd674693281a70950d04e8cac7b02c1a5ab6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 08:49:29 +0900 Subject: [PATCH 1607/2325] docs: fix typo --- user_guide_src/source/changelogs/v4.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index cc1561a98949..941875c03b8f 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -28,7 +28,7 @@ Enhancements - Added Validation Strict Rules. See :ref:`validation-traditional-and-strict-rules`. - Added new OCI8 driver for database. - It can access Oracle Database and supports SQL and PL/SQL statements. -- The ``spark routes`` command now shows closure routes, auto routtes, and filters. See :ref:`URI Routing `. +- The ``spark routes`` command now shows closure routes, auto routes, and filters. See :ref:`URI Routing `. - Exception information logged through ``log_message()`` has now improved. It now includes the file and line where the exception originated. It also does not truncate the message anymore. - The log format has also changed. If users are depending on the log format in their apps, the new log format is "<1-based count> (): " From 60abb80ba558105196e9b05274e77d55414471fe Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 08:54:34 +0900 Subject: [PATCH 1608/2325] docs: add SPARKED in Deprecations --- user_guide_src/source/changelogs/v4.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 941875c03b8f..daad84d662fb 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -48,6 +48,7 @@ Deprecations - ``CodeIgniter\Debug\Exceptions::cleanPath()`` and ``CodeIgniter\Debug\Toolbar\Collectors\BaseCollector::cleanPath()`` are deprecated. Use the ``clean_path()`` function instead. - ``CodeIgniter\Log\Logger::cleanFilenames()`` and ``CodeIgniter\Test\TestLogger::cleanup()`` are both deprecated. Use the ``clean_path()`` function instead. - ``CodeIgniter\Router\Router::setDefaultController()`` is deprecated. +- The constant ``SPARKED`` in **spark** is deprecated. Use the ``$context`` property in ``CodeIgniter\CodeIgniter`` instead. Bugs Fixed ********** From 3a216d0f5e7f711c932355f828f1956b43a8c419 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 09:39:09 +0900 Subject: [PATCH 1609/2325] docs: add note about how to check CI version --- user_guide_src/source/installation/upgrading.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 1e1d63abe9f1..322302d3e011 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -5,6 +5,10 @@ Upgrading From a Previous Version Please read the upgrade notes corresponding to the version you are upgrading from. +.. note:: If you don't know what version of CodeIgniter you are currently running, + you can get it from :ref:`the Debug Toolbar `, + or simply echo the constant ``\CodeIgniter\CodeIgniter::CI_VERSION``. + .. toctree:: :titlesonly: From 52fc49c701774ce7dcacbdced7d20cc633ed143c Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 15:08:44 +0900 Subject: [PATCH 1610/2325] docs: make the file path more detailed --- user_guide_src/source/cli/cli.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/cli/cli.rst b/user_guide_src/source/cli/cli.rst index ba5305e433a6..9c7aa04cd835 100644 --- a/user_guide_src/source/cli/cli.rst +++ b/user_guide_src/source/cli/cli.rst @@ -79,7 +79,7 @@ you with CLI-only tools. CLI-Only Routing ---------------- -In your **Routes.php** file you can create routes that are only accessible from +In your **app/Config/Routes.php** file you can create routes that are only accessible from the CLI as easily as you would create any other route. Instead of using the ``get()``, ``post()``, or similar method, you would use the ``cli()`` method. Everything else works exactly like a normal route definition: From 59715c7b9a7ae0781795f6ae3078e33ce13656ee Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 15:10:14 +0900 Subject: [PATCH 1611/2325] docs: improve page link --- user_guide_src/source/cli/cli.rst | 2 +- user_guide_src/source/incoming/routing.rst | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/cli/cli.rst b/user_guide_src/source/cli/cli.rst index 9c7aa04cd835..e88fc6817f5b 100644 --- a/user_guide_src/source/cli/cli.rst +++ b/user_guide_src/source/cli/cli.rst @@ -87,7 +87,7 @@ works exactly like a normal route definition: .. literalinclude:: cli/002.php :lines: 2- -For more information, see the :doc:`Routes ` page. +For more information, see the :ref:`Routes ` page. The CLI Library --------------- diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 14d98a8c84ed..c57e08fa3bd3 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -335,7 +335,9 @@ You can use the ``add()`` method: only routes that match the current request method are stored, resulting in fewer routes to scan through when trying to find a match. -Command-Line only Routes +.. _command-line-only-routes: + +Command-Line Only Routes ======================== You can create routes that work only from the command-line, and are inaccessible from the web browser, with the From 7c84a3052de2f5ff7ae68e6f86e96d572d0cd633 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 15:10:30 +0900 Subject: [PATCH 1612/2325] docs: add warning about auto-routing --- user_guide_src/source/cli/cli.rst | 3 +++ user_guide_src/source/incoming/routing.rst | 3 +++ 2 files changed, 6 insertions(+) diff --git a/user_guide_src/source/cli/cli.rst b/user_guide_src/source/cli/cli.rst index e88fc6817f5b..45db6a1e6e3e 100644 --- a/user_guide_src/source/cli/cli.rst +++ b/user_guide_src/source/cli/cli.rst @@ -89,6 +89,9 @@ works exactly like a normal route definition: For more information, see the :ref:`Routes ` page. +.. warning:: If you don't disable auto-routing and place the command file in **app/Controllers**, + anyone could access the command with the help of auto-routing via HTTP. + The CLI Library --------------- diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index c57e08fa3bd3..a5c527c3eedb 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -348,6 +348,9 @@ available from the command line: .. literalinclude:: routing/028.php :lines: 2- +.. warning:: If you don't disable auto-routing and place the command file in **app/Controllers**, + anyone could access the command with the help of auto-routing via HTTP. + Global Options ============== From a915d8697808288e98cc9d819231034684407b14 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Tue, 22 Feb 2022 10:19:56 +0100 Subject: [PATCH 1613/2325] Convert non-php code. --- .../source/cli/cli_commands/006.php | 2 +- .../source/cli/cli_commands/007.php | 4 ++-- .../source/database/call_function/002.php | 2 +- .../source/database/configuration/008.php | 6 ++--- .../source/database/query_builder/027.php | 2 +- .../source/extending/events/002.php | 2 +- .../source/extending/events/006.php | 2 +- .../source/general/common_functions/003.php | 2 +- .../source/helpers/array_helper/002.php | 2 +- .../source/helpers/text_helper/020.php | 15 +++++++----- .../source/helpers/url_helper/009.php | 4 ++-- .../source/helpers/url_helper/023.php | 4 +++- .../source/helpers/url_helper/024.php | 4 +++- .../source/incoming/filters/011.php | 2 +- .../source/incoming/incomingrequest/10.php | 15 +++++++----- .../source/incoming/incomingrequest/13.php | 2 +- .../source/incoming/incomingrequest/15.php | 2 +- .../source/incoming/message/003.php | 24 ++++++++++++------- .../source/incoming/message/005.php | 6 +++-- .../source/incoming/routing/029.php | 2 +- .../source/installation/upgrade_412/001.php | 3 +++ .../source/installation/upgrade_412/002.php | 3 +++ .../installation/upgrade_localization/002.php | 2 +- .../installation/upgrade_localization/003.php | 2 +- .../installation/upgrade_responses/001.php | 2 +- .../installation/upgrade_responses/002.php | 2 +- .../installation/upgrade_routing/002.php | 2 +- .../installation/upgrade_security/002.php | 2 +- .../source/libraries/curlrequest/014.php | 11 +++++---- .../source/libraries/curlrequest/019.php | 2 +- .../source/libraries/pagination/011.php | 2 +- .../source/libraries/pagination/012.php | 2 +- .../source/libraries/sessions/002.php | 2 +- .../source/libraries/sessions/005.php | 2 +- .../source/libraries/sessions/007.php | 2 +- .../source/libraries/sessions/009.php | 2 +- .../source/libraries/sessions/010.php | 2 +- .../source/libraries/sessions/014.php | 2 +- .../source/libraries/sessions/024.php | 2 +- .../source/libraries/sessions/033.php | 2 +- .../source/libraries/throttler/003.php | 2 +- user_guide_src/source/libraries/time/038.php | 2 +- user_guide_src/source/libraries/time/041.php | 4 ++-- .../source/libraries/uploaded_files/004.php | 4 ++-- .../source/libraries/uploaded_files/005.php | 4 ++-- .../source/libraries/uploaded_files/006.php | 7 +++--- user_guide_src/source/libraries/uri/020.php | 2 +- user_guide_src/source/libraries/uri/026.php | 2 +- .../source/libraries/validation/002.php | 2 +- .../source/libraries/validation/009.php | 22 +++++++++-------- .../source/libraries/validation/011.php | 13 ++++++---- .../source/libraries/validation/025.php | 2 +- .../source/libraries/validation/027.php | 2 +- user_guide_src/source/models/entities/003.php | 2 +- .../source/outgoing/localization/007.php | 2 +- .../source/outgoing/localization/008.php | 11 +++++---- .../source/outgoing/response/021.php | 2 +- .../source/outgoing/response/026.php | 4 +++- .../source/outgoing/view_parser/016.php | 2 +- .../source/outgoing/view_parser/017.php | 2 +- .../source/outgoing/view_parser/021.php | 2 +- .../source/testing/benchmark/004.php | 2 +- .../source/testing/controllers/012.php | 4 +++- .../source/testing/fabricator/001.php | 4 +++- .../source/testing/fabricator/005.php | 1 + .../source/testing/fabricator/006.php | 3 +++ .../source/testing/fabricator/009.php | 2 +- .../source/testing/fabricator/012.php | 2 +- .../source/testing/fabricator/016.php | 4 ++-- .../source/testing/fabricator/018.php | 4 ++-- .../source/testing/fabricator/021.php | 1 + user_guide_src/source/testing/feature/002.php | 2 +- .../source/testing/overview/006.php | 1 + .../source/testing/overview/007.php | 8 +++++-- .../source/testing/overview/008.php | 2 +- .../source/testing/response/004.php | 2 +- .../source/testing/response/006.php | 2 +- .../source/testing/response/020.php | 2 +- .../source/testing/response/026.php | 2 +- .../source/testing/response/030.php | 12 ++++++---- .../source/testing/response/031.php | 2 +- .../source/testing/response/032.php | 2 +- 82 files changed, 184 insertions(+), 130 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands/006.php b/user_guide_src/source/cli/cli_commands/006.php index 43c03cdab049..bdc252c957be 100644 --- a/user_guide_src/source/cli/cli_commands/006.php +++ b/user_guide_src/source/cli/cli_commands/006.php @@ -1,7 +1,7 @@ showError($e); } diff --git a/user_guide_src/source/cli/cli_commands/007.php b/user_guide_src/source/cli/cli_commands/007.php index 71456025ddac..7fcb90ccf083 100644 --- a/user_guide_src/source/cli/cli_commands/007.php +++ b/user_guide_src/source/cli/cli_commands/007.php @@ -7,5 +7,5 @@ } // Output will be --n Set migration namespace --r override file +// -n Set migration namespace +// -r override file diff --git a/user_guide_src/source/database/call_function/002.php b/user_guide_src/source/database/call_function/002.php index 807a43266dac..64d5e0fbc85f 100644 --- a/user_guide_src/source/database/call_function/002.php +++ b/user_guide_src/source/database/call_function/002.php @@ -1,3 +1,3 @@ callFunction('some_function', $param1, $param2, etc..); +$db->callFunction('some_function', $param1, $param2, /* ... */); diff --git a/user_guide_src/source/database/configuration/008.php b/user_guide_src/source/database/configuration/008.php index 780c89a9b532..9d2d76336d94 100644 --- a/user_guide_src/source/database/configuration/008.php +++ b/user_guide_src/source/database/configuration/008.php @@ -2,9 +2,9 @@ class Database { - public $development = [...]; - public $test = [...]; - public $production = [...]; + public $development = [/* ... */]; + public $test = [/* ... */]; + public $production = [/* ... */]; public function __construct() { diff --git a/user_guide_src/source/database/query_builder/027.php b/user_guide_src/source/database/query_builder/027.php index 8d1b6495e232..7583487da1a2 100644 --- a/user_guide_src/source/database/query_builder/027.php +++ b/user_guide_src/source/database/query_builder/027.php @@ -9,5 +9,5 @@ // Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) // With builder directly -$subQuery = $db->table('orders')->select('MAX(advance_amount)', false)->where('id >', 2) +$subQuery = $db->table('orders')->select('MAX(advance_amount)', false)->where('id >', 2); $builder->where('advance_amount <', $subQuery); diff --git a/user_guide_src/source/extending/events/002.php b/user_guide_src/source/extending/events/002.php index e41a9880c232..1c28aa8dc471 100644 --- a/user_guide_src/source/extending/events/002.php +++ b/user_guide_src/source/extending/events/002.php @@ -13,5 +13,5 @@ // Use a Closure Events::on('pre_system', function (...$params) { - . . . + // ... }); diff --git a/user_guide_src/source/extending/events/006.php b/user_guide_src/source/extending/events/006.php index ff866f8e2392..5233c94e1808 100644 --- a/user_guide_src/source/extending/events/006.php +++ b/user_guide_src/source/extending/events/006.php @@ -3,5 +3,5 @@ \CodeIgniter\Events\Events::trigger('some_events', $foo, $bar, $baz); Events::on('some_event', function ($foo, $bar, $baz) { - ... + // ... }); diff --git a/user_guide_src/source/general/common_functions/003.php b/user_guide_src/source/general/common_functions/003.php index fd713d756325..4fecfb8fc9a0 100644 --- a/user_guide_src/source/general/common_functions/003.php +++ b/user_guide_src/source/general/common_functions/003.php @@ -5,5 +5,5 @@ // Set timer start and stop points timer('controller_loading'); // Will start the timer -. . . +// ... timer('controller_loading'); // Will stop the running timer diff --git a/user_guide_src/source/helpers/array_helper/002.php b/user_guide_src/source/helpers/array_helper/002.php index 64f6a2891fa0..50ce70084c86 100644 --- a/user_guide_src/source/helpers/array_helper/002.php +++ b/user_guide_src/source/helpers/array_helper/002.php @@ -9,4 +9,4 @@ 'baz' => 23, ] ] -] +]; diff --git a/user_guide_src/source/helpers/text_helper/020.php b/user_guide_src/source/helpers/text_helper/020.php index a6de1d0f67f0..e5e6be9350a6 100644 --- a/user_guide_src/source/helpers/text_helper/020.php +++ b/user_guide_src/source/helpers/text_helper/020.php @@ -3,10 +3,13 @@ $string = "Here is a simple string of text that will help us demonstrate this function."; echo word_wrap($string, 25); -// Would produce: -// Here is a simple string -// of text that will help us -// demonstrate this -// function. +/* + Would produce: -Excessively long words will be split, but URLs will not be. \ No newline at end of file + Here is a simple string + of text that will help us + demonstrate this + function. + + Excessively long words will be split, but URLs will not be. +*/ \ No newline at end of file diff --git a/user_guide_src/source/helpers/url_helper/009.php b/user_guide_src/source/helpers/url_helper/009.php index 960bc6f0430e..d8a04af25055 100644 --- a/user_guide_src/source/helpers/url_helper/009.php +++ b/user_guide_src/source/helpers/url_helper/009.php @@ -4,8 +4,8 @@ 'width' => 800, 'height' => 600, 'scrollbars' => 'yes', - 'status'      => 'yes', - 'resizable'   => 'yes', + 'status' => 'yes', + 'resizable' => 'yes', 'screenx' => 0, 'screeny' => 0, 'window_name' => '_blank', diff --git a/user_guide_src/source/helpers/url_helper/023.php b/user_guide_src/source/helpers/url_helper/023.php index 2c17057179f9..5f12524f3029 100644 --- a/user_guide_src/source/helpers/url_helper/023.php +++ b/user_guide_src/source/helpers/url_helper/023.php @@ -1,3 +1,5 @@ \App\Filters\SecureHeaders::class, ]; diff --git a/user_guide_src/source/incoming/incomingrequest/10.php b/user_guide_src/source/incoming/incomingrequest/10.php index 56f9522366b0..d4118cebda7c 100644 --- a/user_guide_src/source/incoming/incomingrequest/10.php +++ b/user_guide_src/source/incoming/incomingrequest/10.php @@ -1,12 +1,15 @@ getVar('foo'); // $data = "bar" diff --git a/user_guide_src/source/incoming/incomingrequest/13.php b/user_guide_src/source/incoming/incomingrequest/13.php index 2b5ffb8498e0..cf4be2eb10ac 100644 --- a/user_guide_src/source/incoming/incomingrequest/13.php +++ b/user_guide_src/source/incoming/incomingrequest/13.php @@ -5,4 +5,4 @@ [ 'Param1' => 'Value1', 'Param2' => 'Value2' -] +]; diff --git a/user_guide_src/source/incoming/incomingrequest/15.php b/user_guide_src/source/incoming/incomingrequest/15.php index 1584967d3bd8..c6e85bfef577 100644 --- a/user_guide_src/source/incoming/incomingrequest/15.php +++ b/user_guide_src/source/incoming/incomingrequest/15.php @@ -6,4 +6,4 @@ 'Host' => CodeIgniter\HTTP\Header, 'Cache-Control' => CodeIgniter\HTTP\Header, 'Accept' => CodeIgniter\HTTP\Header, -] +]; diff --git a/user_guide_src/source/incoming/message/003.php b/user_guide_src/source/incoming/message/003.php index 3ef7db58835a..41aa837fb49f 100644 --- a/user_guide_src/source/incoming/message/003.php +++ b/user_guide_src/source/incoming/message/003.php @@ -2,18 +2,24 @@ echo $message->header('Accept-Language'); -// Outputs something like: -'Accept-Language: en,en-US' +/* + Outputs something like: + 'Accept-Language: en,en-US' +*/ echo $message->header('Accept-Language')->getValue(); -// Outputs something like: -[ - 'en', - 'en-US' -] +/* + Outputs something like: + [ + 'en', + 'en-US' + ] +*/ echo $message->header('Accept-Language')->getValueLine(); -// Outputs something like: -'en,en-US' +/* + Outputs something like: + 'en,en-US' +*/ diff --git a/user_guide_src/source/incoming/message/005.php b/user_guide_src/source/incoming/message/005.php index dd643a1250e4..ea54a21a4407 100644 --- a/user_guide_src/source/incoming/message/005.php +++ b/user_guide_src/source/incoming/message/005.php @@ -2,5 +2,7 @@ echo $message->getHeaderLine('Accept-Language'); -// Outputs: -en, en-US +/* + Outputs: + en, en-US +*/ diff --git a/user_guide_src/source/incoming/routing/029.php b/user_guide_src/source/incoming/routing/029.php index 31c1dda07a70..fad1213d3f22 100644 --- a/user_guide_src/source/incoming/routing/029.php +++ b/user_guide_src/source/incoming/routing/029.php @@ -11,4 +11,4 @@ $routes->match(['get', 'put'], 'from', 'to', $options); $routes->resource('photos', $options); $routes->map($array, $options); -$routes->group('name', $options, function ()); +$routes->group('name', $options, function (){}); diff --git a/user_guide_src/source/installation/upgrade_412/001.php b/user_guide_src/source/installation/upgrade_412/001.php index 9b9373ac6cf0..94fb395e8077 100644 --- a/user_guide_src/source/installation/upgrade_412/001.php +++ b/user_guide_src/source/installation/upgrade_412/001.php @@ -6,3 +6,6 @@ class MyDatabaseTest extends DatabaseTestCase { public function testBadRow() { + // ... + } +} diff --git a/user_guide_src/source/installation/upgrade_412/002.php b/user_guide_src/source/installation/upgrade_412/002.php index 4fc229a77927..75ac87d0e9cf 100644 --- a/user_guide_src/source/installation/upgrade_412/002.php +++ b/user_guide_src/source/installation/upgrade_412/002.php @@ -9,3 +9,6 @@ class MyDatabaseTest extends CIUnitTestCase public function testBadRow() { + // ... + } +} diff --git a/user_guide_src/source/installation/upgrade_localization/002.php b/user_guide_src/source/installation/upgrade_localization/002.php index a377d18193fc..9c2b650415d9 100644 --- a/user_guide_src/source/installation/upgrade_localization/002.php +++ b/user_guide_src/source/installation/upgrade_localization/002.php @@ -5,7 +5,7 @@ $lang['error_url_missing'] = 'You must submit a URL'; $lang['error_username_missing'] = 'You must submit a username'; -... +// ... $this->lang->load('error', $lang); echo $this->lang->line('error_email_missing'); diff --git a/user_guide_src/source/installation/upgrade_localization/003.php b/user_guide_src/source/installation/upgrade_localization/003.php index e0149516841d..8fa627284bdd 100644 --- a/user_guide_src/source/installation/upgrade_localization/003.php +++ b/user_guide_src/source/installation/upgrade_localization/003.php @@ -12,6 +12,6 @@ ], ]; -... +// ... echo lang('Errors.errorEmailMissing'); diff --git a/user_guide_src/source/installation/upgrade_responses/001.php b/user_guide_src/source/installation/upgrade_responses/001.php index f837ab8b6c3b..74ff3a5dc5c8 100644 --- a/user_guide_src/source/installation/upgrade_responses/001.php +++ b/user_guide_src/source/installation/upgrade_responses/001.php @@ -2,7 +2,7 @@ $this->output->set_status_header(404); -... +// ... $this->output ->set_content_type('application/json') diff --git a/user_guide_src/source/installation/upgrade_responses/002.php b/user_guide_src/source/installation/upgrade_responses/002.php index e84279cf273c..469c1c1467f2 100644 --- a/user_guide_src/source/installation/upgrade_responses/002.php +++ b/user_guide_src/source/installation/upgrade_responses/002.php @@ -2,6 +2,6 @@ $this->response->setStatusCode(404); -... +// ... return $this->response->setJSON(['foo' => 'bar']); diff --git a/user_guide_src/source/installation/upgrade_routing/002.php b/user_guide_src/source/installation/upgrade_routing/002.php index 14097435e586..4bc53ace4321 100644 --- a/user_guide_src/source/installation/upgrade_routing/002.php +++ b/user_guide_src/source/installation/upgrade_routing/002.php @@ -11,7 +11,7 @@ require SYSTEMPATH . 'Config/Routes.php'; } -... +// ... $routes->add('posts/index', 'Posts::index'); $routes->add('teams/create', 'Teams::create'); diff --git a/user_guide_src/source/installation/upgrade_security/002.php b/user_guide_src/source/installation/upgrade_security/002.php index 0419285423b0..c1604ae48317 100644 --- a/user_guide_src/source/installation/upgrade_security/002.php +++ b/user_guide_src/source/installation/upgrade_security/002.php @@ -5,7 +5,7 @@ 'hash' => $this->security->get_csrf_hash() ); -... +// ...
    diff --git a/user_guide_src/source/libraries/curlrequest/014.php b/user_guide_src/source/libraries/curlrequest/014.php index 452f30dd45ed..04f6e02ffb18 100644 --- a/user_guide_src/source/libraries/curlrequest/014.php +++ b/user_guide_src/source/libraries/curlrequest/014.php @@ -2,7 +2,10 @@ $client->request('GET', 'http://example.com', ['allow_redirects' => true]); -// Sets the following defaults: -'max' => 5, // Maximum number of redirects to follow before stopping -'strict' => true, // Ensure POST requests stay POST requests through redirects -'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols +/* + Sets the following defaults: + + 'max' => 5, // Maximum number of redirects to follow before stopping + 'strict' => true, // Ensure POST requests stay POST requests through redirects + 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols +*/ \ No newline at end of file diff --git a/user_guide_src/source/libraries/curlrequest/019.php b/user_guide_src/source/libraries/curlrequest/019.php index 96f86c9ea6a2..0382d08e1bbc 100644 --- a/user_guide_src/source/libraries/curlrequest/019.php +++ b/user_guide_src/source/libraries/curlrequest/019.php @@ -1,3 +1,3 @@ request('get', '/', ['cert' => ['/path/server.pem', 'password']); +$client->request('get', '/', ['cert' => ['/path/server.pem', 'password']]); diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php index 86c5e0bcd8b5..8000e782737c 100644 --- a/user_guide_src/source/libraries/pagination/011.php +++ b/user_guide_src/source/libraries/pagination/011.php @@ -1,3 +1,3 @@ 'App\Views\Pagers\foundation_full', +['default_full' => 'App\Views\Pagers\foundation_full']; diff --git a/user_guide_src/source/libraries/pagination/012.php b/user_guide_src/source/libraries/pagination/012.php index 841118b57ae1..5a00b20f70c3 100644 --- a/user_guide_src/source/libraries/pagination/012.php +++ b/user_guide_src/source/libraries/pagination/012.php @@ -1,3 +1,3 @@ 'Pagers/foundation_full', +['default_full' => 'Pagers/foundation_full']; diff --git a/user_guide_src/source/libraries/sessions/002.php b/user_guide_src/source/libraries/sessions/002.php index e154d8544546..2ed7fb3cda92 100644 --- a/user_guide_src/source/libraries/sessions/002.php +++ b/user_guide_src/source/libraries/sessions/002.php @@ -1,3 +1,3 @@ item +$session->item; diff --git a/user_guide_src/source/libraries/sessions/009.php b/user_guide_src/source/libraries/sessions/009.php index 7c66bb38e442..12632835f531 100644 --- a/user_guide_src/source/libraries/sessions/009.php +++ b/user_guide_src/source/libraries/sessions/009.php @@ -4,7 +4,7 @@ // or: -$name = $session->name +$name = $session->name; // or: diff --git a/user_guide_src/source/libraries/sessions/010.php b/user_guide_src/source/libraries/sessions/010.php index e723f1b13ddd..c65740c91dbb 100644 --- a/user_guide_src/source/libraries/sessions/010.php +++ b/user_guide_src/source/libraries/sessions/010.php @@ -1,6 +1,6 @@ \App\Filters\Throttle::class, ]; diff --git a/user_guide_src/source/libraries/time/038.php b/user_guide_src/source/libraries/time/038.php index 5284ee5d5828..880bf193a590 100644 --- a/user_guide_src/source/libraries/time/038.php +++ b/user_guide_src/source/libraries/time/038.php @@ -3,5 +3,5 @@ $time = Time::parse('March 10, 2017', 'America/Chicago'); $diff = $time->difference(Time::now()); -$diff = $time->difference(new DateTime('July 4, 1975', 'America/Chicago'); +$diff = $time->difference(new DateTime('July 4, 1975', 'America/Chicago')); $diff = $time->difference('July 4, 1975 13:32:05', 'America/Chicago'); diff --git a/user_guide_src/source/libraries/time/041.php b/user_guide_src/source/libraries/time/041.php index 98a67ecf7998..754e1e25a58d 100644 --- a/user_guide_src/source/libraries/time/041.php +++ b/user_guide_src/source/libraries/time/041.php @@ -1,8 +1,8 @@ difference($test) +$diff = $current->difference($test); echo $diff->humanize(); // 1 year ago diff --git a/user_guide_src/source/libraries/uploaded_files/004.php b/user_guide_src/source/libraries/uploaded_files/004.php index 368facf4f7ab..51b1732bc522 100644 --- a/user_guide_src/source/libraries/uploaded_files/004.php +++ b/user_guide_src/source/libraries/uploaded_files/004.php @@ -1,5 +1,5 @@ // UploadedFile instance -] + 'avatar' => '...' // UploadedFile instance +]; diff --git a/user_guide_src/source/libraries/uploaded_files/005.php b/user_guide_src/source/libraries/uploaded_files/005.php index bf31373e57bd..190021513ef5 100644 --- a/user_guide_src/source/libraries/uploaded_files/005.php +++ b/user_guide_src/source/libraries/uploaded_files/005.php @@ -3,7 +3,7 @@ [ 'my-form' => [ 'details' => [ - 'avatar' => // UploadedFile instance + 'avatar' => '...' // UploadedFile instance ] ] -] +]; diff --git a/user_guide_src/source/libraries/uploaded_files/006.php b/user_guide_src/source/libraries/uploaded_files/006.php index c53d82a298fc..9a1fde0f053e 100644 --- a/user_guide_src/source/libraries/uploaded_files/006.php +++ b/user_guide_src/source/libraries/uploaded_files/006.php @@ -4,8 +4,9 @@ 'my-form' => [ 'details' => [ 'avatar' => [ - 0 => /* UploadedFile instance */, - 1 => /* UploadedFile instance */ + 0 => '...' /* UploadedFile instance */, + 1 => '...' /* UploadedFile instance */ + ] ] ] -] +]; \ No newline at end of file diff --git a/user_guide_src/source/libraries/uri/020.php b/user_guide_src/source/libraries/uri/020.php index ab991a826cff..53c3b8d66dd9 100644 --- a/user_guide_src/source/libraries/uri/020.php +++ b/user_guide_src/source/libraries/uri/020.php @@ -3,7 +3,7 @@ $uri = new \CodeIgniter\HTTP\URI('http://www.example.com?foo=bar&bar=baz&baz=foz'); // Returns 'foo=bar' -echo $uri->getQuery(['only' => ['foo']); +echo $uri->getQuery(['only' => ['foo']]); // Returns 'foo=bar&baz=foz' echo $uri->getQuery(['except' => ['bar']]); diff --git a/user_guide_src/source/libraries/uri/026.php b/user_guide_src/source/libraries/uri/026.php index c5be0f68c2ff..53a42eb788f4 100644 --- a/user_guide_src/source/libraries/uri/026.php +++ b/user_guide_src/source/libraries/uri/026.php @@ -7,4 +7,4 @@ 0 => 'users', 1 => '15', 2 => 'profile' -] +]; diff --git a/user_guide_src/source/libraries/validation/002.php b/user_guide_src/source/libraries/validation/002.php index 46322fe586bd..1cc4b9e188ab 100644 --- a/user_guide_src/source/libraries/validation/002.php +++ b/user_guide_src/source/libraries/validation/002.php @@ -6,5 +6,5 @@ 'passconf' => 'required|matches[password]', 'email' => 'required|valid_email', ])) { - ... + // ... } diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php index 1678d5530f27..aec2e980c5dc 100644 --- a/user_guide_src/source/libraries/validation/009.php +++ b/user_guide_src/source/libraries/validation/009.php @@ -1,17 +1,19 @@ [ - 'name' => 'Joe Smith', - 'friends' => [ - [ - 'name' => 'Fred Flinstone', - ], - [ - 'name' => 'Wilma', - ], +[ + 'contacts' => [ + 'name' => 'Joe Smith', + 'friends' => [ + [ + 'name' => 'Fred Flinstone', + ], + [ + 'name' => 'Wilma', + ], + ] ] -] +]; // Joe Smith $validation->setRules([ diff --git a/user_guide_src/source/libraries/validation/011.php b/user_guide_src/source/libraries/validation/011.php index 023712f4315e..66fbcda5e1a7 100644 --- a/user_guide_src/source/libraries/validation/011.php +++ b/user_guide_src/source/libraries/validation/011.php @@ -1,11 +1,14 @@ [ - 1, - 2, - 3, -] +[ + 'user_ids' => [ + 1, + 2, + 3, + ] +]; + // Rule $validation->setRules([ 'user_ids.*' => 'required', diff --git a/user_guide_src/source/libraries/validation/025.php b/user_guide_src/source/libraries/validation/025.php index 0531b84be47c..a71f46f29f92 100644 --- a/user_guide_src/source/libraries/validation/025.php +++ b/user_guide_src/source/libraries/validation/025.php @@ -1,3 +1,3 @@ 'Supplied value ({value}) for {field} must have at least {param} characters.' +['min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.']; diff --git a/user_guide_src/source/libraries/validation/027.php b/user_guide_src/source/libraries/validation/027.php index 57aa5a31cb84..c6afaf393f2a 100644 --- a/user_guide_src/source/libraries/validation/027.php +++ b/user_guide_src/source/libraries/validation/027.php @@ -6,4 +6,4 @@ [ 'field1' => 'error message', 'field2' => 'error message', -] +]; diff --git a/user_guide_src/source/models/entities/003.php b/user_guide_src/source/models/entities/003.php index 4b29ea153692..c8cfd58c14db 100644 --- a/user_guide_src/source/models/entities/003.php +++ b/user_guide_src/source/models/entities/003.php @@ -9,7 +9,7 @@ // Updating unset($user->username); -if (! isset($user->username) { +if (! isset($user->username)) { $user->username = 'something new'; } diff --git a/user_guide_src/source/outgoing/localization/007.php b/user_guide_src/source/outgoing/localization/007.php index 48dc3e455282..e2de3a4644d6 100644 --- a/user_guide_src/source/outgoing/localization/007.php +++ b/user_guide_src/source/outgoing/localization/007.php @@ -1,3 +1,3 @@ 'The actual message to be shown.' +['languageKey' => 'The actual message to be shown.']; diff --git a/user_guide_src/source/outgoing/localization/008.php b/user_guide_src/source/outgoing/localization/008.php index b8975a521320..eac50a5f4861 100644 --- a/user_guide_src/source/outgoing/localization/008.php +++ b/user_guide_src/source/outgoing/localization/008.php @@ -1,7 +1,10 @@ [ - 'nested' => [ - 'key' => 'The actual message to be shown.', +[ + 'languageKey' => [ + 'nested' => [ + 'key' => 'The actual message to be shown.', + ], ], -], +] +; \ No newline at end of file diff --git a/user_guide_src/source/outgoing/response/021.php b/user_guide_src/source/outgoing/response/021.php index 41745631aaac..092a758b18db 100644 --- a/user_guide_src/source/outgoing/response/021.php +++ b/user_guide_src/source/outgoing/response/021.php @@ -3,4 +3,4 @@ $response->noCache(); // Sets the following header: -Cache-Control: no-store, max-age=0, no-cache +// Cache-Control: no-store, max-age=0, no-cache diff --git a/user_guide_src/source/outgoing/response/026.php b/user_guide_src/source/outgoing/response/026.php index 55149496da87..4287ddb889ba 100644 --- a/user_guide_src/source/outgoing/response/026.php +++ b/user_guide_src/source/outgoing/response/026.php @@ -1,3 +1,5 @@ hasCookie($name)) ... +if ($response->hasCookie($name)) { + // ... +} \ No newline at end of file diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index 74a18943365c..e93bd3986957 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -5,4 +5,4 @@ ]; // Tag is replaced by the return value of Some\Class::methodName static function. -{+ foo +} +// {+ foo +} diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php index 30d72b247059..4e699d190bcd 100644 --- a/user_guide_src/source/outgoing/view_parser/017.php +++ b/user_guide_src/source/outgoing/view_parser/017.php @@ -4,4 +4,4 @@ 'foo' => ['\Some\Class::methodName'] ]; -{+ foo +} inner content {+ /foo +} +// {+ foo +} inner content {+ /foo +} diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php index cf7b31fa7e30..6dce1f1316e2 100644 --- a/user_guide_src/source/outgoing/view_parser/021.php +++ b/user_guide_src/source/outgoing/view_parser/021.php @@ -7,7 +7,7 @@ ['title' => 'Second Link', 'link' => '/second'], ]; -foreach ($data1 as $menuItem),{ +foreach ($data1 as $menuItem){ $temp .= $parser->setData($menuItem)->renderString($template1); } diff --git a/user_guide_src/source/testing/benchmark/004.php b/user_guide_src/source/testing/benchmark/004.php index 112aea9f2e82..bf84bf6ed21f 100644 --- a/user_guide_src/source/testing/benchmark/004.php +++ b/user_guide_src/source/testing/benchmark/004.php @@ -9,4 +9,4 @@ 'end' => 1345678920, 'duration' => 15.4315, // number of seconds ] -] +]; diff --git a/user_guide_src/source/testing/controllers/012.php b/user_guide_src/source/testing/controllers/012.php index dd3b600d90fd..e9425a085488 100644 --- a/user_guide_src/source/testing/controllers/012.php +++ b/user_guide_src/source/testing/controllers/012.php @@ -10,4 +10,6 @@ protected function testFilterFailsOnAdminRoute() $this->assertHasFilters('unfiltered/route', 'before'); } -... + + // ... +} diff --git a/user_guide_src/source/testing/fabricator/001.php b/user_guide_src/source/testing/fabricator/001.php index f5f2e33ff455..a4e6456549a6 100644 --- a/user_guide_src/source/testing/fabricator/001.php +++ b/user_guide_src/source/testing/fabricator/001.php @@ -1,3 +1,5 @@ config('Auth')->allowRemembering ? date('Y-m-d') : null, ]; } +} \ No newline at end of file diff --git a/user_guide_src/source/testing/fabricator/006.php b/user_guide_src/source/testing/fabricator/006.php index 587a0697d1fa..cfb130f21ede 100644 --- a/user_guide_src/source/testing/fabricator/006.php +++ b/user_guide_src/source/testing/fabricator/006.php @@ -6,3 +6,6 @@ class UserFabricator extends \App\Models\UserModel { public function fake(&$faker) { + // ... + } +} \ No newline at end of file diff --git a/user_guide_src/source/testing/fabricator/009.php b/user_guide_src/source/testing/fabricator/009.php index 3a7507430265..9c8d366d8684 100644 --- a/user_guide_src/source/testing/fabricator/009.php +++ b/user_guide_src/source/testing/fabricator/009.php @@ -6,4 +6,4 @@ 'phone' => "201-886-0269 x3767", 'avatar' => "http://lorempixel.com/800/400/", 'login' => null, -) +); diff --git a/user_guide_src/source/testing/fabricator/012.php b/user_guide_src/source/testing/fabricator/012.php index 782c58f8917f..89731845f145 100644 --- a/user_guide_src/source/testing/fabricator/012.php +++ b/user_guide_src/source/testing/fabricator/012.php @@ -9,4 +9,4 @@ 'login' => null, 'created_at' => "2020-05-08 14:52:10", 'updated_at' => "2020-05-08 14:52:10", -) +); diff --git a/user_guide_src/source/testing/fabricator/016.php b/user_guide_src/source/testing/fabricator/016.php index 72f2b946366e..eb9edc657239 100644 --- a/user_guide_src/source/testing/fabricator/016.php +++ b/user_guide_src/source/testing/fabricator/016.php @@ -6,7 +6,7 @@ 'phone' => "251-806-2169", 'avatar' => "http://lorempixel.com/800/400/", 'login' => null, -) +); array( 'first' => "Bobby", @@ -14,4 +14,4 @@ 'phone' => "525-214-2656 x23546", 'avatar' => "http://lorempixel.com/800/400/", 'login' => null, -) +); diff --git a/user_guide_src/source/testing/fabricator/018.php b/user_guide_src/source/testing/fabricator/018.php index 73a3b932052e..60599b602f6e 100644 --- a/user_guide_src/source/testing/fabricator/018.php +++ b/user_guide_src/source/testing/fabricator/018.php @@ -6,7 +6,7 @@ 'phone' => "741-857-1933 x1351", 'avatar' => "http://lorempixel.com/800/400/", 'login' => null, -) +); array( 'first' => "Hans", @@ -14,4 +14,4 @@ 'phone' => "487-235-7006", 'avatar' => "http://lorempixel.com/800/400/", 'login' => null, -) +); diff --git a/user_guide_src/source/testing/fabricator/021.php b/user_guide_src/source/testing/fabricator/021.php index a1b0111e0903..df10c0b137d7 100644 --- a/user_guide_src/source/testing/fabricator/021.php +++ b/user_guide_src/source/testing/fabricator/021.php @@ -12,3 +12,4 @@ public function fake(Generator &$faker) 'group_id' => rand(1, Fabricator::getCount('groups')), ]; } +} \ No newline at end of file diff --git a/user_guide_src/source/testing/feature/002.php b/user_guide_src/source/testing/feature/002.php index c5f67f42b36c..553aaa0bfd03 100644 --- a/user_guide_src/source/testing/feature/002.php +++ b/user_guide_src/source/testing/feature/002.php @@ -4,7 +4,7 @@ $result = $this->call('get', '/'); // Submit a form -$result = $this->call('post', 'contact'), [ +$result = $this->call('post', 'contact', [ 'name' => 'Fred Flintstone', 'email' => 'flintyfred@example.com' ]); diff --git a/user_guide_src/source/testing/overview/006.php b/user_guide_src/source/testing/overview/006.php index bbd2a333a349..1ab3e692f0eb 100644 --- a/user_guide_src/source/testing/overview/006.php +++ b/user_guide_src/source/testing/overview/006.php @@ -10,3 +10,4 @@ protected function purgeRows() { $this->model->purgeDeleted() } +} diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php index 74bbb533de38..d6ec1d6c45c5 100644 --- a/user_guide_src/source/testing/overview/007.php +++ b/user_guide_src/source/testing/overview/007.php @@ -7,9 +7,13 @@ trait AuthTrait $user = $this->createFakeUser(); $this->logInUser($user); } -... + + // ... +} class AuthenticationFeatureTest { use AuthTrait; -... + + // ... +} \ No newline at end of file diff --git a/user_guide_src/source/testing/overview/008.php b/user_guide_src/source/testing/overview/008.php index 9d84f888c1d4..55077ed36818 100644 --- a/user_guide_src/source/testing/overview/008.php +++ b/user_guide_src/source/testing/overview/008.php @@ -3,7 +3,7 @@ $config = new LoggerConfig(); $logger = new Logger($config); -... do something that you expect a log entry from +// ... do something that you expect a log entry from $logger->log('error', "That's no moon"); $this->assertLogged('error', "That's no moon"); diff --git a/user_guide_src/source/testing/response/004.php b/user_guide_src/source/testing/response/004.php index 3cb56ea74b8f..d3ccbf4f4d12 100644 --- a/user_guide_src/source/testing/response/004.php +++ b/user_guide_src/source/testing/response/004.php @@ -1,5 +1,5 @@ isOK()) { - ... + // ... } diff --git a/user_guide_src/source/testing/response/006.php b/user_guide_src/source/testing/response/006.php index 90da5662c383..dcca55a4938b 100644 --- a/user_guide_src/source/testing/response/006.php +++ b/user_guide_src/source/testing/response/006.php @@ -1,5 +1,5 @@ isRedirect()) { - ... + // ... } diff --git a/user_guide_src/source/testing/response/020.php b/user_guide_src/source/testing/response/020.php index cb490d8a98ff..8b716717b696 100644 --- a/user_guide_src/source/testing/response/020.php +++ b/user_guide_src/source/testing/response/020.php @@ -3,6 +3,6 @@ // Check that an element with class 'notice' exists $results->seeElement('.notice'); // Check that an element with id 'title' exists -$results->seeElement('#title') +$results->seeElement('#title'); // Verify that an element with id 'title' does NOT exist $results->dontSeeElement('#title'); diff --git a/user_guide_src/source/testing/response/026.php b/user_guide_src/source/testing/response/026.php index 773b7dd04833..4afd20161b23 100644 --- a/user_guide_src/source/testing/response/026.php +++ b/user_guide_src/source/testing/response/026.php @@ -3,4 +3,4 @@ // Check that an element with class 'notice' exists $results->seeElement('.notice'); // Check that an element with id 'title' exists -$results->seeElement('#title') +$results->seeElement('#title'); diff --git a/user_guide_src/source/testing/response/030.php b/user_guide_src/source/testing/response/030.php index e6417035e73f..7dfa89e51cc1 100644 --- a/user_guide_src/source/testing/response/030.php +++ b/user_guide_src/source/testing/response/030.php @@ -1,11 +1,13 @@ 'bar'] +['foo' => 'bar']; $json = $result->getJSON(); -// $json is this: -{ - "foo": "bar" -} +/* + $json is this: + { + "foo": "bar" + } +`*/ diff --git a/user_guide_src/source/testing/response/031.php b/user_guide_src/source/testing/response/031.php index 0c9ded88a7f5..6e746800e034 100644 --- a/user_guide_src/source/testing/response/031.php +++ b/user_guide_src/source/testing/response/031.php @@ -1,4 +1,4 @@ assertTrue($result->getJSON() !== false) +$this->assertTrue($result->getJSON() !== false); diff --git a/user_guide_src/source/testing/response/032.php b/user_guide_src/source/testing/response/032.php index e808ca1a43dd..c2d093443b9d 100644 --- a/user_guide_src/source/testing/response/032.php +++ b/user_guide_src/source/testing/response/032.php @@ -3,7 +3,7 @@ // Response body is this: [ 'config' => ['key-a', 'key-b'], -] +]; // Is true $result->assertJSONFragment(['config' => ['key-a']]); From 32e72c813123a0973e08fda92d3a688e0a2331cf Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 18:54:07 +0900 Subject: [PATCH 1614/2325] docs: fix @param of view cell --- system/Common.php | 2 +- system/View/Cell.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Common.php b/system/Common.php index 690275c4fedf..257c238d2b42 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1125,7 +1125,7 @@ function view(string $name, array $data = [], array $options = []): string * View cells are used within views to insert HTML chunks that are managed * by other classes. * - * @param null $params + * @param array|string|null $params * * @throws ReflectionException */ diff --git a/system/View/Cell.php b/system/View/Cell.php index 50168a153be6..c4fa23a6fbba 100644 --- a/system/View/Cell.php +++ b/system/View/Cell.php @@ -62,7 +62,7 @@ public function __construct(CacheInterface $cache) /** * Render a cell, returning its body as a string. * - * @param null $params + * @param array|string|null $params * * @throws ReflectionException */ @@ -141,7 +141,7 @@ public function render(string $library, $params = null, int $ttl = 0, ?string $c * If a string, it should be in the format "key1=value key2=value". * It will be split and returned as an array. * - * @param mixed $params + * @param array|string|null $params * * @return array|null */ From dd80915f52bdca560d60257889a136a7ab38d06a Mon Sep 17 00:00:00 2001 From: Nudasoft <30935025+Nudasoft@users.noreply.github.com> Date: Tue, 22 Feb 2022 17:34:56 +0530 Subject: [PATCH 1615/2325] Use native $g-red: #DD4814; color for badge background. Use native $g-red: #DD4814; color for badge background instead a custom color. --- system/Debug/Toolbar/Views/toolbar.css | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index 47e74d9a4f1b..f160dba91f29 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -315,7 +315,7 @@ #debug-bar .ci-label:hover { background-color: #DFDFDF; } #debug-bar .ci-label .badge { - background-color: #DD7359; + background-color: #DD4814; color: #FFFFFF; } #debug-bar .tab { background-color: #FFFFFF; @@ -406,7 +406,7 @@ #debug-bar .ci-label:hover { background-color: #252525; } #debug-bar .ci-label .badge { - background-color: #DD7359; + background-color: #DD4814; color: #FFFFFF; } #debug-bar .tab { background-color: #252525; @@ -495,7 +495,7 @@ #toolbarContainer.dark #debug-bar .ci-label:hover { background-color: #252525; } #toolbarContainer.dark #debug-bar .ci-label .badge { - background-color: #DD7359; + background-color: #DD4814; color: #FFFFFF; } #toolbarContainer.dark #debug-bar .tab { background-color: #252525; @@ -588,7 +588,7 @@ #toolbarContainer.light #debug-bar .ci-label:hover { background-color: #DFDFDF; } #toolbarContainer.light #debug-bar .ci-label .badge { - background-color: #DD7359; + background-color: #DD4814; color: #FFFFFF; } #toolbarContainer.light #debug-bar .tab { background-color: #FFFFFF; From 09b4b8db7047dd3adc31cec1d3c2ce892a9e953e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Feb 2022 21:20:36 +0900 Subject: [PATCH 1616/2325] refactor: remove `&` before $db $db is an object. We don't need to use reference. --- system/Database/BaseBuilder.php | 2 +- system/Database/BasePreparedQuery.php | 2 +- system/Database/BaseUtils.php | 4 ++-- system/Database/Forge.php | 2 +- system/Database/Query.php | 2 +- system/Database/SQLSRV/Utils.php | 2 +- system/Database/Seeder.php | 2 +- system/Model.php | 4 ++-- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index a3fc6c7563d3..ccfa5bd9d8bb 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -270,7 +270,7 @@ class BaseBuilder * * @throws DatabaseException */ - public function __construct($tableName, ConnectionInterface &$db, ?array $options = null) + public function __construct($tableName, ConnectionInterface $db, ?array $options = null) { if (empty($tableName)) { throw new DatabaseException('A table must be specified when creating a new Query Builder.'); diff --git a/system/Database/BasePreparedQuery.php b/system/Database/BasePreparedQuery.php index ba36915c79fe..b6e2db706d2a 100644 --- a/system/Database/BasePreparedQuery.php +++ b/system/Database/BasePreparedQuery.php @@ -57,7 +57,7 @@ abstract class BasePreparedQuery implements PreparedQueryInterface public function __construct(BaseConnection $db) { - $this->db = &$db; + $this->db = $db; } /** diff --git a/system/Database/BaseUtils.php b/system/Database/BaseUtils.php index 7848ae75ecf0..9ba48c927619 100644 --- a/system/Database/BaseUtils.php +++ b/system/Database/BaseUtils.php @@ -49,9 +49,9 @@ abstract class BaseUtils /** * Class constructor */ - public function __construct(ConnectionInterface &$db) + public function __construct(ConnectionInterface $db) { - $this->db = &$db; + $this->db = $db; } /** diff --git a/system/Database/Forge.php b/system/Database/Forge.php index 60095ae2496f..e5f8c9aedc68 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -179,7 +179,7 @@ class Forge */ public function __construct(BaseConnection $db) { - $this->db = &$db; + $this->db = $db; } /** diff --git a/system/Database/Query.php b/system/Database/Query.php index b9dc4619dd06..702575ca857c 100644 --- a/system/Database/Query.php +++ b/system/Database/Query.php @@ -91,7 +91,7 @@ class Query implements QueryInterface */ public $db; - public function __construct(ConnectionInterface &$db) + public function __construct(ConnectionInterface $db) { $this->db = $db; } diff --git a/system/Database/SQLSRV/Utils.php b/system/Database/SQLSRV/Utils.php index cf94d3dad783..22a12bcdf02a 100755 --- a/system/Database/SQLSRV/Utils.php +++ b/system/Database/SQLSRV/Utils.php @@ -34,7 +34,7 @@ class Utils extends BaseUtils */ protected $optimizeTable = 'ALTER INDEX all ON %s REORGANIZE'; - public function __construct(ConnectionInterface &$db) + public function __construct(ConnectionInterface $db) { parent::__construct($db); diff --git a/system/Database/Seeder.php b/system/Database/Seeder.php index 94bd0612e393..893de7d56ec4 100644 --- a/system/Database/Seeder.php +++ b/system/Database/Seeder.php @@ -92,7 +92,7 @@ public function __construct(Database $config, ?BaseConnection $db = null) $db ??= Database::connect($this->DBGroup); - $this->db = &$db; + $this->db = $db; $this->forge = Database::forge($this->DBGroup); } diff --git a/system/Model.php b/system/Model.php index e2f5b0fca891..31447cb00d72 100644 --- a/system/Model.php +++ b/system/Model.php @@ -100,14 +100,14 @@ class Model extends BaseModel 'getCompiledUpdate', ]; - public function __construct(?ConnectionInterface &$db = null, ?ValidationInterface $validation = null) + public function __construct(?ConnectionInterface $db = null, ?ValidationInterface $validation = null) { /** * @var BaseConnection|null $db */ $db ??= Database::connect($this->DBGroup); - $this->db = &$db; + $this->db = $db; parent::__construct($validation); } From b4fa714feea036b2a596487004ed10e5fc3eb7bf Mon Sep 17 00:00:00 2001 From: Nudasoft Date: Tue, 22 Feb 2022 22:00:45 +0530 Subject: [PATCH 1617/2325] Use red background color for badges instead using blue. This red background color makes text color pop more and go align with the CI4 theme color. --- admin/css/debug-toolbar/_theme-dark.scss | 4 ++-- admin/css/debug-toolbar/_theme-light.scss | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/admin/css/debug-toolbar/_theme-dark.scss b/admin/css/debug-toolbar/_theme-dark.scss index 801b75664f22..ead7d02a58e3 100644 --- a/admin/css/debug-toolbar/_theme-dark.scss +++ b/admin/css/debug-toolbar/_theme-dark.scss @@ -129,8 +129,8 @@ } .badge { - background-color: $g-blue; - color: $m-gray; + background-color: $g-red; + color: $t-light; } } diff --git a/admin/css/debug-toolbar/_theme-light.scss b/admin/css/debug-toolbar/_theme-light.scss index 41dbb9175fde..4e4295ccd131 100644 --- a/admin/css/debug-toolbar/_theme-light.scss +++ b/admin/css/debug-toolbar/_theme-light.scss @@ -125,7 +125,7 @@ } .badge { - background-color: $g-blue; + background-color: $g-red; color: $t-light; } } From dc43271dbc0eb67db80c531feb7998409e4743a2 Mon Sep 17 00:00:00 2001 From: Nudasoft Date: Tue, 22 Feb 2022 22:01:32 +0530 Subject: [PATCH 1618/2325] Fix alignment issues on few buttons. --- admin/css/debug-toolbar/toolbar.scss | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/admin/css/debug-toolbar/toolbar.scss b/admin/css/debug-toolbar/toolbar.scss index c73510182ac7..d9bc347c4b3b 100644 --- a/admin/css/debug-toolbar/toolbar.scss +++ b/admin/css/debug-toolbar/toolbar.scss @@ -77,16 +77,9 @@ // General elements h1 { - bottom: 0; - display: inline-block; - font-size: $base-size - 2; + display: flex; font-weight: normal; - margin: 0 16px 0 0; - padding: 0; - position: absolute; - right: 30px; - text-align: left; - top: 0; + margin: 0 0 0 auto; svg { width: 16px; @@ -238,15 +231,8 @@ // The "Open/Close" toggle #debug-bar-link { - bottom: 0; - display: inline-block; - font-size: $base-size; - line-height: 36px; + display: flex; padding: 6px; - position: absolute; - right: 10px; - top: 0; - width: 24px; } // The toolbar menus From 0e18a6ca4c07dd4c438de22d12c57cb724152515 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 23 Feb 2022 09:40:33 +0900 Subject: [PATCH 1619/2325] docs: change "previous version" to a specific version --- user_guide_src/source/libraries/sessions.rst | 2 +- user_guide_src/source/libraries/uploaded_files.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index ad45f9fea4f3..6c4e71081173 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -69,7 +69,7 @@ Unless you're developing a website with heavy AJAX usage, you can skip this section. If you are, however, and if you're experiencing performance issues, then this note is exactly what you're looking for. -Sessions in previous versions of CodeIgniter didn't implement locking, +Sessions in CodeIgniter v2.x didn't implement locking, which meant that two HTTP requests using the same session could run exactly at the same time. To use a more appropriate technical term - requests were non-blocking. diff --git a/user_guide_src/source/libraries/uploaded_files.rst b/user_guide_src/source/libraries/uploaded_files.rst index 265eb87dc20a..90a4df446d1a 100644 --- a/user_guide_src/source/libraries/uploaded_files.rst +++ b/user_guide_src/source/libraries/uploaded_files.rst @@ -5,7 +5,7 @@ Working with Uploaded Files CodeIgniter makes working with files uploaded through a form much simpler and more secure than using PHP's ``$_FILES`` array directly. This extends the :doc:`File class ` and thus gains all of the features of that class. -.. note:: This is not the same as the File Uploading class in previous versions of CodeIgniter. This provides a raw +.. note:: This is not the same as the File Uploading class in CodeIgniter v3.x. This provides a raw interface to the uploaded files with a few small features. .. contents:: From 6e1219508ce3bbc544e6e2f272bb375b2289f71e Mon Sep 17 00:00:00 2001 From: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> Date: Wed, 23 Feb 2022 17:18:45 +0200 Subject: [PATCH 1620/2325] Update Forge.php --- system/Database/OCI8/Forge.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/system/Database/OCI8/Forge.php b/system/Database/OCI8/Forge.php index d5ca20a9e4d9..9cd5bad945cd 100644 --- a/system/Database/OCI8/Forge.php +++ b/system/Database/OCI8/Forge.php @@ -11,10 +11,12 @@ namespace CodeIgniter\Database\OCI8; +use CodeIgniter\Database\Forge as BaseForge; + /** * Forge for OCI8 */ -class Forge extends \CodeIgniter\Database\Forge +class Forge extends BaseForge { /** * DROP INDEX statement From 97640c9b107b8213e9b1518f62f5927058a86c28 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 24 Feb 2022 09:11:31 +0900 Subject: [PATCH 1621/2325] fix: forceGlobalSecureRequests break URI schemes other than HTTP --- system/HTTP/URI.php | 5 ++++- tests/system/HTTP/URITest.php | 16 ++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 70305ae5864c..2fe9b430213a 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -586,7 +586,10 @@ public function __toString(): string $baseUri = new self($config->baseURL); // If the hosts matches then assume this should be relative to baseURL - if ($this->getHost() === $baseUri->getHost()) { + if ( + substr($this->getScheme(), 0, 4) === 'http' + && $this->getHost() === $baseUri->getHost() + ) { // Check for additional segments $basePath = trim($baseUri->getPath(), '/') . '/'; $trimPath = ltrim($path, '/'); diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index 8536fcc7c801..a4faacfbdd80 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -985,4 +985,20 @@ public function testCreateURIString() $this->assertSame($expected, $uri); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5728 + */ + public function testForceGlobalSecureRequestsAndNonHTTPProtocol() + { + $config = new App(); + $config->forceGlobalSecureRequests = true; + $config->baseURL = 'https://localhost/'; + Factories::injectMock('config', 'App', $config); + + $expected = 'ftp://localhost/path/to/test.txt'; + $uri = new URI($expected); + + $this->assertSame($expected, (string) $uri); + } } From 7c74eae490a92c7b3827d4a76ac31409919e4dd1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 24 Feb 2022 10:33:31 +0900 Subject: [PATCH 1622/2325] refactor: extract the logic to be deprecated --- system/HTTP/URI.php | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/system/HTTP/URI.php b/system/HTTP/URI.php index 2fe9b430213a..e0a6ff9f2386 100644 --- a/system/HTTP/URI.php +++ b/system/HTTP/URI.php @@ -581,11 +581,30 @@ public function __toString(): string $path = $this->getPath(); $scheme = $this->getScheme(); + // If the hosts matches then assume this should be relative to baseURL + [$scheme, $path] = $this->changeSchemeAndPath($scheme, $path); + + return static::createURIString( + $scheme, + $this->getAuthority(), + $path, // Absolute URIs should use a "/" for an empty path + $this->getQuery(), + $this->getFragment() + ); + } + + /** + * Change the path (and scheme) assuming URIs with the same host as baseURL + * should be relative to the project's configuration. + * + * @deprecated This method will be deleted. + */ + private function changeSchemeAndPath(string $scheme, string $path): array + { // Check if this is an internal URI $config = config('App'); $baseUri = new self($config->baseURL); - // If the hosts matches then assume this should be relative to baseURL if ( substr($this->getScheme(), 0, 4) === 'http' && $this->getHost() === $baseUri->getHost() @@ -604,13 +623,7 @@ public function __toString(): string } } - return static::createURIString( - $scheme, - $this->getAuthority(), - $path, // Absolute URIs should use a "/" for an empty path - $this->getQuery(), - $this->getFragment() - ); + return [$scheme, $path]; } /** From f8e7c78cea6a73e2c6a91e32df8a389f2525d9ab Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 24 Feb 2022 10:57:24 +0800 Subject: [PATCH 1623/2325] Add workflow to test SCSS compilation --- .github/workflows/test-scss.yml | 51 +++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 .github/workflows/test-scss.yml diff --git a/.github/workflows/test-scss.yml b/.github/workflows/test-scss.yml new file mode 100644 index 000000000000..b7f66a17f29b --- /dev/null +++ b/.github/workflows/test-scss.yml @@ -0,0 +1,51 @@ +name: SCSS Compilation + +on: + pull_request: + branches: + - 'develop' + - 'v4.x' + paths: + - '**.scss' + - '**.css' + - '.github/workflows/test-scss.yml' + + push: + branches: + - 'develop' + - 'v4.x' + paths: + - '**.scss' + - '**.css' + - '.github/workflows/test-scss.yml' + +jobs: + build: + name: Compilation of SCSS (Dart Sass) + runs-on: ubuntu-20.04 + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Setup Node + uses: actions/setup-node@v2 + with: + # node version based on dart-sass test workflow + node-version: 16 + + - name: Install Dart Sass + run: | + npm install --global sass + sass --version + + - name: Run Dart Sass + run: sass --no-source-map admin/css/debug-toolbar/toolbar.scss system/Debug/Toolbar/Views/toolbar.css + + - name: Check for changed CSS files + run: | + if [[ -n "$(git status --porcelain 2>/dev/null)" ]]; then + echo "Your changes to the SCSS files did not match the expected CSS output." + git diff-files --patch + exit 1 + fi From ea9ffb0f284b5e37acaa7e9b481aedf57d20d67f Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 24 Feb 2022 10:59:22 +0800 Subject: [PATCH 1624/2325] Update contribution guide --- contributing/css.md | 38 ++++++++++++++++++-------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/contributing/css.md b/contributing/css.md index 3108319a0e1b..7accf5e83801 100644 --- a/contributing/css.md +++ b/contributing/css.md @@ -1,6 +1,6 @@ -# Contribution CSS +# Contribution to Debug Toolbar CSS -CodeIgniter uses SASS to generate the debug toolbar's CSS. Therefore, +CodeIgniter uses Dart Sass to generate the debug toolbar's CSS. Therefore, you will need to install it first. You can find further instructions on the official website: @@ -9,34 +9,32 @@ the official website: Open your terminal, and navigate to CodeIgniter's root folder. To generate the CSS file, use the following command: -`sass --no-cache --sourcemap=none admin/css/debug-toolbar/toolbar.scss system/Debug/Toolbar/Views/toolbar.css` +`sass --no-source-map admin/css/debug-toolbar/toolbar.scss system/Debug/Toolbar/Views/toolbar.css` -Details: -- `--no-cache` is a parameter defined to disable SASS cache, -this prevents a "cache" folder from being created -- `--sourcemap=none` is a parameter which prevents soucemap files from being generated -- `admin/css/debug-toolbar/toolbar.scss` is the SASS source +Details: +- `--no-source-map` is an option which prevents sourcemap files from being generated +- `admin/css/debug-toolbar/toolbar.scss` is the SASS source - `system/Debug/Toolbar/Views/toolbar.css` is he CSS destination ## Color scheme **Themes** -Dark: `#252525` / `rgb(37, 37, 37)` -Light: `#FFFFFF` / `rgb(255, 255, 255)` +Dark: `#252525` / `rgb(37, 37, 37)` +Light: `#FFFFFF` / `rgb(255, 255, 255)` **Glossy colors** -Blue: `#5BC0DE` / `rgb(91, 192, 222)` -Gray: `#434343` / `rgb(67, 67, 67)` -Green: `#9ACE25` / `rgb(154, 206, 37)` -Orange: `#DD8615` / `rgb(221, 134, 21)` -Red: `#DD4814` / `rgb(221, 72, 20)` +Blue: `#5BC0DE` / `rgb(91, 192, 222)` +Gray: `#434343` / `rgb(67, 67, 67)` +Green: `#9ACE25` / `rgb(154, 206, 37)` +Orange: `#DD8615` / `rgb(221, 134, 21)` +Red: `#DD4814` / `rgb(221, 72, 20)` **Matt colors** -Blue: `#D8EAF0` / `rgb(216, 234, 240)` -Gray: `#DFDFDF` / `rgb(223, 223, 223)` -Green: `#DFF0D8` / `rgb(223, 240, 216)` -Orange: `#FDC894` / `rgb(253, 200, 148)` -Red: `#EF9090` / `rgb(239, 144, 144)` +Blue: `#D8EAF0` / `rgb(216, 234, 240)` +Gray: `#DFDFDF` / `rgb(223, 223, 223)` +Green: `#DFF0D8` / `rgb(223, 240, 216)` +Orange: `#FDC894` / `rgb(253, 200, 148)` +Red: `#EF9090` / `rgb(239, 144, 144)` From 8721abd5728c8b4ab0cdf7b3825773240573654f Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 24 Feb 2022 10:59:45 +0800 Subject: [PATCH 1625/2325] Fix formatting --- system/Debug/Toolbar/Views/toolbar.css | 1211 ++++++++++++++---------- 1 file changed, 687 insertions(+), 524 deletions(-) diff --git a/system/Debug/Toolbar/Views/toolbar.css b/system/Debug/Toolbar/Views/toolbar.css index f160dba91f29..8fb9c15737c5 100644 --- a/system/Debug/Toolbar/Views/toolbar.css +++ b/system/Debug/Toolbar/Views/toolbar.css @@ -16,16 +16,20 @@ margin: 0px; padding: 0px; clear: both; - text-align: center; } - #debug-icon a svg { - margin: 8px; - max-width: 20px; - max-height: 20px; } - #debug-icon.fixed-top { - bottom: auto; - top: 0; } - #debug-icon .debug-bar-ndisplay { - display: none; } + text-align: center; +} +#debug-icon a svg { + margin: 8px; + max-width: 20px; + max-height: 20px; +} +#debug-icon.fixed-top { + bottom: auto; + top: 0; +} +#debug-icon .debug-bar-ndisplay { + display: none; +} #debug-bar { bottom: 0; @@ -37,199 +41,250 @@ line-height: 36px; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; font-size: 16px; - font-weight: 400; } - #debug-bar h1 { - display: flex; - font-weight: normal; - margin: 0 0 0 auto; } - #debug-bar h1 svg { - width: 16px; - margin-right: 5px; } - #debug-bar h2 { - font-size: 16px; - margin: 0; - padding: 5px 0 10px 0; } - #debug-bar h2 span { - font-size: 13px; } - #debug-bar h3 { - font-size: 12px; - font-weight: 200; - margin: 0 0 0 10px; - padding: 0; - text-transform: uppercase; } - #debug-bar p { - font-size: 12px; - margin: 0 0 0 15px; - padding: 0; } - #debug-bar a { - text-decoration: none; } - #debug-bar a:hover { - text-decoration: underline; } - #debug-bar button { - border: 1px solid; - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - cursor: pointer; - line-height: 15px; } - #debug-bar button:hover { - text-decoration: underline; } - #debug-bar table { - border-collapse: collapse; - font-size: 14px; - line-height: normal; - margin: 5px 10px 15px 10px; - width: calc(100% - 10px); } - #debug-bar table strong { - font-weight: 500; } - #debug-bar table th { - display: table-cell; - font-weight: 600; - padding-bottom: 0.7em; - text-align: left; } - #debug-bar table tr { - border: none; } - #debug-bar table td { - border: none; - display: table-cell; - margin: 0; - text-align: left; } - #debug-bar table td:first-child { - max-width: 20%; } - #debug-bar table td:first-child.narrow { - width: 7em; } - #debug-bar td[data-debugbar-route] form { - display: none; } - #debug-bar td[data-debugbar-route]:hover form { - display: block; } - #debug-bar td[data-debugbar-route]:hover > div { - display: none; } - #debug-bar td[data-debugbar-route] input[type=text] { - padding: 2px; } - #debug-bar .toolbar { - display: flex; - overflow: hidden; - overflow-y: auto; - padding: 0 12px 0 12px; - white-space: nowrap; - z-index: 10000; } - #debug-bar.fixed-top { - bottom: auto; - top: 0; } - #debug-bar.fixed-top .tab { - bottom: auto; - top: 36px; } - #debug-bar #toolbar-position a, - #debug-bar #toolbar-theme a { - padding: 0 6px; - display: inline-flex; - vertical-align: top; } - #debug-bar #toolbar-position a:hover, - #debug-bar #toolbar-theme a:hover { - text-decoration: none; } - #debug-bar #debug-bar-link { - padding: 6px; - display: flex; } - #debug-bar .ci-label { - display: inline-flex; - font-size: 14px; } - #debug-bar .ci-label:hover { - cursor: pointer; } - #debug-bar .ci-label a { - color: inherit; - display: flex; - letter-spacing: normal; - padding: 0 10px; - text-decoration: none; - align-items: center; } - #debug-bar .ci-label img { - margin: 6px 3px 6px 0; - width: 16px !important; } - #debug-bar .ci-label .badge { - border-radius: 12px; - -moz-border-radius: 12px; - -webkit-border-radius: 12px; - display: inline-block; - font-size: 75%; - font-weight: bold; - line-height: 12px; - margin-left: 5px; - padding: 2px 5px; - text-align: center; - vertical-align: baseline; - white-space: nowrap; } - #debug-bar .tab { - bottom: 35px; - display: none; - left: 0; - max-height: 62%; - overflow: hidden; - overflow-y: auto; - padding: 1em 2em; - position: fixed; - right: 0; - z-index: 9999; } - #debug-bar .timeline { - margin-left: 0; - width: 100%; } - #debug-bar .timeline th { - border-left: 1px solid; - font-size: 12px; - font-weight: 200; - padding: 5px 5px 10px 5px; - position: relative; - text-align: left; } - #debug-bar .timeline th:first-child { - border-left: 0; } - #debug-bar .timeline td { - border-left: 1px solid; - padding: 5px; - position: relative; } - #debug-bar .timeline td:first-child { - border-left: 0; - max-width: none; } - #debug-bar .timeline td.child-container { - padding: 0px; } - #debug-bar .timeline td.child-container .timeline { - margin: 0px; } - #debug-bar .timeline td.child-container .timeline td:first-child:not(.child-container) { - padding-left: calc(5px + 10px * var(--level)); } - #debug-bar .timeline .timer { - border-radius: 4px; - -moz-border-radius: 4px; - -webkit-border-radius: 4px; - display: inline-block; - padding: 5px; - position: absolute; - top: 30%; } - #debug-bar .timeline .timeline-parent { - cursor: pointer; } - #debug-bar .timeline .timeline-parent td:first-child nav { - background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; - background-position: 0 25%; - display: inline-block; - height: 15px; - width: 15px; - margin-right: 3px; - vertical-align: middle; } - #debug-bar .timeline .timeline-parent-open { - background-color: #DFDFDF; } - #debug-bar .timeline .timeline-parent-open td:first-child nav { - background-position: 0 75%; } - #debug-bar .timeline .child-row:hover { - background: transparent; } - #debug-bar .route-params, - #debug-bar .route-params-item { - vertical-align: top; } - #debug-bar .route-params td:first-child, - #debug-bar .route-params-item td:first-child { - font-style: italic; - padding-left: 1em; - text-align: right; } + font-weight: 400; +} +#debug-bar h1 { + display: flex; + font-weight: normal; + margin: 0 0 0 auto; +} +#debug-bar h1 svg { + width: 16px; + margin-right: 5px; +} +#debug-bar h2 { + font-size: 16px; + margin: 0; + padding: 5px 0 10px 0; +} +#debug-bar h2 span { + font-size: 13px; +} +#debug-bar h3 { + font-size: 12px; + font-weight: 200; + margin: 0 0 0 10px; + padding: 0; + text-transform: uppercase; +} +#debug-bar p { + font-size: 12px; + margin: 0 0 0 15px; + padding: 0; +} +#debug-bar a { + text-decoration: none; +} +#debug-bar a:hover { + text-decoration: underline; +} +#debug-bar button { + border: 1px solid; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + cursor: pointer; + line-height: 15px; +} +#debug-bar button:hover { + text-decoration: underline; +} +#debug-bar table { + border-collapse: collapse; + font-size: 14px; + line-height: normal; + margin: 5px 10px 15px 10px; + width: calc(100% - 10px); +} +#debug-bar table strong { + font-weight: 500; +} +#debug-bar table th { + display: table-cell; + font-weight: 600; + padding-bottom: 0.7em; + text-align: left; +} +#debug-bar table tr { + border: none; +} +#debug-bar table td { + border: none; + display: table-cell; + margin: 0; + text-align: left; +} +#debug-bar table td:first-child { + max-width: 20%; +} +#debug-bar table td:first-child.narrow { + width: 7em; +} +#debug-bar td[data-debugbar-route] form { + display: none; +} +#debug-bar td[data-debugbar-route]:hover form { + display: block; +} +#debug-bar td[data-debugbar-route]:hover > div { + display: none; +} +#debug-bar td[data-debugbar-route] input[type=text] { + padding: 2px; +} +#debug-bar .toolbar { + display: flex; + overflow: hidden; + overflow-y: auto; + padding: 0 12px 0 12px; + white-space: nowrap; + z-index: 10000; +} +#debug-bar.fixed-top { + bottom: auto; + top: 0; +} +#debug-bar.fixed-top .tab { + bottom: auto; + top: 36px; +} +#debug-bar #toolbar-position a, +#debug-bar #toolbar-theme a { + padding: 0 6px; + display: inline-flex; + vertical-align: top; +} +#debug-bar #toolbar-position a:hover, +#debug-bar #toolbar-theme a:hover { + text-decoration: none; +} +#debug-bar #debug-bar-link { + display: flex; + padding: 6px; +} +#debug-bar .ci-label { + display: inline-flex; + font-size: 14px; +} +#debug-bar .ci-label:hover { + cursor: pointer; +} +#debug-bar .ci-label a { + color: inherit; + display: flex; + letter-spacing: normal; + padding: 0 10px; + text-decoration: none; + align-items: center; +} +#debug-bar .ci-label img { + margin: 6px 3px 6px 0; + width: 16px !important; +} +#debug-bar .ci-label .badge { + border-radius: 12px; + -moz-border-radius: 12px; + -webkit-border-radius: 12px; + display: inline-block; + font-size: 75%; + font-weight: bold; + line-height: 12px; + margin-left: 5px; + padding: 2px 5px; + text-align: center; + vertical-align: baseline; + white-space: nowrap; +} +#debug-bar .tab { + bottom: 35px; + display: none; + left: 0; + max-height: 62%; + overflow: hidden; + overflow-y: auto; + padding: 1em 2em; + position: fixed; + right: 0; + z-index: 9999; +} +#debug-bar .timeline { + margin-left: 0; + width: 100%; +} +#debug-bar .timeline th { + border-left: 1px solid; + font-size: 12px; + font-weight: 200; + padding: 5px 5px 10px 5px; + position: relative; + text-align: left; +} +#debug-bar .timeline th:first-child { + border-left: 0; +} +#debug-bar .timeline td { + border-left: 1px solid; + padding: 5px; + position: relative; +} +#debug-bar .timeline td:first-child { + border-left: 0; + max-width: none; +} +#debug-bar .timeline td.child-container { + padding: 0px; +} +#debug-bar .timeline td.child-container .timeline { + margin: 0px; +} +#debug-bar .timeline td.child-container .timeline td:first-child:not(.child-container) { + padding-left: calc(5px + 10px * var(--level)); +} +#debug-bar .timeline .timer { + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + display: inline-block; + padding: 5px; + position: absolute; + top: 30%; +} +#debug-bar .timeline .timeline-parent { + cursor: pointer; +} +#debug-bar .timeline .timeline-parent td:first-child nav { + background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzMCAxNTAiPjxwYXRoIGQ9Ik02IDdoMThsLTkgMTV6bTAgMzBoMThsLTkgMTV6bTAgNDVoMThsLTktMTV6bTAgMzBoMThsLTktMTV6bTAgMTJsMTggMThtLTE4IDBsMTgtMTgiIGZpbGw9IiM1NTUiLz48cGF0aCBkPSJNNiAxMjZsMTggMThtLTE4IDBsMTgtMTgiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlPSIjNTU1Ii8+PC9zdmc+") no-repeat scroll 0 0/15px 75px transparent; + background-position: 0 25%; + display: inline-block; + height: 15px; + width: 15px; + margin-right: 3px; + vertical-align: middle; +} +#debug-bar .timeline .timeline-parent-open { + background-color: #DFDFDF; +} +#debug-bar .timeline .timeline-parent-open td:first-child nav { + background-position: 0 75%; +} +#debug-bar .timeline .child-row:hover { + background: transparent; +} +#debug-bar .route-params, +#debug-bar .route-params-item { + vertical-align: top; +} +#debug-bar .route-params td:first-child, +#debug-bar .route-params-item td:first-child { + font-style: italic; + padding-left: 1em; + text-align: right; +} .debug-view.show-view { border: 1px solid; - margin: 4px; } + margin: 4px; +} .debug-view-path { font-family: monospace; @@ -237,403 +292,511 @@ letter-spacing: normal; min-height: 16px; padding: 2px; - text-align: left; } + text-align: left; +} .show-view .debug-view-path { - display: block !important; } + display: block !important; +} @media screen and (max-width: 1024px) { #debug-bar .ci-label img { - margin: unset; } - .hide-sm { - display: none !important; } } + margin: unset; + } + .hide-sm { + display: none !important; + } +} #debug-icon { background-color: #FFFFFF; box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, - #debug-icon a:link, - #debug-icon a:visited { - color: #DD8615; } + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#debug-icon a:active, +#debug-icon a:link, +#debug-icon a:visited { + color: #DD8615; +} #debug-bar { background-color: #FFFFFF; - color: #434343; } + color: #434343; +} +#debug-bar h1, +#debug-bar h2, +#debug-bar h3, +#debug-bar p, +#debug-bar a, +#debug-bar button, +#debug-bar table, +#debug-bar thead, +#debug-bar tr, +#debug-bar td, +#debug-bar button, +#debug-bar .toolbar { + background-color: transparent; + color: #434343; +} +#debug-bar button { + background-color: #FFFFFF; +} +#debug-bar table strong { + color: #DD8615; +} +#debug-bar table tbody tr:hover { + background-color: #DFDFDF; +} +#debug-bar table tbody tr.current { + background-color: #FDC894; +} +#debug-bar table tbody tr.current:hover td { + background-color: #DD4814; + color: #FFFFFF; +} +#debug-bar .toolbar { + background-color: #FFFFFF; + box-shadow: 0 0 4px #DFDFDF; + -moz-box-shadow: 0 0 4px #DFDFDF; + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#debug-bar .toolbar img { + filter: brightness(0) invert(0.4); +} +#debug-bar.fixed-top .toolbar { + box-shadow: 0 0 4px #DFDFDF; + -moz-box-shadow: 0 0 4px #DFDFDF; + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#debug-bar.fixed-top .tab { + box-shadow: 0 1px 4px #DFDFDF; + -moz-box-shadow: 0 1px 4px #DFDFDF; + -webkit-box-shadow: 0 1px 4px #DFDFDF; +} +#debug-bar .muted { + color: #434343; +} +#debug-bar .muted td { + color: #DFDFDF; +} +#debug-bar .muted:hover td { + color: #434343; +} +#debug-bar #toolbar-position, +#debug-bar #toolbar-theme { + filter: brightness(0) invert(0.6); +} +#debug-bar .ci-label.active { + background-color: #DFDFDF; +} +#debug-bar .ci-label:hover { + background-color: #DFDFDF; +} +#debug-bar .ci-label .badge { + background-color: #DD4814; + color: #FFFFFF; +} +#debug-bar .tab { + background-color: #FFFFFF; + box-shadow: 0 -1px 4px #DFDFDF; + -moz-box-shadow: 0 -1px 4px #DFDFDF; + -webkit-box-shadow: 0 -1px 4px #DFDFDF; +} +#debug-bar .timeline th, +#debug-bar .timeline td { + border-color: #DFDFDF; +} +#debug-bar .timeline .timer { + background-color: #DD8615; +} + +.debug-view.show-view { + border-color: #DD8615; +} + +.debug-view-path { + background-color: #FDC894; + color: #434343; +} + +@media (prefers-color-scheme: dark) { + #debug-icon { + background-color: #252525; + box-shadow: 0 0 4px #DFDFDF; + -moz-box-shadow: 0 0 4px #DFDFDF; + -webkit-box-shadow: 0 0 4px #DFDFDF; + } + #debug-icon a:active, +#debug-icon a:link, +#debug-icon a:visited { + color: #DD8615; + } + + #debug-bar { + background-color: #252525; + color: #DFDFDF; + } #debug-bar h1, - #debug-bar h2, - #debug-bar h3, - #debug-bar p, - #debug-bar a, - #debug-bar button, - #debug-bar table, - #debug-bar thead, - #debug-bar tr, - #debug-bar td, - #debug-bar button, - #debug-bar .toolbar { +#debug-bar h2, +#debug-bar h3, +#debug-bar p, +#debug-bar a, +#debug-bar button, +#debug-bar table, +#debug-bar thead, +#debug-bar tr, +#debug-bar td, +#debug-bar button, +#debug-bar .toolbar { background-color: transparent; - color: #434343; } + color: #DFDFDF; + } #debug-bar button { - background-color: #FFFFFF; } + background-color: #252525; + } #debug-bar table strong { - color: #DD8615; } + color: #DD8615; + } #debug-bar table tbody tr:hover { - background-color: #DFDFDF; } + background-color: #434343; + } #debug-bar table tbody tr.current { - background-color: #FDC894; } - #debug-bar table tbody tr.current:hover td { - background-color: #DD4814; - color: #FFFFFF; } + background-color: #FDC894; + } + #debug-bar table tbody tr.current td { + color: #252525; + } + #debug-bar table tbody tr.current:hover td { + background-color: #DD4814; + color: #FFFFFF; + } #debug-bar .toolbar { - background-color: #FFFFFF; - box-shadow: 0 0 4px #DFDFDF; - -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-bar .toolbar img { - filter: brightness(0) invert(0.4); } + background-color: #434343; + box-shadow: 0 0 4px #434343; + -moz-box-shadow: 0 0 4px #434343; + -webkit-box-shadow: 0 0 4px #434343; + } + #debug-bar .toolbar img { + filter: brightness(0) invert(1); + } #debug-bar.fixed-top .toolbar { - box-shadow: 0 0 4px #DFDFDF; - -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } + box-shadow: 0 0 4px #434343; + -moz-box-shadow: 0 0 4px #434343; + -webkit-box-shadow: 0 0 4px #434343; + } #debug-bar.fixed-top .tab { - box-shadow: 0 1px 4px #DFDFDF; - -moz-box-shadow: 0 1px 4px #DFDFDF; - -webkit-box-shadow: 0 1px 4px #DFDFDF; } + box-shadow: 0 1px 4px #434343; + -moz-box-shadow: 0 1px 4px #434343; + -webkit-box-shadow: 0 1px 4px #434343; + } #debug-bar .muted { - color: #434343; } - #debug-bar .muted td { - color: #DFDFDF; } - #debug-bar .muted:hover td { - color: #434343; } + color: #DFDFDF; + } + #debug-bar .muted td { + color: #434343; + } + #debug-bar .muted:hover td { + color: #DFDFDF; + } #debug-bar #toolbar-position, - #debug-bar #toolbar-theme { - filter: brightness(0) invert(0.6); } +#debug-bar #toolbar-theme { + filter: brightness(0) invert(0.6); + } #debug-bar .ci-label.active { - background-color: #DFDFDF; } + background-color: #252525; + } #debug-bar .ci-label:hover { - background-color: #DFDFDF; } + background-color: #252525; + } #debug-bar .ci-label .badge { background-color: #DD4814; - color: #FFFFFF; } + color: #FFFFFF; + } #debug-bar .tab { - background-color: #FFFFFF; - box-shadow: 0 -1px 4px #DFDFDF; - -moz-box-shadow: 0 -1px 4px #DFDFDF; - -webkit-box-shadow: 0 -1px 4px #DFDFDF; } + background-color: #252525; + box-shadow: 0 -1px 4px #434343; + -moz-box-shadow: 0 -1px 4px #434343; + -webkit-box-shadow: 0 -1px 4px #434343; + } #debug-bar .timeline th, - #debug-bar .timeline td { - border-color: #DFDFDF; } +#debug-bar .timeline td { + border-color: #434343; + } #debug-bar .timeline .timer { - background-color: #DD8615; } - -.debug-view.show-view { - border-color: #DD8615; } -#debug-bar tr[data-toggle] { - cursor: pointer; } + background-color: #DD8615; + } -.debug-view-path { - background-color: #FDC894; - color: #434343; } - -@media (prefers-color-scheme: dark) { - #debug-icon { - background-color: #252525; - box-shadow: 0 0 4px #DFDFDF; - -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #debug-icon a:active, - #debug-icon a:link, - #debug-icon a:visited { - color: #DD8615; } - #debug-bar { - background-color: #252525; - color: #DFDFDF; } - #debug-bar h1, - #debug-bar h2, - #debug-bar h3, - #debug-bar p, - #debug-bar a, - #debug-bar button, - #debug-bar table, - #debug-bar thead, - #debug-bar tr, - #debug-bar td, - #debug-bar button, - #debug-bar .toolbar { - background-color: transparent; - color: #DFDFDF; } - #debug-bar button { - background-color: #252525; } - #debug-bar table strong { - color: #DD8615; } - #debug-bar table tbody tr:hover { - background-color: #434343; } - #debug-bar table tbody tr.current { - background-color: #FDC894; } - #debug-bar table tbody tr.current td { - color: #252525; } - #debug-bar table tbody tr.current:hover td { - background-color: #DD4814; - color: #FFFFFF; } - #debug-bar .toolbar { - background-color: #434343; - box-shadow: 0 0 4px #434343; - -moz-box-shadow: 0 0 4px #434343; - -webkit-box-shadow: 0 0 4px #434343; } - #debug-bar .toolbar img { - filter: brightness(0) invert(1); } - #debug-bar.fixed-top .toolbar { - box-shadow: 0 0 4px #434343; - -moz-box-shadow: 0 0 4px #434343; - -webkit-box-shadow: 0 0 4px #434343; } - #debug-bar.fixed-top .tab { - box-shadow: 0 1px 4px #434343; - -moz-box-shadow: 0 1px 4px #434343; - -webkit-box-shadow: 0 1px 4px #434343; } - #debug-bar .muted { - color: #DFDFDF; } - #debug-bar .muted td { - color: #797979; } - #debug-bar .muted:hover td { - color: #DFDFDF; } - #debug-bar #toolbar-position, - #debug-bar #toolbar-theme { - filter: brightness(0) invert(0.6); } - #debug-bar .ci-label.active { - background-color: #252525; } - #debug-bar .ci-label:hover { - background-color: #252525; } - #debug-bar .ci-label .badge { - background-color: #DD4814; - color: #FFFFFF; } - #debug-bar .tab { - background-color: #252525; - box-shadow: 0 -1px 4px #434343; - -moz-box-shadow: 0 -1px 4px #434343; - -webkit-box-shadow: 0 -1px 4px #434343; } - #debug-bar .timeline th, - #debug-bar .timeline td { - border-color: #434343; } - #debug-bar .timeline .timer { - background-color: #DD8615; } .debug-view.show-view { - border-color: #DD8615; } + border-color: #DD8615; + } + .debug-view-path { background-color: #FDC894; - color: #434343; } } - + color: #434343; + } +} #toolbarContainer.dark #debug-icon { background-color: #252525; box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.dark #debug-icon a:active, - #toolbarContainer.dark #debug-icon a:link, - #toolbarContainer.dark #debug-icon a:visited { - color: #DD8615; } - + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#toolbarContainer.dark #debug-icon a:active, +#toolbarContainer.dark #debug-icon a:link, +#toolbarContainer.dark #debug-icon a:visited { + color: #DD8615; +} #toolbarContainer.dark #debug-bar { background-color: #252525; - color: #DFDFDF; } - #toolbarContainer.dark #debug-bar h1, - #toolbarContainer.dark #debug-bar h2, - #toolbarContainer.dark #debug-bar h3, - #toolbarContainer.dark #debug-bar p, - #toolbarContainer.dark #debug-bar a, - #toolbarContainer.dark #debug-bar button, - #toolbarContainer.dark #debug-bar table, - #toolbarContainer.dark #debug-bar thead, - #toolbarContainer.dark #debug-bar tr, - #toolbarContainer.dark #debug-bar td, - #toolbarContainer.dark #debug-bar button, - #toolbarContainer.dark #debug-bar .toolbar { - background-color: transparent; - color: #DFDFDF; } - #toolbarContainer.dark #debug-bar button { - background-color: #252525; } - #toolbarContainer.dark #debug-bar table strong { - color: #DD8615; } - #toolbarContainer.dark #debug-bar table tbody tr:hover { - background-color: #434343; } - #toolbarContainer.dark #debug-bar table tbody tr.current { - background-color: #FDC894; } - #toolbarContainer.dark #ci-database table tbody tr.duplicate { - background-color: #434343;} - #toolbarContainer.dark #debug-bar table tbody tr.current td { - color: #252525; } - #toolbarContainer.dark #debug-bar table tbody tr.current:hover td { - background-color: #DD4814; - color: #FFFFFF; } - #toolbarContainer.dark #debug-bar .toolbar { - background-color: #434343; - box-shadow: 0 0 4px #434343; - -moz-box-shadow: 0 0 4px #434343; - -webkit-box-shadow: 0 0 4px #434343; } - #toolbarContainer.dark #debug-bar .toolbar img { - filter: brightness(0) invert(1); } - #toolbarContainer.dark #debug-bar.fixed-top .toolbar { - box-shadow: 0 0 4px #434343; - -moz-box-shadow: 0 0 4px #434343; - -webkit-box-shadow: 0 0 4px #434343; } - #toolbarContainer.dark #debug-bar.fixed-top .tab { - box-shadow: 0 1px 4px #434343; - -moz-box-shadow: 0 1px 4px #434343; - -webkit-box-shadow: 0 1px 4px #434343; } - #toolbarContainer.dark #debug-bar .muted { - color: #DFDFDF; } - #toolbarContainer.dark #debug-bar .muted td { - color: #797979; } - #toolbarContainer.dark #debug-bar .muted:hover td { - color: #DFDFDF; } - #toolbarContainer.dark #debug-bar #toolbar-position, - #toolbarContainer.dark #debug-bar #toolbar-theme { - filter: brightness(0) invert(0.6); } - #toolbarContainer.dark #debug-bar .ci-label.active { - background-color: #252525; } - #toolbarContainer.dark #debug-bar .ci-label:hover { - background-color: #252525; } - #toolbarContainer.dark #debug-bar .ci-label .badge { - background-color: #DD4814; - color: #FFFFFF; } - #toolbarContainer.dark #debug-bar .tab { - background-color: #252525; - box-shadow: 0 -1px 4px #434343; - -moz-box-shadow: 0 -1px 4px #434343; - -webkit-box-shadow: 0 -1px 4px #434343; } - #toolbarContainer.dark #debug-bar .timeline th, - #toolbarContainer.dark #debug-bar .timeline td { - border-color: #434343; } - #toolbarContainer.dark #debug-bar .timeline .timer { - background-color: #DD8615; } - + color: #DFDFDF; +} +#toolbarContainer.dark #debug-bar h1, +#toolbarContainer.dark #debug-bar h2, +#toolbarContainer.dark #debug-bar h3, +#toolbarContainer.dark #debug-bar p, +#toolbarContainer.dark #debug-bar a, +#toolbarContainer.dark #debug-bar button, +#toolbarContainer.dark #debug-bar table, +#toolbarContainer.dark #debug-bar thead, +#toolbarContainer.dark #debug-bar tr, +#toolbarContainer.dark #debug-bar td, +#toolbarContainer.dark #debug-bar button, +#toolbarContainer.dark #debug-bar .toolbar { + background-color: transparent; + color: #DFDFDF; +} +#toolbarContainer.dark #debug-bar button { + background-color: #252525; +} +#toolbarContainer.dark #debug-bar table strong { + color: #DD8615; +} +#toolbarContainer.dark #debug-bar table tbody tr:hover { + background-color: #434343; +} +#toolbarContainer.dark #debug-bar table tbody tr.current { + background-color: #FDC894; +} +#toolbarContainer.dark #debug-bar table tbody tr.current td { + color: #252525; +} +#toolbarContainer.dark #debug-bar table tbody tr.current:hover td { + background-color: #DD4814; + color: #FFFFFF; +} +#toolbarContainer.dark #debug-bar .toolbar { + background-color: #434343; + box-shadow: 0 0 4px #434343; + -moz-box-shadow: 0 0 4px #434343; + -webkit-box-shadow: 0 0 4px #434343; +} +#toolbarContainer.dark #debug-bar .toolbar img { + filter: brightness(0) invert(1); +} +#toolbarContainer.dark #debug-bar.fixed-top .toolbar { + box-shadow: 0 0 4px #434343; + -moz-box-shadow: 0 0 4px #434343; + -webkit-box-shadow: 0 0 4px #434343; +} +#toolbarContainer.dark #debug-bar.fixed-top .tab { + box-shadow: 0 1px 4px #434343; + -moz-box-shadow: 0 1px 4px #434343; + -webkit-box-shadow: 0 1px 4px #434343; +} +#toolbarContainer.dark #debug-bar .muted { + color: #DFDFDF; +} +#toolbarContainer.dark #debug-bar .muted td { + color: #434343; +} +#toolbarContainer.dark #debug-bar .muted:hover td { + color: #DFDFDF; +} +#toolbarContainer.dark #debug-bar #toolbar-position, +#toolbarContainer.dark #debug-bar #toolbar-theme { + filter: brightness(0) invert(0.6); +} +#toolbarContainer.dark #debug-bar .ci-label.active { + background-color: #252525; +} +#toolbarContainer.dark #debug-bar .ci-label:hover { + background-color: #252525; +} +#toolbarContainer.dark #debug-bar .ci-label .badge { + background-color: #DD4814; + color: #FFFFFF; +} +#toolbarContainer.dark #debug-bar .tab { + background-color: #252525; + box-shadow: 0 -1px 4px #434343; + -moz-box-shadow: 0 -1px 4px #434343; + -webkit-box-shadow: 0 -1px 4px #434343; +} +#toolbarContainer.dark #debug-bar .timeline th, +#toolbarContainer.dark #debug-bar .timeline td { + border-color: #434343; +} +#toolbarContainer.dark #debug-bar .timeline .timer { + background-color: #DD8615; +} #toolbarContainer.dark .debug-view.show-view { - border-color: #DD8615; } - + border-color: #DD8615; +} #toolbarContainer.dark .debug-view-path { background-color: #FDC894; - color: #434343; } - + color: #434343; +} #toolbarContainer.dark td[data-debugbar-route] input[type=text] { background: #000; - color: #fff; } + color: #fff; +} #toolbarContainer.light #debug-icon { background-color: #FFFFFF; box-shadow: 0 0 4px #DFDFDF; -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.light #debug-icon a:active, - #toolbarContainer.light #debug-icon a:link, - #toolbarContainer.light #debug-icon a:visited { - color: #DD8615; } - + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#toolbarContainer.light #debug-icon a:active, +#toolbarContainer.light #debug-icon a:link, +#toolbarContainer.light #debug-icon a:visited { + color: #DD8615; +} #toolbarContainer.light #debug-bar { background-color: #FFFFFF; - color: #434343; } - #toolbarContainer.light #debug-bar h1, - #toolbarContainer.light #debug-bar h2, - #toolbarContainer.light #debug-bar h3, - #toolbarContainer.light #debug-bar p, - #toolbarContainer.light #debug-bar a, - #toolbarContainer.light #debug-bar button, - #toolbarContainer.light #debug-bar table, - #toolbarContainer.light #debug-bar thead, - #toolbarContainer.light #debug-bar tr, - #toolbarContainer.light #debug-bar td, - #toolbarContainer.light #debug-bar button, - #toolbarContainer.light #debug-bar .toolbar { - background-color: transparent; - color: #434343; } - #toolbarContainer.light #debug-bar button { - background-color: #FFFFFF; } - #toolbarContainer.light #debug-bar table strong { - color: #DD8615; } - #toolbarContainer.light #debug-bar table tbody tr:hover { - background-color: #DFDFDF; } - #toolbarContainer.light #debug-bar table tbody tr.current { - background-color: #FDC894; } - #toolbarContainer.light #ci-database table tbody tr.duplicate { - background-color: #DFDFDF;} - #toolbarContainer.light #debug-bar table tbody tr.current:hover td { - background-color: #DD4814; - color: #FFFFFF; } - #toolbarContainer.light #debug-bar .toolbar { - background-color: #FFFFFF; - box-shadow: 0 0 4px #DFDFDF; - -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.light #debug-bar .toolbar img { - filter: brightness(0) invert(0.4); } - #toolbarContainer.light #debug-bar.fixed-top .toolbar { - box-shadow: 0 0 4px #DFDFDF; - -moz-box-shadow: 0 0 4px #DFDFDF; - -webkit-box-shadow: 0 0 4px #DFDFDF; } - #toolbarContainer.light #debug-bar.fixed-top .tab { - box-shadow: 0 1px 4px #DFDFDF; - -moz-box-shadow: 0 1px 4px #DFDFDF; - -webkit-box-shadow: 0 1px 4px #DFDFDF; } - #toolbarContainer.light #debug-bar .muted { - color: #797979; } - #toolbarContainer.light #debug-bar .muted td { - color: #797979; } - #toolbarContainer.light #debug-bar .muted:hover td { - color: #434343; } - #toolbarContainer.light #debug-bar #toolbar-position, - #toolbarContainer.light #debug-bar #toolbar-theme { - filter: brightness(0) invert(0.6); } - #toolbarContainer.light #debug-bar .ci-label.active { - background-color: #DFDFDF; } - #toolbarContainer.light #debug-bar .ci-label:hover { - background-color: #DFDFDF; } - #toolbarContainer.light #debug-bar .ci-label .badge { - background-color: #DD4814; - color: #FFFFFF; } - #toolbarContainer.light #debug-bar .tab { - background-color: #FFFFFF; - box-shadow: 0 -1px 4px #DFDFDF; - -moz-box-shadow: 0 -1px 4px #DFDFDF; - -webkit-box-shadow: 0 -1px 4px #DFDFDF; } - #toolbarContainer.light #debug-bar .timeline th, - #toolbarContainer.light #debug-bar .timeline td { - border-color: #DFDFDF; } - #toolbarContainer.light #debug-bar .timeline .timer { - background-color: #DD8615; } - + color: #434343; +} +#toolbarContainer.light #debug-bar h1, +#toolbarContainer.light #debug-bar h2, +#toolbarContainer.light #debug-bar h3, +#toolbarContainer.light #debug-bar p, +#toolbarContainer.light #debug-bar a, +#toolbarContainer.light #debug-bar button, +#toolbarContainer.light #debug-bar table, +#toolbarContainer.light #debug-bar thead, +#toolbarContainer.light #debug-bar tr, +#toolbarContainer.light #debug-bar td, +#toolbarContainer.light #debug-bar button, +#toolbarContainer.light #debug-bar .toolbar { + background-color: transparent; + color: #434343; +} +#toolbarContainer.light #debug-bar button { + background-color: #FFFFFF; +} +#toolbarContainer.light #debug-bar table strong { + color: #DD8615; +} +#toolbarContainer.light #debug-bar table tbody tr:hover { + background-color: #DFDFDF; +} +#toolbarContainer.light #debug-bar table tbody tr.current { + background-color: #FDC894; +} +#toolbarContainer.light #debug-bar table tbody tr.current:hover td { + background-color: #DD4814; + color: #FFFFFF; +} +#toolbarContainer.light #debug-bar .toolbar { + background-color: #FFFFFF; + box-shadow: 0 0 4px #DFDFDF; + -moz-box-shadow: 0 0 4px #DFDFDF; + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#toolbarContainer.light #debug-bar .toolbar img { + filter: brightness(0) invert(0.4); +} +#toolbarContainer.light #debug-bar.fixed-top .toolbar { + box-shadow: 0 0 4px #DFDFDF; + -moz-box-shadow: 0 0 4px #DFDFDF; + -webkit-box-shadow: 0 0 4px #DFDFDF; +} +#toolbarContainer.light #debug-bar.fixed-top .tab { + box-shadow: 0 1px 4px #DFDFDF; + -moz-box-shadow: 0 1px 4px #DFDFDF; + -webkit-box-shadow: 0 1px 4px #DFDFDF; +} +#toolbarContainer.light #debug-bar .muted { + color: #434343; +} +#toolbarContainer.light #debug-bar .muted td { + color: #DFDFDF; +} +#toolbarContainer.light #debug-bar .muted:hover td { + color: #434343; +} +#toolbarContainer.light #debug-bar #toolbar-position, +#toolbarContainer.light #debug-bar #toolbar-theme { + filter: brightness(0) invert(0.6); +} +#toolbarContainer.light #debug-bar .ci-label.active { + background-color: #DFDFDF; +} +#toolbarContainer.light #debug-bar .ci-label:hover { + background-color: #DFDFDF; +} +#toolbarContainer.light #debug-bar .ci-label .badge { + background-color: #DD4814; + color: #FFFFFF; +} +#toolbarContainer.light #debug-bar .tab { + background-color: #FFFFFF; + box-shadow: 0 -1px 4px #DFDFDF; + -moz-box-shadow: 0 -1px 4px #DFDFDF; + -webkit-box-shadow: 0 -1px 4px #DFDFDF; +} +#toolbarContainer.light #debug-bar .timeline th, +#toolbarContainer.light #debug-bar .timeline td { + border-color: #DFDFDF; +} +#toolbarContainer.light #debug-bar .timeline .timer { + background-color: #DD8615; +} #toolbarContainer.light .debug-view.show-view { - border-color: #DD8615; } - + border-color: #DD8615; +} #toolbarContainer.light .debug-view-path { background-color: #FDC894; - color: #434343; } + color: #434343; +} .debug-bar-width30 { - width: 30%; } + width: 30%; +} .debug-bar-width10 { - width: 10%; } + width: 10%; +} .debug-bar-width70p { - width: 70px; } + width: 70px; +} .debug-bar-width140p { - width: 140px; } + width: 140px; +} .debug-bar-width20e { - width: 20em; } + width: 20em; +} .debug-bar-width6r { - width: 6rem; } + width: 6rem; +} .debug-bar-ndisplay { - display: none; } + display: none; +} .debug-bar-alignRight { - text-align: right; } + text-align: right; +} .debug-bar-alignLeft { - text-align: left; } + text-align: left; +} .debug-bar-noverflow { - overflow: hidden; } + overflow: hidden; +} From 950d45bf22d0934cc6a3d57250159f4a13512de0 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Thu, 24 Feb 2022 11:40:01 +0800 Subject: [PATCH 1626/2325] Nonce generation optimization. Signed-off-by: Andrey Pyzhikov <5071@mail.ru> --- system/HTTP/ContentSecurityPolicy.php | 16 +++++----------- tests/system/HTTP/ContentSecurityPolicyTest.php | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index b7f9b066d7d8..a2d3ec6f0a24 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -671,18 +671,12 @@ protected function generateNonces(ResponseInterface &$response) return; } - // Replace style placeholders with nonces - $pattern = '/' . preg_quote($this->styleNonceTag, '/') . '/'; - $body = preg_replace_callback($pattern, function () { - $nonce = $this->getStyleNonce(); + // Replace style and script placeholders with nonces + $pattern = '/(' . preg_quote($this->styleNonceTag, '/') + . '|' . preg_quote($this->scriptNonceTag, '/') . ')/'; - return "nonce=\"{$nonce}\""; - }, $body); - - // Replace script placeholders with nonces - $pattern = '/' . preg_quote($this->scriptNonceTag, '/') . '/'; - $body = preg_replace_callback($pattern, function () { - $nonce = $this->getScriptNonce(); + $body = preg_replace_callback($pattern, function ($match) { + $nonce = $match[0] === $this->styleNonceTag ? $this->getStyleNonce() : $this->getScriptNonce(); return "nonce=\"{$nonce}\""; }, $body); diff --git a/tests/system/HTTP/ContentSecurityPolicyTest.php b/tests/system/HTTP/ContentSecurityPolicyTest.php index 2ab6ee747d91..d2113e28e366 100644 --- a/tests/system/HTTP/ContentSecurityPolicyTest.php +++ b/tests/system/HTTP/ContentSecurityPolicyTest.php @@ -459,11 +459,16 @@ public function testBodyScriptNonce() $this->response->setBody($body); $this->csp->addScriptSrc('cdn.cloudy.com'); - $result = $this->work($body); + $result = $this->work($body); + $nonceStyle = array_filter( + $this->getPrivateProperty($this->csp, 'styleSrc'), + static fn ($value) => strpos($value, 'nonce-') === 0 + ); $this->assertStringContainsString('nonce=', $this->response->getBody()); $result = $this->getHeaderEmitted('Content-Security-Policy'); $this->assertStringContainsString('nonce-', $result); + $this->assertSame([], $nonceStyle); } public function testBodyScriptNonceCustomScriptTag() @@ -525,11 +530,16 @@ public function testBodyStyleNonce() $this->response->setBody($body); $this->csp->addStyleSrc('cdn.cloudy.com'); - $result = $this->work($body); + $result = $this->work($body); + $nonceScript = array_filter( + $this->getPrivateProperty($this->csp, 'scriptSrc'), + static fn ($value) => strpos($value, 'nonce-') === 0 + ); $this->assertStringContainsString('nonce=', $this->response->getBody()); $result = $this->getHeaderEmitted('Content-Security-Policy'); $this->assertStringContainsString('nonce-', $result); + $this->assertSame([], $nonceScript); } public function testBodyStyleNonceCustomStyleTag() From b7c26b68941e256462e443731993317ce8793645 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 24 Feb 2022 13:35:53 +0900 Subject: [PATCH 1627/2325] refactor: remove unneeded `&` references --- system/HTTP/ContentSecurityPolicy.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index b7f9b066d7d8..0428431ed41d 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -298,7 +298,7 @@ public function getScriptNonce(): string * * Should be called just prior to sending the response to the user agent. */ - public function finalize(ResponseInterface &$response) + public function finalize(ResponseInterface $response) { if ($this->autoNonce === false) { return; @@ -663,7 +663,7 @@ protected function addOption($options, string $target, ?bool $explicitReporting * placeholders with actual nonces, that we'll then add to our * headers. */ - protected function generateNonces(ResponseInterface &$response) + protected function generateNonces(ResponseInterface $response) { $body = $response->getBody(); @@ -695,7 +695,7 @@ protected function generateNonces(ResponseInterface &$response) * Content-Security-Policy and Content-Security-Policy-Report-Only headers * with their values to the response object. */ - protected function buildHeaders(ResponseInterface &$response) + protected function buildHeaders(ResponseInterface $response) { /** * Ensure both headers are available and arrays... From 1541d0665ae3e29a8527e519f28dc294049e5539 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Thu, 24 Feb 2022 13:22:49 +0800 Subject: [PATCH 1628/2325] Feature: Subquery for SELECT Signed-off-by: Andrey Pyzhikov <5071@mail.ru> --- system/Database/BaseBuilder.php | 16 ++++++++++++++++ tests/system/Database/Builder/SelectTest.php | 13 +++++++++++++ user_guide_src/source/changelogs/v4.2.0.rst | 1 + user_guide_src/source/database/query_builder.rst | 16 ++++++++++++++++ .../source/database/query_builder/098.php | 7 +++++++ 5 files changed, 53 insertions(+) create mode 100644 user_guide_src/source/database/query_builder/098.php diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index a3fc6c7563d3..92d35945565e 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -445,6 +445,22 @@ public function selectCount(string $select = '', string $alias = '') return $this->maxMinAvgSum($select, $alias, 'COUNT'); } + /** + * Adds a subquery to the selection + * + * @return static + */ + public function selectSubquery(BaseBuilder $subquery, string $as) + { + if (! $this->isSubquery($subquery)) { + throw new DatabaseException('The BaseBuilder::selectSubquery method expects a BaseBuilder instance'); + } + + $this->QBSelect[] = $this->buildSubquery($subquery, true, $as); + + return $this; + } + /** * SELECT [MAX|MIN|AVG|SUM|COUNT]() * diff --git a/tests/system/Database/Builder/SelectTest.php b/tests/system/Database/Builder/SelectTest.php index 7a9e7570221d..97460f0010da 100644 --- a/tests/system/Database/Builder/SelectTest.php +++ b/tests/system/Database/Builder/SelectTest.php @@ -246,4 +246,17 @@ public function testSimpleSelectWithSQLSRV() $this->assertSame($expected, str_replace("\n", ' ', $builder->getCompiledSelect())); } + + public function testSelectSubquery() + { + $builder = new BaseBuilder('users', $this->db); + $subquery = new BaseBuilder('countries', $this->db); + + $subquery->select('name')->where('id', 1); + $builder->select('name')->selectSubquery($subquery, 'country'); + + $expected = 'SELECT "name", (SELECT "name" FROM "countries" WHERE "id" = 1) AS "country" FROM "users"'; + + $this->assertSame($expected, str_replace("\n", ' ', $builder->getCompiledSelect())); + } } diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index f22ddae1aa17..a1660d8cf8ca 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -24,6 +24,7 @@ Enhancements - See :ref:`content-security-policy` for details. - New View Decorators allow modifying the generated HTML prior to caching. - Added Subqueries in the FROM section. See :ref:`query-builder-from-subquery`. +- Added Subqueries in the SELECT section. - Added Validation Strict Rules. See :ref:`validation-traditional-and-strict-rules`. - Added new OCI8 driver for database. - It can access Oracle Database and supports SQL and PL/SQL statements. diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 1969620b63a8..0a1861e23810 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -167,6 +167,13 @@ the resulting field. .. literalinclude:: query_builder/014.php :lines: 2- +**$builder->selectSubquery()** + +Adds a subquery to the SELECT section. + +.. literalinclude:: query_builder/098.php + :lines: 2- + From ==== @@ -1066,6 +1073,15 @@ Class Reference Adds a ``SELECT COUNT(field)`` clause to a query. +.. php:method:: selectSubquery(BaseBuilder $subquery, string $as) + + :param string $subquery: Instance of BaseBuilder + :param string $as: Alias for the resulting value name + :returns: ``BaseBuilder`` instance (method chaining) + :rtype: ``BaseBuilder`` + + Adds a subquery to the selection + .. php:method:: distinct([$val = true]) :param bool $val: Desired value of the "distinct" flag diff --git a/user_guide_src/source/database/query_builder/098.php b/user_guide_src/source/database/query_builder/098.php new file mode 100644 index 000000000000..96d1d0d9025b --- /dev/null +++ b/user_guide_src/source/database/query_builder/098.php @@ -0,0 +1,7 @@ +table('countries')->select('name')->where('id', 1); +$builder = $db->table('users')->select('name')->selectSubquery($subquery, 'country'); +$query = $builder->get(); + +// Produces: SELECT `name`, (SELECT `name` FROM `countries` WHERE `id` = 1) AS `country` FROM `users` \ No newline at end of file From f668b8d91e646b5418193658d1c29d853f9a92ac Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 24 Feb 2022 10:24:55 +0800 Subject: [PATCH 1629/2325] Limit running PHP workflows to related PHP files --- .github/workflows/test-deptrac.yml | 8 ++++---- .github/workflows/test-phpcpd.yml | 13 +++++++------ .github/workflows/test-phpstan.yml | 19 +++++++++++-------- .github/workflows/test-phpunit.yml | 13 +++++++++---- .github/workflows/test-rector.yml | 17 +++++++++-------- 5 files changed, 40 insertions(+), 30 deletions(-) diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml index 52b58d51d5d8..262da202c02f 100644 --- a/.github/workflows/test-deptrac.yml +++ b/.github/workflows/test-deptrac.yml @@ -8,8 +8,8 @@ on: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'system/**' + - 'app/**.php' + - 'system/**.php' - 'composer.json' - 'depfile.yaml' - '.github/workflows/test-deptrac.yml' @@ -18,8 +18,8 @@ on: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'system/**' + - 'app/**.php' + - 'system/**.php' - 'composer.json' - 'depfile.yaml' - '.github/workflows/test-deptrac.yml' diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index 018acd11cbd2..6cfd76a054f1 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -8,18 +8,19 @@ on: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'public/**' - - 'system/**' + - 'app/**.php' + - 'public/**.php' + - 'system/**.php' - '.github/workflows/test-phpcpd.yml' + push: branches: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'public/**' - - 'system/**' + - 'app/**.php' + - 'public/**.php' + - 'system/**.php' - '.github/workflows/test-phpcpd.yml' jobs: diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index 6c0d40efa83a..d0235ec9beb6 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -8,21 +8,24 @@ on: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'system/**' + - 'app/**.php' + - 'system/**.php' + - 'utils/**.php' - composer.json - - phpstan.neon.dist - - phpstan-baseline.neon.dist + - '**.neon.dist' + - '.github/workflows/test-phpstan.yml' + push: branches: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'system/**' + - 'app/**.php' + - 'system/**.php' + - 'utils/**.php' - composer.json - - phpstan.neon.dist - - phpstan-baseline.neon.dist + - '**.neon.dist' + - '.github/workflows/test-phpstan.yml' jobs: build: diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 1d788f9d86e1..964f9fcb3f72 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -5,20 +5,25 @@ on: branches: - develop paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'spark' - composer.json - - spark - phpunit.xml.dist - - '**.php' - .github/workflows/test-phpunit.yml + pull_request: branches: - develop - 'v4.*' paths: + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'spark' - composer.json - - spark - phpunit.xml.dist - - '**.php' - .github/workflows/test-phpunit.yml jobs: diff --git a/.github/workflows/test-rector.yml b/.github/workflows/test-rector.yml index 03aa90f9bb8c..1282205c8bf6 100644 --- a/.github/workflows/test-rector.yml +++ b/.github/workflows/test-rector.yml @@ -8,23 +8,24 @@ on: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'system/**' + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'utils/**.php' - '.github/workflows/test-rector.yml' - composer.json - - 'utils/Rector/**' - - 'rector.php' + push: branches: - 'develop' - 'v4.*' paths: - - 'app/**' - - 'system/**' + - 'app/**.php' + - 'system/**.php' + - 'tests/**.php' + - 'utils/**.php' - '.github/workflows/test-rector.yml' - composer.json - - 'utils/Rector/**' - - 'rector.php' jobs: build: From c49c8a60abb1f5876bac81162f408a6875a66882 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Thu, 24 Feb 2022 08:29:44 +0100 Subject: [PATCH 1630/2325] Fix newlines. --- user_guide_src/source/helpers/text_helper/020.php | 2 +- user_guide_src/source/libraries/curlrequest/014.php | 2 +- user_guide_src/source/libraries/uploaded_files/006.php | 2 +- user_guide_src/source/outgoing/localization/008.php | 3 +-- user_guide_src/source/outgoing/response/026.php | 2 +- user_guide_src/source/testing/fabricator/005.php | 2 +- user_guide_src/source/testing/fabricator/006.php | 2 +- user_guide_src/source/testing/fabricator/021.php | 2 +- user_guide_src/source/testing/overview/007.php | 2 +- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/helpers/text_helper/020.php b/user_guide_src/source/helpers/text_helper/020.php index e5e6be9350a6..1b235b77497e 100644 --- a/user_guide_src/source/helpers/text_helper/020.php +++ b/user_guide_src/source/helpers/text_helper/020.php @@ -12,4 +12,4 @@ function. Excessively long words will be split, but URLs will not be. -*/ \ No newline at end of file +*/ diff --git a/user_guide_src/source/libraries/curlrequest/014.php b/user_guide_src/source/libraries/curlrequest/014.php index 04f6e02ffb18..9147c8861423 100644 --- a/user_guide_src/source/libraries/curlrequest/014.php +++ b/user_guide_src/source/libraries/curlrequest/014.php @@ -8,4 +8,4 @@ 'max' => 5, // Maximum number of redirects to follow before stopping 'strict' => true, // Ensure POST requests stay POST requests through redirects 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols -*/ \ No newline at end of file +*/ diff --git a/user_guide_src/source/libraries/uploaded_files/006.php b/user_guide_src/source/libraries/uploaded_files/006.php index 9a1fde0f053e..f046d86b63bc 100644 --- a/user_guide_src/source/libraries/uploaded_files/006.php +++ b/user_guide_src/source/libraries/uploaded_files/006.php @@ -9,4 +9,4 @@ ] ] ] -]; \ No newline at end of file +]; diff --git a/user_guide_src/source/outgoing/localization/008.php b/user_guide_src/source/outgoing/localization/008.php index eac50a5f4861..1b9b79725642 100644 --- a/user_guide_src/source/outgoing/localization/008.php +++ b/user_guide_src/source/outgoing/localization/008.php @@ -6,5 +6,4 @@ 'key' => 'The actual message to be shown.', ], ], -] -; \ No newline at end of file +]; diff --git a/user_guide_src/source/outgoing/response/026.php b/user_guide_src/source/outgoing/response/026.php index 4287ddb889ba..ee92fa38c094 100644 --- a/user_guide_src/source/outgoing/response/026.php +++ b/user_guide_src/source/outgoing/response/026.php @@ -2,4 +2,4 @@ if ($response->hasCookie($name)) { // ... -} \ No newline at end of file +} diff --git a/user_guide_src/source/testing/fabricator/005.php b/user_guide_src/source/testing/fabricator/005.php index 1bee37a0b99a..de1e6d7ef6c5 100644 --- a/user_guide_src/source/testing/fabricator/005.php +++ b/user_guide_src/source/testing/fabricator/005.php @@ -12,4 +12,4 @@ public function fake(Generator &$faker) 'login' => config('Auth')->allowRemembering ? date('Y-m-d') : null, ]; } -} \ No newline at end of file +} diff --git a/user_guide_src/source/testing/fabricator/006.php b/user_guide_src/source/testing/fabricator/006.php index cfb130f21ede..13b4b96cb07d 100644 --- a/user_guide_src/source/testing/fabricator/006.php +++ b/user_guide_src/source/testing/fabricator/006.php @@ -8,4 +8,4 @@ public function fake(&$faker) { // ... } -} \ No newline at end of file +} diff --git a/user_guide_src/source/testing/fabricator/021.php b/user_guide_src/source/testing/fabricator/021.php index df10c0b137d7..d6c848ac3c06 100644 --- a/user_guide_src/source/testing/fabricator/021.php +++ b/user_guide_src/source/testing/fabricator/021.php @@ -12,4 +12,4 @@ public function fake(Generator &$faker) 'group_id' => rand(1, Fabricator::getCount('groups')), ]; } -} \ No newline at end of file +} diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php index d6ec1d6c45c5..c829e5b99cce 100644 --- a/user_guide_src/source/testing/overview/007.php +++ b/user_guide_src/source/testing/overview/007.php @@ -16,4 +16,4 @@ class AuthenticationFeatureTest use AuthTrait; // ... -} \ No newline at end of file +} From 9594c458d97b2dd20861170d9d20b7d9a9049a5f Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" <51850998+paulbalandan@users.noreply.github.com> Date: Thu, 24 Feb 2022 15:35:10 +0800 Subject: [PATCH 1631/2325] Delete stale.yml --- stale.yml | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 stale.yml diff --git a/stale.yml b/stale.yml deleted file mode 100644 index 897cc082a10e..000000000000 --- a/stale.yml +++ /dev/null @@ -1,17 +0,0 @@ -# Number of days of inactivity before an issue becomes stale -daysUntilStale: 60 -# Number of days of inactivity before a stale issue is closed -daysUntilClose: 7 -# Issues with these labels will never be considered stale -exemptLabels: - - pinned - - security -# Label to use when marking an issue as stale -staleLabel: wontfix -# Comment to post when marking an issue as stale. Set to `false` to disable -markComment: > - This issue has been automatically marked as stale because it has not had - recent activity. It will be automatically closed in a week if no further activity occurs. - Thank you for your contributions. -# Comment to post when closing a stale issue. Set to `false` to disable -closeComment: false From af4995f2cda37024ab64f32b7bd3b5761638ccb0 Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:01:00 +0100 Subject: [PATCH 1632/2325] Fix space. Co-authored-by: kenjis --- user_guide_src/source/incoming/incomingrequest/10.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/incomingrequest/10.php b/user_guide_src/source/incoming/incomingrequest/10.php index d4118cebda7c..e223b7772d54 100644 --- a/user_guide_src/source/incoming/incomingrequest/10.php +++ b/user_guide_src/source/incoming/incomingrequest/10.php @@ -1,7 +1,7 @@ Date: Thu, 24 Feb 2022 11:33:28 +0100 Subject: [PATCH 1633/2325] Convert array dumps and prints to comments. --- .../source/incoming/incomingrequest/13.php | 12 ++++++--- .../source/incoming/incomingrequest/15.php | 14 ++++++---- user_guide_src/source/libraries/uri/026.php | 15 ++++++----- .../source/libraries/validation/009.php | 27 ++++++++++--------- .../source/libraries/validation/011.php | 17 +++++++----- .../source/libraries/validation/027.php | 13 +++++---- .../source/testing/benchmark/004.php | 17 +++++++----- .../source/testing/response/030.php | 8 ++++-- .../source/testing/response/032.php | 11 +++++--- 9 files changed, 82 insertions(+), 52 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest/13.php b/user_guide_src/source/incoming/incomingrequest/13.php index cf4be2eb10ac..8f62b6dd32a9 100644 --- a/user_guide_src/source/incoming/incomingrequest/13.php +++ b/user_guide_src/source/incoming/incomingrequest/13.php @@ -2,7 +2,11 @@ var_dump($request->getRawInput()); -[ - 'Param1' => 'Value1', - 'Param2' => 'Value2' -]; +/* + Outputs: + + [ + 'Param1' => 'Value1', + 'Param2' => 'Value2' + ] +*/ diff --git a/user_guide_src/source/incoming/incomingrequest/15.php b/user_guide_src/source/incoming/incomingrequest/15.php index c6e85bfef577..95d483206211 100644 --- a/user_guide_src/source/incoming/incomingrequest/15.php +++ b/user_guide_src/source/incoming/incomingrequest/15.php @@ -2,8 +2,12 @@ var_dump($request->headers()); -[ - 'Host' => CodeIgniter\HTTP\Header, - 'Cache-Control' => CodeIgniter\HTTP\Header, - 'Accept' => CodeIgniter\HTTP\Header, -]; +/* + Outputs: + + [ + 'Host' => CodeIgniter\HTTP\Header, + 'Cache-Control' => CodeIgniter\HTTP\Header, + 'Accept' => CodeIgniter\HTTP\Header, + ] +*/ diff --git a/user_guide_src/source/libraries/uri/026.php b/user_guide_src/source/libraries/uri/026.php index 53a42eb788f4..6491e0d20ca4 100644 --- a/user_guide_src/source/libraries/uri/026.php +++ b/user_guide_src/source/libraries/uri/026.php @@ -2,9 +2,12 @@ $segments = $uri->getSegments(); -// $segments = -[ - 0 => 'users', - 1 => '15', - 2 => 'profile' -]; +/* + Produces: + + [ + 0 => 'users', + 1 => '15', + 2 => 'profile' + ] +*/ diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php index aec2e980c5dc..8792a8a8f728 100644 --- a/user_guide_src/source/libraries/validation/009.php +++ b/user_guide_src/source/libraries/validation/009.php @@ -1,19 +1,22 @@ [ - 'name' => 'Joe Smith', - 'friends' => [ - [ - 'name' => 'Fred Flinstone', - ], - [ - 'name' => 'Wilma', - ], +/* + The data to test: + + [ + 'contacts' => [ + 'name' => 'Joe Smith', + 'friends' => [ + [ + 'name' => 'Fred Flinstone', + ], + [ + 'name' => 'Wilma', + ], + ] ] ] -]; +*/ // Joe Smith $validation->setRules([ diff --git a/user_guide_src/source/libraries/validation/011.php b/user_guide_src/source/libraries/validation/011.php index 66fbcda5e1a7..ec6b9c9adbab 100644 --- a/user_guide_src/source/libraries/validation/011.php +++ b/user_guide_src/source/libraries/validation/011.php @@ -1,13 +1,16 @@ [ - 1, - 2, - 3, +/* + The data to test: + + [ + 'user_ids' => [ + 1, + 2, + 3, + ] ] -]; +*/ // Rule $validation->setRules([ diff --git a/user_guide_src/source/libraries/validation/027.php b/user_guide_src/source/libraries/validation/027.php index c6afaf393f2a..e633f5cdd1e3 100644 --- a/user_guide_src/source/libraries/validation/027.php +++ b/user_guide_src/source/libraries/validation/027.php @@ -2,8 +2,11 @@ $errors = $validation->getErrors(); -// Returns: -[ - 'field1' => 'error message', - 'field2' => 'error message', -]; +/* + Produces: + + [ + 'field1' => 'error message', + 'field2' => 'error message', + ] +*/ diff --git a/user_guide_src/source/testing/benchmark/004.php b/user_guide_src/source/testing/benchmark/004.php index bf84bf6ed21f..3048a2851ff3 100644 --- a/user_guide_src/source/testing/benchmark/004.php +++ b/user_guide_src/source/testing/benchmark/004.php @@ -2,11 +2,14 @@ $timers = $benchmark->getTimers(); -// Timers = -[ - 'render view' => [ - 'start' => 1234567890, - 'end' => 1345678920, - 'duration' => 15.4315, // number of seconds +/* + Produces: + + [ + 'render view' => [ + 'start' => 1234567890, + 'end' => 1345678920, + 'duration' => 15.4315, // number of seconds + ] ] -]; +*/ diff --git a/user_guide_src/source/testing/response/030.php b/user_guide_src/source/testing/response/030.php index 7dfa89e51cc1..53887b278572 100644 --- a/user_guide_src/source/testing/response/030.php +++ b/user_guide_src/source/testing/response/030.php @@ -1,12 +1,16 @@ 'bar']; +/* + Response body is this: + + ['foo' => 'bar']; +*/ $json = $result->getJSON(); /* $json is this: + { "foo": "bar" } diff --git a/user_guide_src/source/testing/response/032.php b/user_guide_src/source/testing/response/032.php index c2d093443b9d..6de63a9cfce8 100644 --- a/user_guide_src/source/testing/response/032.php +++ b/user_guide_src/source/testing/response/032.php @@ -1,9 +1,12 @@ ['key-a', 'key-b'], -]; +/* + Response body is this: + + [ + 'config' => ['key-a', 'key-b'], + ] +*/ // Is true $result->assertJSONFragment(['config' => ['key-a']]); From 36976f5945df3484ddf33c0df217e862aee9961a Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Thu, 24 Feb 2022 11:38:03 +0100 Subject: [PATCH 1634/2325] Fix output of getHeaderLine. Co-authored-by: kenjis --- user_guide_src/source/incoming/message/005.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/message/005.php b/user_guide_src/source/incoming/message/005.php index ea54a21a4407..b67851a9258a 100644 --- a/user_guide_src/source/incoming/message/005.php +++ b/user_guide_src/source/incoming/message/005.php @@ -4,5 +4,5 @@ /* Outputs: - en, en-US + 'en,en-US' */ From 087ef29cb56348c1fb437a474b7e23a04ed60c9c Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Thu, 24 Feb 2022 11:52:32 +0100 Subject: [PATCH 1635/2325] Fix delimiters in renumerate script. --- user_guide_src/{renumerate.php => renumerate} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename user_guide_src/{renumerate.php => renumerate} (93%) diff --git a/user_guide_src/renumerate.php b/user_guide_src/renumerate similarity index 93% rename from user_guide_src/renumerate.php rename to user_guide_src/renumerate index ca885551d168..814ea18430d0 100644 --- a/user_guide_src/renumerate.php +++ b/user_guide_src/renumerate @@ -81,7 +81,7 @@ rename($sectionFolder . '/' . $prefix . $exampleName . '.php', $sectionFolder . '/' . $newName . '.php'); // Fix include link - $sectionContent = preg_replace(preg_quote(str_replace($exampleName, $prefix . $exampleName, $includeStrings[$exampleIndex]), '~'), str_replace($exampleName, $newName, $includeStrings[$exampleIndex]), $sectionContent, 1, $count); + $sectionContent = preg_replace('~' . preg_quote(str_replace($exampleName, $prefix . $exampleName, $includeStrings[$exampleIndex]), '~') . '~', str_replace($exampleName, $newName, $includeStrings[$exampleIndex]), $sectionContent, 1, $count); } // Write new content to rst From da96ff3519b5a0eca6fa9e61d834cabe6cd575c9 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Thu, 24 Feb 2022 11:58:29 +0100 Subject: [PATCH 1636/2325] Revert extraction of single array elements. --- user_guide_src/source/libraries/pagination.rst | 10 ++++------ user_guide_src/source/libraries/pagination/011.php | 3 --- user_guide_src/source/libraries/pagination/012.php | 3 --- user_guide_src/source/libraries/validation.rst | 5 ++--- user_guide_src/source/libraries/validation/025.php | 3 --- 5 files changed, 6 insertions(+), 18 deletions(-) delete mode 100644 user_guide_src/source/libraries/pagination/011.php delete mode 100644 user_guide_src/source/libraries/pagination/012.php delete mode 100644 user_guide_src/source/libraries/validation/025.php diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 8a79531326d6..5eec05cf0c43 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -166,16 +166,14 @@ methods, respectively. To change the way those are displayed application-wide, y For example, say you create a new view file that works with the Foundation CSS framework, and you place that file at **app/Views/Pagers/foundation_full.php**. Since the **application** directory is namespaced as ``App``, and all directories underneath it map directly to segments of the namespace, you can locate -the view file through it's namespace: +the view file through it's namespace:: -.. literalinclude:: pagination/011.php - :lines: 2- + 'default_full' => 'App\Views\Pagers\foundation_full' Since it is under the standard **app/Views** directory, though, you do not need to namespace it since the -``view()`` method can locate it by filename. In that case, you can simply give the sub-directory and file name: +``view()`` method can locate it by filename. In that case, you can simply give the sub-directory and file name:: -.. literalinclude:: pagination/012.php - :lines: 2- + 'default_full' => 'Pagers/foundation_full' Once you have created the view and set it in the configuration, it will automatically be used. You don't have to replace the existing templates. You can create as many additional templates as you need in the configuration diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php deleted file mode 100644 index 8000e782737c..000000000000 --- a/user_guide_src/source/libraries/pagination/011.php +++ /dev/null @@ -1,3 +0,0 @@ - 'App\Views\Pagers\foundation_full']; diff --git a/user_guide_src/source/libraries/pagination/012.php b/user_guide_src/source/libraries/pagination/012.php deleted file mode 100644 index 5a00b20f70c3..000000000000 --- a/user_guide_src/source/libraries/pagination/012.php +++ /dev/null @@ -1,3 +0,0 @@ - 'Pagers/foundation_full']; diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index a74bca7904d8..4f53eab33260 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -435,10 +435,9 @@ Or as a labeled style: :lines: 2- If you’d like to include a field’s “human” name, or the optional parameter some rules allow for (such as max_length), -or the value that was validated you can add the ``{field}``, ``{param}`` and ``{value}`` tags to your message, respectively: +or the value that was validated you can add the ``{field}``, ``{param}`` and ``{value}`` tags to your message, respectively:: -.. literalinclude:: validation/025.php - :lines: 2- + 'min_length' => 'Supplied value ({value}) for {field} must have at least {param} characters.' On a field with the human name Username and a rule of ``min_length[6]`` with a value of “Pizza”, an error would display: “Supplied value (Pizza) for Username must have at least 6 characters.” diff --git a/user_guide_src/source/libraries/validation/025.php b/user_guide_src/source/libraries/validation/025.php deleted file mode 100644 index a71f46f29f92..000000000000 --- a/user_guide_src/source/libraries/validation/025.php +++ /dev/null @@ -1,3 +0,0 @@ - 'Supplied value ({value}) for {field} must have at least {param} characters.']; From c2883077a6acf35cd53676935f4d35583ee126f8 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Thu, 24 Feb 2022 11:58:35 +0100 Subject: [PATCH 1637/2325] Add return statement for localization arrays. --- user_guide_src/source/outgoing/localization/007.php | 4 +++- user_guide_src/source/outgoing/localization/008.php | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/localization/007.php b/user_guide_src/source/outgoing/localization/007.php index e2de3a4644d6..adc24e5d6242 100644 --- a/user_guide_src/source/outgoing/localization/007.php +++ b/user_guide_src/source/outgoing/localization/007.php @@ -1,3 +1,5 @@ 'The actual message to be shown.']; +return [ + 'languageKey' => 'The actual message to be shown.' +]; diff --git a/user_guide_src/source/outgoing/localization/008.php b/user_guide_src/source/outgoing/localization/008.php index 1b9b79725642..319fa750429b 100644 --- a/user_guide_src/source/outgoing/localization/008.php +++ b/user_guide_src/source/outgoing/localization/008.php @@ -1,6 +1,6 @@ [ 'nested' => [ 'key' => 'The actual message to be shown.', From c4d4281274fb016517d197674eb284151dc70dba Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Thu, 24 Feb 2022 11:59:15 +0100 Subject: [PATCH 1638/2325] Remove wrong semicolon in response body. --- user_guide_src/source/testing/response/030.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/testing/response/030.php b/user_guide_src/source/testing/response/030.php index 53887b278572..060f5c551a87 100644 --- a/user_guide_src/source/testing/response/030.php +++ b/user_guide_src/source/testing/response/030.php @@ -3,7 +3,7 @@ /* Response body is this: - ['foo' => 'bar']; + ['foo' => 'bar'] */ $json = $result->getJSON(); From b7bb3f29afad9e577b3fd406ca88e8ded08b5f6d Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Thu, 24 Feb 2022 12:00:43 +0100 Subject: [PATCH 1639/2325] Renumerate incomingrequest, pagination and validation. --- .../source/incoming/incomingrequest.rst | 76 +++++++++---------- .../incomingrequest/{1.php => 001.php} | 0 .../incomingrequest/{2.php => 002.php} | 0 .../incomingrequest/{3.php => 003.php} | 0 .../incomingrequest/{4.php => 004.php} | 0 .../incomingrequest/{5.php => 005.php} | 0 .../incomingrequest/{6.php => 006.php} | 0 .../incomingrequest/{7.php => 007.php} | 0 .../incomingrequest/{8.php => 008.php} | 0 .../incomingrequest/{9.php => 009.php} | 0 .../incomingrequest/{10.php => 010.php} | 0 .../incomingrequest/{11.php => 011.php} | 0 .../incomingrequest/{12.php => 012.php} | 0 .../incomingrequest/{13.php => 013.php} | 0 .../incomingrequest/{14.php => 014.php} | 0 .../incomingrequest/{15.php => 015.php} | 0 .../incomingrequest/{16.php => 016.php} | 0 .../incomingrequest/{17.php => 017.php} | 0 .../incomingrequest/{18.php => 018.php} | 0 .../incomingrequest/{19.php => 019.php} | 0 .../incomingrequest/{20.php => 020.php} | 0 .../incomingrequest/{21.php => 021.php} | 0 .../incomingrequest/{22.php => 022.php} | 0 .../incomingrequest/{23.php => 023.php} | 0 .../incomingrequest/{24.php => 024.php} | 0 .../incomingrequest/{25.php => 025.php} | 0 .../incomingrequest/{26.php => 026.php} | 0 .../incomingrequest/{27.php => 027.php} | 0 .../incomingrequest/{28.php => 028.php} | 0 .../incomingrequest/{29.php => 029.php} | 0 .../incomingrequest/{30.php => 030.php} | 0 .../incomingrequest/{31.php => 031.php} | 0 .../incomingrequest/{32.php => 032.php} | 0 .../incomingrequest/{33.php => 033.php} | 0 .../incomingrequest/{34.php => 034.php} | 0 .../incomingrequest/{35.php => 035.php} | 0 .../incomingrequest/{36.php => 036.php} | 0 .../incomingrequest/{37.php => 037.php} | 0 .../incomingrequest/{38.php => 038.php} | 0 .../source/libraries/pagination.rst | 8 +- .../source/libraries/pagination/011.php | 7 ++ .../source/libraries/pagination/012.php | 39 ++++++++++ .../source/libraries/pagination/013.php | 8 +- .../source/libraries/pagination/014.php | 66 ++++++++-------- .../source/libraries/pagination/015.php | 7 -- .../source/libraries/pagination/016.php | 37 --------- .../source/libraries/validation.rst | 26 +++---- .../source/libraries/validation/025.php | 19 +++++ .../source/libraries/validation/026.php | 25 +++--- .../source/libraries/validation/027.php | 11 +-- .../source/libraries/validation/028.php | 4 +- .../source/libraries/validation/029.php | 12 +-- .../source/libraries/validation/030.php | 13 ++-- .../source/libraries/validation/031.php | 7 +- .../source/libraries/validation/032.php | 14 +++- .../source/libraries/validation/033.php | 18 ++--- .../source/libraries/validation/034.php | 11 ++- .../source/libraries/validation/035.php | 13 +--- .../source/libraries/validation/036.php | 35 ++++++++- .../source/libraries/validation/037.php | 40 ++-------- .../source/libraries/validation/038.php | 10 --- 61 files changed, 253 insertions(+), 253 deletions(-) rename user_guide_src/source/incoming/incomingrequest/{1.php => 001.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{2.php => 002.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{3.php => 003.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{4.php => 004.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{5.php => 005.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{6.php => 006.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{7.php => 007.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{8.php => 008.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{9.php => 009.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{10.php => 010.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{11.php => 011.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{12.php => 012.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{13.php => 013.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{14.php => 014.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{15.php => 015.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{16.php => 016.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{17.php => 017.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{18.php => 018.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{19.php => 019.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{20.php => 020.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{21.php => 021.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{22.php => 022.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{23.php => 023.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{24.php => 024.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{25.php => 025.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{26.php => 026.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{27.php => 027.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{28.php => 028.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{29.php => 029.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{30.php => 030.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{31.php => 031.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{32.php => 032.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{33.php => 033.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{34.php => 034.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{35.php => 035.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{36.php => 036.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{37.php => 037.php} (100%) rename user_guide_src/source/incoming/incomingrequest/{38.php => 038.php} (100%) create mode 100644 user_guide_src/source/libraries/pagination/011.php create mode 100644 user_guide_src/source/libraries/pagination/012.php delete mode 100644 user_guide_src/source/libraries/pagination/015.php delete mode 100644 user_guide_src/source/libraries/pagination/016.php create mode 100644 user_guide_src/source/libraries/validation/025.php delete mode 100644 user_guide_src/source/libraries/validation/038.php diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index 70692d1aa4c4..2691a034aeaf 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -15,18 +15,18 @@ Accessing the Request An instance of the request class already populated for you if the current class is a descendant of ``CodeIgniter\Controller`` and can be accessed as a class property: -.. literalinclude:: incomingrequest/1.php +.. literalinclude:: incomingrequest/001.php If you are not within a controller, but still need access to the application's Request object, you can get a copy of it through the :doc:`Services class `: -.. literalinclude:: incomingrequest/2.php +.. literalinclude:: incomingrequest/002.php :lines: 2- It's preferable, though, to pass the request in as a dependency if the class is anything other than the controller, where you can save it as a class property: -.. literalinclude:: incomingrequest/3.php +.. literalinclude:: incomingrequest/003.php Determining Request Type ------------------------ @@ -34,7 +34,7 @@ Determining Request Type A request could be of several types, including an AJAX request or a request from the command line. This can be checked with the ``isAJAX()`` and ``isCLI()`` methods: -.. literalinclude:: incomingrequest/4.php +.. literalinclude:: incomingrequest/004.php :lines: 2- .. note:: The ``isAJAX()`` method depends on the ``X-Requested-With`` header, @@ -43,7 +43,7 @@ be checked with the ``isAJAX()`` and ``isCLI()`` methods: You can check the HTTP method that this request represents with the ``method()`` method: -.. literalinclude:: incomingrequest/5.php +.. literalinclude:: incomingrequest/005.php :lines: 2- By default, the method is returned as a lower-case string (i.e., 'get', 'post', etc). You can get an @@ -54,7 +54,7 @@ uppercase version by wrapping the call in ``str_to_upper()``:: You can also check if the request was made through and HTTPS connection with the ``isSecure()`` method: -.. literalinclude:: incomingrequest/6.php +.. literalinclude:: incomingrequest/006.php :lines: 2- Retrieving Input @@ -67,12 +67,12 @@ will return null if the item doesn't exist, and you can have the data filtered. use data without having to test whether an item exists first. In other words, normally you might do something like this: -.. literalinclude:: incomingrequest/7.php +.. literalinclude:: incomingrequest/007.php :lines: 2- With CodeIgniter’s built in methods you can simply do this: -.. literalinclude:: incomingrequest/8.php +.. literalinclude:: incomingrequest/008.php :lines: 2- The ``getVar()`` method will pull from $_REQUEST, so will return any data from $_GET, $POST, or $_COOKIE. While this @@ -97,7 +97,7 @@ You can grab the contents of php://input as a JSON stream with ``getJSON()``. method if you know that you're expecting JSON. -.. literalinclude:: incomingrequest/9.php +.. literalinclude:: incomingrequest/009.php :lines: 2- By default, this will return any objects in the JSON data as objects. If you want that converted to associative @@ -115,7 +115,7 @@ You can get a specific piece of data from a JSON stream by passing a variable na data that you want or you can use "dot" notation to dig into the JSON to get data that is not on the root level. -.. literalinclude:: incomingrequest/10.php +.. literalinclude:: incomingrequest/010.php :lines: 2- @@ -124,7 +124,7 @@ true in the second parameter. This function can also be used if you can't guaran correct ``CONTENT_TYPE`` header. -.. literalinclude:: incomingrequest/11.php +.. literalinclude:: incomingrequest/011.php :lines: 2- .. note:: See the documentation for ``dot_array_search()`` in the ``Array`` helper for more information on "dot" notation. @@ -133,12 +133,12 @@ correct ``CONTENT_TYPE`` header. Finally, you can grab the contents of php://input as a raw stream with ``getRawInput()``: -.. literalinclude:: incomingrequest/12.php +.. literalinclude:: incomingrequest/012.php :lines: 2- This will retrieve data and convert it to an array. Like this: -.. literalinclude:: incomingrequest/13.php +.. literalinclude:: incomingrequest/013.php :lines: 2- **Filtering Input Data** @@ -150,7 +150,7 @@ filter types `_. Filtering a POST variable would look like this: -.. literalinclude:: incomingrequest/14.php +.. literalinclude:: incomingrequest/014.php :lines: 2- All of the methods mentioned above support the filter type passed in as the second parameter, with the @@ -163,28 +163,28 @@ You can get access to any header that was sent with the request with the ``heade an array of all headers, with the key as the name of the header, and the value is an instance of ``CodeIgniter\HTTP\Header``: -.. literalinclude:: incomingrequest/15.php +.. literalinclude:: incomingrequest/015.php :lines: 2- If you only need a single header, you can pass the name into the ``header()`` method. This will grab the specified header object in a case-insensitive manner if it exists. If not, then it will return ``null``: -.. literalinclude:: incomingrequest/16.php +.. literalinclude:: incomingrequest/016.php :lines: 2- You can always use ``hasHeader()`` to see if the header existed in this request: -.. literalinclude:: incomingrequest/17.php +.. literalinclude:: incomingrequest/017.php :lines: 2- If you need the value of header as a string with all values on one line, you can use the ``getHeaderLine()`` method: -.. literalinclude:: incomingrequest/18.php +.. literalinclude:: incomingrequest/018.php :lines: 2- If you need the entire header, with the name and values in a single string, simply cast the header as a string: -.. literalinclude:: incomingrequest/19.php +.. literalinclude:: incomingrequest/019.php :lines: 2- The Request URL @@ -193,19 +193,19 @@ The Request URL You can retrieve a :doc:`URI ` object that represents the current URI for this request through the ``$request->getUri()`` method. You can cast this object as a string to get a full URL for the current request: -.. literalinclude:: incomingrequest/20.php +.. literalinclude:: incomingrequest/020.php :lines: 2- The object gives you full abilities to grab any part of the request on it's own: -.. literalinclude:: incomingrequest/21.php +.. literalinclude:: incomingrequest/021.php :lines: 2- You can work with the current URI string (the path relative to your baseURL) using the ``getPath()`` and ``setPath()`` methods. Note that this relative path on the shared instance of ``IncomingRequest`` is what the :doc:`URL Helper ` functions use, so this is a helpful way to "spoof" an incoming request for testing: -.. literalinclude:: incomingrequest/22.php +.. literalinclude:: incomingrequest/022.php :lines: 2- Uploaded Files @@ -215,20 +215,20 @@ Information about all uploaded files can be retrieved through ``$request->getFil ``CodeIgniter\HTTP\Files\UploadedFile`` instance. This helps to ease the pain of working with uploaded files, and uses best practices to minimize any security risks. -.. literalinclude:: incomingrequest/23.php +.. literalinclude:: incomingrequest/023.php :lines: 2- See :ref:`Working with Uploaded Files ` for the details. You can retrieve a single file uploaded on its own, based on the filename given in the HTML file input: -.. literalinclude:: incomingrequest/24.php +.. literalinclude:: incomingrequest/024.php :lines: 2- You can retrieve an array of same-named files uploaded as part of a multi-file upload, based on the filename given in the HTML file input: -.. literalinclude:: incomingrequest/25.php +.. literalinclude:: incomingrequest/025.php :lines: 2- .. note:: The files here correspond to ``$_FILES``. Even if a user just clicks submit button of a form and does not upload any file, the file will still exist. You can check that the file was actually uploaded by the ``isValid()`` method in UploadedFile. See :ref:`verify-a-file` for more details. @@ -238,7 +238,7 @@ Content Negotiation You can easily negotiate content types with the request through the ``negotiate()`` method: -.. literalinclude:: incomingrequest/26.php +.. literalinclude:: incomingrequest/026.php :lines: 2- See the :doc:`Content Negotiation ` page for more details. @@ -303,7 +303,7 @@ The methods provided by the parent classes that are available are: The first parameter will contain the name of the REQUEST item you are looking for: - .. literalinclude:: incomingrequest/27.php + .. literalinclude:: incomingrequest/027.php :lines: 2- The method returns null if the item you are attempting to retrieve @@ -312,7 +312,7 @@ The methods provided by the parent classes that are available are: The second optional parameter lets you run the data through the PHP's filters. Pass in the desired filter type as the second parameter: - .. literalinclude:: incomingrequest/28.php + .. literalinclude:: incomingrequest/028.php :lines: 2- To return an array of all POST items call without any parameters. @@ -321,18 +321,18 @@ The methods provided by the parent classes that are available are: first parameter to null while setting the second parameter to the filter you want to use: - .. literalinclude:: incomingrequest/29.php + .. literalinclude:: incomingrequest/029.php :lines: 2- To return an array of multiple POST parameters, pass all the required keys as an array: - .. literalinclude:: incomingrequest/30.php + .. literalinclude:: incomingrequest/030.php :lines: 2- Same rule applied here, to retrieve the parameters with filtering, set the second parameter to the filter type to apply: - .. literalinclude:: incomingrequest/31.php + .. literalinclude:: incomingrequest/031.php :lines: 2- .. php:method:: getGet([$index = null[, $filter = null[, $flags = null]]]) @@ -373,7 +373,7 @@ The methods provided by the parent classes that are available are: It will search through both POST and GET streams for data, looking first in POST, and then in GET: - .. literalinclude:: incomingrequest/32.php + .. literalinclude:: incomingrequest/032.php :lines: 2- .. php:method:: getGetPost([$index = null[, $filter = null[, $flags = null]]]) @@ -390,7 +390,7 @@ The methods provided by the parent classes that are available are: It will search through both POST and GET streams for data, looking first in GET, and then in POST: - .. literalinclude:: incomingrequest/33.php + .. literalinclude:: incomingrequest/033.php :lines: 2- .. php:method:: getCookie([$index = null[, $filter = null[, $flags = null]]]) @@ -406,12 +406,12 @@ The methods provided by the parent classes that are available are: This method is identical to ``getPost()`` and ``getGet()``, only it fetches cookie data: - .. literalinclude:: incomingrequest/34.php + .. literalinclude:: incomingrequest/034.php :lines: 2- To return an array of multiple cookie values, pass all the required keys as an array: - .. literalinclude:: incomingrequest/35.php + .. literalinclude:: incomingrequest/035.php :lines: 2- .. note:: Unlike the :doc:`Cookie Helper <../helpers/cookie_helper>` @@ -432,13 +432,13 @@ The methods provided by the parent classes that are available are: This method is identical to the ``getPost()``, ``getGet()`` and ``getCookie()`` methods, only it fetches getServer data (``$_SERVER``): - .. literalinclude:: incomingrequest/36.php + .. literalinclude:: incomingrequest/036.php :lines: 2- To return an array of multiple ``$_SERVER`` values, pass all the required keys as an array. - .. literalinclude:: incomingrequest/37.php + .. literalinclude:: incomingrequest/037.php :lines: 2- .. php:method:: getUserAgent([$filter = null]) @@ -450,7 +450,7 @@ The methods provided by the parent classes that are available are: This method returns the User Agent string from the SERVER data: - .. literalinclude:: incomingrequest/38.php + .. literalinclude:: incomingrequest/038.php :lines: 2- .. php:method:: getPath() diff --git a/user_guide_src/source/incoming/incomingrequest/1.php b/user_guide_src/source/incoming/incomingrequest/001.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/1.php rename to user_guide_src/source/incoming/incomingrequest/001.php diff --git a/user_guide_src/source/incoming/incomingrequest/2.php b/user_guide_src/source/incoming/incomingrequest/002.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/2.php rename to user_guide_src/source/incoming/incomingrequest/002.php diff --git a/user_guide_src/source/incoming/incomingrequest/3.php b/user_guide_src/source/incoming/incomingrequest/003.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/3.php rename to user_guide_src/source/incoming/incomingrequest/003.php diff --git a/user_guide_src/source/incoming/incomingrequest/4.php b/user_guide_src/source/incoming/incomingrequest/004.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/4.php rename to user_guide_src/source/incoming/incomingrequest/004.php diff --git a/user_guide_src/source/incoming/incomingrequest/5.php b/user_guide_src/source/incoming/incomingrequest/005.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/5.php rename to user_guide_src/source/incoming/incomingrequest/005.php diff --git a/user_guide_src/source/incoming/incomingrequest/6.php b/user_guide_src/source/incoming/incomingrequest/006.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/6.php rename to user_guide_src/source/incoming/incomingrequest/006.php diff --git a/user_guide_src/source/incoming/incomingrequest/7.php b/user_guide_src/source/incoming/incomingrequest/007.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/7.php rename to user_guide_src/source/incoming/incomingrequest/007.php diff --git a/user_guide_src/source/incoming/incomingrequest/8.php b/user_guide_src/source/incoming/incomingrequest/008.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/8.php rename to user_guide_src/source/incoming/incomingrequest/008.php diff --git a/user_guide_src/source/incoming/incomingrequest/9.php b/user_guide_src/source/incoming/incomingrequest/009.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/9.php rename to user_guide_src/source/incoming/incomingrequest/009.php diff --git a/user_guide_src/source/incoming/incomingrequest/10.php b/user_guide_src/source/incoming/incomingrequest/010.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/10.php rename to user_guide_src/source/incoming/incomingrequest/010.php diff --git a/user_guide_src/source/incoming/incomingrequest/11.php b/user_guide_src/source/incoming/incomingrequest/011.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/11.php rename to user_guide_src/source/incoming/incomingrequest/011.php diff --git a/user_guide_src/source/incoming/incomingrequest/12.php b/user_guide_src/source/incoming/incomingrequest/012.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/12.php rename to user_guide_src/source/incoming/incomingrequest/012.php diff --git a/user_guide_src/source/incoming/incomingrequest/13.php b/user_guide_src/source/incoming/incomingrequest/013.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/13.php rename to user_guide_src/source/incoming/incomingrequest/013.php diff --git a/user_guide_src/source/incoming/incomingrequest/14.php b/user_guide_src/source/incoming/incomingrequest/014.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/14.php rename to user_guide_src/source/incoming/incomingrequest/014.php diff --git a/user_guide_src/source/incoming/incomingrequest/15.php b/user_guide_src/source/incoming/incomingrequest/015.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/15.php rename to user_guide_src/source/incoming/incomingrequest/015.php diff --git a/user_guide_src/source/incoming/incomingrequest/16.php b/user_guide_src/source/incoming/incomingrequest/016.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/16.php rename to user_guide_src/source/incoming/incomingrequest/016.php diff --git a/user_guide_src/source/incoming/incomingrequest/17.php b/user_guide_src/source/incoming/incomingrequest/017.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/17.php rename to user_guide_src/source/incoming/incomingrequest/017.php diff --git a/user_guide_src/source/incoming/incomingrequest/18.php b/user_guide_src/source/incoming/incomingrequest/018.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/18.php rename to user_guide_src/source/incoming/incomingrequest/018.php diff --git a/user_guide_src/source/incoming/incomingrequest/19.php b/user_guide_src/source/incoming/incomingrequest/019.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/19.php rename to user_guide_src/source/incoming/incomingrequest/019.php diff --git a/user_guide_src/source/incoming/incomingrequest/20.php b/user_guide_src/source/incoming/incomingrequest/020.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/20.php rename to user_guide_src/source/incoming/incomingrequest/020.php diff --git a/user_guide_src/source/incoming/incomingrequest/21.php b/user_guide_src/source/incoming/incomingrequest/021.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/21.php rename to user_guide_src/source/incoming/incomingrequest/021.php diff --git a/user_guide_src/source/incoming/incomingrequest/22.php b/user_guide_src/source/incoming/incomingrequest/022.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/22.php rename to user_guide_src/source/incoming/incomingrequest/022.php diff --git a/user_guide_src/source/incoming/incomingrequest/23.php b/user_guide_src/source/incoming/incomingrequest/023.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/23.php rename to user_guide_src/source/incoming/incomingrequest/023.php diff --git a/user_guide_src/source/incoming/incomingrequest/24.php b/user_guide_src/source/incoming/incomingrequest/024.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/24.php rename to user_guide_src/source/incoming/incomingrequest/024.php diff --git a/user_guide_src/source/incoming/incomingrequest/25.php b/user_guide_src/source/incoming/incomingrequest/025.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/25.php rename to user_guide_src/source/incoming/incomingrequest/025.php diff --git a/user_guide_src/source/incoming/incomingrequest/26.php b/user_guide_src/source/incoming/incomingrequest/026.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/26.php rename to user_guide_src/source/incoming/incomingrequest/026.php diff --git a/user_guide_src/source/incoming/incomingrequest/27.php b/user_guide_src/source/incoming/incomingrequest/027.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/27.php rename to user_guide_src/source/incoming/incomingrequest/027.php diff --git a/user_guide_src/source/incoming/incomingrequest/28.php b/user_guide_src/source/incoming/incomingrequest/028.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/28.php rename to user_guide_src/source/incoming/incomingrequest/028.php diff --git a/user_guide_src/source/incoming/incomingrequest/29.php b/user_guide_src/source/incoming/incomingrequest/029.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/29.php rename to user_guide_src/source/incoming/incomingrequest/029.php diff --git a/user_guide_src/source/incoming/incomingrequest/30.php b/user_guide_src/source/incoming/incomingrequest/030.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/30.php rename to user_guide_src/source/incoming/incomingrequest/030.php diff --git a/user_guide_src/source/incoming/incomingrequest/31.php b/user_guide_src/source/incoming/incomingrequest/031.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/31.php rename to user_guide_src/source/incoming/incomingrequest/031.php diff --git a/user_guide_src/source/incoming/incomingrequest/32.php b/user_guide_src/source/incoming/incomingrequest/032.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/32.php rename to user_guide_src/source/incoming/incomingrequest/032.php diff --git a/user_guide_src/source/incoming/incomingrequest/33.php b/user_guide_src/source/incoming/incomingrequest/033.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/33.php rename to user_guide_src/source/incoming/incomingrequest/033.php diff --git a/user_guide_src/source/incoming/incomingrequest/34.php b/user_guide_src/source/incoming/incomingrequest/034.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/34.php rename to user_guide_src/source/incoming/incomingrequest/034.php diff --git a/user_guide_src/source/incoming/incomingrequest/35.php b/user_guide_src/source/incoming/incomingrequest/035.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/35.php rename to user_guide_src/source/incoming/incomingrequest/035.php diff --git a/user_guide_src/source/incoming/incomingrequest/36.php b/user_guide_src/source/incoming/incomingrequest/036.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/36.php rename to user_guide_src/source/incoming/incomingrequest/036.php diff --git a/user_guide_src/source/incoming/incomingrequest/37.php b/user_guide_src/source/incoming/incomingrequest/037.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/37.php rename to user_guide_src/source/incoming/incomingrequest/037.php diff --git a/user_guide_src/source/incoming/incomingrequest/38.php b/user_guide_src/source/incoming/incomingrequest/038.php similarity index 100% rename from user_guide_src/source/incoming/incomingrequest/38.php rename to user_guide_src/source/incoming/incomingrequest/038.php diff --git a/user_guide_src/source/libraries/pagination.rst b/user_guide_src/source/libraries/pagination.rst index 5eec05cf0c43..37163c1ec14d 100644 --- a/user_guide_src/source/libraries/pagination.rst +++ b/user_guide_src/source/libraries/pagination.rst @@ -179,7 +179,7 @@ Once you have created the view and set it in the configuration, it will automati replace the existing templates. You can create as many additional templates as you need in the configuration file. A common situation would be needing different styles for the frontend and the backend of your application. -.. literalinclude:: pagination/013.php +.. literalinclude:: pagination/011.php :lines: 2- Once configured, you can specify it as a the last parameter in the ``links()``, ``simpleLinks()``, and ``makeLinks()`` @@ -196,7 +196,7 @@ When you create a new view, you only need to create the code that is needed for You should not create unnecessary wrapping divs since it might be used in multiple places and you only limit their usefulness. It is easiest to demonstrate creating a new view by showing you the existing ``default_full`` template: -.. literalinclude:: pagination/014.php +.. literalinclude:: pagination/012.php **setSurroundCount()** @@ -226,7 +226,7 @@ result set. Returns an array of data about all of the numbered links. Each link's array contains the uri for the link, the title, which is just the number, and a boolean that tells whether the link is the current/active link or not: -.. literalinclude:: pagination/015.php +.. literalinclude:: pagination/013.php :lines: 2- In the code presented for the standard pagination structure, the methods ``getPrevious()`` and ``getNext()`` are used to obtain the links to the previous and next pagination groups respectively. @@ -235,7 +235,7 @@ If you want to use the pagination structure where prev and next will be links to See following an example with these changes: -.. literalinclude:: pagination/016.php +.. literalinclude:: pagination/014.php **hasPreviousPage()** & **hasNextPage()** diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php new file mode 100644 index 000000000000..fa59edbacf9b --- /dev/null +++ b/user_guide_src/source/libraries/pagination/011.php @@ -0,0 +1,7 @@ + 'CodeIgniter\Pager\Views\default_full', + 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', + 'front_full' => 'App\Views\Pagers\foundation_full', +]; diff --git a/user_guide_src/source/libraries/pagination/012.php b/user_guide_src/source/libraries/pagination/012.php new file mode 100644 index 000000000000..00bdee764c7f --- /dev/null +++ b/user_guide_src/source/libraries/pagination/012.php @@ -0,0 +1,39 @@ +setSurroundCount(2) ?> + + diff --git a/user_guide_src/source/libraries/pagination/013.php b/user_guide_src/source/libraries/pagination/013.php index fa59edbacf9b..43a8f2624d64 100644 --- a/user_guide_src/source/libraries/pagination/013.php +++ b/user_guide_src/source/libraries/pagination/013.php @@ -1,7 +1,7 @@ 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', - 'front_full' => 'App\Views\Pagers\foundation_full', +$link = [ + 'active' => false, + 'uri' => 'https://example.com/foo?page=2', + 'title' => 1, ]; diff --git a/user_guide_src/source/libraries/pagination/014.php b/user_guide_src/source/libraries/pagination/014.php index 00bdee764c7f..e827bd15a457 100644 --- a/user_guide_src/source/libraries/pagination/014.php +++ b/user_guide_src/source/libraries/pagination/014.php @@ -1,39 +1,37 @@ -setSurroundCount(2) ?> - -
    +?> + + + diff --git a/user_guide_src/source/outgoing/table/015.php b/user_guide_src/source/outgoing/table/015.php index 4f4349ec66b4..5bc5a7029ed3 100644 --- a/user_guide_src/source/outgoing/table/015.php +++ b/user_guide_src/source/outgoing/table/015.php @@ -6,15 +6,28 @@ $table->generate($newList); -// Generates a table with this prototype +?> +
    BlueRedGreenBlueRedGreen
    - - - - - - - - + + + + + + + + + + + + + + + + + + + +
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    onetwothree
    fourfivesix
    seveneightnine
    teneleventwelve
    diff --git a/user_guide_src/source/outgoing/view_decorators.rst b/user_guide_src/source/outgoing/view_decorators.rst index 1620446785b0..83f3154f54c5 100644 --- a/user_guide_src/source/outgoing/view_decorators.rst +++ b/user_guide_src/source/outgoing/view_decorators.rst @@ -18,7 +18,6 @@ the resulting HTML. Once created, the class must be registered in ``app/Config/View.php``: .. literalinclude:: view_decorators/002.php - :lines: 2- Now that it's registered the decorator will be called for every view that is rendered or parsed. Decorators are called in the order specified in this configuration setting. diff --git a/user_guide_src/source/outgoing/view_layouts.rst b/user_guide_src/source/outgoing/view_layouts.rst index 2dca286b6052..2600b1c08922 100644 --- a/user_guide_src/source/outgoing/view_layouts.rst +++ b/user_guide_src/source/outgoing/view_layouts.rst @@ -80,7 +80,6 @@ Rendering the View Rendering the view and it's layout is done exactly as any other view would be displayed within a controller: .. literalinclude:: view_layouts/001.php - :lines: 2- It renders the View **app/Views/some_view.php** and if it extends ``default``, the Layout **app/Views/default.php** is also used automatically. diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index ef17f8d7fa6e..cee76727ef84 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -46,13 +46,11 @@ Using the View Parser Class The simplest method to load the parser class is through its service: .. literalinclude:: view_parser/001.php - :lines: 2- Alternately, if you are not using the ``Parser`` class as your default renderer, you can instantiate it directly: .. literalinclude:: view_parser/002.php - :lines: 2- Then you can use any of the three standard rendering methods that it provides: ``render(viewpath, options, save)``, ``setVar(name, value, context)`` and @@ -90,7 +88,6 @@ You can use the ``render()`` method to parse (or render) simple templates, like this: .. literalinclude:: view_parser/003.php - :lines: 2- View parameters are passed to ``setData()`` as an associative array of data to be replaced in the template. In the above example, the @@ -114,7 +111,6 @@ Several options can be passed to the ``render()`` or ``renderString()`` methods. substitutions; default is **true** .. literalinclude:: view_parser/004.php - :lines: 2- *********************** Substitution Variations @@ -128,7 +124,6 @@ replacement of pseudo-variables where the corresponding data parameter has either a scalar or string value, as in this example: .. literalinclude:: view_parser/005.php - :lines: 2- The ``Parser`` takes substitution a lot further with "variable pairs", used for nested substitutions or looping, and with some advanced @@ -176,7 +171,6 @@ parse single variables, except, you will add a multi-dimensional array corresponding to your variable pair data. Consider this example: .. literalinclude:: view_parser/006.php - :lines: 2- The value for the pseudo-variable ``blog_entries`` is a sequential array of associative arrays. The outer level does not have keys associated @@ -187,7 +181,6 @@ multi-dimensional array, you can simply use the database ``getResultArray()`` method: .. literalinclude:: view_parser/007.php - :lines: 2- If the array you are trying to loop over contains objects instead of arrays, the parser will first look for an ``asArray()`` method on the object. If it exists, @@ -206,7 +199,6 @@ A nested substitution happens when the value for a pseudo-variable is an associative array of values, like a record from a database: .. literalinclude:: view_parser/008.php - :lines: 2- The value for the pseudo-variable ``blog_entry`` is an associative array. The key/value pairs defined inside it will be exposed inside @@ -250,12 +242,10 @@ data pairs into the inner substitution. The following example is not impacted by cascading: .. literalinclude:: view_parser/009.php - :lines: 2- This example gives different results, depending on cascading: .. literalinclude:: view_parser/010.php - :lines: 2- Preventing Parsing ================== @@ -414,7 +404,6 @@ You can easily create your own filters by editing **app/Config/View.php** and ad callable: .. literalinclude:: view_parser/012.php - :lines: 2- PHP Native functions as Filters ------------------------------- @@ -424,7 +413,6 @@ You can use native php function as filters by editing **app/Config/View.php** an function prefixed with: .. literalinclude:: view_parser/013.php - :lines: 2- Parser Plugins ============== @@ -482,24 +470,20 @@ At its simplest, all you need to do to register a new plugin and make it ready f used within the template file. The value is any valid PHP callable, including static class methods, and closures: .. literalinclude:: view_parser/014.php - :lines: 2- Any closures that are being used must be defined in the config file's constructor: .. literalinclude:: view_parser/015.php - :lines: 2- If the callable is on its own, it is treated as a single tag, not a open/close one. It will be replaced by the return value from the plugin: .. literalinclude:: view_parser/016.php - :lines: 2- If the callable is wrapped in an array, it is treated as an open/close tag pair that can operate on any of the content between its tags: .. literalinclude:: view_parser/017.php - :lines: 2- *********** Usage Notes @@ -509,20 +493,17 @@ If you include substitution parameters that are not referenced in your template, they are ignored: .. literalinclude:: view_parser/018.php - :lines: 2- If you do not include a substitution parameter that is referenced in your template, the original pseudo-variable is shown in the result: .. literalinclude:: view_parser/019.php - :lines: 2- If you provide a string substitution parameter when an array is expected, i.e., for a variable pair, the substitution is done for the opening variable pair tag, but the closing variable pair tag is not rendered properly: .. literalinclude:: view_parser/020.php - :lines: 2- View Fragments ============== @@ -558,7 +539,6 @@ An example with the iteration controlled in the controller, using a view fragment: .. literalinclude:: view_parser/021.php - :lines: 2- Result:: @@ -584,7 +564,6 @@ Class Reference Builds the output based upon a file name and any data that has already been set: .. literalinclude:: view_parser/022.php - :lines: 2- Options supported: @@ -609,7 +588,6 @@ Class Reference Builds the output based upon a provided template source and any data that has already been set: .. literalinclude:: view_parser/023.php - :lines: 2- Options supported, and behavior, as above. @@ -623,7 +601,6 @@ Class Reference Sets several pieces of view data at once: .. literalinclude:: view_parser/024.php - :lines: 2- Supported escape contexts: html, css, js, url, or attr or raw. If 'raw', no escaping will happen. @@ -639,7 +616,6 @@ Class Reference Sets a single piece of view data: .. literalinclude:: view_parser/025.php - :lines: 2- Supported escape contexts: html, css, js, url, attr or raw. If 'raw', no escaping will happen. @@ -654,4 +630,3 @@ Class Reference Override the substitution field delimiters: .. literalinclude:: view_parser/026.php - :lines: 2- diff --git a/user_guide_src/source/outgoing/view_renderer.rst b/user_guide_src/source/outgoing/view_renderer.rst index bf1570cede9c..feda1affda3d 100644 --- a/user_guide_src/source/outgoing/view_renderer.rst +++ b/user_guide_src/source/outgoing/view_renderer.rst @@ -15,13 +15,11 @@ exactly what you want, you may find times where you want to work with it more di In that case you can access the View service directly: .. literalinclude:: view_renderer/001.php - :lines: 2- Alternately, if you are not using the ``View`` class as your default renderer, you can instantiate it directly: .. literalinclude:: view_renderer/002.php - :lines: 2- .. important:: You should create services only within controllers. If you need access to the View class from a library, you should set that as a dependency @@ -54,7 +52,6 @@ The ``setVar()`` and ``setData()`` methods are chainable, allowing you to combin number of different calls together in a chain: .. literalinclude:: view_renderer/003.php - :lines: 2- Escaping Data ============= @@ -66,7 +63,6 @@ escape the data for. See below for context descriptions. If you don't want the data to be escaped, you can pass ``null`` or ``'raw'`` as the final parameter to each function: .. literalinclude:: view_renderer/004.php - :lines: 2- If you choose not to escape data, or you are passing in an object instance, you can manually escape the data within the view with the ``esc()`` function. The first parameter is the string to escape. The second parameter is the @@ -123,7 +119,6 @@ Class Reference Builds the output based upon a file name and any data that has already been set: .. literalinclude:: view_renderer/005.php - :lines: 2- .. php:method:: renderString($view[, $options[, $saveData = false]]) :noindex: @@ -137,7 +132,6 @@ Class Reference Builds the output based upon a view fragment and any data that has already been set: .. literalinclude:: view_renderer/006.php - :lines: 2- .. warning:: This could be used for displaying content that might have been stored in a database, but you need to be aware that this is a potential security vulnerability, @@ -155,7 +149,6 @@ Class Reference Sets several pieces of view data at once: .. literalinclude:: view_renderer/007.php - :lines: 2- Supported escape contexts: ``html``, ``css``, ``js``, ``url``, or ``attr`` or ``raw``. If ``'raw'``, no escaping will happen. @@ -175,7 +168,6 @@ Class Reference Sets a single piece of view data: .. literalinclude:: view_renderer/008.php - :lines: 2- Supported escape contexts: ``html``, ``css``, ``js``, ``url``, ``attr`` or ``raw``. If ``'raw'``, no escaping will happen. diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 2960a3c3c79a..55da9ed98a22 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -38,7 +38,6 @@ Displaying a View To load and display a particular view file you will use the following function: .. literalinclude:: views/001.php - :lines: 2- Where *name* is the name of your view file. @@ -73,7 +72,6 @@ Your view files can also be stored within sub-directories if you prefer that typ When doing so you will need to include the directory name loading the view. Example: .. literalinclude:: views/004.php - :lines: 2- Namespaced Views ================ @@ -87,7 +85,6 @@ under the namespace ``Example\Blog``, you could retrieve view files as if they w example, you could load the **blog_view.php** file from **example/blog/Views** by prepending the namespace to the view name: .. literalinclude:: views/005.php - :lines: 2- .. _caching-views: @@ -98,13 +95,11 @@ You can cache a view with the ``view`` command by passing a ``cache`` option wit the view for, in the third parameter: .. literalinclude:: views/006.php - :lines: 2- By default, the view will be cached using the same name as the view file itself. You can customize this by passing along ``cache_name`` and the cache ID you wish to use: .. literalinclude:: views/007.php - :lines: 2- Adding Dynamic Data to the View =============================== @@ -113,7 +108,6 @@ Data is passed from the controller to the view by way of an array in the second Here's an example: .. literalinclude:: views/008.php - :lines: 2- Let's try it with your controller file. Open it and add this code: @@ -138,7 +132,6 @@ other views, potentially causing issues. If you would prefer the data to persist into the `$option` array in the third parameter. .. literalinclude:: views/010.php - :lines: 2- Additionally, if you would like the default functionality of the view function to be that it does save the data between calls, you can set ``$saveData`` to **true** in **app/Config/Views.php**. diff --git a/user_guide_src/source/testing/benchmark.rst b/user_guide_src/source/testing/benchmark.rst index 33fe7c200be9..1e7a5c9607b7 100644 --- a/user_guide_src/source/testing/benchmark.rst +++ b/user_guide_src/source/testing/benchmark.rst @@ -26,12 +26,10 @@ The ``start()`` methods takes a single parameter: the name of this timer. You ca of the timer. It is only used for you to reference later to know which measurement is which: .. literalinclude:: benchmark/001.php - :lines: 2- The ``stop()`` method takes the name of the timer that you want to stop as the only parameter, also: .. literalinclude:: benchmark/002.php - :lines: 2- The name is not case-sensitive, but otherwise must match the name you gave it when you started the timer. @@ -39,7 +37,6 @@ Alternatively, you can use the :doc:`global function and stop timers: .. literalinclude:: benchmark/003.php - :lines: 2- Viewing Your Benchmark Points ============================= @@ -49,13 +46,11 @@ not automatically display them, though. You can retrieve all of your timers by c This returns an array of benchmark information, including start, end, and duration: .. literalinclude:: benchmark/004.php - :lines: 2- You can change the precision of the calculated duration by passing in the number of decimal places you want to be shown as the only parameter. The default value is 4 numbers behind the decimal point: .. literalinclude:: benchmark/005.php - :lines: 2- The timers are automatically displayed in the :doc:`Debub Toolbar `. @@ -67,7 +62,6 @@ the duration of a single timer, in seconds, with the `getElapsedTime()` method. the timer to display. The second is the number of decimal places to display. This defaults to 4: .. literalinclude:: benchmark/006.php - :lines: 2- ================== Using the Iterator @@ -86,7 +80,6 @@ added to the Iterator class through the `add()` method. The first parameter is a this test by. The second parameter is the Closure, itself: .. literalinclude:: benchmark/007.php - :lines: 2- Running the Tasks ================= @@ -96,10 +89,8 @@ By default, it will run each task 1000 times. This is probably sufficient for mo to run the tests more times than that, you can pass the number as the first parameter: .. literalinclude:: benchmark/008.php - :lines: 2- Once it has run, it will return an HTML table with the results of the test. If you don't want the results displayed, you can pass in `false` as the second parameter: .. literalinclude:: benchmark/009.php - :lines: 2- diff --git a/user_guide_src/source/testing/controllers.rst b/user_guide_src/source/testing/controllers.rst index 590e491ed687..604a118e4ead 100644 --- a/user_guide_src/source/testing/controllers.rst +++ b/user_guide_src/source/testing/controllers.rst @@ -37,14 +37,12 @@ Specifies the class name of the controller to test. The first parameter must be (i.e., include the namespace): .. literalinclude:: controllers/003.php - :lines: 2- **execute(string $method, ...$params)** Executes the specified method within the controller. The first parameter is the name of the method to run: .. literalinclude:: controllers/004.php - :lines: 2- By specifying the second and subsequent parameters, you can pass them to the controller method. @@ -56,7 +54,6 @@ for details. Allows you to pass in a modified version of **Config\App.php** to test with different settings: .. literalinclude:: controllers/005.php - :lines: 2- If you do not provide one, the application's App config file will be used. @@ -65,7 +62,6 @@ If you do not provide one, the application's App config file will be used. Allows you to provide an **IncomingRequest** instance tailored to your testing needs: .. literalinclude:: controllers/006.php - :lines: 2- If you do not provide one, a new IncomingRequest instance with the default application values will be passed into your controller. @@ -75,7 +71,6 @@ into your controller. Allows you to provide a **Response** instance: .. literalinclude:: controllers/007.php - :lines: 2- If you do not provide one, a new Response instance with the default application values will be passed into your controller. @@ -85,7 +80,6 @@ into your controller. Allows you to provide a **Logger** instance: .. literalinclude:: controllers/008.php - :lines: 2- If you do not provide one, a new Logger instance with the default configuration values will be passed into your controller. @@ -97,7 +91,6 @@ This is helpful if you need to check URI segments within your controller. The on representing a valid URI: .. literalinclude:: controllers/009.php - :lines: 2- It is a good practice to always provide the URI during testing to avoid surprises. @@ -107,7 +100,6 @@ Allows you to provide a custom body for the request. This can be helpful when te you need to set a JSON value as the body. The only parameter is a string that represents the body of the request: .. literalinclude:: controllers/010.php - :lines: 2- Checking the Response ===================== @@ -149,7 +141,6 @@ a "live" project, but (for example) if you wanted to simulate a filter triggerin on an unfiltered route you could add it to the Config: .. literalinclude:: controllers/012.php - :lines: 2- Checking Routes --------------- @@ -169,7 +160,6 @@ a large performance advantage over Controller and HTTP Testing. Usage example: .. literalinclude:: controllers/013.php - :lines: 2- Calling Filter Methods ---------------------- @@ -188,7 +178,6 @@ method using these properties to test your Filter code safely and check the resu Usage example: .. literalinclude:: controllers/014.php - :lines: 2- Notice how the ``Closure`` can take input parameters which are passed to your filter method. @@ -201,19 +190,15 @@ to streamline your test methods. The **assertFilter()** method checks that the given route at position uses the filter (by its alias): .. literalinclude:: controllers/015.php - :lines: 2- The **assertNotFilter()** method checks that the given route at position does not use the filter (by its alias): .. literalinclude:: controllers/016.php - :lines: 2- The **assertHasFilters()** method checks that the given route at position has at least one filter set: .. literalinclude:: controllers/017.php - :lines: 2- The **assertNotHasFilters()** method checks that the given route at position has no filters set: .. literalinclude:: controllers/018.php - :lines: 2- diff --git a/user_guide_src/source/testing/database.rst b/user_guide_src/source/testing/database.rst index 614099449e29..680c0a3f3518 100644 --- a/user_guide_src/source/testing/database.rst +++ b/user_guide_src/source/testing/database.rst @@ -110,14 +110,12 @@ must be present within the path specified in ``$basePath``. Asserts that a row with criteria matching the key/value pairs in ``$criteria`` DOES NOT exist in the database. .. literalinclude:: database/004.php - :lines: 2- **seeInDatabase($table, $criteria)** Asserts that a row with criteria matching the key/value pairs in ``$criteria`` DOES exist in the database. .. literalinclude:: database/005.php - :lines: 2- **grabFromDatabase($table, $column, $criteria)** @@ -125,7 +123,6 @@ Returns the value of ``$column`` from the specified table where the row matches row is found, it will only test against the first one. .. literalinclude:: database/006.php - :lines: 2- **hasInDatabase($table, $data)** @@ -133,11 +130,9 @@ Inserts a new row into the database. This row is removed after the current test array with the data to insert into the table. .. literalinclude:: database/007.php - :lines: 2- **seeNumRecords($expected, $table, $criteria)** Asserts that a number of matching rows are found in the database that match ``$criteria``. .. literalinclude:: database/008.php - :lines: 2- diff --git a/user_guide_src/source/testing/debugging.rst b/user_guide_src/source/testing/debugging.rst index 0b841517846e..fc04a08921d5 100644 --- a/user_guide_src/source/testing/debugging.rst +++ b/user_guide_src/source/testing/debugging.rst @@ -32,7 +32,6 @@ The ``d()`` method dumps all of the data it knows about the contents passed as t allows the script to continue executing: .. literalinclude:: debugging/001.php - :lines: 2- **dd()** @@ -43,7 +42,6 @@ This method is identical to ``d()``, except that it also ``dies()`` and no furth This provides a backtrace to the current execution point, with Kint's own unique spin: .. literalinclude:: debugging/002.php - :lines: 2- For more information, see `Kint's page `_. @@ -79,7 +77,6 @@ can easily make your own to customize the toolbar. To determine which collectors the **app/Config/Toolbar.php** configuration file: .. literalinclude:: debugging/003.php - :lines: 2- Comment out any collectors that you do not want to show. Add custom Collectors here by providing the fully-qualified class name. The exact collectors that appear here will affect which tabs are shown, as well as what information is @@ -159,7 +156,6 @@ The ``formatTimelineData()`` method must return an array of arrays formatted in it to sort it correctly and display the correct information. The inner arrays must include the following information: .. literalinclude:: debugging/005.php - :lines: 2- Providing Vars -------------- @@ -173,4 +169,3 @@ The ``getVarData()`` method should return an array containing arrays of key/valu outer array's key is the name of the section on the Vars tab: .. literalinclude:: debugging/006.php - :lines: 2- diff --git a/user_guide_src/source/testing/fabricator.rst b/user_guide_src/source/testing/fabricator.rst index 3e419353ef07..9acec31b5db2 100644 --- a/user_guide_src/source/testing/fabricator.rst +++ b/user_guide_src/source/testing/fabricator.rst @@ -17,7 +17,6 @@ Supported Models You may use your own custom models by ensuring they implement ``CodeIgniter\Test\Interfaces\FabricatorModel``: .. literalinclude:: fabricator/001.php - :lines: 2- .. note:: In addition to methods, the interface outlines some necessary properties for the target model. Please see the interface code for details. @@ -27,12 +26,10 @@ Loading Fabricators At its most basic a fabricator takes the model to act on: .. literalinclude:: fabricator/002.php - :lines: 2- The parameter can be a string specifying the name of the model, or an instance of the model itself: .. literalinclude:: fabricator/003.php - :lines: 2- Defining Formatters =================== @@ -44,7 +41,6 @@ correspond with common formatters, or if you don't care much about the content o of the time you will want to specify the formatters to use as the second parameter to the constructor: .. literalinclude:: fabricator/004.php - :lines: 2- You can also change the formatters after a fabricator is initialized by using the ``setFormatters()`` method. @@ -55,7 +51,6 @@ to further limit the scope of random data. A fabricator will check its represent method where you can define exactly what the faked data should look like: .. literalinclude:: fabricator/005.php - :lines: 2- Notice in this example how the first three values are equivalent to the formatters from before. However for ``avatar`` we have requested an image size other than the default and ``login`` uses a conditional based on app configuration, @@ -64,7 +59,6 @@ You may want to keep your test data separate from your production models, so it a child class in your test support folder: .. literalinclude:: fabricator/006.php - :lines: 2- Localization ============ @@ -73,7 +67,6 @@ Faker supports a lot of different locales. Check their documentation to determin support your locale. Specify a locale in the third parameter while initiating a fabricator: .. literalinclude:: fabricator/007.php - :lines: 2- If no locale is specified it will use the one defined in **app/Config/App.php** as ``defaultLocale``. You can check the locale of an existing fabricator using its ``getLocale()`` method. @@ -84,23 +77,19 @@ Faking the Data Once you have a properly-initialized fabricator it is easy to generate test data with the ``make()`` command: .. literalinclude:: fabricator/008.php - :lines: 2- You might get back something like this: .. literalinclude:: fabricator/009.php - :lines: 2- You can also get a lot of them back by supplying a count: .. literalinclude:: fabricator/010.php - :lines: 2- The return type of ``make()`` mimics what is defined in the representative model, but you can force a type using the methods directly: .. literalinclude:: fabricator/011.php - :lines: 2- The return from ``make()`` is ready to be used in tests or inserted into the database. Alternatively ``Fabricator`` includes the ``create()`` command to insert it for you, and return the result. Due @@ -108,19 +97,16 @@ to model callbacks, database formatting, and special keys like primary and times from ``create()`` can differ from ``make()``. You might get back something like this: .. literalinclude:: fabricator/012.php - :lines: 2- Similar to ``make()`` you can supply a count to insert and return an array of objects: .. literalinclude:: fabricator/013.php - :lines: 2- Finally, there may be times you want to test with the full database object but you are not actually using a database. ``create()`` takes a second parameter to allowing mocking the object, returning the object with extra database fields above without actually touching the database: .. literalinclude:: fabricator/014.php - :lines: 2- Specifying Test Data ==================== @@ -130,23 +116,19 @@ compromising your formatters configuration. Rather then creating a new fabricato you can use ``setOverrides()`` to specify the value for any fields: .. literalinclude:: fabricator/015.php - :lines: 2- Now any data generated with ``make()`` or ``create()`` will always use "Bobby" for the ``first`` field: .. literalinclude:: fabricator/016.php - :lines: 2- ``setOverrides()`` can take a second parameter to indicate whether this should be a persistent override or only for a single action: .. literalinclude:: fabricator/017.php - :lines: 2- Notice after the first return the fabricator stops using the overrides: .. literalinclude:: fabricator/018.php - :lines: 2- If no second parameter is supplied then passed values will persist by default. @@ -157,12 +139,10 @@ Often all you will need is a one-and-done fake object for testing. The Test Help the ``fake($model, $overrides, $persist = true)`` function to do just this: .. literalinclude:: fabricator/019.php - :lines: 2- This is equivalent to: .. literalinclude:: fabricator/020.php - :lines: 2- If you just need a fake object without saving it to the database you can pass false into the persist parameter. @@ -179,7 +159,6 @@ Now you want to create fake users but don't want to assign them to a non-existan Your model's fake method could look like this: .. literalinclude:: fabricator/021.php - :lines: 2- Now creating a new user will ensure it is a part of a valid group: ``$user = fake(UserModel::class);`` diff --git a/user_guide_src/source/testing/feature.rst b/user_guide_src/source/testing/feature.rst index 36ab73d4eea2..df40937ed14b 100644 --- a/user_guide_src/source/testing/feature.rst +++ b/user_guide_src/source/testing/feature.rst @@ -31,12 +31,10 @@ superglobal variables for the HTTP verb you are using. So, a method of **GET** w populated, while a **post** request would have the **$_POST** array populated. .. literalinclude:: feature/002.php - :lines: 2- Shorthand methods for each of the HTTP verbs exist to ease typing and make things clearer: .. literalinclude:: feature/003.php - :lines: 2- .. note:: The ``$params`` array does not make sense for every HTTP verb, but is included for consistency. @@ -47,7 +45,6 @@ You can use a custom collection of routes by passing an array of "routes" into t override any existing routes in the system: .. literalinclude:: feature/004.php - :lines: 2- Each of the "routes" is a 3 element array containing the HTTP verb (or "add" for all), the URI to match, and the routing destination. @@ -60,7 +57,6 @@ of key/value pairs that should exist within the ``$_SESSION`` variable when this that the current values of ``$_SESSION`` should be used. This is handy for testing authentication and more. .. literalinclude:: feature/005.php - :lines: 2- Setting Headers --------------- @@ -69,7 +65,6 @@ You can set header values with the ``withHeaders()`` method. This takes an array passed as a header into the call: .. literalinclude:: feature/006.php - :lines: 2- Bypassing Events ---------------- @@ -78,7 +73,6 @@ Events are handy to use in your application, but can be problematic during testi to send out emails. You can tell the system to skip any event handling with the ``skipEvents()`` method: .. literalinclude:: feature/007.php - :lines: 2- Formatting The Request ----------------------- @@ -89,7 +83,6 @@ body of the request in the given format. This will also set the `Content-Type` h This is useful when testing JSON or XML API's so that you can set the request in the form that the controller will expect. .. literalinclude:: feature/008.php - :lines: 2- Setting the Body ---------------- diff --git a/user_guide_src/source/testing/mocking.rst b/user_guide_src/source/testing/mocking.rst index 8c4b8b54d222..967cfba7f634 100644 --- a/user_guide_src/source/testing/mocking.rst +++ b/user_guide_src/source/testing/mocking.rst @@ -17,7 +17,6 @@ Cache You can mock the cache with the ``mock()`` method, using the ``CacheFactory`` as its only parameter. .. literalinclude:: mocking/001.php - :lines: 2- While this returns an instance of ``CodeIgniter\Test\Mock\MockCache`` that you can use directly, it also inserts the mock into the Service class, so any calls within your code to ``service('cache')`` or ``Config\Services::cache()`` will @@ -33,7 +32,6 @@ You can instruct the mocked cache handler to never do any caching with the ``byp using the dummy handler and ensures that your test does not rely on cached data for your tests. .. literalinclude:: mocking/002.php - :lines: 2- Available Assertions -------------------- @@ -41,4 +39,3 @@ Available Assertions The following new assertions are available on the mocked class for using during testing: .. literalinclude:: mocking/003.php - :lines: 2- diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 1b32a3337c63..b689a8e90259 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -86,26 +86,22 @@ Most tests require some preparation in order to run correctly. PHPUnit's ``TestC to help with staging and clean up: .. literalinclude:: overview/003.php - :lines: 2- 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 parent as well so extended test cases do not interfere with staging: .. literalinclude:: overview/004.php - :lines: 2- 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: .. literalinclude:: overview/005.php - :lines: 2- You can see by default these handle the mocking of intrusive services, but your class may override that or provide their own: .. literalinclude:: overview/006.php - :lines: 2- Traits ------ @@ -117,7 +113,6 @@ of your test cases you could create an authentication trait with a set up method logged in user: .. literalinclude:: overview/007.php - :lines: 2- Additional Assertions --------------------- @@ -129,21 +124,18 @@ Additional Assertions Ensure that something you expected to be logged actually was: .. literalinclude:: overview/008.php - :lines: 2- **assertEventTriggered($eventName)** Ensure that an event you expected to be triggered actually was: .. literalinclude:: overview/009.php - :lines: 2- **assertHeaderEmitted($header, $ignoreCase = false)** Ensure that a header or cookie was actually emitted: .. literalinclude:: overview/010.php - :lines: 2- Note: the test case with this should be `run as a separate process in PHPunit `_. @@ -153,7 +145,6 @@ in PHPunit `_. @@ -164,7 +155,6 @@ For extended execution time testing, tests that the absolute difference between expected and actual time is within the prescribed tolerance: .. literalinclude:: overview/012.php - :lines: 2- The above test will allow the actual time to be either 660 or 661 seconds. @@ -174,7 +164,6 @@ For extended execution time testing, tests that the absolute difference between expected and actual time, formatted as strings, is within the prescribed tolerance: .. literalinclude:: overview/013.php - :lines: 2- The above test will allow the actual time to be either 660 or 661 seconds. @@ -190,7 +179,6 @@ Enables you to call private methods from outside the class. This returns a funct parameter is an instance of the class to test. The second parameter is the name of the method you want to call. .. literalinclude:: overview/014.php - :lines: 2- **getPrivateProperty($instance, $property)** @@ -198,7 +186,6 @@ Retrieves the value of a private/protected class property from an instance of a instance of the class to test. The second parameter is the name of the property. .. literalinclude:: overview/015.php - :lines: 2- **setPrivateProperty($instance, $property, $value)** @@ -206,7 +193,6 @@ Set a protected value within a class instance. The first parameter is an instanc parameter is the name of the property to set the value of. The third parameter is the value to set it to: .. literalinclude:: overview/016.php - :lines: 2- Mocking Services ================ @@ -222,7 +208,6 @@ This method allows you to define the exact instance that will be returned by the set properties of a service so that it behaves in a certain way, or replace a service with a mocked class. .. literalinclude:: overview/017.php - :lines: 2- The first parameter is the service that you are replacing. The name must match the function name in the Services class exactly. The second parameter is the instance to replace it with. @@ -246,7 +231,6 @@ static methods like **Services**, but they take an additional preceding paramete component name: .. literalinclude:: overview/018.php - :lines: 2- .. note:: All component Factories are reset by default between each test. Modify your test case's ``$setUpMethods`` if you need instances to persist. @@ -261,4 +245,3 @@ might be helpful. The ``CITestStreamFilter`` helps you capture the output from t An example demonstrating this inside one of your test cases: .. literalinclude:: overview/019.php - :lines: 2- diff --git a/user_guide_src/source/testing/response.rst b/user_guide_src/source/testing/response.rst index e39df524affc..99c44be38c62 100644 --- a/user_guide_src/source/testing/response.rst +++ b/user_guide_src/source/testing/response.rst @@ -8,7 +8,6 @@ from your test cases. Usually a ``TestResponse`` will be provided for you as a r create your own directly using any ``ResponseInterface``: .. literalinclude:: response/001.php - :lines: 2- .. contents:: :local: @@ -28,14 +27,12 @@ Accessing Request/Response You can access directly the Request object, if it was set during testing: .. literalinclude:: response/002.php - :lines: 2- **response()** This allows you direct access to the response object: .. literalinclude:: response/003.php - :lines: 2- Checking Response Status ------------------------ @@ -46,28 +43,24 @@ Returns a boolean true/false based on whether the response is perceived to be "o a response status code in the 200 or 300's. An empty body is not considered valid, unless in redirects. .. literalinclude:: response/004.php - :lines: 2- **assertOK()** This assertion simply uses the **isOK()** method to test a response. **assertNotOK** is the inverse of this assertion. .. literalinclude:: response/005.php - :lines: 2- **isRedirect()** Returns a boolean true/false based on whether the response is a redirected response. .. literalinclude:: response/006.php - :lines: 2- **assertRedirect()** Asserts that the Response is an instance of RedirectResponse. **assertNotRedirect** is the inverse of this assertion. .. literalinclude:: response/007.php - :lines: 2- **assertRedirectTo()** @@ -75,21 +68,18 @@ Asserts that the Response is an instance of RedirectResponse and the destination matches the uri given. .. literalinclude:: response/008.php - :lines: 2- **getRedirectUrl()** Returns the URL set for a RedirectResponse, or null for failure. .. literalinclude:: response/009.php - :lines: 2- **assertStatus(int $code)** Asserts that the HTTP status code returned matches $code. .. literalinclude:: response/010.php - :lines: 2- Session Assertions ------------------ @@ -100,14 +90,12 @@ Asserts that a value exists in the resulting session. If $value is passed, will matches what was specified. .. literalinclude:: response/011.php - :lines: 2- **assertSessionMissing(string $key)** Asserts that the resulting session does not include the specified $key. .. literalinclude:: response/012.php - :lines: 2- Header Assertions ----------------- @@ -118,14 +106,12 @@ Asserts that a header named **$key** exists in the response. If **$value** is no the values match. .. literalinclude:: response/013.php - :lines: 2- **assertHeaderMissing(string $key)** Asserts that a header name **$key** does not exist in the response. .. literalinclude:: response/014.php - :lines: 2- Cookie Assertions ----------------- @@ -136,14 +122,12 @@ Asserts that a cookie named **$key** exists in the response. If **$value** is no the values match. You can set the cookie prefix, if needed, by passing it in as the third parameter. .. literalinclude:: response/015.php - :lines: 2- **assertCookieMissing(string $key)** Asserts that a cookie named **$key** does not exist in the response. .. literalinclude:: response/016.php - :lines: 2- **assertCookieExpired(string $key, string $prefix = '')** @@ -151,7 +135,6 @@ Asserts that a cookie named **$key** exists, but has expired. You can set the co in as the second parameter. .. literalinclude:: response/017.php - :lines: 2- DOM Helpers ----------- @@ -163,33 +146,27 @@ The **see()** method checks the text on the page to see if it exists either by i a tag, as specified by type, class, or id: .. literalinclude:: response/018.php - :lines: 2- The **dontSee()** method is the exact opposite: .. literalinclude:: response/019.php - :lines: 2- The **seeElement()** and **dontSeeElement()** are very similar to the previous methods, but do not look at the values of the elements. Instead, they simply check that the elements exist on the page: .. literalinclude:: response/020.php - :lines: 2- You can use **seeLink()** to ensure that a link appears on the page with the specified text: .. literalinclude:: response/021.php - :lines: 2- The **seeInField()** method checks for any input tags exist with the name and value: .. literalinclude:: response/022.php - :lines: 2- Finally, you can check if a checkbox exists and is checked with the **seeCheckboxIsChecked()** method: .. literalinclude:: response/023.php - :lines: 2- DOM Assertions -------------- @@ -203,21 +180,18 @@ Asserts that text/HTML is on the page, either by itself or - more specifically - a tag, as specified by type, class, or id: .. literalinclude:: response/024.php - :lines: 2- **assertDontSee(string $search = null, string $element = null)** Asserts the exact opposite of the **assertSee()** method: .. literalinclude:: response/025.php - :lines: 2- **assertSeeElement(string $search)** Similar to **assertSee()**, however this only checks for an existing element. It does not check for specific text: .. literalinclude:: response/026.php - :lines: 2- **assertDontSeeElement(string $search)** @@ -225,21 +199,18 @@ Similar to **assertSee()**, however this only checks for an existing element tha specific text: .. literalinclude:: response/027.php - :lines: 2- **assertSeeLink(string $text, string $details=null)** Asserts that an anchor tag is found with matching **$text** as the body of the tag: .. literalinclude:: response/028.php - :lines: 2- **assertSeeInField(string $field, string $value=null)** Asserts that an input tag exists with the name and value: .. literalinclude:: response/029.php - :lines: 2- Working With JSON ----------------- @@ -252,12 +223,10 @@ can help to test the responses. This method will return the body of the response as a JSON string: .. literalinclude:: response/030.php - :lines: 2- You can use this method to determine if ``$response`` actually holds JSON content: .. literalinclude:: response/031.php - :lines: 2- .. note:: Be aware that the JSON string will be pretty-printed in the result. @@ -266,7 +235,6 @@ You can use this method to determine if ``$response`` actually holds JSON conten Asserts that $fragment is found within the JSON response. It does not need to match the entire JSON value. .. literalinclude:: response/032.php - :lines: 2- **assertJSONExact($test)** diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index acf04e52d0f6..7925edc05fd1 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -14,7 +14,6 @@ Before creating a form, let's enable the CSRF protection. Open the **app/Config/Filters.php** file and update the ``$methods`` property like the following: .. literalinclude:: create_news_items/001.php - :lines: 2- It configures the CSRF filter to be enabled for all **POST** requests. You can read more about the CSRF protection in :doc:`Security ` library. @@ -67,7 +66,6 @@ passed the validation rules. You'll use the :doc:`form validation <../libraries/validation>` library to do this. .. literalinclude:: create_news_items/002.php - :lines: 2- The code above adds a lot of functionality. First we load the NewsModel. After that, we check if we deal with the **POST** request and then @@ -130,7 +128,6 @@ as a method instead of a news item's slug. You can read more about different routing types :doc:`here `. .. literalinclude:: create_news_items/004.php - :lines: 2- Now point your browser to your local development environment where you installed CodeIgniter and add ``/news/create`` to the URL. diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index f51e68c5abc7..9a144dd06c19 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -93,7 +93,6 @@ some additional tools to make working with data simpler. Add the following code to your model. .. literalinclude:: news_section/002.php - :lines: 2- With this code, you can perform two different queries. You can get all news records, or get a news item by its slug. You might have @@ -140,7 +139,6 @@ nothing is displayed yet. The next thing to do is, passing this data to the views. Modify the ``index()`` method to look like this: .. literalinclude:: news_section/004.php - :lines: 2- The code above gets all news records from the model and assigns it to a variable. The value for the title is also assigned to the ``$data['title']`` @@ -167,7 +165,6 @@ add some code to the controller and create a new view. Go back to the ``News`` controller and update the ``view()`` method with the following: .. literalinclude:: news_section/006.php - :lines: 2- Instead of calling the ``getNews()`` method without a parameter, the ``$slug`` variable is passed, so it will return the specific news item. @@ -187,7 +184,6 @@ going directly to the ``Pages`` controller. The first line routes URI's with a slug to the ``view()`` method in the ``News`` controller. .. literalinclude:: news_section/008.php - :lines: 2- Point your browser to your "news" page, i.e., ``localhost:8080/news``, you should see a list of the news items, each of which has a link diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index a5bcaf7fa94b..090a4d79e2f8 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -102,7 +102,6 @@ page actually exists. This will be the body of the ``view()`` method in the ``Pages`` controller created above: .. literalinclude:: static_pages/002.php - :lines: 2- Now, when the requested page does exist, it is loaded, including the header and footer, and displayed to the user. If the requested page doesn't exist, a "404 @@ -196,7 +195,6 @@ section of the configuration file. The only uncommented line there to start with should be: .. literalinclude:: static_pages/003.php - :lines: 2- This directive says that any incoming request without any content specified should be handled by the ``index()`` method inside the ``Home`` controller. @@ -204,7 +202,6 @@ specified should be handled by the ``index()`` method inside the ``Home`` contro Add the following line, **after** the route directive for '/'. .. literalinclude:: static_pages/004.php - :lines: 2- CodeIgniter reads its routing rules from top to bottom and routes the request to the first matching rule. Each rule is a regular expression From e5bc03d8037fc1791ef912a85938fd0dabdfd00c Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 26 Feb 2022 07:59:09 +0800 Subject: [PATCH 1663/2325] Update tests/system/Database/Builder/BaseTest.php Co-authored-by: kenjis --- tests/system/Database/Builder/BaseTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/system/Database/Builder/BaseTest.php b/tests/system/Database/Builder/BaseTest.php index 5a2a4f1578db..c7386066aa74 100644 --- a/tests/system/Database/Builder/BaseTest.php +++ b/tests/system/Database/Builder/BaseTest.php @@ -63,6 +63,5 @@ public function testSubquerySameBaseBuilderObject() $builder = $this->db->table('users'); $builder->fromSubquery($builder, 'sub'); - $builder->getCompiledSelect(); } } From 6b35f0375de8d0733a1fe6cb1d93418d21dd425b Mon Sep 17 00:00:00 2001 From: MGatner Date: Sat, 26 Feb 2022 00:47:27 +0000 Subject: [PATCH 1664/2325] Set release date --- CHANGELOG.md | 2 +- user_guide_src/source/changelogs/v4.1.9.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85928ad2b111..d2bf2ed7119c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## [v4.1.9](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.9) (2022-02-xx) +## [v4.1.9](https://github.com/codeigniter4/CodeIgniter4/tree/v4.1.9) (2022-02-25) [Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.1.8...v4.1.9) diff --git a/user_guide_src/source/changelogs/v4.1.9.rst b/user_guide_src/source/changelogs/v4.1.9.rst index ea41903d979d..e409da06e271 100644 --- a/user_guide_src/source/changelogs/v4.1.9.rst +++ b/user_guide_src/source/changelogs/v4.1.9.rst @@ -1,7 +1,7 @@ Version 4.1.9 ############# -Release Date: February xx, 2022 +Release Date: February 25, 2022 **4.1.9 release of CodeIgniter4** From ab30e0ef0cf9c4b41db3792feea352a53d005e1e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 11:45:43 +0900 Subject: [PATCH 1665/2325] test: fix failed tests --- tests/system/Commands/RoutesTest.php | 5 +++++ tests/system/Commands/ScaffoldGeneratorTest.php | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index 0f569a2e42ad..dd5e6b3280a8 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -26,6 +26,8 @@ final class RoutesTest extends CIUnitTestCase protected function setUp(): void { + $this->resetServices(); + parent::setUp(); CITestStreamFilter::$buffer = ''; @@ -40,6 +42,8 @@ protected function setUp(): void protected function tearDown(): void { stream_filter_remove($this->streamFilter); + + $this->resetServices(); } protected function getBuffer() @@ -60,6 +64,7 @@ public function testRoutesCommand() public function testRoutesCommandRouteFilterAndAutoRoute() { $routes = Services::routes(); + $routes->setDefaultNamespace('App\Controllers'); $routes->resetRoutes(); $routes->get('/', 'Home::index', ['filter' => 'csrf']); diff --git a/tests/system/Commands/ScaffoldGeneratorTest.php b/tests/system/Commands/ScaffoldGeneratorTest.php index d3cbf1088f30..3aa6164cc2c5 100644 --- a/tests/system/Commands/ScaffoldGeneratorTest.php +++ b/tests/system/Commands/ScaffoldGeneratorTest.php @@ -13,6 +13,9 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Filters\CITestStreamFilter; +use Config\Autoload; +use Config\Modules; +use Config\Services; /** * @internal @@ -23,6 +26,9 @@ final class ScaffoldGeneratorTest extends CIUnitTestCase protected function setUp(): void { + $this->resetServices(); + Services::autoloader()->initialize(new Autoload(), new Modules()); + CITestStreamFilter::$buffer = ''; $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); From 257392b70a80c023c96dd56f2a5ee699d1c2da47 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 11:46:51 +0900 Subject: [PATCH 1666/2325] test: remove deprecated `session:migration` command test --- .../system/Commands/SessionsCommandsTest.php | 76 ------------------- 1 file changed, 76 deletions(-) diff --git a/tests/system/Commands/SessionsCommandsTest.php b/tests/system/Commands/SessionsCommandsTest.php index 6af2d09bf536..e69de29bb2d1 100644 --- a/tests/system/Commands/SessionsCommandsTest.php +++ b/tests/system/Commands/SessionsCommandsTest.php @@ -1,76 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace CodeIgniter\Commands; - -use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; - -/** - * @internal - */ -final class SessionsCommandsTest extends CIUnitTestCase -{ - private $streamFilter; - - protected function setUp(): void - { - parent::setUp(); - - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->streamFilter); - - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); - $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); - if (file_exists($file)) { - unlink($file); - } - } - - public function testCreateMigrationCommand() - { - command('session:migration'); - - // make sure we end up with a migration class in the right place - // or at least that we claim to have done so - // separate assertions avoid console color codes - $this->assertStringContainsString('_CreateCiSessionsTable.php', CITestStreamFilter::$buffer); - } - - public function testOverriddenCreateMigrationCommand() - { - command('session:migration -t mygoodies'); - - // make sure we end up with a migration class in the right place - $this->assertStringContainsString('_CreateMygoodiesTable.php', CITestStreamFilter::$buffer); - } - - public function testCannotWriteFileOnCreateMigrationCommand() - { - if ('\\' === DIRECTORY_SEPARATOR) { - $this->markTestSkipped('chmod does not work as expected on Windows'); - } - - chmod(APPPATH . 'Database/Migrations', 0444); - - command('session:migration'); - $this->assertStringContainsString('Error while creating file:', CITestStreamFilter::$buffer); - - chmod(APPPATH . 'Database/Migrations', 0755); - } -} From e14e709ea29b476d0d0697319d9ee94b6cdf6a54 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 11:59:26 +0900 Subject: [PATCH 1667/2325] test: add param to $this->resetService() --- system/Test/CIUnitTestCase.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Test/CIUnitTestCase.php b/system/Test/CIUnitTestCase.php index 00d936cd4251..4fd3bca63016 100644 --- a/system/Test/CIUnitTestCase.php +++ b/system/Test/CIUnitTestCase.php @@ -299,9 +299,9 @@ protected function resetFactories() /** * Resets shared instanced for all Services */ - protected function resetServices() + protected function resetServices(bool $initAutoloader = false) { - Services::reset(); + Services::reset($initAutoloader); } /** From 7198b3b556c5bf8d9bc65a1400871cc4660ce4ae Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 15:59:53 +0900 Subject: [PATCH 1668/2325] docs: fix title level and move "Organizing Your Controllers into Sub-directories" It is about auto-routing. --- .../source/incoming/controllers.rst | 82 +++++++++---------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 296e245bd35e..43a8c8d99f04 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -9,7 +9,7 @@ Controllers are the heart of your application, as they determine how HTTP reques :depth: 2 What is a Controller? -===================== +********************* A Controller is simply a class file that is named in a way that it can be associated with a URI. @@ -141,8 +141,40 @@ see the "Hello World" message. For more information, please refer to the :ref:`routes-configuration-options` section of the :doc:`URI Routing ` documentation. +Organizing Your Controllers into Sub-directories +================================================ + +If you are building a large application you might want to hierarchically +organize or structure your controllers into sub-directories. CodeIgniter +permits you to do this. + +Simply create sub-directories under the main **app/Controllers/**, +and place your controller classes within them. + +.. important:: Folder names MUST start with an uppercase letter and ONLY the first character can be uppercase. + +When using this feature the first segment of your URI must +specify the folder. For example, let's say you have a controller located here:: + + app/Controllers/Products/Shoes.php + +To call the above controller your URI will look something like this:: + + example.com/index.php/products/shoes/show/123 + +.. note:: You cannot have directories with the same name in **app/Controllers/** and **public/**. + This is because if there is a directory, the web server will search for it and + it will not be routed to CodeIgniter. + +Each of your sub-directories may contain a default controller which will be +called if the URL contains *only* the sub-directory. Simply put a controller +in there that matches the name of your default controller as specified in +your **app/Config/Routes.php** file. + +CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. + Remapping Method Calls -====================== +********************** As noted above, the second segment of the URI typically determines which method in the controller gets called. CodeIgniter permits you to override @@ -168,7 +200,7 @@ Example: .. literalinclude:: controllers/012.php Private methods -=============== +*************** In some cases, you may want certain methods hidden from public access. To achieve this, simply declare the method as ``private`` or ``protected``. @@ -181,40 +213,8 @@ then trying to access it using the following URL will not work:: example.com/index.php/helloworld/utility/ -Organizing Your Controllers into Sub-directories -================================================ - -If you are building a large application you might want to hierarchically -organize or structure your controllers into sub-directories. CodeIgniter -permits you to do this. - -Simply create sub-directories under the main **app/Controllers/**, -and place your controller classes within them. - -.. important:: Folder names MUST start with an uppercase letter and ONLY the first character can be uppercase. - -When using this feature the first segment of your URI must -specify the folder. For example, let's say you have a controller located here:: - - app/Controllers/Products/Shoes.php - -To call the above controller your URI will look something like this:: - - example.com/index.php/products/shoes/show/123 - -.. note:: You cannot have directories with the same name in **app/Controllers/** and **public/**. - This is because if there is a directory, the web server will search for it and - it will not be routed to CodeIgniter. - -Each of your sub-directories may contain a default controller which will be -called if the URL contains *only* the sub-directory. Simply put a controller -in there that matches the name of your default controller as specified in -your **app/Config/Routes.php** file. - -CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. - Included Properties -=================== +******************* Every controller you create should extend ``CodeIgniter\Controller`` class. This class provides several features that are available to all of your controllers. @@ -250,7 +250,7 @@ modify this by passing the duration (in seconds) as the first parameter: .. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. Helpers -------- +======= You can define an array of helper files as a class property. Whenever the controller is loaded these helper files will be automatically loaded into memory so that you can use their methods anywhere @@ -261,10 +261,10 @@ inside the controller: .. _controllers-validating-data: Validating data -=============== +*************** $this->validate() ------------------ +================= To simplify data checking, the controller also provides the convenience method ``validate()``. The method accepts an array of rules in the first parameter, @@ -284,7 +284,7 @@ the ``$rules`` array with the name of the group as defined in ``Config\Validatio .. note:: Validation can also be handled automatically in the model, but sometimes it's easier to do it in the controller. Where is up to you. $this->validateData() ---------------------- +===================== Sometimes you may want to check the controller method parameters or other custom data. In that case, you can use the ``$this->validateData()`` method. @@ -293,6 +293,6 @@ The method accepts an array of data to validate in the first parameter: .. literalinclude:: controllers/019.php That's it! -========== +********** That, in a nutshell, is all there is to know about controllers. From 31a941cf6508cd9d7ac6a6b44480052d03d96f2d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:04:54 +0900 Subject: [PATCH 1669/2325] docs: add section title "Auto Routing", and move the section below --- .../source/incoming/controllers.rst | 241 +++++++++--------- 1 file changed, 122 insertions(+), 119 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 43a8c8d99f04..277b17c0ae6a 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -13,6 +13,128 @@ What is a Controller? A Controller is simply a class file that is named in a way that it can be associated with a URI. +Remapping Method Calls +********************** + +As noted above, the second segment of the URI typically determines which +method in the controller gets called. CodeIgniter permits you to override +this behavior through the use of the ``_remap()`` method: + +.. literalinclude:: controllers/010.php + +.. important:: If your controller contains a method named ``_remap()``, + it will **always** get called regardless of what your URI contains. It + overrides the normal behavior in which the URI determines which method + is called, allowing you to define your own method routing rules. + +The overridden method call (typically the second segment of the URI) will +be passed as a parameter to the ``_remap()`` method: + +.. literalinclude:: controllers/011.php + +Any extra segments after the method name are passed into ``_remap()``. These parameters can be passed to the method +to emulate CodeIgniter's default behavior. + +Example: + +.. literalinclude:: controllers/012.php + +Private methods +*************** + +In some cases, you may want certain methods hidden from public access. +To achieve this, simply declare the method as ``private`` or ``protected``. +That will prevent it from being served by a URL request. For example, +if you were to define a method like this for the ``Helloworld`` controller: + +.. literalinclude:: controllers/013.php + +then trying to access it using the following URL will not work:: + + example.com/index.php/helloworld/utility/ + +Included Properties +******************* + +Every controller you create should extend ``CodeIgniter\Controller`` class. +This class provides several features that are available to all of your controllers. + +**Request Object** + +The application's main :doc:`Request Instance ` is always available +as a class property, ``$this->request``. + +**Response Object** + +The application's main :doc:`Response Instance ` is always available +as a class property, ``$this->response``. + +**Logger Object** + +An instance of the :doc:`Logger <../general/logging>` class is available as a class property, +``$this->logger``. + +**forceHTTPS** + +A convenience method for forcing a method to be accessed via HTTPS is available within all +controllers: + +.. literalinclude:: controllers/014.php + +By default, and in modern browsers that support the HTTP Strict Transport Security header, this +call should force the browser to convert non-HTTPS calls to HTTPS calls for one year. You can +modify this by passing the duration (in seconds) as the first parameter: + +.. literalinclude:: controllers/015.php + +.. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. + +Helpers +======= + +You can define an array of helper files as a class property. Whenever the controller is loaded +these helper files will be automatically loaded into memory so that you can use their methods anywhere +inside the controller: + +.. literalinclude:: controllers/016.php + +.. _controllers-validating-data: + +Validating data +*************** + +$this->validate() +================= + +To simplify data checking, the controller also provides the convenience method ``validate()``. +The method accepts an array of rules in the first parameter, +and in the optional second parameter, an array of custom error messages to display +if the items are not valid. Internally, this uses the controller's +``$this->request`` instance to get the data to be validated. +The :doc:`Validation Library docs ` have details on +rule and message array formats, as well as available rules: + +.. literalinclude:: controllers/017.php + +If you find it simpler to keep the rules in the configuration file, you can replace +the ``$rules`` array with the name of the group as defined in ``Config\Validation.php``: + +.. literalinclude:: controllers/018.php + +.. note:: Validation can also be handled automatically in the model, but sometimes it's easier to do it in the controller. Where is up to you. + +$this->validateData() +===================== + +Sometimes you may want to check the controller method parameters or other custom data. +In that case, you can use the ``$this->validateData()`` method. +The method accepts an array of data to validate in the first parameter: + +.. literalinclude:: controllers/019.php + +Auto Routing +************ + Consider this URI:: example.com/index.php/helloworld/ @@ -173,125 +295,6 @@ your **app/Config/Routes.php** file. CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. -Remapping Method Calls -********************** - -As noted above, the second segment of the URI typically determines which -method in the controller gets called. CodeIgniter permits you to override -this behavior through the use of the ``_remap()`` method: - -.. literalinclude:: controllers/010.php - -.. important:: If your controller contains a method named ``_remap()``, - it will **always** get called regardless of what your URI contains. It - overrides the normal behavior in which the URI determines which method - is called, allowing you to define your own method routing rules. - -The overridden method call (typically the second segment of the URI) will -be passed as a parameter to the ``_remap()`` method: - -.. literalinclude:: controllers/011.php - -Any extra segments after the method name are passed into ``_remap()``. These parameters can be passed to the method -to emulate CodeIgniter's default behavior. - -Example: - -.. literalinclude:: controllers/012.php - -Private methods -*************** - -In some cases, you may want certain methods hidden from public access. -To achieve this, simply declare the method as ``private`` or ``protected``. -That will prevent it from being served by a URL request. For example, -if you were to define a method like this for the ``Helloworld`` controller: - -.. literalinclude:: controllers/013.php - -then trying to access it using the following URL will not work:: - - example.com/index.php/helloworld/utility/ - -Included Properties -******************* - -Every controller you create should extend ``CodeIgniter\Controller`` class. -This class provides several features that are available to all of your controllers. - -**Request Object** - -The application's main :doc:`Request Instance ` is always available -as a class property, ``$this->request``. - -**Response Object** - -The application's main :doc:`Response Instance ` is always available -as a class property, ``$this->response``. - -**Logger Object** - -An instance of the :doc:`Logger <../general/logging>` class is available as a class property, -``$this->logger``. - -**forceHTTPS** - -A convenience method for forcing a method to be accessed via HTTPS is available within all -controllers: - -.. literalinclude:: controllers/014.php - -By default, and in modern browsers that support the HTTP Strict Transport Security header, this -call should force the browser to convert non-HTTPS calls to HTTPS calls for one year. You can -modify this by passing the duration (in seconds) as the first parameter: - -.. literalinclude:: controllers/015.php - -.. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. - -Helpers -======= - -You can define an array of helper files as a class property. Whenever the controller is loaded -these helper files will be automatically loaded into memory so that you can use their methods anywhere -inside the controller: - -.. literalinclude:: controllers/016.php - -.. _controllers-validating-data: - -Validating data -*************** - -$this->validate() -================= - -To simplify data checking, the controller also provides the convenience method ``validate()``. -The method accepts an array of rules in the first parameter, -and in the optional second parameter, an array of custom error messages to display -if the items are not valid. Internally, this uses the controller's -``$this->request`` instance to get the data to be validated. -The :doc:`Validation Library docs ` have details on -rule and message array formats, as well as available rules: - -.. literalinclude:: controllers/017.php - -If you find it simpler to keep the rules in the configuration file, you can replace -the ``$rules`` array with the name of the group as defined in ``Config\Validation.php``: - -.. literalinclude:: controllers/018.php - -.. note:: Validation can also be handled automatically in the model, but sometimes it's easier to do it in the controller. Where is up to you. - -$this->validateData() -===================== - -Sometimes you may want to check the controller method parameters or other custom data. -In that case, you can use the ``$this->validateData()`` method. -The method accepts an array of data to validate in the first parameter: - -.. literalinclude:: controllers/019.php - That's it! ********** From 1cb1ba695f0585e54f22d7fb3d52ba97d5d8ee17 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:07:30 +0900 Subject: [PATCH 1670/2325] docs: add explanation for auto-routing --- user_guide_src/source/incoming/controllers.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 277b17c0ae6a..f21e1aa4d366 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -135,6 +135,15 @@ The method accepts an array of data to validate in the first parameter: Auto Routing ************ +This section describes the functionality of the auto-routing. +It automatically routes an HTTP request, and executes the corresponding controller method +without route definitions. The auto-routing is enabled by default. + +.. note:: To prevent misconfiguration and miscoding, we recommend that you disable + the auto-routing feature. See :ref:`use-defined-routes-only`. + +.. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. + Consider this URI:: example.com/index.php/helloworld/ From d8a1a0a6a46d11963ed6dda0879d56816f180c28 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:07:52 +0900 Subject: [PATCH 1671/2325] docs: update what's controller --- user_guide_src/source/incoming/controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index f21e1aa4d366..fff2e02ff2ec 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -11,7 +11,7 @@ Controllers are the heart of your application, as they determine how HTTP reques What is a Controller? ********************* -A Controller is simply a class file that is named in a way that it can be associated with a URI. +A Controller is simply a class file that handles a HTTP request. :doc:`URI Routing ` associates a URI with a controller. Remapping Method Calls ********************** From 77efb6d96cec1b58bd8c536e02485313739b7f45 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:09:42 +0900 Subject: [PATCH 1672/2325] docs: change the position of sections --- .../source/incoming/controllers.rst | 80 +++++++++---------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index fff2e02ff2ec..dced7111a363 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -13,46 +13,6 @@ What is a Controller? A Controller is simply a class file that handles a HTTP request. :doc:`URI Routing ` associates a URI with a controller. -Remapping Method Calls -********************** - -As noted above, the second segment of the URI typically determines which -method in the controller gets called. CodeIgniter permits you to override -this behavior through the use of the ``_remap()`` method: - -.. literalinclude:: controllers/010.php - -.. important:: If your controller contains a method named ``_remap()``, - it will **always** get called regardless of what your URI contains. It - overrides the normal behavior in which the URI determines which method - is called, allowing you to define your own method routing rules. - -The overridden method call (typically the second segment of the URI) will -be passed as a parameter to the ``_remap()`` method: - -.. literalinclude:: controllers/011.php - -Any extra segments after the method name are passed into ``_remap()``. These parameters can be passed to the method -to emulate CodeIgniter's default behavior. - -Example: - -.. literalinclude:: controllers/012.php - -Private methods -*************** - -In some cases, you may want certain methods hidden from public access. -To achieve this, simply declare the method as ``private`` or ``protected``. -That will prevent it from being served by a URL request. For example, -if you were to define a method like this for the ``Helloworld`` controller: - -.. literalinclude:: controllers/013.php - -then trying to access it using the following URL will not work:: - - example.com/index.php/helloworld/utility/ - Included Properties ******************* @@ -132,6 +92,20 @@ The method accepts an array of data to validate in the first parameter: .. literalinclude:: controllers/019.php +Private methods +*************** + +In some cases, you may want certain methods hidden from public access. +To achieve this, simply declare the method as ``private`` or ``protected``. +That will prevent it from being served by a URL request. For example, +if you were to define a method like this for the ``Helloworld`` controller: + +.. literalinclude:: controllers/013.php + +then trying to access it using the following URL will not work:: + + example.com/index.php/helloworld/utility/ + Auto Routing ************ @@ -304,6 +278,32 @@ your **app/Config/Routes.php** file. CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. +Remapping Method Calls +********************** + +As noted above, the second segment of the URI typically determines which +method in the controller gets called. CodeIgniter permits you to override +this behavior through the use of the ``_remap()`` method: + +.. literalinclude:: controllers/010.php + +.. important:: If your controller contains a method named ``_remap()``, + it will **always** get called regardless of what your URI contains. It + overrides the normal behavior in which the URI determines which method + is called, allowing you to define your own method routing rules. + +The overridden method call (typically the second segment of the URI) will +be passed as a parameter to the ``_remap()`` method: + +.. literalinclude:: controllers/011.php + +Any extra segments after the method name are passed into ``_remap()``. These parameters can be passed to the method +to emulate CodeIgniter's default behavior. + +Example: + +.. literalinclude:: controllers/012.php + That's it! ********** From ffbf4f628c7daa6c3d3e56ca3a1dfd7b11ae010d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:10:29 +0900 Subject: [PATCH 1673/2325] docs: fix title level --- user_guide_src/source/incoming/controllers.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index dced7111a363..a4c248d3979d 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -34,7 +34,8 @@ as a class property, ``$this->response``. An instance of the :doc:`Logger <../general/logging>` class is available as a class property, ``$this->logger``. -**forceHTTPS** +forceHTTPS +********** A convenience method for forcing a method to be accessed via HTTPS is available within all controllers: From d9facbb20901e0e0074b15733ce766b3354cbc41 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:13:47 +0900 Subject: [PATCH 1674/2325] docs: change the position of sections --- .../source/incoming/controllers.rst | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index a4c248d3979d..0cc90da352a5 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -34,6 +34,17 @@ as a class property, ``$this->response``. An instance of the :doc:`Logger <../general/logging>` class is available as a class property, ``$this->logger``. +Helpers +======= + +You can define an array of helper files as a class property. Whenever the controller is loaded +these helper files will be automatically loaded into memory so that you can use their methods anywhere +inside the controller: + +.. literalinclude:: controllers/016.php + +.. _controllers-validating-data: + forceHTTPS ********** @@ -50,17 +61,6 @@ modify this by passing the duration (in seconds) as the first parameter: .. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. -Helpers -======= - -You can define an array of helper files as a class property. Whenever the controller is loaded -these helper files will be automatically loaded into memory so that you can use their methods anywhere -inside the controller: - -.. literalinclude:: controllers/016.php - -.. _controllers-validating-data: - Validating data *************** From 65c6ad200302b1bf6b0eaa39172b3a458cd1060e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:13:58 +0900 Subject: [PATCH 1675/2325] docs: fix link to Request --- user_guide_src/source/incoming/controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 0cc90da352a5..4456eb5c8aa3 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -21,7 +21,7 @@ This class provides several features that are available to all of your controlle **Request Object** -The application's main :doc:`Request Instance ` is always available +The application's main :doc:`Request Instance ` is always available as a class property, ``$this->request``. **Response Object** From 31451b5353f345558e1c0e454c91fd7cce7df6ca Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:17:43 +0900 Subject: [PATCH 1676/2325] docs: change page order, now routing is before controllers --- user_guide_src/source/incoming/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/index.rst b/user_guide_src/source/incoming/index.rst index b334cc5c5ac2..b4399e18d1ba 100644 --- a/user_guide_src/source/incoming/index.rst +++ b/user_guide_src/source/incoming/index.rst @@ -7,8 +7,8 @@ Controllers handle incoming requests. .. toctree:: :titlesonly: - controllers routing + controllers filters message request From c83057baf505c7224b89ca7ba38aaca9e03086f2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 16:58:16 +0900 Subject: [PATCH 1677/2325] docs: move auto-routing section down --- .../source/incoming/controllers.rst | 2 + user_guide_src/source/incoming/routing.rst | 76 +++++++++---------- 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 4456eb5c8aa3..21c717d9eace 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -107,6 +107,8 @@ then trying to access it using the following URL will not work:: example.com/index.php/helloworld/utility/ +.. _controller-auto-routing: + Auto Routing ************ diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 716e71674962..1f3bde9a02f0 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -6,46 +6,13 @@ URI Routing :local: :depth: 2 -****************************** -Auto Routes and Defined Routes -****************************** +What is URI Routing? +******************** -Auto Routes -=========== +URI Routing associates a URI with a controller's method. -Typically there is a one-to-one relationship between a URL string and its corresponding -controller class/method. The segments in a URI normally follow this pattern:: - - example.com/class/method/id/ - -We call this "**Auto Routes**". CodeIgniter automatically routes an HTTP request, -and executes the corresponding controller method. The auto-routing is enabled by default. - -.. note:: To prevent misconfiguration and miscoding, we recommend that you disable - the auto-routing feature. See :ref:`use-defined-routes-only`. - -.. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. - -Defined Routes -============== - -In some instances, however, you may want to remap this relationship so that a different -class/method can be called instead of the one corresponding to the URL. - -For example, let's say you want your URLs to have this prototype:: - - example.com/product/1/ - example.com/product/2/ - example.com/product/3/ - example.com/product/4/ - -Normally the second segment of the URL path is reserved for the method name, but in the example -above it instead has a product ID. To overcome this, CodeIgniter allows you to remap the URI handler. -We call this "**Defined Routes**". - -****************************** -Setting Your Own Routing Rules -****************************** +Setting Routing Rules +********************* Routing rules are defined in the **app/Config/Routes.php** file. In it you'll see that it creates an instance of the RouteCollection class (``$routes``) that permits you to specify your own routing criteria. @@ -56,7 +23,7 @@ If you expect a GET request, you use the ``get()`` method: .. literalinclude:: routing/001.php -A route simply takes the URI path on the left, and maps it to the controller and method on the right, +A route simply takes the URI path (``/``) on the left, and maps it to the controller and method (``Home::index``) on the right, along with any parameters that should be passed to the controller. The controller and method should be listed in the same way that you would use a static method, by separating the class and its method with a double-colon, like ``Users::list``. If that method requires parameters to be @@ -539,7 +506,7 @@ Use Defined Routes Only ======================= When no defined route is found that matches the URI, the system will attempt to match that URI against the -controllers and methods as described above. You can disable this automatic matching, and restrict routes +controllers and methods as described in :ref:`auto-routing`. You can disable this automatic matching, and restrict routes to only those defined by you, by setting the ``setAutoRoute()`` option to false: .. literalinclude:: routing/046.php @@ -565,7 +532,32 @@ For an example use of lowering the priority see :ref:`routing-priority`: .. literalinclude:: routing/048.php -***************** +.. _auto-routing: + +Auto Routing +************ + +It is recommended that all routes are defined in the **app/Config/Routes.php** file. +However, CodeIgniter can also automatically route HTTP requests based on conventions +and execute the corresponding controller methods. + +Consider this URI:: + + example.com/index.php/helloworld/index/1 + +In the above example, CodeIgniter would attempt to find a controller named **Helloworld.php** +and executes ``index()`` method with passing ``'1'`` as the first argument. + +We call this "**Auto Routes**". CodeIgniter automatically routes an HTTP request, +and executes the corresponding controller method. The auto-routing is enabled by default. + +.. note:: To prevent misconfiguration and miscoding, we recommend that you disable + the auto-routing feature. See :ref:`use-defined-routes-only`. + +.. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. + +See :ref:`Auto Routing in Controllers ` for more info. + Confirming Routes ***************** @@ -601,4 +593,4 @@ But ``[/...]`` in the route of an auto route is indicates any number of segments .. note:: When auto routing is enabled, if you have the route ``home``, it can be also accessd by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. But the command shows only ``home``. -.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. But the filters defined in **app/Config/Routes.php** are always displayed correctly. \ No newline at end of file +.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. But the filters defined in **app/Config/Routes.php** are always displayed correctly. From 76d3acddbe7bb01d527ba73c33e82f879bd11778 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 17:05:04 +0900 Subject: [PATCH 1678/2325] docs: move the description on auto-routing in general/urls.rst to incoming/routing.rst --- user_guide_src/source/general/urls.rst | 15 ++------------- user_guide_src/source/incoming/routing.rst | 11 +++++++++++ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/user_guide_src/source/general/urls.rst b/user_guide_src/source/general/urls.rst index da056cc96cbc..252a907358dd 100644 --- a/user_guide_src/source/general/urls.rst +++ b/user_guide_src/source/general/urls.rst @@ -11,20 +11,9 @@ By default, URLs in CodeIgniter are designed to be search-engine and human-frien example.com/news/article/my_article -URI Segments -============ +Your URLs can be defined using the :doc:`URI Routing ` feature with flexibility. -The segments in the URL, in following with the Model-View-Controller approach, usually represent:: - - example.com/class/method/ID - -1. The first segment represents the controller **class** that should be invoked. -2. The second segment represents the class **method** that should be called. -3. The third, and any additional segments, represent the ID and any variables that will be passed to the controller. - -The :doc:`URI Library <../libraries/uri>` and the :doc:`URL Helper <../helpers/url_helper>` contain functions that make it easy -to work with your URI data. In addition, your URLs can be remapped using the :doc:`URI Routing ` -feature for more flexibility. +The :doc:`URI Library <../libraries/uri>` and the :doc:`URL Helper <../helpers/url_helper>` contain functions that make it easy to work with your URI data. Removing the index.php file =========================== diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 1f3bde9a02f0..5c527b7d0ada 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -541,6 +541,17 @@ It is recommended that all routes are defined in the **app/Config/Routes.php** f However, CodeIgniter can also automatically route HTTP requests based on conventions and execute the corresponding controller methods. +URI Segments +============ + +The segments in the URL, in following with the Model-View-Controller approach, usually represent:: + + example.com/class/method/ID + +1. The first segment represents the controller **class** that should be invoked. +2. The second segment represents the class **method** that should be called. +3. The third, and any additional segments, represent the ID and any variables that will be passed to the controller. + Consider this URI:: example.com/index.php/helloworld/index/1 From 3fb2756c9258c1da3ad89e35acfe318d6da5eed0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 26 Feb 2022 18:03:10 +0900 Subject: [PATCH 1679/2325] docs: fix section title level --- user_guide_src/source/incoming/routing.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 5c527b7d0ada..e5e0d04be5cc 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -443,7 +443,6 @@ To disable this functionality, you must call the method with the parameter ``fal .. _routes-configuration-options: -**************************** Routes Configuration Options **************************** From db4acf11d7b6280ca39a785391f33d834a5281b3 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 26 Feb 2022 21:06:35 +0700 Subject: [PATCH 1680/2325] [Doc] Upgrading to 4.2.0 from 4.1.9 Latest version is 4.1.9, so the note should be from 4.1.9 --- user_guide_src/source/installation/upgrade_420.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_420.rst index d2050e08fa36..a302f113ae61 100644 --- a/user_guide_src/source/installation/upgrade_420.rst +++ b/user_guide_src/source/installation/upgrade_420.rst @@ -1,5 +1,5 @@ ############################# -Upgrading from 4.1.8 to 4.2.0 +Upgrading from 4.1.9 to 4.2.0 ############################# Please refer to the upgrade instructions corresponding to your installation method. From 194c2a072e7060fe7f104ee120d09ceb27eba192 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 27 Feb 2022 09:23:12 +0900 Subject: [PATCH 1681/2325] docs: remove "simply" See https://jameshfisher.com/2017/02/22/dont-use-simply/ --- user_guide_src/source/incoming/routing.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index e5e0d04be5cc..83cb4cc95e6d 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -23,7 +23,7 @@ If you expect a GET request, you use the ``get()`` method: .. literalinclude:: routing/001.php -A route simply takes the URI path (``/``) on the left, and maps it to the controller and method (``Home::index``) on the right, +A route takes the URI path (``/``) on the left, and maps it to the controller and method (``Home::index``) on the right, along with any parameters that should be passed to the controller. The controller and method should be listed in the same way that you would use a static method, by separating the class and its method with a double-colon, like ``Users::list``. If that method requires parameters to be From e838375e9435a21b67c064bcc985cbdb7285fda0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 27 Feb 2022 09:28:28 +0900 Subject: [PATCH 1682/2325] docs: make it clear to recommend Composer installation --- user_guide_src/source/installation/index.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/user_guide_src/source/installation/index.rst b/user_guide_src/source/installation/index.rst index 92fe78d38184..3312ee24a4bf 100644 --- a/user_guide_src/source/installation/index.rst +++ b/user_guide_src/source/installation/index.rst @@ -7,10 +7,9 @@ using `Composer `_, or using `Git `_. Which is right for you? +- We recommend the Composer installation. Because it keeps CodeIgniter up to date easily. - If you would like the simple "download & go" install that CodeIgniter3 is known for, choose the manual installation. -- If you plan to add third party packages to your project, or want to keep - CodeIgniter up to date easily, we recommend the Composer installation. .. toctree:: :titlesonly: From cd7e011c951092210567efa6c7bd1e7d47f2edca Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 27 Feb 2022 09:29:10 +0900 Subject: [PATCH 1683/2325] docs: move up paragraph and note --- user_guide_src/source/installation/index.rst | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/installation/index.rst b/user_guide_src/source/installation/index.rst index 3312ee24a4bf..31d58ac25673 100644 --- a/user_guide_src/source/installation/index.rst +++ b/user_guide_src/source/installation/index.rst @@ -11,6 +11,15 @@ Which is right for you? - If you would like the simple "download & go" install that CodeIgniter3 is known for, choose the manual installation. +However you choose to install and run CodeIgniter4, the +`user guide `_ is accessible online. + +.. note:: Before using CodeIgniter 4, make sure that your server meets the + :doc:`requirements `, in particular the PHP + version and the PHP extensions that are needed. + You may find that you have to uncomment the ``php.ini`` "extension" + lines to enable "curl" and "intl", for instance. + .. toctree:: :titlesonly: @@ -21,12 +30,3 @@ Which is right for you? upgrading troubleshooting repositories - -However you choose to install and run CodeIgniter4, the -`user guide `_ is accessible online. - -.. note:: Before using CodeIgniter 4, make sure that your server meets the - :doc:`requirements `, in particular the PHP - version and the PHP extensions that are needed. - You may find that you have to uncomment the ``php.ini`` "extension" - lines to enable "curl" and "intl", for instance. From becabdc48324275e53cf4e238d59ce1fe2889d36 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 27 Feb 2022 19:06:23 +0900 Subject: [PATCH 1684/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/installation/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/index.rst b/user_guide_src/source/installation/index.rst index 31d58ac25673..243dd1a5b314 100644 --- a/user_guide_src/source/installation/index.rst +++ b/user_guide_src/source/installation/index.rst @@ -7,7 +7,7 @@ using `Composer `_, or using `Git `_. Which is right for you? -- We recommend the Composer installation. Because it keeps CodeIgniter up to date easily. +- We recommend the Composer installation because it keeps CodeIgniter up to date easily. - If you would like the simple "download & go" install that CodeIgniter3 is known for, choose the manual installation. From 7aa73b9cd5ce33d50696ad1b3478729bd715127b Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 28 Feb 2022 10:08:23 +0900 Subject: [PATCH 1685/2325] docs: remove unneeded page titles --- .../source/installation/upgrading.rst | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 322302d3e011..aa79ef0d6bc7 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -12,15 +12,15 @@ upgrading from. .. toctree:: :titlesonly: - Upgrading from 4.1.8 to 4.2.0 - Upgrading from 4.1.7 to 4.1.8 - Upgrading from 4.1.6 to 4.1.7 - Upgrading from 4.1.5 to 4.1.6 - Upgrading from 4.1.4 to 4.1.5 - Upgrading from 4.1.3 to 4.1.4 - Upgrading from 4.1.2 to 4.1.3 - Upgrading from 4.1.1 to 4.1.2 - Upgrading from 4.0.5 to 4.1.0 or 4.1.1 - Upgrading from 4.0.4 to 4.0.5 - Upgrading from 4.0.x to 4.0.4 - Upgrading from 3.x to 4.x + upgrade_420 + upgrade_418 + upgrade_417 + upgrade_416 + upgrade_415 + upgrade_414 + upgrade_413 + upgrade_412 + upgrade_410 + upgrade_405 + upgrade_404 + upgrade_4xx From 4aad6438e1f298170cedbb6a11bfe5c56f840293 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 12:11:54 +0100 Subject: [PATCH 1686/2325] Fix cli. --- .../source/cli/cli_commands/004.php | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands/004.php b/user_guide_src/source/cli/cli_commands/004.php index 64b5af943315..e6178256c524 100644 --- a/user_guide_src/source/cli/cli_commands/004.php +++ b/user_guide_src/source/cli/cli_commands/004.php @@ -1,11 +1,21 @@ Date: Mon, 28 Feb 2022 12:12:20 +0100 Subject: [PATCH 1687/2325] Fix concepts. --- user_guide_src/source/concepts/factories/003.php | 8 ++++++-- user_guide_src/source/concepts/services/007.php | 7 +++++-- user_guide_src/source/concepts/services/008.php | 7 +++++-- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/concepts/factories/003.php b/user_guide_src/source/concepts/factories/003.php index 6c5b966f35cc..5b34b3ff4fcd 100644 --- a/user_guide_src/source/concepts/factories/003.php +++ b/user_guide_src/source/concepts/factories/003.php @@ -2,6 +2,10 @@ class SomeOtherClass { - $widgets = Factories::models('WidgetModel'); - // ... + public function someFunction() + { + $widgets = Factories::models('WidgetModel'); + + // ... + } } diff --git a/user_guide_src/source/concepts/services/007.php b/user_guide_src/source/concepts/services/007.php index 64a1119f0ace..6096fe592142 100644 --- a/user_guide_src/source/concepts/services/007.php +++ b/user_guide_src/source/concepts/services/007.php @@ -1,6 +1,9 @@ Date: Mon, 28 Feb 2022 12:12:33 +0100 Subject: [PATCH 1688/2325] Fix database. --- .../source/database/configuration/001.php | 39 ++++++++++--------- .../source/database/configuration/006.php | 39 ++++++++++--------- 2 files changed, 42 insertions(+), 36 deletions(-) diff --git a/user_guide_src/source/database/configuration/001.php b/user_guide_src/source/database/configuration/001.php index c868ee08eb37..5a59fabfcfdc 100644 --- a/user_guide_src/source/database/configuration/001.php +++ b/user_guide_src/source/database/configuration/001.php @@ -1,20 +1,23 @@ '', - 'hostname' => 'localhost', - 'username' => 'root', - 'password' => '', - 'database' => 'database_name', - 'DBDriver' => 'MySQLi', - 'DBPrefix' => '', - 'pConnect' => true, - 'DBDebug' => true, - 'charset' => 'utf8', - 'DBCollat' => 'utf8_general_ci', - 'swapPre' => '', - 'encrypt' => false, - 'compress' => false, - 'strictOn' => false, - 'failover' => [], -]; +class Database extends Config +{ + public $default = [ + 'DSN' => '', + 'hostname' => 'localhost', + 'username' => 'root', + 'password' => '', + 'database' => 'database_name', + 'DBDriver' => 'MySQLi', + 'DBPrefix' => '', + 'pConnect' => true, + 'DBDebug' => true, + 'charset' => 'utf8', + 'DBCollat' => 'utf8_general_ci', + 'swapPre' => '', + 'encrypt' => false, + 'compress' => false, + 'strictOn' => false, + 'failover' => [], + ]; +} diff --git a/user_guide_src/source/database/configuration/006.php b/user_guide_src/source/database/configuration/006.php index 31b56a677829..d5b4a5d691d5 100644 --- a/user_guide_src/source/database/configuration/006.php +++ b/user_guide_src/source/database/configuration/006.php @@ -1,20 +1,23 @@ '', - 'hostname' => 'localhost', - 'username' => 'root', - 'password' => '', - 'database' => 'database_name', - 'DBDriver' => 'MySQLi', - 'DBPrefix' => '', - 'pConnect' => true, - 'DBDebug' => true, - 'charset' => 'utf8', - 'DBCollat' => 'utf8_general_ci', - 'swapPre' => '', - 'compress' => false, - 'encrypt' => false, - 'strictOn' => false, - 'failover' => [] -); +class Database extends Config +{ + public $test = [ + 'DSN' => '', + 'hostname' => 'localhost', + 'username' => 'root', + 'password' => '', + 'database' => 'database_name', + 'DBDriver' => 'MySQLi', + 'DBPrefix' => '', + 'pConnect' => true, + 'DBDebug' => true, + 'charset' => 'utf8', + 'DBCollat' => 'utf8_general_ci', + 'swapPre' => '', + 'compress' => false, + 'encrypt' => false, + 'strictOn' => false, + 'failover' => [], + ]; +} From b6fe091fed9b941e39fdde07891aed71b1c011cf Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 12:12:44 +0100 Subject: [PATCH 1689/2325] Fix dbmgmt. --- user_guide_src/source/dbmgmt/migration/002.php | 12 +++++++----- user_guide_src/source/dbmgmt/seeds/003.php | 9 ++++++--- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/dbmgmt/migration/002.php b/user_guide_src/source/dbmgmt/migration/002.php index 07d2b2034775..35726a23aade 100644 --- a/user_guide_src/source/dbmgmt/migration/002.php +++ b/user_guide_src/source/dbmgmt/migration/002.php @@ -1,10 +1,12 @@ db->disableForeignKeyChecks() + public function up() + { + $this->db->disableForeignKeyChecks(); - // Migration rules would go here.. - - $this->db->enableForeignKeyChecks(); + // Migration rules would go here.. + $this->db->enableForeignKeyChecks(); + } } diff --git a/user_guide_src/source/dbmgmt/seeds/003.php b/user_guide_src/source/dbmgmt/seeds/003.php index 12dbcbd74835..099904f4f2ab 100644 --- a/user_guide_src/source/dbmgmt/seeds/003.php +++ b/user_guide_src/source/dbmgmt/seeds/003.php @@ -1,7 +1,10 @@ call('UserSeeder'); - $this->call('My\Database\Seeds\CountrySeeder'); + public function run() + { + $this->call('UserSeeder'); + $this->call('My\Database\Seeds\CountrySeeder'); + } } From 6822f25618ba622edac30193523764353ad17383 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 12:12:57 +0100 Subject: [PATCH 1690/2325] Fix extending. --- .../source/extending/basecontroller/002.php | 5 ++++- .../source/extending/basecontroller/003.php | 11 +++++++---- .../source/extending/core_classes/002.php | 13 ++++++++----- 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/extending/basecontroller/002.php b/user_guide_src/source/extending/basecontroller/002.php index dee702c36ecb..509bb27a8707 100644 --- a/user_guide_src/source/extending/basecontroller/002.php +++ b/user_guide_src/source/extending/basecontroller/002.php @@ -1,3 +1,6 @@ session = \Config\Services::session(); + $this->session = \Config\Services::session(); + } } diff --git a/user_guide_src/source/extending/core_classes/002.php b/user_guide_src/source/extending/core_classes/002.php index 65fb5c240f41..cc3f38347ccf 100644 --- a/user_guide_src/source/extending/core_classes/002.php +++ b/user_guide_src/source/extending/core_classes/002.php @@ -1,10 +1,13 @@ Date: Mon, 28 Feb 2022 12:16:30 +0100 Subject: [PATCH 1691/2325] Fix events. --- user_guide_src/source/database/events/001.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/user_guide_src/source/database/events/001.php b/user_guide_src/source/database/events/001.php index 1c8b56b1d1ca..2065ef3d426b 100644 --- a/user_guide_src/source/database/events/001.php +++ b/user_guide_src/source/database/events/001.php @@ -2,9 +2,3 @@ // In Config\Events.php Events::on('DBQuery', 'CodeIgniter\Debug\Toolbar\Collectors\Database::collect'); - -// Collect the queries so something can be done with them later. -public static function collect(CodeIgniter\Database\Query $query) -{ - static::$queries[] = $query; -} From 591abc91f700137268670c39a3b8f2470647d875 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 12:34:03 +0100 Subject: [PATCH 1692/2325] Fix testing. --- .../source/testing/controllers/014.php | 13 ++++++--- .../source/testing/debugging/003.php | 23 ++++++++------- user_guide_src/source/testing/overview.rst | 7 +++-- .../source/testing/overview/003.php | 6 ---- .../source/testing/overview/004.php | 9 ++++-- .../source/testing/overview/005.php | 14 +++++---- .../source/testing/overview/006.php | 4 +-- .../source/testing/overview/007.php | 8 +++-- .../source/testing/overview/017.php | 15 ++++++---- .../source/testing/overview/018.php | 11 ++++--- .../source/testing/overview/019.php | 29 ++++++++++--------- 11 files changed, 80 insertions(+), 59 deletions(-) delete mode 100644 user_guide_src/source/testing/overview/003.php diff --git a/user_guide_src/source/testing/controllers/014.php b/user_guide_src/source/testing/controllers/014.php index 19f2310392fa..bc6dc8bf9e18 100644 --- a/user_guide_src/source/testing/controllers/014.php +++ b/user_guide_src/source/testing/controllers/014.php @@ -1,9 +1,14 @@ getFilterCaller('permission', 'before'); - $result = $caller('MayEditWidgets'); + use FilterTestTrait; - $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); + protected function testUnauthorizedAccessRedirects() + { + $caller = $this->getFilterCaller('permission', 'before'); + $result = $caller('MayEditWidgets'); + + $this->assertInstanceOf('CodeIgniter\HTTP\RedirectResponse', $result); + } } diff --git a/user_guide_src/source/testing/debugging/003.php b/user_guide_src/source/testing/debugging/003.php index b7e19588fae9..de9476fe7d39 100644 --- a/user_guide_src/source/testing/debugging/003.php +++ b/user_guide_src/source/testing/debugging/003.php @@ -1,12 +1,15 @@ model->purgeDeleted() + $this->model->purgeDeleted(); } } diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php index c829e5b99cce..1ba21e197b0a 100644 --- a/user_guide_src/source/testing/overview/007.php +++ b/user_guide_src/source/testing/overview/007.php @@ -2,16 +2,18 @@ trait AuthTrait { - protected setUpAuthTrait() + protected function setUpAuthTrait() { $user = $this->createFakeUser(); $this->logInUser($user); } - // ... } -class AuthenticationFeatureTest +/** + * @internal + */ +final class AuthenticationFeatureTest { use AuthTrait; diff --git a/user_guide_src/source/testing/overview/017.php b/user_guide_src/source/testing/overview/017.php index 653c7d0947ba..9fb311e795e3 100644 --- a/user_guide_src/source/testing/overview/017.php +++ b/user_guide_src/source/testing/overview/017.php @@ -1,11 +1,14 @@ getMockBuilder('CodeIgniter\HTTP\CURLRequest') - ->setMethods(['request']) - ->getMock(); - Services::injectMock('curlrequest', $curlrequest); + public function testSomething() + { + $curlrequest = $this->getMockBuilder('CodeIgniter\HTTP\CURLRequest') + ->setMethods(['request']) + ->getMock(); + Services::injectMock('curlrequest', $curlrequest); - // Do normal testing here.... + // Do normal testing here.... + } } diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index 743074117d9e..4c607dddb77e 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -1,9 +1,12 @@ stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); -} + protected function setUp() + { + CITestStreamFilter::$buffer = ''; + $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + } -public function tearDown() -{ - stream_filter_remove($this->stream_filter); -} + protected function tearDown() + { + stream_filter_remove($this->stream_filter); + } -public function testSomeOutput() -{ - CLI::write('first.'); - $expected = "first.\n"; - $this->assertSame($expected, CITestStreamFilter::$buffer); + public function testSomeOutput() + { + CLI::write('first.'); + $expected = "first.\n"; + $this->assertSame($expected, CITestStreamFilter::$buffer); + } } From 237f218424869d0b0707d5b0db2571fdfd5500fd Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 12:36:03 +0100 Subject: [PATCH 1693/2325] Fix helpers. --- user_guide_src/source/helpers/test_helper/002.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/helpers/test_helper/002.php b/user_guide_src/source/helpers/test_helper/002.php index 58decc5bfeb3..10fb42b1260f 100644 --- a/user_guide_src/source/helpers/test_helper/002.php +++ b/user_guide_src/source/helpers/test_helper/002.php @@ -1,8 +1,11 @@ assertTrue($this->userHasAccess($user)); + $this->assertTrue($this->userHasAccess($user)); + } } From 7c9091c3fe900467d030bf444cdb0b256015ceb1 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 13:38:10 +0100 Subject: [PATCH 1694/2325] Fix incoming. --- .../source/incoming/controllers/005.php | 6 +++- .../source/incoming/controllers/010.php | 7 +++-- .../source/incoming/controllers/011.php | 11 ++++--- .../source/incoming/controllers/012.php | 15 ++++++---- .../source/incoming/controllers/013.php | 7 +++-- .../source/incoming/controllers/017.php | 23 +++++++------- .../source/incoming/controllers/018.php | 17 ++++++----- .../source/incoming/controllers/019.php | 30 +++++++++++-------- .../source/incoming/filters/002.php | 11 ++++--- .../source/incoming/filters/003.php | 9 ++++-- .../source/incoming/filters/004.php | 15 ++++++---- .../source/incoming/filters/005.php | 15 ++++++---- .../source/incoming/filters/006.php | 15 ++++++---- .../source/incoming/filters/007.php | 15 ++++++---- .../source/incoming/filters/008.php | 11 ++++--- .../source/incoming/filters/009.php | 11 ++++--- .../source/incoming/filters/011.php | 11 ++++--- .../source/incoming/routing/011.php | 12 +++++--- 18 files changed, 149 insertions(+), 92 deletions(-) diff --git a/user_guide_src/source/incoming/controllers/005.php b/user_guide_src/source/incoming/controllers/005.php index 5d3892bfafb8..84b910be2507 100644 --- a/user_guide_src/source/incoming/controllers/005.php +++ b/user_guide_src/source/incoming/controllers/005.php @@ -1,5 +1,9 @@ (\)*\ +/* + Folder and file structure: + + \(\)*\ + */ $routes->get('helloworld', '\App\Controllers\HelloWorld::index'); diff --git a/user_guide_src/source/incoming/controllers/010.php b/user_guide_src/source/incoming/controllers/010.php index e017dcd45cdb..b74d386d6289 100644 --- a/user_guide_src/source/incoming/controllers/010.php +++ b/user_guide_src/source/incoming/controllers/010.php @@ -1,6 +1,9 @@ $method(); - } else { + public function _remap($method) + { + if ($method === 'some_method') { + return $this->{$method}(); + } + return $this->default_method(); } } diff --git a/user_guide_src/source/incoming/controllers/012.php b/user_guide_src/source/incoming/controllers/012.php index 25d064b859cd..e6cc91140f6f 100644 --- a/user_guide_src/source/incoming/controllers/012.php +++ b/user_guide_src/source/incoming/controllers/012.php @@ -1,12 +1,15 @@ $method(...$params); - } + if (method_exists($this, $method)) { + return $this->{$method}(...$params); + } - throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); + } } diff --git a/user_guide_src/source/incoming/controllers/013.php b/user_guide_src/source/incoming/controllers/013.php index eed95b673ad2..2586a7781dfe 100644 --- a/user_guide_src/source/incoming/controllers/013.php +++ b/user_guide_src/source/incoming/controllers/013.php @@ -1,6 +1,9 @@ validate([ - 'email' => "required|is_unique[users.email,id,{$userID}]", - 'name' => 'required|alpha_numeric_spaces' - ])) { - return view('users/update', [ - 'errors' => $this->validator->getErrors() - ]); - } + public function updateUser(int $userID) + { + if (! $this->validate([ + 'email' => "required|is_unique[users.email,id,{$userID}]", + 'name' => 'required|alpha_numeric_spaces', + ])) { + return view('users/update', [ + 'errors' => $this->validator->getErrors(), + ]); + } - // do something here if successful... + // do something here if successful... + } } diff --git a/user_guide_src/source/incoming/controllers/018.php b/user_guide_src/source/incoming/controllers/018.php index 54697409827a..29c3780cc854 100644 --- a/user_guide_src/source/incoming/controllers/018.php +++ b/user_guide_src/source/incoming/controllers/018.php @@ -1,12 +1,15 @@ validate('userRules')) { - return view('users/update', [ - 'errors' => $this->validator->getErrors() - ]); - } + public function updateUser(int $userID) + { + if (! $this->validate('userRules')) { + return view('users/update', [ + 'errors' => $this->validator->getErrors(), + ]); + } - // do something here if successful... + // do something here if successful... + } } diff --git a/user_guide_src/source/incoming/controllers/019.php b/user_guide_src/source/incoming/controllers/019.php index e5a96084c2c2..c27156d7232a 100644 --- a/user_guide_src/source/incoming/controllers/019.php +++ b/user_guide_src/source/incoming/controllers/019.php @@ -1,19 +1,23 @@ $id, - 'name' => $this->request->getVar('name'), - ]; - $rule = [ - 'id' => 'integer', - 'name' => 'required|max_length[255]', - ]; + public function product(int $id) + { + $data = [ + 'id' => $id, + 'name' => $this->request->getVar('name'), + ]; + + $rule = [ + 'id' => 'integer', + 'name' => 'required|max_length[255]', + ]; + + if (! $this->validateData($data, $rule)) { + // ... + } - if (! $this->validateData($data, $rule) { // ... } - - // ... -} \ No newline at end of file +} diff --git a/user_guide_src/source/incoming/filters/002.php b/user_guide_src/source/incoming/filters/002.php index 792921a348ef..b6c77a2eaa34 100644 --- a/user_guide_src/source/incoming/filters/002.php +++ b/user_guide_src/source/incoming/filters/002.php @@ -1,10 +1,13 @@ isLoggedIn()) { - return redirect()->to(site_url('login')); + if (! $auth->isLoggedIn()) { + return redirect()->to(site_url('login')); + } } } diff --git a/user_guide_src/source/incoming/filters/003.php b/user_guide_src/source/incoming/filters/003.php index 1ef6a461f3c6..a757fdf8f029 100644 --- a/user_guide_src/source/incoming/filters/003.php +++ b/user_guide_src/source/incoming/filters/003.php @@ -1,5 +1,8 @@ \CodeIgniter\Filters\CSRF::class, -]; +class Filters extends BaseConfig +{ + public $aliases = [ + 'csrf' => \CodeIgniter\Filters\CSRF::class, + ]; +} diff --git a/user_guide_src/source/incoming/filters/004.php b/user_guide_src/source/incoming/filters/004.php index a7f31363edad..3615cf8f6072 100644 --- a/user_guide_src/source/incoming/filters/004.php +++ b/user_guide_src/source/incoming/filters/004.php @@ -1,8 +1,11 @@ [ - \App\Filters\Negotiate::class, - \App\Filters\ApiAuth::class, - ] -]; +class Filters extends BaseConfig +{ + public $aliases = [ + 'apiPrep' => [ + \App\Filters\Negotiate::class, + \App\Filters\ApiAuth::class, + ], + ]; +} diff --git a/user_guide_src/source/incoming/filters/005.php b/user_guide_src/source/incoming/filters/005.php index 3f3801f5ce59..7599c93e1203 100644 --- a/user_guide_src/source/incoming/filters/005.php +++ b/user_guide_src/source/incoming/filters/005.php @@ -1,8 +1,11 @@ [ - 'csrf', - ], - 'after' => [], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + 'csrf', + ], + 'after' => [], + ]; +} diff --git a/user_guide_src/source/incoming/filters/006.php b/user_guide_src/source/incoming/filters/006.php index 3706979688cd..3cd37f8224e9 100644 --- a/user_guide_src/source/incoming/filters/006.php +++ b/user_guide_src/source/incoming/filters/006.php @@ -1,8 +1,11 @@ [ - 'csrf' => ['except' => 'api/*'], - ], - 'after' => [], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + 'csrf' => ['except' => 'api/*'], + ], + 'after' => [], + ]; +} diff --git a/user_guide_src/source/incoming/filters/007.php b/user_guide_src/source/incoming/filters/007.php index a6790adbf9b7..e9c1dba48fc6 100644 --- a/user_guide_src/source/incoming/filters/007.php +++ b/user_guide_src/source/incoming/filters/007.php @@ -1,8 +1,11 @@ [ - 'csrf' => ['except' => ['foo/*', 'bar/*']], - ], - 'after' => [], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + 'csrf' => ['except' => ['foo/*', 'bar/*']], + ], + 'after' => [], + ]; +} diff --git a/user_guide_src/source/incoming/filters/008.php b/user_guide_src/source/incoming/filters/008.php index 2f216281e982..e50628a13bd5 100644 --- a/user_guide_src/source/incoming/filters/008.php +++ b/user_guide_src/source/incoming/filters/008.php @@ -1,6 +1,9 @@ ['foo', 'bar'], - 'get' => ['baz'], -] +class Filters extends BaseConfig +{ + public $methods = [ + 'post' => ['foo', 'bar'], + 'get' => ['baz'], + ]; +} diff --git a/user_guide_src/source/incoming/filters/009.php b/user_guide_src/source/incoming/filters/009.php index 258edd689d3c..2505d8fcc2a2 100644 --- a/user_guide_src/source/incoming/filters/009.php +++ b/user_guide_src/source/incoming/filters/009.php @@ -1,6 +1,9 @@ ['before' => ['admin/*'], 'after' => ['users/*']], - 'bar' => ['before' => ['api/*', 'admin/*']], -]; +class Filters extends BaseConfig +{ + public $filters = [ + 'foo' => ['before' => ['admin/*'], 'after' => ['users/*']], + 'bar' => ['before' => ['api/*', 'admin/*']], + ]; +} diff --git a/user_guide_src/source/incoming/filters/011.php b/user_guide_src/source/incoming/filters/011.php index 10db5ad2eb40..54b276967859 100644 --- a/user_guide_src/source/incoming/filters/011.php +++ b/user_guide_src/source/incoming/filters/011.php @@ -1,6 +1,9 @@ \App\Filters\SecureHeaders::class, -]; +class Filters extends BaseConfig +{ + public $aliases = [ + // ... + 'secureheaders' => \App\Filters\SecureHeaders::class, + ]; +} diff --git a/user_guide_src/source/incoming/routing/011.php b/user_guide_src/source/incoming/routing/011.php index 11437a5881c2..790f965912ca 100644 --- a/user_guide_src/source/incoming/routing/011.php +++ b/user_guide_src/source/incoming/routing/011.php @@ -1,7 +1,11 @@ Date: Mon, 28 Feb 2022 13:41:56 +0100 Subject: [PATCH 1695/2325] Fix installation. --- .../source/installation/troubleshooting/001.php | 5 ++++- .../source/installation/troubleshooting/002.php | 5 ++++- .../source/installation/upgrade_404.rst | 10 ++++++---- .../source/installation/upgrade_404/001.php | 4 ---- .../source/installation/upgrade_404/002.php | 4 ---- .../source/installation/upgrade_415/001.php | 11 +++++++---- .../installation/upgrade_localization/001.php | 5 ++++- .../source/installation/upgrade_security/001.php | 15 +++++++++------ 8 files changed, 34 insertions(+), 25 deletions(-) delete mode 100644 user_guide_src/source/installation/upgrade_404/001.php delete mode 100644 user_guide_src/source/installation/upgrade_404/002.php diff --git a/user_guide_src/source/installation/troubleshooting/001.php b/user_guide_src/source/installation/troubleshooting/001.php index 54798c261dae..c3aa124d6ce2 100644 --- a/user_guide_src/source/installation/troubleshooting/001.php +++ b/user_guide_src/source/installation/troubleshooting/001.php @@ -1,3 +1,6 @@ ['csrf'], - 'post' => ['csrf'], -]; +class Filters extends BaseConfig +{ + public $methods = [ + 'get' => ['csrf'], + 'post' => ['csrf'], + ]; +} diff --git a/user_guide_src/source/installation/upgrade_localization/001.php b/user_guide_src/source/installation/upgrade_localization/001.php index c3b3de65be20..53d156de0545 100644 --- a/user_guide_src/source/installation/upgrade_localization/001.php +++ b/user_guide_src/source/installation/upgrade_localization/001.php @@ -1,3 +1,6 @@ [ - //'honeypot', - 'csrf', - ] -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + // 'honeypot', + 'csrf', + ], + ]; +} From ab46edc81069ae1344a7a6e458ca2ca891fde39b Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 14:15:04 +0100 Subject: [PATCH 1696/2325] Fix models. --- user_guide_src/source/models/entities/020.php | 19 ++++++++------ user_guide_src/source/models/model/038.php | 9 ++++--- user_guide_src/source/models/model/040.php | 9 ++++--- user_guide_src/source/models/model/041.php | 5 +++- user_guide_src/source/models/model/050.php | 17 +++++++------ user_guide_src/source/models/model/051.php | 7 ++++-- user_guide_src/source/models/model/052.php | 5 +++- user_guide_src/source/models/model/054.php | 25 +++++++++++-------- 8 files changed, 61 insertions(+), 35 deletions(-) diff --git a/user_guide_src/source/models/entities/020.php b/user_guide_src/source/models/entities/020.php index 4e7908e5c20d..0fa4e8e140df 100644 --- a/user_guide_src/source/models/entities/020.php +++ b/user_guide_src/source/models/entities/020.php @@ -1,11 +1,14 @@ 'class[App\SomeClass, param2, param3]', -]; +class MyEntity extends Entity +{ + // Defining a type with parameters + protected $casts = [ + 'some_attribute' => 'class[App\SomeClass, param2, param3]', + ]; -// Bind the type to the handler -protected $castHandlers = [ - 'class' => 'SomeHandler', -]; + // Bind the type to the handler + protected $castHandlers = [ + 'class' => 'SomeHandler', + ]; +} diff --git a/user_guide_src/source/models/model/038.php b/user_guide_src/source/models/model/038.php index 0a0dffd7dba5..d08b6333bc84 100644 --- a/user_guide_src/source/models/model/038.php +++ b/user_guide_src/source/models/model/038.php @@ -1,5 +1,8 @@ 'required|valid_email|is_unique[users.email,id,{id}]' -]; +class MyModel extends Model +{ + protected $validationRules = [ + 'email' => 'required|valid_email|is_unique[users.email,id,{id}]', + ]; +} diff --git a/user_guide_src/source/models/model/040.php b/user_guide_src/source/models/model/040.php index 68f9c5c13143..9e3402559d62 100644 --- a/user_guide_src/source/models/model/040.php +++ b/user_guide_src/source/models/model/040.php @@ -1,5 +1,8 @@ 'required|valid_email|is_unique[users.email,id,4]' -]; +class MyModel extends Model +{ + protected $validationRules = [ + 'email' => 'required|valid_email|is_unique[users.email,id,4]', + ]; +} diff --git a/user_guide_src/source/models/model/041.php b/user_guide_src/source/models/model/041.php index 8aaa151c61a1..f2f89729a632 100644 --- a/user_guide_src/source/models/model/041.php +++ b/user_guide_src/source/models/model/041.php @@ -1,3 +1,6 @@ getCachedItem($data['id']])) { - $data['data'] = $item; - $data['returnData'] = true; - - return $data; - } + protected $beforeFind = ['checkCache']; // ... + + protected function checkCache(array $data) + { + // Check if the requested item is already in our cache + if (isset($data['id']) && $item = $this->getCachedItem($data['id'])) { + $data['data'] = $item; + $data['returnData'] = true; + + return $data; + } + + // ... + } } From 9b8373600edfd565c990ff8a81c71a599c07d2dd Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 15:43:42 +0100 Subject: [PATCH 1697/2325] Fix tutorial. --- .../source/tutorial/create_news_items/001.php | 9 +++-- .../source/tutorial/create_news_items/002.php | 35 ++++++++++--------- .../source/tutorial/news_section/002.php | 13 ++++--- .../source/tutorial/news_section/004.php | 21 ++++++----- .../source/tutorial/news_section/006.php | 23 ++++++------ .../source/tutorial/static_pages/002.php | 21 ++++++----- 6 files changed, 70 insertions(+), 52 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items/001.php b/user_guide_src/source/tutorial/create_news_items/001.php index 80d86db34633..5091ec750126 100644 --- a/user_guide_src/source/tutorial/create_news_items/001.php +++ b/user_guide_src/source/tutorial/create_news_items/001.php @@ -1,5 +1,8 @@ ['csrf'], -]; +class Filters extends BaseConfig +{ + public $methods = [ + 'post' => ['csrf'], + ]; +} diff --git a/user_guide_src/source/tutorial/create_news_items/002.php b/user_guide_src/source/tutorial/create_news_items/002.php index 2dc230c3a720..b5a5004e0961 100644 --- a/user_guide_src/source/tutorial/create_news_items/002.php +++ b/user_guide_src/source/tutorial/create_news_items/002.php @@ -1,23 +1,26 @@ request->getMethod() === 'post' && $this->validate([ - 'title' => 'required|min_length[3]|max_length[255]', - 'body' => 'required', - ])) { - $model->save([ - 'title' => $this->request->getPost('title'), - 'slug' => url_title($this->request->getPost('title'), '-', true), - 'body' => $this->request->getPost('body'), - ]); + if ($this->request->getMethod() === 'post' && $this->validate([ + 'title' => 'required|min_length[3]|max_length[255]', + 'body' => 'required', + ])) { + $model->save([ + 'title' => $this->request->getPost('title'), + 'slug' => url_title($this->request->getPost('title'), '-', true), + 'body' => $this->request->getPost('body'), + ]); - echo view('news/success'); - } else { - echo view('templates/header', ['title' => 'Create a news item']); - echo view('news/create'); - echo view('templates/footer'); + echo view('news/success'); + } else { + echo view('templates/header', ['title' => 'Create a news item']); + echo view('news/create'); + echo view('templates/footer'); + } } } diff --git a/user_guide_src/source/tutorial/news_section/002.php b/user_guide_src/source/tutorial/news_section/002.php index bf8f4217be57..66a6d8f224dd 100644 --- a/user_guide_src/source/tutorial/news_section/002.php +++ b/user_guide_src/source/tutorial/news_section/002.php @@ -1,10 +1,13 @@ findAll(); - } + public function getNews($slug = false) + { + if ($slug === false) { + return $this->findAll(); + } - return $this->where(['slug' => $slug])->first(); + return $this->where(['slug' => $slug])->first(); + } } diff --git a/user_guide_src/source/tutorial/news_section/004.php b/user_guide_src/source/tutorial/news_section/004.php index 0fac31909775..f6973a3deafc 100644 --- a/user_guide_src/source/tutorial/news_section/004.php +++ b/user_guide_src/source/tutorial/news_section/004.php @@ -1,15 +1,18 @@ $model->getNews(), - 'title' => 'News archive', - ]; + $data = [ + 'news' => $model->getNews(), + 'title' => 'News archive', + ]; - echo view('templates/header', $data); - echo view('news/overview', $data); - echo view('templates/footer', $data); + echo view('templates/header', $data); + echo view('news/overview', $data); + echo view('templates/footer', $data); + } } diff --git a/user_guide_src/source/tutorial/news_section/006.php b/user_guide_src/source/tutorial/news_section/006.php index ea7331dbf77f..afaa1cee5800 100644 --- a/user_guide_src/source/tutorial/news_section/006.php +++ b/user_guide_src/source/tutorial/news_section/006.php @@ -1,18 +1,21 @@ getNews($slug); + $data['news'] = $model->getNews($slug); - if (empty($data['news'])) { - throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug); - } + if (empty($data['news'])) { + throw new \CodeIgniter\Exceptions\PageNotFoundException('Cannot find the news item: ' . $slug); + } - $data['title'] = $data['news']['title']; + $data['title'] = $data['news']['title']; - echo view('templates/header', $data); - echo view('news/view', $data); - echo view('templates/footer', $data); + echo view('templates/header', $data); + echo view('news/view', $data); + echo view('templates/footer', $data); + } } diff --git a/user_guide_src/source/tutorial/static_pages/002.php b/user_guide_src/source/tutorial/static_pages/002.php index 4f5901845f9d..bd3eb8938a57 100644 --- a/user_guide_src/source/tutorial/static_pages/002.php +++ b/user_guide_src/source/tutorial/static_pages/002.php @@ -1,15 +1,18 @@ Date: Mon, 28 Feb 2022 15:48:29 +0100 Subject: [PATCH 1698/2325] Fix general. --- .../source/general/configuration/008.php | 9 ++++++--- user_guide_src/source/general/errors/003.php | 4 +++- user_guide_src/source/general/errors/004.php | 4 +++- user_guide_src/source/general/logging/002.php | 5 ++++- user_guide_src/source/general/logging/003.php | 7 +++++-- user_guide_src/source/general/logging/004.php | 15 +++++++++------ .../source/general/managing_apps/001.php | 5 ++++- user_guide_src/source/general/modules/001.php | 13 ++++++++----- user_guide_src/source/general/modules/002.php | 13 ++++++++----- user_guide_src/source/general/modules/003.php | 13 ++++++++----- user_guide_src/source/general/modules/004.php | 5 ++++- 11 files changed, 62 insertions(+), 31 deletions(-) diff --git a/user_guide_src/source/general/configuration/008.php b/user_guide_src/source/general/configuration/008.php index 54072ca22fba..dd301d8c69a1 100644 --- a/user_guide_src/source/general/configuration/008.php +++ b/user_guide_src/source/general/configuration/008.php @@ -1,5 +1,8 @@ find($id); +} catch (\CodeIgniter\UnknownFileException $e) { // do something here... } diff --git a/user_guide_src/source/general/errors/004.php b/user_guide_src/source/general/errors/004.php index 06a972cfc4d8..752b23bdba30 100644 --- a/user_guide_src/source/general/errors/004.php +++ b/user_guide_src/source/general/errors/004.php @@ -1,6 +1,8 @@ find($id); +} catch (\CodeIgniter\UnknownFileException $e) { // do something here... throw new \RuntimeException($e->getMessage(), $e->getCode(), $e); diff --git a/user_guide_src/source/general/logging/002.php b/user_guide_src/source/general/logging/002.php index bf08b8722b63..d542f40b4ccb 100644 --- a/user_guide_src/source/general/logging/002.php +++ b/user_guide_src/source/general/logging/002.php @@ -1,3 +1,6 @@ [ - 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'], - ] -]; +class Logger extends BaseConfig +{ + public $handlers = [ + // File Handler + 'CodeIgniter\Log\Handlers\FileHandler' => [ + 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'], + ], + ]; +} diff --git a/user_guide_src/source/general/managing_apps/001.php b/user_guide_src/source/general/managing_apps/001.php index 27deaaf4b994..d1690bdd55e6 100644 --- a/user_guide_src/source/general/managing_apps/001.php +++ b/user_guide_src/source/general/managing_apps/001.php @@ -1,3 +1,6 @@ APPPATH, // For custom namespace - 'Config' => APPPATH . 'Config', - 'Acme' => ROOTPATH . 'acme', -]; +class Autoload extends AutoloadConfig +{ + public $psr4 = [ + APP_NAMESPACE => APPPATH, // For custom namespace + 'Config' => APPPATH . 'Config', + 'Acme' => ROOTPATH . 'acme', + ]; +} diff --git a/user_guide_src/source/general/modules/002.php b/user_guide_src/source/general/modules/002.php index 7cab63838ec5..4d7b355da602 100644 --- a/user_guide_src/source/general/modules/002.php +++ b/user_guide_src/source/general/modules/002.php @@ -1,7 +1,10 @@ APPPATH, // For custom namespace - 'Config' => APPPATH . 'Config', - 'Acme\Blog' => ROOTPATH . 'acme/Blog', // Change -]; +class Autoload extends AutoloadConfig +{ + public $psr4 = [ + APP_NAMESPACE => APPPATH, // For custom namespace + 'Config' => APPPATH . 'Config', + 'Acme\Blog' => ROOTPATH . 'acme/Blog', // Change + ]; +} diff --git a/user_guide_src/source/general/modules/004.php b/user_guide_src/source/general/modules/004.php index 56804cc2e579..0f2c1c3967ad 100644 --- a/user_guide_src/source/general/modules/004.php +++ b/user_guide_src/source/general/modules/004.php @@ -1,3 +1,6 @@ Date: Mon, 28 Feb 2022 16:18:16 +0100 Subject: [PATCH 1699/2325] Fix outgoing. --- .../source/outgoing/api_responses/003.php | 11 +++++++---- .../source/outgoing/api_responses/004.php | 11 +++++++---- .../source/outgoing/localization/001.php | 5 ++++- .../source/outgoing/localization/002.php | 5 ++++- .../source/outgoing/localization/003.php | 5 ++++- user_guide_src/source/outgoing/response/011.php | 5 ++++- .../source/outgoing/view_decorators/002.php | 9 ++++++--- .../source/outgoing/view_layouts/001.php | 7 +++++-- .../source/outgoing/view_parser/012.php | 11 +++++++---- .../source/outgoing/view_parser/013.php | 9 ++++++--- .../source/outgoing/view_parser/014.php | 15 +++++++++------ .../source/outgoing/view_parser/016.php | 9 ++++++--- .../source/outgoing/view_parser/017.php | 9 ++++++--- 13 files changed, 75 insertions(+), 36 deletions(-) diff --git a/user_guide_src/source/outgoing/api_responses/003.php b/user_guide_src/source/outgoing/api_responses/003.php index ab1db7ccdc45..a8e8ed09de64 100644 --- a/user_guide_src/source/outgoing/api_responses/003.php +++ b/user_guide_src/source/outgoing/api_responses/003.php @@ -1,6 +1,9 @@ \CodeIgniter\Format\JSONFormatter::class, - 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, -]; +class Format extends BaseConfig +{ + public $formatters = [ + 'application/json' => \CodeIgniter\Format\JSONFormatter::class, + 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, + ]; +} diff --git a/user_guide_src/source/outgoing/localization/001.php b/user_guide_src/source/outgoing/localization/001.php index c3b3de65be20..53d156de0545 100644 --- a/user_guide_src/source/outgoing/localization/001.php +++ b/user_guide_src/source/outgoing/localization/001.php @@ -1,3 +1,6 @@ '\CodeIgniter\View\Filters::abs', - 'capitalize' => '\CodeIgniter\View\Filters::capitalize', -]; +class View extends BaseView +{ + public $filters = [ + 'abs' => '\CodeIgniter\View\Filters::abs', + 'capitalize' => '\CodeIgniter\View\Filters::capitalize', + ]; +} diff --git a/user_guide_src/source/outgoing/view_parser/013.php b/user_guide_src/source/outgoing/view_parser/013.php index dbb096b416fb..78788515d081 100644 --- a/user_guide_src/source/outgoing/view_parser/013.php +++ b/user_guide_src/source/outgoing/view_parser/013.php @@ -1,5 +1,8 @@ '\str_repeat', -]; +class View extends BaseView +{ + public $filters = [ + 'str_repeat' => '\str_repeat', + ]; +} diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php index d959d153d415..6219ce03b07d 100644 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -1,8 +1,11 @@ '\Some\Class::methodName', - 'bar' => function ($str, array $params=[]) { - return $str; - }, -]; +class View extends BaseView +{ + 'foo' => '\Some\Class::methodName', + public $plugins = [ + 'bar' => function($str, array $params = []) { + return $str; + }, + ]; +} diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index e93bd3986957..5e2f5a2f0b0b 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -1,8 +1,11 @@ '\Some\Class::methodName' -]; +class View extends BaseView +{ + public $plugins = [ + 'foo' => '\Some\Class::methodName', + ]; +} // Tag is replaced by the return value of Some\Class::methodName static function. // {+ foo +} diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php index 4e699d190bcd..d38e54c5274f 100644 --- a/user_guide_src/source/outgoing/view_parser/017.php +++ b/user_guide_src/source/outgoing/view_parser/017.php @@ -1,7 +1,10 @@ ['\Some\Class::methodName'] -]; +class View extends BaseView +{ + public $plugins = [ + 'foo' => ['\Some\Class::methodName'], + ]; +} // {+ foo +} inner content {+ /foo +} From e877550f220028a98bf330e484009d263c3be85a Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 16:31:53 +0100 Subject: [PATCH 1700/2325] Fix libraries. --- .../source/libraries/caching/013.php | 15 +++--- .../source/libraries/caching/014.php | 17 ++++--- .../source/libraries/curlrequest/001.php | 5 +- .../source/libraries/encryption/005.php | 5 +- .../source/libraries/encryption/008.php | 11 +++-- .../source/libraries/honeypot/001.php | 23 +++++---- .../source/libraries/pagination/003.php | 10 ++-- .../source/libraries/pagination/004.php | 22 +++++---- .../source/libraries/pagination/010.php | 11 +++-- .../source/libraries/pagination/011.php | 13 +++-- .../source/libraries/security/002.php | 5 +- .../source/libraries/security/003.php | 5 +- .../source/libraries/security/004.php | 5 +- .../source/libraries/security/005.php | 5 +- .../source/libraries/security/006.php | 15 +++--- .../source/libraries/security/007.php | 13 +++-- .../source/libraries/security/008.php | 13 +++-- .../source/libraries/security/009.php | 11 +++-- .../source/libraries/sessions/040.php | 7 ++- .../source/libraries/sessions/041.php | 5 +- .../source/libraries/sessions/042.php | 7 ++- .../source/libraries/sessions/043.php | 7 ++- .../source/libraries/sessions/044.php | 9 ++-- .../source/libraries/throttler/003.php | 11 +++-- .../source/libraries/throttler/004.php | 9 ++-- .../source/libraries/validation/003.php | 15 +++--- .../source/libraries/validation/031.php | 13 +++-- .../source/libraries/validation/032.php | 15 +++--- .../source/libraries/validation/034.php | 15 +++--- .../source/libraries/validation/036.php | 49 ++++++++++--------- 30 files changed, 228 insertions(+), 138 deletions(-) diff --git a/user_guide_src/source/libraries/caching/013.php b/user_guide_src/source/libraries/caching/013.php index 66f0fa99e959..52e77d4b7f4b 100644 --- a/user_guide_src/source/libraries/caching/013.php +++ b/user_guide_src/source/libraries/caching/013.php @@ -1,8 +1,11 @@ '127.0.0.1', - 'port' => 11211, - 'weight' => 1, - 'raw' => false, -]; +class Cache extends BaseConfig +{ + public $memcached = [ + 'host' => '127.0.0.1', + 'port' => 11211, + 'weight' => 1, + 'raw' => false, + ]; +} diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php index 20dfb69ce9b0..2c0f5eb719bd 100644 --- a/user_guide_src/source/libraries/caching/014.php +++ b/user_guide_src/source/libraries/caching/014.php @@ -1,9 +1,12 @@ '127.0.0.1', - 'password' => null, - 'port' => 6379, - 'timeout' => 0, - 'database' => 0, -]; +class Cache extends BaseConfig +{ + public $redis = [ + 'host' => '127.0.0.1', + 'password' => null, + 'port' => 6379, + 'timeout' => 0, + 'database' => 0, + ]; +} diff --git a/user_guide_src/source/libraries/curlrequest/001.php b/user_guide_src/source/libraries/curlrequest/001.php index 43e1f74bc943..35d47924e213 100644 --- a/user_guide_src/source/libraries/curlrequest/001.php +++ b/user_guide_src/source/libraries/curlrequest/001.php @@ -1,3 +1,6 @@ ' +class Encryption extends BaseConfig +{ + // In Encryption, you may use + public $key = 'hex2bin:'; -// or -public $key = 'base64:' + // or + public $key = 'base64:'; +} diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php index 1ed16460a9a4..8d73a4f1e586 100644 --- a/user_guide_src/source/libraries/honeypot/001.php +++ b/user_guide_src/source/libraries/honeypot/001.php @@ -1,12 +1,15 @@ [ - 'honeypot' - // 'csrf', - ], - 'after' => [ - 'toolbar', - 'honeypot', - ], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + 'honeypot', + // 'csrf', + ], + 'after' => [ + 'toolbar', + 'honeypot', + ], + ]; +} diff --git a/user_guide_src/source/libraries/pagination/003.php b/user_guide_src/source/libraries/pagination/003.php index f0ea0d90ed76..423adc232c19 100644 --- a/user_guide_src/source/libraries/pagination/003.php +++ b/user_guide_src/source/libraries/pagination/003.php @@ -10,10 +10,14 @@ // You can move the conditions to a separate method. // Model method -public function banned() +class UserModel extends Model { - $this->builder()->where('ban', 1); - return $this; // This will allow the call chain to be used. + public function banned() + { + $this->builder()->where('ban', 1); + + return $this; // This will allow the call chain to be used. + } } $data = [ diff --git a/user_guide_src/source/libraries/pagination/004.php b/user_guide_src/source/libraries/pagination/004.php index cd425a1026eb..6326d1f9c825 100644 --- a/user_guide_src/source/libraries/pagination/004.php +++ b/user_guide_src/source/libraries/pagination/004.php @@ -1,20 +1,22 @@ $userModel->paginate(10, 'group1'), - 'pages' => $pageModel->paginate(15, 'group2'), - 'pager' => $userModel->pager, - ]; + $data = [ + 'users' => $userModel->paginate(10, 'group1'), + 'pages' => $pageModel->paginate(15, 'group2'), + 'pager' => $userModel->pager, + ]; - echo view('users/index', $data); + echo view('users/index', $data); + } } - ?> diff --git a/user_guide_src/source/libraries/pagination/010.php b/user_guide_src/source/libraries/pagination/010.php index 95d27f8e4e3c..1f97238b0506 100644 --- a/user_guide_src/source/libraries/pagination/010.php +++ b/user_guide_src/source/libraries/pagination/010.php @@ -1,6 +1,9 @@ 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', -]; +class Pager extends BaseConfig +{ + public $templates = [ + 'default_full' => 'CodeIgniter\Pager\Views\default_full', + 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', + ]; +} diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php index fa59edbacf9b..8387b1e82dbd 100644 --- a/user_guide_src/source/libraries/pagination/011.php +++ b/user_guide_src/source/libraries/pagination/011.php @@ -1,7 +1,10 @@ 'CodeIgniter\Pager\Views\default_full', - 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', - 'front_full' => 'App\Views\Pagers\foundation_full', -]; +class Pager extends BaseConfig +{ + public $templates = [ + 'default_full' => 'CodeIgniter\Pager\Views\default_full', + 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', + 'front_full' => 'App\Views\Pagers\foundation_full', + ]; +} diff --git a/user_guide_src/source/libraries/security/002.php b/user_guide_src/source/libraries/security/002.php index 292d5a9410dc..1ce5fbba68d9 100644 --- a/user_guide_src/source/libraries/security/002.php +++ b/user_guide_src/source/libraries/security/002.php @@ -1,3 +1,6 @@ [ - // 'honeypot', - 'csrf', - ], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + // 'honeypot', + 'csrf', + ], + ]; +} diff --git a/user_guide_src/source/libraries/security/007.php b/user_guide_src/source/libraries/security/007.php index d647d1b8c120..db1b03df65fb 100644 --- a/user_guide_src/source/libraries/security/007.php +++ b/user_guide_src/source/libraries/security/007.php @@ -1,7 +1,10 @@ [ - 'csrf' => ['except' => ['api/record/save']], - ], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + 'csrf' => ['except' => ['api/record/save']], + ], + ]; +} diff --git a/user_guide_src/source/libraries/security/008.php b/user_guide_src/source/libraries/security/008.php index c78d18937b08..2138994f0241 100644 --- a/user_guide_src/source/libraries/security/008.php +++ b/user_guide_src/source/libraries/security/008.php @@ -1,7 +1,10 @@ [ - 'csrf' => ['except' => ['api/record/[0-9]+']], - ], -]; +class Filters extends BaseConfig +{ + public $globals = [ + 'before' => [ + 'csrf' => ['except' => ['api/record/[0-9]+']], + ], + ]; +} diff --git a/user_guide_src/source/libraries/security/009.php b/user_guide_src/source/libraries/security/009.php index e2b03e79ba25..b2ffbeaadc37 100644 --- a/user_guide_src/source/libraries/security/009.php +++ b/user_guide_src/source/libraries/security/009.php @@ -1,6 +1,9 @@ ['csrf'], - 'post' => ['csrf'], -]; +class Filters extends BaseConfig +{ + public $methods = [ + 'get' => ['csrf'], + 'post' => ['csrf'], + ]; +} diff --git a/user_guide_src/source/libraries/sessions/040.php b/user_guide_src/source/libraries/sessions/040.php index a3724620886d..7aa5f051b875 100644 --- a/user_guide_src/source/libraries/sessions/040.php +++ b/user_guide_src/source/libraries/sessions/040.php @@ -1,4 +1,7 @@ \App\Filters\Throttle::class, -]; +class Filters extends BaseConfig +{ + public $aliases = [ + // ... + 'throttle' => \App\Filters\Throttle::class, + ]; +} diff --git a/user_guide_src/source/libraries/throttler/004.php b/user_guide_src/source/libraries/throttler/004.php index 455874cd5730..e7d0643db053 100644 --- a/user_guide_src/source/libraries/throttler/004.php +++ b/user_guide_src/source/libraries/throttler/004.php @@ -1,5 +1,8 @@ ['throttle'], -]; +class Filters extends BaseConfig +{ + public $methods = [ + 'post' => ['throttle'], + ]; +} diff --git a/user_guide_src/source/libraries/validation/003.php b/user_guide_src/source/libraries/validation/003.php index a6ae3a4a6fff..a9e83b94698b 100644 --- a/user_guide_src/source/libraries/validation/003.php +++ b/user_guide_src/source/libraries/validation/003.php @@ -1,8 +1,11 @@ 'CodeIgniter\Validation\Views\list', - 'single' => 'CodeIgniter\Validation\Views\single', - 'my_list' => '_errors_list', -]; +class Validation +{ + public $templates = [ + 'list' => 'CodeIgniter\Validation\Views\list', + 'single' => 'CodeIgniter\Validation\Views\single', + 'my_list' => '_errors_list', + ]; +} diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php index ccee27b08ad7..9877e6e85579 100644 --- a/user_guide_src/source/libraries/validation/032.php +++ b/user_guide_src/source/libraries/validation/032.php @@ -5,9 +5,12 @@ use CodeIgniter\Validation\FormatRules; use CodeIgniter\Validation\Rules; -public $ruleSets = [ - Rules::class, - FormatRules::class, - FileRules::class, - CreditCardRules::class, -]; +class Validation +{ + public $ruleSets = [ + Rules::class, + FormatRules::class, + FileRules::class, + CreditCardRules::class, + ]; +} diff --git a/user_guide_src/source/libraries/validation/034.php b/user_guide_src/source/libraries/validation/034.php index a6a9b07f54ef..843b623ba98c 100644 --- a/user_guide_src/source/libraries/validation/034.php +++ b/user_guide_src/source/libraries/validation/034.php @@ -1,12 +1,15 @@ required($str ?? ''); + // If the field is present we can safely assume that + // the field is here, no matter whether the corresponding + // search field is present or not. + $present = $this->required($str ?? ''); - if ($present) { - return true; - } + if ($present) { + return true; + } - // Still here? Then we fail this test if - // any of the fields are present in $data - // as $fields is the lis - $requiredFields = []; + // Still here? Then we fail this test if + // any of the fields are present in $data + // as $fields is the lis + $requiredFields = []; - foreach ($fields as $field) { - if (array_key_exists($field, $data)) { - $requiredFields[] = $field; + foreach ($fields as $field) { + if (array_key_exists($field, $data)) { + $requiredFields[] = $field; + } } - } - // Remove any keys with empty values since, that means they - // weren't truly there, as far as this is concerned. - $requiredFields = array_filter($requiredFields, function ($item) use ($data) { - return ! empty($data[$item]); - }); + // Remove any keys with empty values since, that means they + // weren't truly there, as far as this is concerned. + $requiredFields = array_filter($requiredFields, static function ($item) use ($data) { + return ! empty($data[$item]); + }); - return empty($requiredFields); + return empty($requiredFields); + } } From 9aad6521d16ae398618ba6b2ae1486a88ae48c1e Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 16:34:19 +0100 Subject: [PATCH 1701/2325] Edit view_parser. --- user_guide_src/source/outgoing/view_parser/014.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php index 6219ce03b07d..182480337653 100644 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -2,8 +2,9 @@ class View extends BaseView { - 'foo' => '\Some\Class::methodName', + public $plugins = [ + 'foo' => '\Some\Class::methodName', 'bar' => function($str, array $params = []) { return $str; }, From 439153fe4838ab68ef592d9c227e95fd10a24f2e Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 16:40:00 +0100 Subject: [PATCH 1702/2325] Fix testing from code review. --- user_guide_src/source/testing/overview.rst | 5 +++-- user_guide_src/source/testing/overview/007.php | 5 +---- user_guide_src/source/testing/overview/019.php | 6 +++--- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 648b3b4e79d9..2cfae8328caa 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -87,8 +87,9 @@ to help with staging and clean up:: public static function setUpBeforeClass(): void public static function tearDownAfterClass(): void - public function setUp(): void - public function tearDown(): void + + 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 diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php index 1ba21e197b0a..4921e027b721 100644 --- a/user_guide_src/source/testing/overview/007.php +++ b/user_guide_src/source/testing/overview/007.php @@ -10,10 +10,7 @@ protected function setUpAuthTrait() // ... } -/** - * @internal - */ -final class AuthenticationFeatureTest +final class AuthenticationFeatureTest extends CIUnitTestCase { use AuthTrait; diff --git a/user_guide_src/source/testing/overview/019.php b/user_guide_src/source/testing/overview/019.php index 3ede5c1e1291..d45682fcffaa 100644 --- a/user_guide_src/source/testing/overview/019.php +++ b/user_guide_src/source/testing/overview/019.php @@ -2,18 +2,18 @@ final class Sometest extends CIUnitTestCase { - protected function setUp() + protected function setUp(): void { CITestStreamFilter::$buffer = ''; $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); } - protected function tearDown() + protected function tearDown(): void { stream_filter_remove($this->stream_filter); } - public function testSomeOutput() + public function testSomeOutput(): void { CLI::write('first.'); $expected = "first.\n"; From a1206a62e64c79cf42d65c4a066025150842cda2 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Mon, 28 Feb 2022 22:33:01 +0100 Subject: [PATCH 1703/2325] Fix view_parser examples. --- user_guide_src/source/outgoing/view_parser.rst | 4 ++-- user_guide_src/source/outgoing/view_parser/014.php | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index cee76727ef84..2e615e52bdb9 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -467,11 +467,11 @@ Registering a Plugin At its simplest, all you need to do to register a new plugin and make it ready for use is to add it to the **app/Config/View.php**, under the **$plugins** array. The key is the name of the plugin that is -used within the template file. The value is any valid PHP callable, including static class methods, and closures: +used within the template file. The value is any valid PHP callable, including static class methods: .. literalinclude:: view_parser/014.php -Any closures that are being used must be defined in the config file's constructor: +You can also use closures, but these can only be defined in the config file's constructor: .. literalinclude:: view_parser/015.php diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php index 182480337653..22dd679fb9bd 100644 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -2,11 +2,7 @@ class View extends BaseView { - public $plugins = [ 'foo' => '\Some\Class::methodName', - 'bar' => function($str, array $params = []) { - return $str; - }, ]; } From de2113d130d3739baf4510496a9b7c9c5678e4b5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 28 Feb 2022 16:36:08 +0900 Subject: [PATCH 1704/2325] docs: add section to link to "Extending the Controller" --- user_guide_src/source/incoming/controllers.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 21c717d9eace..5ade052c563a 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -307,6 +307,11 @@ Example: .. literalinclude:: controllers/012.php +Extending the Controller +************************ + +If you want to extend the controller, see :doc:`../extending/basecontroller`. + That's it! ********** From 4b5fd2fb341f16d1ea4f3d353b43f98e1964b2c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 13:43:29 +0900 Subject: [PATCH 1705/2325] docs: fix section titles and its marks --- .../source/tutorial/create_news_items.rst | 14 ++++++------ .../source/tutorial/news_section.rst | 22 +++++++++---------- .../source/tutorial/static_pages.rst | 16 +++++++------- 3 files changed, 26 insertions(+), 26 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 7925edc05fd1..4300b44c3155 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -1,4 +1,4 @@ -Create news items +Create News Items ################# You now know how you can read data from a database using CodeIgniter, but @@ -7,7 +7,7 @@ you'll expand your news controller and model created earlier to include this functionality. Enable CSRF Filter ------------------- +****************** Before creating a form, let's enable the CSRF protection. @@ -22,8 +22,8 @@ You can read more about the CSRF protection in :doc:`Security `. @@ -47,8 +47,8 @@ The seed records might be something like: (2,'Say it isn\'t so!','say-it-isnt-so','Scientists conclude that some programmers have a sense of humor.'), (3,'Caffeination, Yes!','caffeination-yes','World\'s largest coffee shop open onsite nested coffee shop for staff only.'); -Connect to your database -------------------------------------------------------- +Connect to Your Database +************************ The local configuration file, ``.env``, that you created when you installed CodeIgniter, should have the database property settings uncommented and @@ -63,8 +63,8 @@ your database properly as described :doc:`here <../database/configuration>`. database.default.password = root database.default.DBDriver = MySQLi -Setting up your model -------------------------------------------------------- +Setting up Your Model +********************* Instead of writing database operations right in the controller, queries should be placed in a model, so they can easily be reused later. Models @@ -106,8 +106,8 @@ that use the Query Builder to run their commands on the current table, and returning an array of results in the format of your choice. In this example, ``findAll()`` returns an array of array. -Display the news -------------------------------------------------------- +Display the News +**************** Now that the queries are written, the model should be tied to the views that are going to display the news items to the user. This could be done @@ -174,7 +174,7 @@ The only thing left to do is create the corresponding view at .. literalinclude:: news_section/007.php Routing -------------------------------------------------------- +******* Because of the wildcard routing rule created earlier, you need an extra route to view the controller that you just made. Modify your routing file diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index 090a4d79e2f8..c6091aa46609 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -1,5 +1,5 @@ -Static pages -############################################################################### +Static Pages +############ .. note:: This tutorial assumes you've downloaded CodeIgniter and :doc:`installed the framework <../installation/index>` in your @@ -27,8 +27,8 @@ you'll see URL patterns that match: As URL schemes become more complex, this may change. But for now, this is all we will need to know. -Let's make our first controller -------------------------------------------------------- +Let's Make our First Controller +******************************* Create a file at **app/Controllers/Pages.php** with the following code. @@ -85,8 +85,8 @@ includes the following code:: function. It's a global function provided by CodeIgniter to help prevent XSS attacks. You can read more about it :doc:`here `. -Adding logic to the controller -------------------------------------------------------- +Adding Logic to the Controller +****************************** Earlier you set up a controller with a ``view()`` method. The method accepts one parameter, which is the name of the page to be loaded. The @@ -131,7 +131,7 @@ view. :doc:`here `. Running the App -------------------------------------------------------- +*************** Ready to test? You cannot run the app using PHP's built-in server, since it will not properly process the ``.htaccess`` rules that are provided in @@ -177,7 +177,7 @@ controller you made above produces... +---------------------------------+-----------------------------------------------------------------+ Routing -------------------------------------------------------- +******* The controller is now functioning! From 6f3dde36f192b77a2f683d2fa2742b361438de16 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 13:47:57 +0900 Subject: [PATCH 1706/2325] docs: fix RST format `::` --- .../source/tutorial/create_news_items.rst | 8 ++----- user_guide_src/source/tutorial/index.rst | 8 ++----- .../source/tutorial/news_section.rst | 21 +++++++------------ .../source/tutorial/static_pages.rst | 16 ++++---------- 4 files changed, 16 insertions(+), 37 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 4300b44c3155..32bc4b703e18 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -29,9 +29,7 @@ To input data into the database, you need to create a form where you can input the information to be stored. This means you'll be needing a form with two fields, one for the title and one for the text. You'll derive the slug from our title in the model. Create a new view at -**app/Views/news/create.php**. - -:: +**app/Views/news/create.php**::

    @@ -89,9 +87,7 @@ slug, perfect for creating URIs. After this, a view is loaded to display a success message. Create a view at **app/Views/news/success.php** and write a success message. -This could be as simple as: - -:: +This could be as simple as:: News item created successfully. diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst index 35cb5ba9ba7f..a47cdab405d1 100644 --- a/user_guide_src/source/tutorial/index.rst +++ b/user_guide_src/source/tutorial/index.rst @@ -55,9 +55,7 @@ Getting Up and Running You can download a release manually from the site, but for this tutorial we will use the recommended way and install the AppStarter package through Composer. -From your command line type the following: - -:: +From your command line type the following:: > composer create-project codeigniter4/appstarter ci-news @@ -88,9 +86,7 @@ The Welcome Page **************** Now point your browser to the correct URL you will be greeted by a welcome screen. -Try it now by heading to the following URL: - -:: +Try it now by heading to the following URL:: http://localhost:8080 diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index b9713c3acadb..2797c8a5cfaa 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -18,13 +18,7 @@ commands (mysql, MySQL Workbench, or phpMyAdmin). You need to create a database that can be used for this tutorial, and then configure CodeIgniter to use it. -Using your database client, connect to your database and run the SQL command below (MySQL). -Also, add some seed records. For now, we'll just show you the SQL statements needed -to create the table, but you should be aware that this can be done programmatically -once you are more familiar with CodeIgniter; you can read about :doc:`Migrations <../dbmgmt/migration>` -and :doc:`Seeds <../dbmgmt/seeds>` to create more useful database setups later. - -:: +Using your database client, connect to your database and run the SQL command below (MySQL):: CREATE TABLE news ( id INT UNSIGNED NOT NULL AUTO_INCREMENT, @@ -35,12 +29,15 @@ and :doc:`Seeds <../dbmgmt/seeds>` to create more useful database setups later. KEY slug (slug) ); +Also, add some seed records. For now, we'll just show you the SQL statements needed +to create the table, but you should be aware that this can be done programmatically +once you are more familiar with CodeIgniter; you can read about :doc:`Migrations <../dbmgmt/migration>` +and :doc:`Seeds <../dbmgmt/seeds>` to create more useful database setups later. + A note of interest: a "slug", in the context of web publishing, is a user- and SEO-friendly short text used in a URL to identify and describe a resource. -The seed records might be something like: - -:: +The seed records might be something like:: INSERT INTO news VALUES (1,'Elvis sighted','elvis-sighted','Elvis was sighted at the Podunk internet cafe. It looked like he was writing a CodeIgniter app.'), @@ -53,9 +50,7 @@ Connect to Your Database The local configuration file, ``.env``, that you created when you installed CodeIgniter, should have the database property settings uncommented and set appropriately for the database you want to use. Make sure you've configured -your database properly as described :doc:`here <../database/configuration>`. - -:: +your database properly as described :doc:`here <../database/configuration>`:: database.default.hostname = localhost database.default.database = ci4tutorial diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index c6091aa46609..5128d6665e2c 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -9,18 +9,14 @@ The first thing you're going to do is set up a **controller** to handle static pages. A controller is simply a class that helps delegate work. It is the glue of your web application. -For example, when a call is made to: - -:: +For example, when a call is made to:: http://example.com/news/latest/10 We might imagine that there is a controller named "news". The method being called on news would be "latest". The news method's job could be to grab 10 news items, and render them on the page. Very often in MVC, -you'll see URL patterns that match: - -:: +you'll see URL patterns that match:: http://example.com/[controller-class]/[controller-method]/[arguments] @@ -138,9 +134,7 @@ since it will not properly process the ``.htaccess`` rules that are provided in ``public``, and which eliminate the need to specify "index.php/" as part of a URL. CodeIgniter has its own command that you can use though. -From the command line, at the root of your project: - -:: +From the command line, at the root of your project:: > php spark serve @@ -182,9 +176,7 @@ Routing The controller is now functioning! Using custom routing rules, you have the power to map any URI to any -controller and method, and break free from the normal convention: - -:: +controller and method, and break free from the normal convention:: http://example.com/[controller-class]/[controller-method]/[arguments] From 4e4ab0b381e57a334c89d0626812c24746656bf7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 13:48:24 +0900 Subject: [PATCH 1707/2325] docs: fix out-of-dated description --- user_guide_src/source/tutorial/index.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/tutorial/index.rst b/user_guide_src/source/tutorial/index.rst index a47cdab405d1..e940ec849057 100644 --- a/user_guide_src/source/tutorial/index.rst +++ b/user_guide_src/source/tutorial/index.rst @@ -22,7 +22,7 @@ This tutorial will primarily focus on: - Model-View-Controller basics - Routing basics - Form validation -- Performing basic database queries using CodeIgniter's "Query Builder" +- Performing basic database queries using CodeIgniter's Model The entire tutorial is split up over several pages, each explaining a small part of the functionality of the CodeIgniter framework. You'll go From 6288b6b60722a750483feed8da5dd90dbe71a24a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 14:43:32 +0900 Subject: [PATCH 1708/2325] docs: add how to code to prevent CSRF --- user_guide_src/source/libraries/security.rst | 33 +++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/security.rst b/user_guide_src/source/libraries/security.rst index 7d69bc84ea2c..456d92207ef9 100644 --- a/user_guide_src/source/libraries/security.rst +++ b/user_guide_src/source/libraries/security.rst @@ -22,12 +22,43 @@ If you find a case where you do need direct access though, you may load it throu .. _cross-site-request-forgery: ********************************* -Cross-site request forgery (CSRF) +Cross-Site Request Forgery (CSRF) ********************************* .. warning:: The CSRF Protection is only available for **POST/PUT/PATCH/DELETE** requests. Requests for other methods are not protected. +Prerequisite +============ + +When you use the CodeIgniter's CSRF protection, you still need to code as the following. +Otherwise, the CSRF protection may be bypassed. + +When Auto-Routing is Disabled +----------------------------- + +Do one of the following: + +1. Do not use ``$routes->add()``, and use HTTP verbs in routes. +2. Check the request method in the controller method before processing. + +E.g.:: + + if (strtolower($this->request->getMethod()) !== 'post') { + return $this->response->setStatusCode(405)->setBody('Method Not Allowed'); + } + +When Auto-Routing is Enabled +---------------------------- + +1. Check the request method in the controller method before processing. + +E.g.:: + + if (strtolower($this->request->getMethod()) !== 'post') { + return $this->response->setStatusCode(405)->setBody('Method Not Allowed'); + } + Config for CSRF =============== From bcb3607debb42fa23ee5669ab6ffccf5e91065b6 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Tue, 1 Mar 2022 14:55:18 +0800 Subject: [PATCH 1709/2325] unnecessary parameter check. Signed-off-by: Andrey Pyzhikov <5071@mail.ru> --- system/Database/BaseBuilder.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index cc3e245a107b..43ce80c34abf 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -450,12 +450,6 @@ public function selectCount(string $select = '', string $alias = '') */ public function selectSubquery(BaseBuilder $subquery, string $as): self { - if (! $this->isSubquery($subquery)) { - throw new DatabaseException( - 'The BaseBuilder::selectSubquery() method expects a BaseBuilder instance.' - ); - } - $this->QBSelect[] = $this->buildSubquery($subquery, true, $as); return $this; From 8f8a2e760ced0d7ed651c404c35783e858240440 Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Tue, 1 Mar 2022 08:48:25 +0100 Subject: [PATCH 1710/2325] Fix class names. Co-authored-by: kenjis --- user_guide_src/source/incoming/controllers/010.php | 2 +- user_guide_src/source/incoming/controllers/011.php | 2 +- user_guide_src/source/incoming/controllers/012.php | 2 +- user_guide_src/source/incoming/controllers/013.php | 2 +- user_guide_src/source/incoming/controllers/017.php | 2 +- user_guide_src/source/incoming/controllers/018.php | 2 +- user_guide_src/source/incoming/controllers/019.php | 2 +- user_guide_src/source/incoming/routing/011.php | 2 +- user_guide_src/source/testing/overview/017.php | 2 +- user_guide_src/source/testing/overview/018.php | 2 +- user_guide_src/source/testing/overview/019.php | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/incoming/controllers/010.php b/user_guide_src/source/incoming/controllers/010.php index b74d386d6289..1add1c02464e 100644 --- a/user_guide_src/source/incoming/controllers/010.php +++ b/user_guide_src/source/incoming/controllers/010.php @@ -1,6 +1,6 @@ Date: Tue, 1 Mar 2022 08:57:39 +0100 Subject: [PATCH 1711/2325] Indicate other class methods/properties by '...'. Co-authored-by: kenjis --- user_guide_src/source/database/configuration/001.php | 2 ++ user_guide_src/source/general/modules/001.php | 2 ++ user_guide_src/source/general/modules/002.php | 4 ++++ user_guide_src/source/general/modules/003.php | 2 ++ user_guide_src/source/general/modules/004.php | 2 ++ user_guide_src/source/incoming/filters/003.php | 2 ++ user_guide_src/source/installation/troubleshooting/001.php | 4 ++++ user_guide_src/source/installation/upgrade_415/001.php | 4 ++++ .../source/installation/upgrade_localization/001.php | 4 ++++ user_guide_src/source/installation/upgrade_security/001.php | 4 ++++ user_guide_src/source/libraries/caching/013.php | 3 +++ user_guide_src/source/libraries/encryption/005.php | 2 ++ 12 files changed, 35 insertions(+) diff --git a/user_guide_src/source/database/configuration/001.php b/user_guide_src/source/database/configuration/001.php index 5a59fabfcfdc..ed5ba8a34304 100644 --- a/user_guide_src/source/database/configuration/001.php +++ b/user_guide_src/source/database/configuration/001.php @@ -20,4 +20,6 @@ class Database extends Config 'strictOn' => false, 'failover' => [], ]; + + // ... } diff --git a/user_guide_src/source/general/modules/001.php b/user_guide_src/source/general/modules/001.php index 47a56e70072f..a11a9c4345cc 100644 --- a/user_guide_src/source/general/modules/001.php +++ b/user_guide_src/source/general/modules/001.php @@ -7,4 +7,6 @@ class Autoload extends AutoloadConfig 'Config' => APPPATH . 'Config', 'Acme' => ROOTPATH . 'acme', ]; + + // ... } diff --git a/user_guide_src/source/general/modules/002.php b/user_guide_src/source/general/modules/002.php index 4d7b355da602..5b2826e9fcbc 100644 --- a/user_guide_src/source/general/modules/002.php +++ b/user_guide_src/source/general/modules/002.php @@ -2,9 +2,13 @@ class Autoload extends AutoloadConfig { + // ... + public $files = [ 'path/to/my/functions.php', 'path/to/my/constants.php', 'path/to/my/bootstrap.php', ]; + + // ... } diff --git a/user_guide_src/source/general/modules/003.php b/user_guide_src/source/general/modules/003.php index 1124ef4d04db..a6247cd94103 100644 --- a/user_guide_src/source/general/modules/003.php +++ b/user_guide_src/source/general/modules/003.php @@ -7,4 +7,6 @@ class Autoload extends AutoloadConfig 'Config' => APPPATH . 'Config', 'Acme\Blog' => ROOTPATH . 'acme/Blog', // Change ]; + + // ... } diff --git a/user_guide_src/source/general/modules/004.php b/user_guide_src/source/general/modules/004.php index 0f2c1c3967ad..c085dfa81736 100644 --- a/user_guide_src/source/general/modules/004.php +++ b/user_guide_src/source/general/modules/004.php @@ -3,4 +3,6 @@ class Modules extends BaseModules { public $discoverInComposer = false; + + // ... } diff --git a/user_guide_src/source/incoming/filters/003.php b/user_guide_src/source/incoming/filters/003.php index a757fdf8f029..6957806f0bf5 100644 --- a/user_guide_src/source/incoming/filters/003.php +++ b/user_guide_src/source/incoming/filters/003.php @@ -5,4 +5,6 @@ class Filters extends BaseConfig public $aliases = [ 'csrf' => \CodeIgniter\Filters\CSRF::class, ]; + + // ... } diff --git a/user_guide_src/source/installation/troubleshooting/001.php b/user_guide_src/source/installation/troubleshooting/001.php index c3aa124d6ce2..f8d52a35fb83 100644 --- a/user_guide_src/source/installation/troubleshooting/001.php +++ b/user_guide_src/source/installation/troubleshooting/001.php @@ -2,5 +2,9 @@ class App extends BaseConfig { + // ... + public $indexPage = 'index.php'; + + // ... } diff --git a/user_guide_src/source/installation/upgrade_415/001.php b/user_guide_src/source/installation/upgrade_415/001.php index b2ffbeaadc37..98909b124369 100644 --- a/user_guide_src/source/installation/upgrade_415/001.php +++ b/user_guide_src/source/installation/upgrade_415/001.php @@ -2,8 +2,12 @@ class Filters extends BaseConfig { + // ... + public $methods = [ 'get' => ['csrf'], 'post' => ['csrf'], ]; + + // ... } diff --git a/user_guide_src/source/installation/upgrade_localization/001.php b/user_guide_src/source/installation/upgrade_localization/001.php index 53d156de0545..a3d7897a9956 100644 --- a/user_guide_src/source/installation/upgrade_localization/001.php +++ b/user_guide_src/source/installation/upgrade_localization/001.php @@ -2,5 +2,9 @@ class App extends BaseConfig { + // ... + public $defaultLocale = 'en'; + + // ... } diff --git a/user_guide_src/source/installation/upgrade_security/001.php b/user_guide_src/source/installation/upgrade_security/001.php index 3e487bb37686..57c7b583ed88 100644 --- a/user_guide_src/source/installation/upgrade_security/001.php +++ b/user_guide_src/source/installation/upgrade_security/001.php @@ -2,10 +2,14 @@ class Filters extends BaseConfig { + // ... + public $globals = [ 'before' => [ // 'honeypot', 'csrf', ], ]; + + // ... } diff --git a/user_guide_src/source/libraries/caching/013.php b/user_guide_src/source/libraries/caching/013.php index 52e77d4b7f4b..a68fb194b935 100644 --- a/user_guide_src/source/libraries/caching/013.php +++ b/user_guide_src/source/libraries/caching/013.php @@ -2,10 +2,13 @@ class Cache extends BaseConfig { + // ... public $memcached = [ 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 1, 'raw' => false, ]; + + // ... } diff --git a/user_guide_src/source/libraries/encryption/005.php b/user_guide_src/source/libraries/encryption/005.php index 992d322a1bd2..37e9ae3fe79b 100644 --- a/user_guide_src/source/libraries/encryption/005.php +++ b/user_guide_src/source/libraries/encryption/005.php @@ -3,4 +3,6 @@ class Encryption extends BaseConfig { public $key = 'YOUR KEY'; + + // ... } From 546015f97e1c5ba96492d58cf5274cdf6e47e35a Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Tue, 1 Mar 2022 09:50:45 +0100 Subject: [PATCH 1712/2325] Fix ... Co-authored-by: kenjis --- user_guide_src/source/libraries/encryption/008.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/libraries/encryption/008.php b/user_guide_src/source/libraries/encryption/008.php index 77849fb96f6a..f48f42a0bbf5 100644 --- a/user_guide_src/source/libraries/encryption/008.php +++ b/user_guide_src/source/libraries/encryption/008.php @@ -7,4 +7,6 @@ class Encryption extends BaseConfig // or public $key = 'base64:'; + + // ... } From 4cc4ecc0c2771ba1b30295bf0c613bd9db49c36c Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Tue, 1 Mar 2022 09:59:31 +0100 Subject: [PATCH 1713/2325] Add namspaces and use statements - first run. Co-authored-by: kenjis --- user_guide_src/source/database/configuration/001.php | 4 ++++ user_guide_src/source/dbmgmt/migration/002.php | 4 ++++ user_guide_src/source/dbmgmt/seeds/003.php | 4 ++++ user_guide_src/source/extending/basecontroller/002.php | 2 ++ user_guide_src/source/extending/basecontroller/003.php | 2 ++ user_guide_src/source/extending/core_classes/002.php | 4 ++++ user_guide_src/source/general/configuration/008.php | 4 ++++ user_guide_src/source/general/logging/002.php | 4 ++++ user_guide_src/source/general/logging/003.php | 4 ++++ user_guide_src/source/general/logging/004.php | 4 ++++ user_guide_src/source/general/managing_apps/001.php | 2 ++ user_guide_src/source/general/modules/001.php | 4 ++++ user_guide_src/source/general/modules/002.php | 4 ++++ user_guide_src/source/general/modules/003.php | 4 ++++ user_guide_src/source/general/modules/004.php | 4 ++++ user_guide_src/source/incoming/controllers/010.php | 2 ++ user_guide_src/source/incoming/filters/002.php | 6 ++++++ user_guide_src/source/incoming/filters/003.php | 4 ++++ user_guide_src/source/incoming/routing/011.php | 2 ++ user_guide_src/source/installation/troubleshooting/001.php | 4 ++++ user_guide_src/source/installation/upgrade_415/001.php | 4 ++++ .../source/installation/upgrade_localization/001.php | 4 ++++ user_guide_src/source/installation/upgrade_security/001.php | 4 ++++ user_guide_src/source/libraries/caching/013.php | 4 ++++ user_guide_src/source/libraries/curlrequest/001.php | 4 ++++ user_guide_src/source/libraries/encryption/005.php | 4 ++++ 26 files changed, 96 insertions(+) diff --git a/user_guide_src/source/database/configuration/001.php b/user_guide_src/source/database/configuration/001.php index ed5ba8a34304..5631cf7faede 100644 --- a/user_guide_src/source/database/configuration/001.php +++ b/user_guide_src/source/database/configuration/001.php @@ -1,5 +1,9 @@ Date: Tue, 1 Mar 2022 11:05:37 +0100 Subject: [PATCH 1714/2325] Add namespaces and use statements - second run. --- user_guide_src/source/cli/cli_library/001.php | 4 ++-- user_guide_src/source/concepts/services/006.php | 6 +++++- user_guide_src/source/concepts/services/007.php | 4 ++++ user_guide_src/source/concepts/services/008.php | 4 ++++ user_guide_src/source/concepts/services/010.php | 6 +++++- user_guide_src/source/database/configuration/006.php | 4 ++++ user_guide_src/source/database/configuration/008.php | 6 +++++- user_guide_src/source/dbmgmt/migration/005.php | 4 +++- user_guide_src/source/extending/basecontroller/001.php | 2 -- user_guide_src/source/extending/basecontroller/004.php | 8 ++++++-- user_guide_src/source/general/errors/005.php | 4 ++++ user_guide_src/source/general/errors/006.php | 6 +++++- user_guide_src/source/helpers/test_helper/002.php | 4 +++- user_guide_src/source/incoming/controllers/002.php | 2 +- user_guide_src/source/incoming/controllers/003.php | 2 +- user_guide_src/source/incoming/controllers/004.php | 2 +- user_guide_src/source/incoming/controllers/011.php | 2 ++ user_guide_src/source/incoming/controllers/012.php | 2 ++ user_guide_src/source/incoming/controllers/013.php | 2 ++ user_guide_src/source/incoming/controllers/017.php | 2 ++ user_guide_src/source/incoming/controllers/018.php | 2 ++ user_guide_src/source/incoming/controllers/019.php | 2 ++ user_guide_src/source/incoming/filters/003.php | 3 +-- user_guide_src/source/incoming/filters/004.php | 4 ++++ user_guide_src/source/incoming/filters/005.php | 4 ++++ user_guide_src/source/incoming/filters/006.php | 4 ++++ user_guide_src/source/incoming/filters/007.php | 4 ++++ user_guide_src/source/incoming/filters/008.php | 4 ++++ user_guide_src/source/incoming/filters/009.php | 4 ++++ user_guide_src/source/incoming/filters/011.php | 4 ++++ user_guide_src/source/incoming/incomingrequest/022.php | 4 +++- .../source/installation/troubleshooting/002.php | 7 +++++++ user_guide_src/source/installation/upgrade_415/001.php | 5 ++--- .../source/installation/upgrade_security/001.php | 5 ++--- user_guide_src/source/libraries/caching/013.php | 3 +-- user_guide_src/source/libraries/caching/014.php | 4 ++++ user_guide_src/source/libraries/encryption/008.php | 5 ++++- user_guide_src/source/libraries/files/014.php | 4 +++- user_guide_src/source/libraries/honeypot/001.php | 4 ++++ user_guide_src/source/libraries/pagination/004.php | 5 ++++- user_guide_src/source/libraries/pagination/010.php | 4 ++++ user_guide_src/source/libraries/pagination/011.php | 4 ++++ user_guide_src/source/libraries/security/002.php | 4 ++++ user_guide_src/source/libraries/security/003.php | 4 ++++ user_guide_src/source/libraries/security/004.php | 4 ++++ user_guide_src/source/libraries/security/005.php | 4 ++++ user_guide_src/source/libraries/security/006.php | 4 ++++ user_guide_src/source/libraries/security/007.php | 4 ++++ user_guide_src/source/libraries/security/008.php | 4 ++++ user_guide_src/source/libraries/security/009.php | 4 ++++ user_guide_src/source/libraries/sessions/040.php | 4 ++++ user_guide_src/source/libraries/sessions/041.php | 4 ++++ user_guide_src/source/libraries/sessions/042.php | 4 ++++ user_guide_src/source/libraries/sessions/043.php | 4 ++++ user_guide_src/source/libraries/sessions/044.php | 4 ++++ user_guide_src/source/libraries/throttler/003.php | 4 ++++ user_guide_src/source/libraries/throttler/004.php | 4 ++++ user_guide_src/source/libraries/validation/003.php | 2 ++ user_guide_src/source/libraries/validation/013.php | 2 ++ user_guide_src/source/libraries/validation/015.php | 7 ++++--- user_guide_src/source/libraries/validation/016.php | 4 +++- user_guide_src/source/libraries/validation/031.php | 2 ++ user_guide_src/source/libraries/validation/032.php | 2 ++ user_guide_src/source/models/entities/019.php | 4 +++- user_guide_src/source/models/entities/020.php | 4 ++++ user_guide_src/source/models/entities/021.php | 8 +++++--- user_guide_src/source/models/model/021.php | 8 +++++--- user_guide_src/source/models/model/027.php | 9 ++++++--- user_guide_src/source/models/model/034.php | 4 ++++ user_guide_src/source/models/model/038.php | 4 ++++ user_guide_src/source/models/model/040.php | 4 ++++ user_guide_src/source/models/model/041.php | 4 ++++ user_guide_src/source/models/model/050.php | 4 ++++ user_guide_src/source/models/model/051.php | 4 ++++ user_guide_src/source/models/model/052.php | 4 ++++ user_guide_src/source/models/model/054.php | 4 ++++ user_guide_src/source/outgoing/api_responses/001.php | 3 ++- user_guide_src/source/outgoing/api_responses/003.php | 4 ++++ user_guide_src/source/outgoing/api_responses/004.php | 4 ++++ user_guide_src/source/outgoing/localization/001.php | 4 ++++ user_guide_src/source/outgoing/localization/002.php | 4 ++++ user_guide_src/source/outgoing/localization/003.php | 4 ++++ user_guide_src/source/outgoing/localization/005.php | 2 +- user_guide_src/source/outgoing/response/011.php | 4 ++++ user_guide_src/source/outgoing/view_decorators/002.php | 4 ++++ user_guide_src/source/outgoing/view_layouts/001.php | 2 ++ user_guide_src/source/outgoing/view_parser/012.php | 4 ++++ user_guide_src/source/outgoing/view_parser/013.php | 4 ++++ user_guide_src/source/outgoing/view_parser/014.php | 4 ++++ user_guide_src/source/outgoing/view_parser/015.php | 8 ++++++-- user_guide_src/source/outgoing/view_parser/016.php | 4 ++++ user_guide_src/source/outgoing/view_parser/017.php | 4 ++++ user_guide_src/source/outgoing/views/002.php | 4 +++- user_guide_src/source/outgoing/views/003.php | 4 +++- user_guide_src/source/outgoing/views/009.php | 8 +++++--- user_guide_src/source/outgoing/views/011.php | 4 +++- user_guide_src/source/testing/controllers/012.php | 8 ++++++-- user_guide_src/source/testing/controllers/014.php | 5 +++++ user_guide_src/source/testing/debugging/003.php | 4 ++++ user_guide_src/source/testing/fabricator/001.php | 7 ++++++- user_guide_src/source/testing/fabricator/005.php | 2 ++ user_guide_src/source/testing/fabricator/006.php | 4 +++- user_guide_src/source/testing/fabricator/021.php | 4 +++- user_guide_src/source/testing/overview/004.php | 4 ++++ user_guide_src/source/testing/overview/005.php | 4 ++++ user_guide_src/source/testing/overview/006.php | 4 ++++ user_guide_src/source/testing/overview/007.php | 2 ++ user_guide_src/source/testing/overview/017.php | 2 ++ user_guide_src/source/testing/overview/018.php | 2 ++ user_guide_src/source/testing/overview/019.php | 2 ++ user_guide_src/source/tutorial/create_news_items/001.php | 4 ++++ user_guide_src/source/tutorial/create_news_items/002.php | 2 ++ user_guide_src/source/tutorial/news_section/004.php | 4 ++++ user_guide_src/source/tutorial/news_section/006.php | 4 ++++ user_guide_src/source/tutorial/static_pages/002.php | 2 ++ 115 files changed, 404 insertions(+), 58 deletions(-) diff --git a/user_guide_src/source/cli/cli_library/001.php b/user_guide_src/source/cli/cli_library/001.php index d0b0af7095c1..89e798a5647b 100644 --- a/user_guide_src/source/cli/cli_library/001.php +++ b/user_guide_src/source/cli/cli_library/001.php @@ -2,9 +2,9 @@ namespace App\Controllers; -use CodeIgniter\CLI\CLI; +use CodeIgniter\Controller; -class MyController extends \CodeIgniter\Controller +class MyController extends Controller { // ... } diff --git a/user_guide_src/source/concepts/services/006.php b/user_guide_src/source/concepts/services/006.php index 65d27f7c734a..c352a4365710 100644 --- a/user_guide_src/source/concepts/services/006.php +++ b/user_guide_src/source/concepts/services/006.php @@ -1,6 +1,10 @@ \CodeIgniter\Filters\CSRF::class, ]; - // ... } diff --git a/user_guide_src/source/incoming/filters/004.php b/user_guide_src/source/incoming/filters/004.php index 3615cf8f6072..c6ebb321f7e2 100644 --- a/user_guide_src/source/incoming/filters/004.php +++ b/user_guide_src/source/incoming/filters/004.php @@ -1,5 +1,9 @@ ['csrf'], 'post' => ['csrf'], ]; - // ... } diff --git a/user_guide_src/source/installation/upgrade_security/001.php b/user_guide_src/source/installation/upgrade_security/001.php index 70be69c69684..38536bd67cce 100644 --- a/user_guide_src/source/installation/upgrade_security/001.php +++ b/user_guide_src/source/installation/upgrade_security/001.php @@ -2,18 +2,17 @@ namespace Config; -// ... +use CodeIgniter\Config\BaseConfig; class Filters extends BaseConfig { // ... - + public $globals = [ 'before' => [ // 'honeypot', 'csrf', ], ]; - // ... } diff --git a/user_guide_src/source/libraries/caching/013.php b/user_guide_src/source/libraries/caching/013.php index 74bda7604f34..3dd8ff740944 100644 --- a/user_guide_src/source/libraries/caching/013.php +++ b/user_guide_src/source/libraries/caching/013.php @@ -2,7 +2,7 @@ namespace Config; -// ... +use CodeIgniter\Config\BaseConfig; class Cache extends BaseConfig { @@ -13,6 +13,5 @@ class Cache extends BaseConfig 'weight' => 1, 'raw' => false, ]; - // ... } diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php index 2c0f5eb719bd..716bf637161b 100644 --- a/user_guide_src/source/libraries/caching/014.php +++ b/user_guide_src/source/libraries/caching/014.php @@ -1,5 +1,9 @@ '; - // ... } diff --git a/user_guide_src/source/libraries/files/014.php b/user_guide_src/source/libraries/files/014.php index a768829427f3..cbd6f90e5388 100644 --- a/user_guide_src/source/libraries/files/014.php +++ b/user_guide_src/source/libraries/files/014.php @@ -1,6 +1,8 @@ 'required|matches[password]', 'email' => 'required|valid_email', ]; - public $signup_errors = [ 'username' => [ - 'required' => 'You must choose a username.', + 'required' => 'You must choose a username.', ], - 'email' => [ + 'email' => [ 'valid_email' => 'Please check the Email field. It does not appear to be valid.', ], ]; diff --git a/user_guide_src/source/libraries/validation/016.php b/user_guide_src/source/libraries/validation/016.php index 55d9f6985cf9..3b777bb92ddd 100644 --- a/user_guide_src/source/libraries/validation/016.php +++ b/user_guide_src/source/libraries/validation/016.php @@ -1,5 +1,7 @@ 'You must choose a Username.', ], ], - 'email' => [ + 'email' => [ 'rules' => 'required|valid_email', 'errors' => [ 'valid_email' => 'Please check the Email field. It does not appear to be valid.', diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php index d8917ff8ec87..e85808bdab63 100644 --- a/user_guide_src/source/libraries/validation/031.php +++ b/user_guide_src/source/libraries/validation/031.php @@ -1,5 +1,7 @@ - // string(13) "App\SomeClass" + // string(13) "App\SomeClass" // [1]=> - // string(6) "param2" + // string(6) "param2" // [2]=> - // string(6) "param3" + // string(6) "param3" // } } } diff --git a/user_guide_src/source/models/model/021.php b/user_guide_src/source/models/model/021.php index a49cfe210163..f0367b5044e2 100644 --- a/user_guide_src/source/models/model/021.php +++ b/user_guide_src/source/models/model/021.php @@ -1,12 +1,14 @@ 'required|alpha_numeric_space|min_length[3]', 'email' => 'required|valid_email|is_unique[users.email]', 'password' => 'required|min_length[8]', 'pass_confirm' => 'required_with[password]|matches[password]', ]; - protected $validationMessages = [ - 'email' => [ + 'email' => [ 'is_unique' => 'Sorry. That email has already been taken. Please choose another.', ], ]; diff --git a/user_guide_src/source/models/model/034.php b/user_guide_src/source/models/model/034.php index 8de746bec4cd..b18544ee555e 100644 --- a/user_guide_src/source/models/model/034.php +++ b/user_guide_src/source/models/model/034.php @@ -1,5 +1,9 @@ plugins['bar'] = function (array $params=[]) { + $this->plugins['bar'] = static function (array $params = []) { return $params[0] ?? ''; }; diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index 5e2f5a2f0b0b..a78667ef2762 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -1,5 +1,9 @@ assertHasFilters('unfiltered/route', 'before'); } - // ... } diff --git a/user_guide_src/source/testing/controllers/014.php b/user_guide_src/source/testing/controllers/014.php index bc6dc8bf9e18..feb1d4448540 100644 --- a/user_guide_src/source/testing/controllers/014.php +++ b/user_guide_src/source/testing/controllers/014.php @@ -1,5 +1,10 @@ $faker->firstName, 'email' => $faker->email, - 'group_id' => rand(1, Fabricator::getCount('groups')), + 'group_id' => mt_rand(1, Fabricator::getCount('groups')), ]; } } diff --git a/user_guide_src/source/testing/overview/004.php b/user_guide_src/source/testing/overview/004.php index 2f8a20c6ca52..4d2e7ef4b5a8 100644 --- a/user_guide_src/source/testing/overview/004.php +++ b/user_guide_src/source/testing/overview/004.php @@ -1,5 +1,9 @@ Date: Tue, 1 Mar 2022 11:16:31 +0100 Subject: [PATCH 1715/2325] Add '...' for config examples. --- user_guide_src/source/concepts/factories/005.php | 1 + user_guide_src/source/concepts/services/007.php | 1 + user_guide_src/source/concepts/services/008.php | 1 + user_guide_src/source/concepts/services/010.php | 1 + user_guide_src/source/database/configuration/006.php | 1 + user_guide_src/source/database/configuration/008.php | 1 + user_guide_src/source/extending/core_classes/002.php | 1 + user_guide_src/source/general/configuration/004.php | 2 +- user_guide_src/source/general/configuration/008.php | 3 +-- user_guide_src/source/general/logging/002.php | 1 + user_guide_src/source/general/logging/003.php | 1 + user_guide_src/source/general/logging/004.php | 1 + user_guide_src/source/general/managing_apps/001.php | 1 + user_guide_src/source/incoming/filters/004.php | 1 + user_guide_src/source/incoming/filters/005.php | 1 + user_guide_src/source/incoming/filters/006.php | 1 + user_guide_src/source/incoming/filters/007.php | 1 + user_guide_src/source/incoming/filters/008.php | 1 + user_guide_src/source/incoming/filters/009.php | 1 + user_guide_src/source/incoming/filters/011.php | 1 + .../source/installation/upgrade_configuration/002.php | 5 +++-- user_guide_src/source/libraries/caching/014.php | 3 +++ user_guide_src/source/libraries/curlrequest/001.php | 1 + user_guide_src/source/libraries/honeypot/001.php | 1 + user_guide_src/source/libraries/pagination/010.php | 1 + user_guide_src/source/libraries/pagination/011.php | 1 + user_guide_src/source/libraries/security/002.php | 1 + user_guide_src/source/libraries/security/003.php | 1 + user_guide_src/source/libraries/security/004.php | 1 + user_guide_src/source/libraries/security/005.php | 1 + user_guide_src/source/libraries/security/006.php | 1 + user_guide_src/source/libraries/security/007.php | 1 + user_guide_src/source/libraries/security/008.php | 1 + user_guide_src/source/libraries/security/009.php | 1 + user_guide_src/source/libraries/sessions/040.php | 1 + user_guide_src/source/libraries/sessions/041.php | 1 + user_guide_src/source/libraries/sessions/042.php | 1 + user_guide_src/source/libraries/sessions/043.php | 1 + user_guide_src/source/libraries/sessions/044.php | 1 + user_guide_src/source/libraries/throttler/003.php | 1 + user_guide_src/source/libraries/throttler/004.php | 1 + user_guide_src/source/libraries/validation/003.php | 1 + user_guide_src/source/libraries/validation/013.php | 1 + user_guide_src/source/libraries/validation/015.php | 1 + user_guide_src/source/libraries/validation/016.php | 1 + user_guide_src/source/libraries/validation/031.php | 1 + user_guide_src/source/libraries/validation/032.php | 1 + user_guide_src/source/outgoing/api_responses/003.php | 1 + user_guide_src/source/outgoing/api_responses/004.php | 1 + user_guide_src/source/outgoing/localization/001.php | 1 + user_guide_src/source/outgoing/localization/002.php | 1 + user_guide_src/source/outgoing/localization/003.php | 1 + user_guide_src/source/outgoing/response/011.php | 1 + user_guide_src/source/outgoing/view_decorators/002.php | 1 + user_guide_src/source/outgoing/view_parser/012.php | 1 + user_guide_src/source/outgoing/view_parser/013.php | 1 + user_guide_src/source/outgoing/view_parser/014.php | 1 + user_guide_src/source/outgoing/view_parser/015.php | 1 + user_guide_src/source/outgoing/view_parser/016.php | 1 + user_guide_src/source/outgoing/view_parser/017.php | 1 + user_guide_src/source/testing/debugging/003.php | 1 + user_guide_src/source/tutorial/create_news_items/001.php | 1 + 62 files changed, 66 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/concepts/factories/005.php b/user_guide_src/source/concepts/factories/005.php index 10a82b828d73..0c860b7a1672 100644 --- a/user_guide_src/source/concepts/factories/005.php +++ b/user_guide_src/source/concepts/factories/005.php @@ -10,4 +10,5 @@ class Factories extends BaseFactory public $filters = [ 'instanceOf' => FilterInterface::class, ]; + // ... } diff --git a/user_guide_src/source/concepts/services/007.php b/user_guide_src/source/concepts/services/007.php index ed1990b3dca2..298b8abd010f 100644 --- a/user_guide_src/source/concepts/services/007.php +++ b/user_guide_src/source/concepts/services/007.php @@ -10,4 +10,5 @@ public static function routes() { return new \App\Router\MyRouter(); } + // ... } diff --git a/user_guide_src/source/concepts/services/008.php b/user_guide_src/source/concepts/services/008.php index 1f1db41226b0..52edb387792c 100644 --- a/user_guide_src/source/concepts/services/008.php +++ b/user_guide_src/source/concepts/services/008.php @@ -10,4 +10,5 @@ public static function renderer($viewPath = APPPATH . 'views/') { return new \CodeIgniter\View\View($viewPath); } + // ... } diff --git a/user_guide_src/source/concepts/services/010.php b/user_guide_src/source/concepts/services/010.php index f4332f6404e3..fd5d3f6c4e35 100644 --- a/user_guide_src/source/concepts/services/010.php +++ b/user_guide_src/source/concepts/services/010.php @@ -14,4 +14,5 @@ public static function routes($getShared = false) return static::getSharedInstance('routes'); } + // ... } diff --git a/user_guide_src/source/database/configuration/006.php b/user_guide_src/source/database/configuration/006.php index 31cd766c4f8e..afc24022c199 100644 --- a/user_guide_src/source/database/configuration/006.php +++ b/user_guide_src/source/database/configuration/006.php @@ -24,4 +24,5 @@ class Database extends Config 'strictOn' => false, 'failover' => [], ]; + // ... } diff --git a/user_guide_src/source/database/configuration/008.php b/user_guide_src/source/database/configuration/008.php index 5639c484d125..c6084e212234 100644 --- a/user_guide_src/source/database/configuration/008.php +++ b/user_guide_src/source/database/configuration/008.php @@ -14,4 +14,5 @@ public function __construct() { $this->defaultGroup = ENVIRONMENT; } + // ... } diff --git a/user_guide_src/source/extending/core_classes/002.php b/user_guide_src/source/extending/core_classes/002.php index df96db2fa7bf..1d0de27ee238 100644 --- a/user_guide_src/source/extending/core_classes/002.php +++ b/user_guide_src/source/extending/core_classes/002.php @@ -14,4 +14,5 @@ public static function routes(bool $getShared = true) return new \App\Libraries\RouteCollection(static::locator(), config('Modules')); } + // ... } diff --git a/user_guide_src/source/general/configuration/004.php b/user_guide_src/source/general/configuration/004.php index 5d39a34c48b5..cc013d77583f 100644 --- a/user_guide_src/source/general/configuration/004.php +++ b/user_guide_src/source/general/configuration/004.php @@ -8,5 +8,5 @@ class CustomClass extends BaseConfig { public $siteName = 'My Great Site'; public $siteEmail = 'webmaster@example.com'; - + // ... } diff --git a/user_guide_src/source/general/configuration/008.php b/user_guide_src/source/general/configuration/008.php index 197c200970ab..86749331c9c5 100644 --- a/user_guide_src/source/general/configuration/008.php +++ b/user_guide_src/source/general/configuration/008.php @@ -2,11 +2,10 @@ namespace Config; -use CodeIgniter\Config\BaseService; - class MyConfig extends BaseConfig { public static $registrars = [ SupportingPackageRegistrar::class, ]; + // ... } diff --git a/user_guide_src/source/general/logging/002.php b/user_guide_src/source/general/logging/002.php index 8d1409b481fe..1c27f2410126 100644 --- a/user_guide_src/source/general/logging/002.php +++ b/user_guide_src/source/general/logging/002.php @@ -7,4 +7,5 @@ class Logger extends BaseConfig { public $threshold = 5; + // ... } diff --git a/user_guide_src/source/general/logging/003.php b/user_guide_src/source/general/logging/003.php index e34a67075a09..170b74457967 100644 --- a/user_guide_src/source/general/logging/003.php +++ b/user_guide_src/source/general/logging/003.php @@ -8,4 +8,5 @@ class Logger extends BaseConfig { // Log only debug and info type messages public $threshold = [5, 8]; + // ... } diff --git a/user_guide_src/source/general/logging/004.php b/user_guide_src/source/general/logging/004.php index 32746068e2b6..ff5f9511d81f 100644 --- a/user_guide_src/source/general/logging/004.php +++ b/user_guide_src/source/general/logging/004.php @@ -12,4 +12,5 @@ class Logger extends BaseConfig 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'], ], ]; + // ... } diff --git a/user_guide_src/source/general/managing_apps/001.php b/user_guide_src/source/general/managing_apps/001.php index 253d888d316c..2d0690cabc41 100644 --- a/user_guide_src/source/general/managing_apps/001.php +++ b/user_guide_src/source/general/managing_apps/001.php @@ -5,4 +5,5 @@ class Paths { public $appDirectory = '/path/to/your/app'; + // ... } diff --git a/user_guide_src/source/incoming/filters/004.php b/user_guide_src/source/incoming/filters/004.php index c6ebb321f7e2..d39de5a0bee8 100644 --- a/user_guide_src/source/incoming/filters/004.php +++ b/user_guide_src/source/incoming/filters/004.php @@ -12,4 +12,5 @@ class Filters extends BaseConfig \App\Filters\ApiAuth::class, ], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/005.php b/user_guide_src/source/incoming/filters/005.php index 7dca9d31631d..55b7d1fa522b 100644 --- a/user_guide_src/source/incoming/filters/005.php +++ b/user_guide_src/source/incoming/filters/005.php @@ -12,4 +12,5 @@ class Filters extends BaseConfig ], 'after' => [], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/006.php b/user_guide_src/source/incoming/filters/006.php index 3781a875cff8..ed7ce0a8a120 100644 --- a/user_guide_src/source/incoming/filters/006.php +++ b/user_guide_src/source/incoming/filters/006.php @@ -12,4 +12,5 @@ class Filters extends BaseConfig ], 'after' => [], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/007.php b/user_guide_src/source/incoming/filters/007.php index 03844d9f763d..fa79b5bbb7c8 100644 --- a/user_guide_src/source/incoming/filters/007.php +++ b/user_guide_src/source/incoming/filters/007.php @@ -12,4 +12,5 @@ class Filters extends BaseConfig ], 'after' => [], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/008.php b/user_guide_src/source/incoming/filters/008.php index f35895d26e2e..a37967a538c0 100644 --- a/user_guide_src/source/incoming/filters/008.php +++ b/user_guide_src/source/incoming/filters/008.php @@ -10,4 +10,5 @@ class Filters extends BaseConfig 'post' => ['foo', 'bar'], 'get' => ['baz'], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/009.php b/user_guide_src/source/incoming/filters/009.php index 1fd9ab69ec4c..bfc7d6176b77 100644 --- a/user_guide_src/source/incoming/filters/009.php +++ b/user_guide_src/source/incoming/filters/009.php @@ -10,4 +10,5 @@ class Filters extends BaseConfig 'foo' => ['before' => ['admin/*'], 'after' => ['users/*']], 'bar' => ['before' => ['api/*', 'admin/*']], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/011.php b/user_guide_src/source/incoming/filters/011.php index ccc7c2cbd1f5..8b6e24c5fe91 100644 --- a/user_guide_src/source/incoming/filters/011.php +++ b/user_guide_src/source/incoming/filters/011.php @@ -10,4 +10,5 @@ class Filters extends BaseConfig // ... 'secureheaders' => \App\Filters\SecureHeaders::class, ]; + // ... } diff --git a/user_guide_src/source/installation/upgrade_configuration/002.php b/user_guide_src/source/installation/upgrade_configuration/002.php index 5150d6b8896d..cc013d77583f 100644 --- a/user_guide_src/source/installation/upgrade_configuration/002.php +++ b/user_guide_src/source/installation/upgrade_configuration/002.php @@ -6,6 +6,7 @@ class CustomClass extends BaseConfig { - public $siteName = 'My Great Site'; - public $siteEmail = 'webmaster@example.com'; + public $siteName = 'My Great Site'; + public $siteEmail = 'webmaster@example.com'; + // ... } diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php index 716bf637161b..cfb6eeb6698f 100644 --- a/user_guide_src/source/libraries/caching/014.php +++ b/user_guide_src/source/libraries/caching/014.php @@ -6,6 +6,8 @@ class Cache extends BaseConfig { + // ... + public $redis = [ 'host' => '127.0.0.1', 'password' => null, @@ -13,4 +15,5 @@ class Cache extends BaseConfig 'timeout' => 0, 'database' => 0, ]; + // ... } diff --git a/user_guide_src/source/libraries/curlrequest/001.php b/user_guide_src/source/libraries/curlrequest/001.php index 35fd4621a92a..35486f4e7971 100644 --- a/user_guide_src/source/libraries/curlrequest/001.php +++ b/user_guide_src/source/libraries/curlrequest/001.php @@ -7,4 +7,5 @@ class CURLRequest extends BaseConfig { public $shareOptions = false; + // ... } diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php index 5fd6cefc3036..8463a919d54a 100644 --- a/user_guide_src/source/libraries/honeypot/001.php +++ b/user_guide_src/source/libraries/honeypot/001.php @@ -16,4 +16,5 @@ class Filters extends BaseConfig 'honeypot', ], ]; + // ... } diff --git a/user_guide_src/source/libraries/pagination/010.php b/user_guide_src/source/libraries/pagination/010.php index 868bc5e8620f..d168163446ee 100644 --- a/user_guide_src/source/libraries/pagination/010.php +++ b/user_guide_src/source/libraries/pagination/010.php @@ -10,4 +10,5 @@ class Pager extends BaseConfig 'default_full' => 'CodeIgniter\Pager\Views\default_full', 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', ]; + // ... } diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php index 4d596e593312..4302997f8bff 100644 --- a/user_guide_src/source/libraries/pagination/011.php +++ b/user_guide_src/source/libraries/pagination/011.php @@ -11,4 +11,5 @@ class Pager extends BaseConfig 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 'front_full' => 'App\Views\Pagers\foundation_full', ]; + // ... } diff --git a/user_guide_src/source/libraries/security/002.php b/user_guide_src/source/libraries/security/002.php index 64de01125e4f..39df6fa8d292 100644 --- a/user_guide_src/source/libraries/security/002.php +++ b/user_guide_src/source/libraries/security/002.php @@ -7,4 +7,5 @@ class Security extends BaseConfig { public $csrfProtection = 'session'; + // ... } diff --git a/user_guide_src/source/libraries/security/003.php b/user_guide_src/source/libraries/security/003.php index c877680a923b..7d8b3241c285 100644 --- a/user_guide_src/source/libraries/security/003.php +++ b/user_guide_src/source/libraries/security/003.php @@ -7,4 +7,5 @@ class Security extends BaseConfig { public $tokenRandomize = true; + // ... } diff --git a/user_guide_src/source/libraries/security/004.php b/user_guide_src/source/libraries/security/004.php index d12b4e2243f7..7187a1b523c5 100644 --- a/user_guide_src/source/libraries/security/004.php +++ b/user_guide_src/source/libraries/security/004.php @@ -7,4 +7,5 @@ class Security extends BaseConfig { public $regenerate = true; + // ... } diff --git a/user_guide_src/source/libraries/security/005.php b/user_guide_src/source/libraries/security/005.php index 51040f3be460..f7539874c023 100644 --- a/user_guide_src/source/libraries/security/005.php +++ b/user_guide_src/source/libraries/security/005.php @@ -7,4 +7,5 @@ class Security extends BaseConfig { public $redirect = false; + // ... } diff --git a/user_guide_src/source/libraries/security/006.php b/user_guide_src/source/libraries/security/006.php index c2a392bbcc63..cc3ef9d162c6 100644 --- a/user_guide_src/source/libraries/security/006.php +++ b/user_guide_src/source/libraries/security/006.php @@ -12,4 +12,5 @@ class Filters extends BaseConfig 'csrf', ], ]; + // ... } diff --git a/user_guide_src/source/libraries/security/007.php b/user_guide_src/source/libraries/security/007.php index c32e7bc2b517..0b099addb52c 100644 --- a/user_guide_src/source/libraries/security/007.php +++ b/user_guide_src/source/libraries/security/007.php @@ -11,4 +11,5 @@ class Filters extends BaseConfig 'csrf' => ['except' => ['api/record/save']], ], ]; + // ... } diff --git a/user_guide_src/source/libraries/security/008.php b/user_guide_src/source/libraries/security/008.php index faa45c0bd605..370bd2bcedad 100644 --- a/user_guide_src/source/libraries/security/008.php +++ b/user_guide_src/source/libraries/security/008.php @@ -11,4 +11,5 @@ class Filters extends BaseConfig 'csrf' => ['except' => ['api/record/[0-9]+']], ], ]; + // ... } diff --git a/user_guide_src/source/libraries/security/009.php b/user_guide_src/source/libraries/security/009.php index 397681518d26..d90632e53f1c 100644 --- a/user_guide_src/source/libraries/security/009.php +++ b/user_guide_src/source/libraries/security/009.php @@ -10,4 +10,5 @@ class Filters extends BaseConfig 'get' => ['csrf'], 'post' => ['csrf'], ]; + // ... } diff --git a/user_guide_src/source/libraries/sessions/040.php b/user_guide_src/source/libraries/sessions/040.php index 29d50c78302c..3aedc2f047af 100644 --- a/user_guide_src/source/libraries/sessions/040.php +++ b/user_guide_src/source/libraries/sessions/040.php @@ -8,4 +8,5 @@ class App extends BaseConfig { public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; public $sessionSavePath = 'ci_sessions'; + // ... } diff --git a/user_guide_src/source/libraries/sessions/041.php b/user_guide_src/source/libraries/sessions/041.php index fe2777cae60c..f645887ec2be 100644 --- a/user_guide_src/source/libraries/sessions/041.php +++ b/user_guide_src/source/libraries/sessions/041.php @@ -7,4 +7,5 @@ class App extends BaseConfig { public $sessionDBGroup = 'groupName'; + // ... } diff --git a/user_guide_src/source/libraries/sessions/042.php b/user_guide_src/source/libraries/sessions/042.php index 830569b5dcbb..f0aed919a816 100644 --- a/user_guide_src/source/libraries/sessions/042.php +++ b/user_guide_src/source/libraries/sessions/042.php @@ -8,4 +8,5 @@ class App extends BaseConfig { public $sessionDiver = 'CodeIgniter\Session\Handlers\RedisHandler'; public $sessionSavePath = 'tcp://localhost:6379'; + // ... } diff --git a/user_guide_src/source/libraries/sessions/043.php b/user_guide_src/source/libraries/sessions/043.php index 4a50d0e20c51..cad56413151c 100644 --- a/user_guide_src/source/libraries/sessions/043.php +++ b/user_guide_src/source/libraries/sessions/043.php @@ -8,4 +8,5 @@ class App extends BaseConfig { public $sessionDriver = 'CodeIgniter\Session\Handlers\MemcachedHandler'; public $sessionSavePath = 'localhost:11211'; + // ... } diff --git a/user_guide_src/source/libraries/sessions/044.php b/user_guide_src/source/libraries/sessions/044.php index 3e889f270f3d..2cc31e9035db 100644 --- a/user_guide_src/source/libraries/sessions/044.php +++ b/user_guide_src/source/libraries/sessions/044.php @@ -9,4 +9,5 @@ class App extends BaseConfig // localhost will be given higher priority (5) here, // compared to 192.0.2.1 with a weight of 1. public $sessionSavePath = 'localhost:11211:5,192.0.2.1:11211:1'; + // ... } diff --git a/user_guide_src/source/libraries/throttler/003.php b/user_guide_src/source/libraries/throttler/003.php index 56b0fe4e1c59..ae13441bb8ad 100644 --- a/user_guide_src/source/libraries/throttler/003.php +++ b/user_guide_src/source/libraries/throttler/003.php @@ -10,4 +10,5 @@ class Filters extends BaseConfig // ... 'throttle' => \App\Filters\Throttle::class, ]; + // ... } diff --git a/user_guide_src/source/libraries/throttler/004.php b/user_guide_src/source/libraries/throttler/004.php index e8ec69b0b046..077cb46a66dc 100644 --- a/user_guide_src/source/libraries/throttler/004.php +++ b/user_guide_src/source/libraries/throttler/004.php @@ -9,4 +9,5 @@ class Filters extends BaseConfig public $methods = [ 'post' => ['throttle'], ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/003.php b/user_guide_src/source/libraries/validation/003.php index 79e2c7820e1d..fbcbb7690260 100644 --- a/user_guide_src/source/libraries/validation/003.php +++ b/user_guide_src/source/libraries/validation/003.php @@ -10,4 +10,5 @@ class Validation \CodeIgniter\Validation\StrictRules\FormatRules::class, \CodeIgniter\Validation\StrictRules\Rules::class, ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/013.php b/user_guide_src/source/libraries/validation/013.php index 827e86e51957..4e2982d7564f 100644 --- a/user_guide_src/source/libraries/validation/013.php +++ b/user_guide_src/source/libraries/validation/013.php @@ -10,4 +10,5 @@ class Validation 'pass_confirm' => 'required|matches[password]', 'email' => 'required|valid_email', ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/015.php b/user_guide_src/source/libraries/validation/015.php index e223cdaaa504..46ef2c4431a1 100644 --- a/user_guide_src/source/libraries/validation/015.php +++ b/user_guide_src/source/libraries/validation/015.php @@ -18,4 +18,5 @@ class Validation 'valid_email' => 'Please check the Email field. It does not appear to be valid.', ], ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/016.php b/user_guide_src/source/libraries/validation/016.php index 3b777bb92ddd..5b08e73980a8 100644 --- a/user_guide_src/source/libraries/validation/016.php +++ b/user_guide_src/source/libraries/validation/016.php @@ -18,4 +18,5 @@ class Validation ], ], ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php index e85808bdab63..7ed5d307b0e2 100644 --- a/user_guide_src/source/libraries/validation/031.php +++ b/user_guide_src/source/libraries/validation/031.php @@ -9,4 +9,5 @@ class Validation 'single' => 'CodeIgniter\Validation\Views\single', 'my_list' => '_errors_list', ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php index 86534cd84ed4..5f16ca283c1e 100644 --- a/user_guide_src/source/libraries/validation/032.php +++ b/user_guide_src/source/libraries/validation/032.php @@ -15,4 +15,5 @@ class Validation FileRules::class, CreditCardRules::class, ]; + // ... } diff --git a/user_guide_src/source/outgoing/api_responses/003.php b/user_guide_src/source/outgoing/api_responses/003.php index 1b5a498b5940..eebb83c43fc1 100644 --- a/user_guide_src/source/outgoing/api_responses/003.php +++ b/user_guide_src/source/outgoing/api_responses/003.php @@ -10,4 +10,5 @@ class Format extends BaseConfig 'application/json', 'application/xml', ]; + // ... } diff --git a/user_guide_src/source/outgoing/api_responses/004.php b/user_guide_src/source/outgoing/api_responses/004.php index b092ec70372e..57532911f13b 100644 --- a/user_guide_src/source/outgoing/api_responses/004.php +++ b/user_guide_src/source/outgoing/api_responses/004.php @@ -10,4 +10,5 @@ class Format extends BaseConfig 'application/json' => \CodeIgniter\Format\JSONFormatter::class, 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, ]; + // ... } diff --git a/user_guide_src/source/outgoing/localization/001.php b/user_guide_src/source/outgoing/localization/001.php index 7af57b09d921..ebc1e57ef45c 100644 --- a/user_guide_src/source/outgoing/localization/001.php +++ b/user_guide_src/source/outgoing/localization/001.php @@ -7,4 +7,5 @@ class App extends BaseConfig { public $defaultLocale = 'en'; + // ... } diff --git a/user_guide_src/source/outgoing/localization/002.php b/user_guide_src/source/outgoing/localization/002.php index ae6aa825e7a8..6a0cce0ea027 100644 --- a/user_guide_src/source/outgoing/localization/002.php +++ b/user_guide_src/source/outgoing/localization/002.php @@ -7,4 +7,5 @@ class App extends BaseConfig { public $negotiateLocale = true; + // ... } diff --git a/user_guide_src/source/outgoing/localization/003.php b/user_guide_src/source/outgoing/localization/003.php index dd3cad7ee548..81aa073152a0 100644 --- a/user_guide_src/source/outgoing/localization/003.php +++ b/user_guide_src/source/outgoing/localization/003.php @@ -7,4 +7,5 @@ class App extends BaseConfig { public $supportedLocales = ['en', 'es', 'fr-FR']; + // ... } diff --git a/user_guide_src/source/outgoing/response/011.php b/user_guide_src/source/outgoing/response/011.php index 5f546ff5781a..2ad152a51755 100644 --- a/user_guide_src/source/outgoing/response/011.php +++ b/user_guide_src/source/outgoing/response/011.php @@ -7,4 +7,5 @@ class App extends BaseConfig { public $CSPEnabled = true; + // ... } diff --git a/user_guide_src/source/outgoing/view_decorators/002.php b/user_guide_src/source/outgoing/view_decorators/002.php index a7d0f3937fa9..6bd050126f90 100644 --- a/user_guide_src/source/outgoing/view_decorators/002.php +++ b/user_guide_src/source/outgoing/view_decorators/002.php @@ -9,4 +9,5 @@ class View extends BaseView public array $decorators = [ 'App\Views\Decorators\MyDecorator', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/012.php b/user_guide_src/source/outgoing/view_parser/012.php index 40a6a62e3964..a006a51d5c33 100644 --- a/user_guide_src/source/outgoing/view_parser/012.php +++ b/user_guide_src/source/outgoing/view_parser/012.php @@ -10,4 +10,5 @@ class View extends BaseView 'abs' => '\CodeIgniter\View\Filters::abs', 'capitalize' => '\CodeIgniter\View\Filters::capitalize', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/013.php b/user_guide_src/source/outgoing/view_parser/013.php index 20a7f800af10..c45a72b89bde 100644 --- a/user_guide_src/source/outgoing/view_parser/013.php +++ b/user_guide_src/source/outgoing/view_parser/013.php @@ -9,4 +9,5 @@ class View extends BaseView public $filters = [ 'str_repeat' => '\str_repeat', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php index 87e70e1a43b5..866a547e3b28 100644 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -9,4 +9,5 @@ class View extends BaseView public $plugins = [ 'foo' => '\Some\Class::methodName', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/015.php b/user_guide_src/source/outgoing/view_parser/015.php index 008d6f748622..ecfafffbf97a 100644 --- a/user_guide_src/source/outgoing/view_parser/015.php +++ b/user_guide_src/source/outgoing/view_parser/015.php @@ -16,4 +16,5 @@ public function __construct() parent::__construct(); } + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index a78667ef2762..0350043cf4fa 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -9,6 +9,7 @@ class View extends BaseView public $plugins = [ 'foo' => '\Some\Class::methodName', ]; + // ... } // Tag is replaced by the return value of Some\Class::methodName static function. diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php index 6c98122dd7af..1042665a0fcf 100644 --- a/user_guide_src/source/outgoing/view_parser/017.php +++ b/user_guide_src/source/outgoing/view_parser/017.php @@ -9,6 +9,7 @@ class View extends BaseView public $plugins = [ 'foo' => ['\Some\Class::methodName'], ]; + // ... } // {+ foo +} inner content {+ /foo +} diff --git a/user_guide_src/source/testing/debugging/003.php b/user_guide_src/source/testing/debugging/003.php index ec42da23856a..4c1804e2d82b 100644 --- a/user_guide_src/source/testing/debugging/003.php +++ b/user_guide_src/source/testing/debugging/003.php @@ -16,4 +16,5 @@ class Toolbar extends BaseConfig \CodeIgniter\Debug\Toolbar\Collectors\Routes::class, \CodeIgniter\Debug\Toolbar\Collectors\Events::class, ]; + // ... } diff --git a/user_guide_src/source/tutorial/create_news_items/001.php b/user_guide_src/source/tutorial/create_news_items/001.php index 5982d0b159ab..c63e033af0bf 100644 --- a/user_guide_src/source/tutorial/create_news_items/001.php +++ b/user_guide_src/source/tutorial/create_news_items/001.php @@ -9,4 +9,5 @@ class Filters extends BaseConfig public $methods = [ 'post' => ['csrf'], ]; + // ... } From 589bd7ca252fd757d8617a579bc05b7e4664da5b Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Wed, 2 Mar 2022 08:31:36 +0100 Subject: [PATCH 1716/2325] Fix cli_library. Co-authored-by: kenjis --- user_guide_src/source/cli/cli_library/001.php | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/cli/cli_library/001.php b/user_guide_src/source/cli/cli_library/001.php index 89e798a5647b..e42c9a9231e6 100644 --- a/user_guide_src/source/cli/cli_library/001.php +++ b/user_guide_src/source/cli/cli_library/001.php @@ -2,6 +2,7 @@ namespace App\Controllers; +use CodeIgniter\CLI\CLI; use CodeIgniter\Controller; class MyController extends Controller From 8c83892af24a6821ad4d6500c8282cd0508d0877 Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Wed, 2 Mar 2022 10:09:59 +0100 Subject: [PATCH 1717/2325] Apply suggestions from code review. Co-authored-by: kenjis --- user_guide_src/source/concepts/factories/005.php | 1 - user_guide_src/source/database/configuration/008.php | 1 - user_guide_src/source/extending/basecontroller/003.php | 2 ++ .../source/installation/upgrade_configuration/002.php | 1 - user_guide_src/source/testing/overview/018.php | 2 +- 5 files changed, 3 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/concepts/factories/005.php b/user_guide_src/source/concepts/factories/005.php index 0c860b7a1672..10a82b828d73 100644 --- a/user_guide_src/source/concepts/factories/005.php +++ b/user_guide_src/source/concepts/factories/005.php @@ -10,5 +10,4 @@ class Factories extends BaseFactory public $filters = [ 'instanceOf' => FilterInterface::class, ]; - // ... } diff --git a/user_guide_src/source/database/configuration/008.php b/user_guide_src/source/database/configuration/008.php index c6084e212234..5639c484d125 100644 --- a/user_guide_src/source/database/configuration/008.php +++ b/user_guide_src/source/database/configuration/008.php @@ -14,5 +14,4 @@ public function __construct() { $this->defaultGroup = ENVIRONMENT; } - // ... } diff --git a/user_guide_src/source/extending/basecontroller/003.php b/user_guide_src/source/extending/basecontroller/003.php index 4948b49bf0ac..22afdf184f75 100644 --- a/user_guide_src/source/extending/basecontroller/003.php +++ b/user_guide_src/source/extending/basecontroller/003.php @@ -4,6 +4,8 @@ class Home extends BaseController { + // ... + public function initController(/* ... */) { // Do Not Edit This Line diff --git a/user_guide_src/source/installation/upgrade_configuration/002.php b/user_guide_src/source/installation/upgrade_configuration/002.php index cc013d77583f..f62f19b7c5ad 100644 --- a/user_guide_src/source/installation/upgrade_configuration/002.php +++ b/user_guide_src/source/installation/upgrade_configuration/002.php @@ -8,5 +8,4 @@ class CustomClass extends BaseConfig { public $siteName = 'My Great Site'; public $siteEmail = 'webmaster@example.com'; - // ... } diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index b7138b5ec63b..67ccc4a634dc 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -4,7 +4,7 @@ final class SomeTest extends CIUnitTestCase { - protected function setUp() + protected function setUp(): void { parent::setUp(); From 7011b01108352310fa7653e9aa42a2e80583c1df Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Wed, 2 Mar 2022 10:14:53 +0100 Subject: [PATCH 1718/2325] Fix spaces. --- user_guide_src/source/models/entities/021.php | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/models/entities/021.php b/user_guide_src/source/models/entities/021.php index a117e2a81f37..219c437b378c 100644 --- a/user_guide_src/source/models/entities/021.php +++ b/user_guide_src/source/models/entities/021.php @@ -9,13 +9,17 @@ class SomeHandler extends BaseCast public static function get($value, array $params = []) { var_dump($params); - // array(3) { - // [0]=> - // string(13) "App\SomeClass" - // [1]=> - // string(6) "param2" - // [2]=> - // string(6) "param3" - // } + /* + Output: + + array(3) { + [0]=> + string(13) "App\SomeClass" + [1]=> + string(6) "param2" + [2]=> + string(6) "param3" + } + */ } } From f7d93e3ed2d2767e8bac8eaaea69c32c496191bc Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Wed, 2 Mar 2022 10:22:34 +0100 Subject: [PATCH 1719/2325] Fix BaseController examples. --- user_guide_src/source/extending/basecontroller/002.php | 8 +++++++- user_guide_src/source/extending/basecontroller/003.php | 6 ++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/extending/basecontroller/002.php b/user_guide_src/source/extending/basecontroller/002.php index bd7de42a0a94..1add155f1b4c 100644 --- a/user_guide_src/source/extending/basecontroller/002.php +++ b/user_guide_src/source/extending/basecontroller/002.php @@ -2,7 +2,13 @@ namespace App\Controllers; -class Home extends BaseController +use CodeIgniter\Controller; + +abstract class BaseController extends Controller { + // ... + protected $helpers = ['html', 'text']; + + // ... } diff --git a/user_guide_src/source/extending/basecontroller/003.php b/user_guide_src/source/extending/basecontroller/003.php index 22afdf184f75..5c9fcf1fc255 100644 --- a/user_guide_src/source/extending/basecontroller/003.php +++ b/user_guide_src/source/extending/basecontroller/003.php @@ -2,10 +2,12 @@ namespace App\Controllers; -class Home extends BaseController +use CodeIgniter\Controller; + +abstract class BaseController extends Controller { // ... - + public function initController(/* ... */) { // Do Not Edit This Line From b4f3c06cd78c8cb73bc64d4b8a9f7c7b8c40cde2 Mon Sep 17 00:00:00 2001 From: Alex Schmitz <40514119+sfadschm@users.noreply.github.com> Date: Wed, 2 Mar 2022 10:22:58 +0100 Subject: [PATCH 1720/2325] Fix empty line. Co-authored-by: kenjis --- user_guide_src/source/dbmgmt/migration/002.php | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/dbmgmt/migration/002.php b/user_guide_src/source/dbmgmt/migration/002.php index 6a8482fb1478..b324f22003a7 100644 --- a/user_guide_src/source/dbmgmt/migration/002.php +++ b/user_guide_src/source/dbmgmt/migration/002.php @@ -11,6 +11,7 @@ public function up() $this->db->disableForeignKeyChecks(); // Migration rules would go here.. + $this->db->enableForeignKeyChecks(); } } From 561706af62db143cbd494e70242a3a4a1d3133c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 3 Mar 2022 00:45:54 +0800 Subject: [PATCH 1721/2325] chore(deps): bump actions/checkout from 2 to 3 (#5760) Bumps [actions/checkout](https://github.com/actions/checkout) from 2 to 3. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/deploy-apidocs.yml | 4 ++-- .github/workflows/deploy-framework.yml | 8 ++++---- .github/workflows/deploy-userguide-latest.yml | 2 +- .github/workflows/test-autoreview.yml | 2 +- .github/workflows/test-coding-standards.yml | 2 +- .github/workflows/test-deptrac.yml | 2 +- .github/workflows/test-phpcpd.yml | 2 +- .github/workflows/test-phpstan.yml | 2 +- .github/workflows/test-phpunit.yml | 2 +- .github/workflows/test-rector.yml | 2 +- .github/workflows/test-scss.yml | 2 +- .github/workflows/test-userguide.yml | 2 +- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/deploy-apidocs.yml b/.github/workflows/deploy-apidocs.yml index 4a7d20dd502b..55480f4fd5a4 100644 --- a/.github/workflows/deploy-apidocs.yml +++ b/.github/workflows/deploy-apidocs.yml @@ -24,12 +24,12 @@ jobs: git config --global user.name "${GITHUB_ACTOR}" - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: source - name: Checkout target - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: codeigniter4/api token: ${{ secrets.ACCESS_TOKEN }} diff --git a/.github/workflows/deploy-framework.yml b/.github/workflows/deploy-framework.yml index 339565dcfdfc..9fdbc8f08127 100644 --- a/.github/workflows/deploy-framework.yml +++ b/.github/workflows/deploy-framework.yml @@ -18,12 +18,12 @@ jobs: git config --global user.name "${GITHUB_ACTOR}" - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: source - name: Checkout target - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: codeigniter4/framework token: ${{ secrets.ACCESS_TOKEN }} @@ -63,12 +63,12 @@ jobs: git config --global user.name "${GITHUB_ACTOR}" - name: Checkout source - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: path: source - name: Checkout target - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: repository: codeigniter4/appstarter token: ${{ secrets.ACCESS_TOKEN }} diff --git a/.github/workflows/deploy-userguide-latest.yml b/.github/workflows/deploy-userguide-latest.yml index 22e6eed4db4f..fb453f0c9694 100644 --- a/.github/workflows/deploy-userguide-latest.yml +++ b/.github/workflows/deploy-userguide-latest.yml @@ -19,7 +19,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Build the latest User Guide - name: Build with Sphinx diff --git a/.github/workflows/test-autoreview.yml b/.github/workflows/test-autoreview.yml index 28f1230b0073..ccc97dcf137e 100644 --- a/.github/workflows/test-autoreview.yml +++ b/.github/workflows/test-autoreview.yml @@ -21,7 +21,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-coding-standards.yml b/.github/workflows/test-coding-standards.yml index 583f4d5df72c..4e9509f4fb2e 100644 --- a/.github/workflows/test-coding-standards.yml +++ b/.github/workflows/test-coding-standards.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml index 262da202c02f..ac280f964d0a 100644 --- a/.github/workflows/test-deptrac.yml +++ b/.github/workflows/test-deptrac.yml @@ -30,7 +30,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-phpcpd.yml b/.github/workflows/test-phpcpd.yml index 6cfd76a054f1..e4d869c09d4a 100644 --- a/.github/workflows/test-phpcpd.yml +++ b/.github/workflows/test-phpcpd.yml @@ -29,7 +29,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index d0235ec9beb6..f7c09d1aa89e 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -37,7 +37,7 @@ jobs: php-versions: ['8.0', '8.1'] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 964f9fcb3f72..623d13f59475 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -120,7 +120,7 @@ jobs: run: echo -e "ALTER SESSION SET CONTAINER = XEPDB1;\nCREATE BIGFILE TABLESPACE \"TEST\" DATAFILE '/opt/oracle/product/18c/dbhomeXE/dbs/TEST' SIZE 10M AUTOEXTEND ON MAXSIZE UNLIMITED SEGMENT SPACE MANAGEMENT AUTO EXTENT MANAGEMENT LOCAL AUTOALLOCATE;\nCREATE USER \"ORACLE\" IDENTIFIED BY \"ORACLE\" DEFAULT TABLESPACE \"TEST\" TEMPORARY TABLESPACE TEMP QUOTA UNLIMITED ON \"TEST\";\nGRANT CONNECT,RESOURCE TO \"ORACLE\";\nexit;" | /lib/oracle/18.5/client64/bin/sqlplus -s sys/Oracle18@localhost:1521/XE as sysdba - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP, with composer and extensions uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-rector.yml b/.github/workflows/test-rector.yml index 1282205c8bf6..a96821da3191 100644 --- a/.github/workflows/test-rector.yml +++ b/.github/workflows/test-rector.yml @@ -37,7 +37,7 @@ jobs: php-versions: ['7.4', '8.0'] steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 diff --git a/.github/workflows/test-scss.yml b/.github/workflows/test-scss.yml index ff65863fe3a6..0d335a29552a 100644 --- a/.github/workflows/test-scss.yml +++ b/.github/workflows/test-scss.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup Node uses: actions/setup-node@v3.0.0 diff --git a/.github/workflows/test-userguide.yml b/.github/workflows/test-userguide.yml index 44cfa52c8b17..b01c141a9c61 100644 --- a/.github/workflows/test-userguide.yml +++ b/.github/workflows/test-userguide.yml @@ -17,7 +17,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Detect usage of tabs in RST files run: php utils/check_tabs_in_rst.php From 45c8e27663107cede2a2da64ad07b934a8c19ca6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 3 Mar 2022 08:56:34 +0900 Subject: [PATCH 1722/2325] docs: fix incorrect config filename --- user_guide_src/source/concepts/factories.rst | 6 +++--- user_guide_src/source/concepts/factories/005.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index db48a58e8f74..2ddab73f2216 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -79,8 +79,8 @@ Factories Behavior Options can be applied in one of three ways (listed in ascending priority): -* A configuration file ``Factory`` with a component property. -* The static method ``Factories::setOptions``. +* A configuration class ``Config\Factory`` with a ``$component`` property. +* The static method ``Factories::setOptions()``. * Passing options directly at call time with a parameter. Configurations @@ -89,7 +89,7 @@ Configurations To set default component options, create a new Config files at **app/Config/Factory.php** that supplies options as an array property that matches the name of the component. For example, if you wanted to ensure that all Filters used by your app were valid framework instances, -your **Factories.php** file might look like this: +your **Factory.php** file might look like this: .. literalinclude:: factories/005.php diff --git a/user_guide_src/source/concepts/factories/005.php b/user_guide_src/source/concepts/factories/005.php index 10a82b828d73..1c63105feb04 100644 --- a/user_guide_src/source/concepts/factories/005.php +++ b/user_guide_src/source/concepts/factories/005.php @@ -5,7 +5,7 @@ use CodeIgniter\Config\Factory as BaseFactory; use CodeIgniter\Filters\FilterInterface; -class Factories extends BaseFactory +class Factory extends BaseFactory { public $filters = [ 'instanceOf' => FilterInterface::class, From eb45f56dcd2ef942a044e3ea45df5234954fa091 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Thu, 3 Mar 2022 20:36:03 +0700 Subject: [PATCH 1723/2325] [Rector] Update to Rector 0.12.17 and Re-run it --- composer.json | 2 +- phpstan-baseline.neon.dist | 4 ++++ tests/system/Database/Live/FabricatorLiveTest.php | 2 +- tests/system/Database/Live/ForgeTest.php | 8 ++------ tests/system/Filters/HoneypotTest.php | 2 +- tests/system/HTTP/URITest.php | 2 +- tests/system/Honeypot/HoneypotTest.php | 2 +- tests/system/I18n/TimeTest.php | 2 +- 8 files changed, 12 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index d9daf5748fb3..945e9d30e723 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.16" + "rector/rector": "0.12.17" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 3343075a3159..7c0704286696 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -915,3 +915,7 @@ parameters: paths: - system/Cache/CacheFactory.php - system/Filters/Filters.php + + - + message: "#^Binary operation \"/\" between string and 8 results in an error\\.$#" + path: system/Encryption/Handlers/OpenSSLHandler.php diff --git a/tests/system/Database/Live/FabricatorLiveTest.php b/tests/system/Database/Live/FabricatorLiveTest.php index b1cf373f1244..761de0a39fae 100644 --- a/tests/system/Database/Live/FabricatorLiveTest.php +++ b/tests/system/Database/Live/FabricatorLiveTest.php @@ -50,7 +50,7 @@ public function testCreateAddsCountToDatabase() // Some countries violate the 40 character limit so override that $fabricator->setOverrides(['country' => 'France']); - $result = $fabricator->create($count); + $fabricator->create($count); $this->seeNumRecords($count, 'user', []); } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index e20f26556f1d..113f2c0a211e 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -30,11 +30,7 @@ final class ForgeTest extends CIUnitTestCase protected $refresh = true; protected $seed = 'Tests\Support\Database\Seeds\CITestSeeder'; - - /** - * @var Forge - */ - protected $forge; + protected Forge $forge; protected function setUp(): void { @@ -812,7 +808,7 @@ public function testAddFields() $this->forge->addKey('id', true); $this->forge->addUniqueKey(['username', 'active']); - $create = $this->forge->createTable($tableName, true); + $this->forge->createTable($tableName, true); $fieldsNames = $this->db->getFieldNames($tableName); $fieldsData = $this->db->getFieldData($tableName); diff --git a/tests/system/Filters/HoneypotTest.php b/tests/system/Filters/HoneypotTest.php index 938f0fe525f5..4919b8490fde 100644 --- a/tests/system/Filters/HoneypotTest.php +++ b/tests/system/Filters/HoneypotTest.php @@ -53,7 +53,7 @@ public function testBeforeTriggered() $uri = 'admin/foo/bar'; $this->expectException(HoneypotException::class); - $request = $filters->run($uri, 'before'); + $filters->run($uri, 'before'); } public function testBeforeClean() diff --git a/tests/system/HTTP/URITest.php b/tests/system/HTTP/URITest.php index a4faacfbdd80..1a51741b8c36 100644 --- a/tests/system/HTTP/URITest.php +++ b/tests/system/HTTP/URITest.php @@ -155,7 +155,7 @@ public function testMalformedUri() { $this->expectException(HTTPException::class); $url = 'http://abc:a123'; - $uri = new URI($url); + new URI($url); } public function testMissingScheme() diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index e7f6893b9cf9..860d552d4e86 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -114,7 +114,7 @@ public function testHoneypotFilterBefore() $uri = 'admin/foo/bar'; $this->expectException(HoneypotException::class); - $request = $filters->run($uri, 'before'); + $filters->run($uri, 'before'); } public function testHoneypotFilterAfter() diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index bdc605d2d253..ed1b747699a4 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -235,7 +235,7 @@ public function testCreateFromFormatWithInvalidFormat() $this->expectException(I18nException::class); $this->expectExceptionMessage(lang('Time.invalidFormat', [$format])); - $time = Time::createFromFormat($format, 'America/Chicago'); + Time::createFromFormat($format, 'America/Chicago'); } public function testCreateFromTimestamp() From f9ef14a2064c1c6981d0fa95b02ccec9e09e545a Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 11:37:07 +0900 Subject: [PATCH 1724/2325] docs: change comment style --- user_guide_src/source/cli/cli_library/007.php | 14 ++++++++------ user_guide_src/source/cli/cli_library/008.php | 14 ++++++++------ 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/cli/cli_library/007.php b/user_guide_src/source/cli/cli_library/007.php index 474229ba6e6a..6d77ee91e4a0 100644 --- a/user_guide_src/source/cli/cli_library/007.php +++ b/user_guide_src/source/cli/cli_library/007.php @@ -2,9 +2,11 @@ $fruit = CLI::promptByKey('These are your choices:', ['The red apple', 'The plump orange', 'The ripe banana']); -//These are your choices: -// [0] The red apple -// [1] The plump orange -// [2] The ripe banana -// -//[0, 1, 2]: +/* +These are your choices: + [0] The red apple + [1] The plump orange + [2] The ripe banana + +[0, 1, 2]: +*/ diff --git a/user_guide_src/source/cli/cli_library/008.php b/user_guide_src/source/cli/cli_library/008.php index 003c9a362444..b455b7efe22e 100644 --- a/user_guide_src/source/cli/cli_library/008.php +++ b/user_guide_src/source/cli/cli_library/008.php @@ -6,9 +6,11 @@ 'banana' => 'The ripe banana' ]); -//These are your choices: -// [apple] The red apple -// [orange] The plump orange -// [banana] The ripe banana -// -//Which would you like? [apple, orange, banana]: +/* +These are your choices: + [apple] The red apple + [orange] The plump orange + [banana] The ripe banana + +Which would you like? [apple, orange, banana]: +*/ From 85e624f5d724a451d496f0caa90873cbd5a99dcd Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 11:57:25 +0900 Subject: [PATCH 1725/2325] docs: move CodeIgniter 3 sample code to `ci3sample` folder --- user_guide_src/source/installation/upgrade_configuration.rst | 2 +- .../installation/upgrade_configuration/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_controllers.rst | 2 +- .../installation/upgrade_controllers/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_database.rst | 2 +- .../installation/upgrade_database/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_emails.rst | 2 +- .../source/installation/upgrade_emails/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_encryption.rst | 2 +- .../installation/upgrade_encryption/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_file_upload.rst | 2 +- .../installation/upgrade_file_upload/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_html_tables.rst | 2 +- .../installation/upgrade_html_tables/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_localization.rst | 2 +- .../installation/upgrade_localization/{ => ci3sample}/002.php | 0 user_guide_src/source/installation/upgrade_migrations.rst | 2 +- .../installation/upgrade_migrations/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_models.rst | 2 +- .../source/installation/upgrade_models/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_pagination.rst | 2 +- .../installation/upgrade_pagination/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_responses.rst | 2 +- .../installation/upgrade_responses/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_routing.rst | 2 +- .../source/installation/upgrade_routing/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_security.rst | 2 +- .../installation/upgrade_security/{ => ci3sample}/002.php | 0 user_guide_src/source/installation/upgrade_sessions.rst | 2 +- .../installation/upgrade_sessions/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_validations.rst | 2 +- .../installation/upgrade_validations/{ => ci3sample}/002.php | 0 user_guide_src/source/installation/upgrade_view_parser.rst | 2 +- .../installation/upgrade_view_parser/{ => ci3sample}/001.php | 0 user_guide_src/source/installation/upgrade_views.rst | 2 +- .../source/installation/upgrade_views/{ => ci3sample}/001.php | 0 36 files changed, 18 insertions(+), 18 deletions(-) rename user_guide_src/source/installation/upgrade_configuration/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_controllers/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_database/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_emails/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_encryption/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_file_upload/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_html_tables/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_localization/{ => ci3sample}/002.php (100%) rename user_guide_src/source/installation/upgrade_migrations/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_models/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_pagination/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_responses/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_routing/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_security/{ => ci3sample}/002.php (100%) rename user_guide_src/source/installation/upgrade_sessions/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_validations/{ => ci3sample}/002.php (100%) rename user_guide_src/source/installation/upgrade_view_parser/{ => ci3sample}/001.php (100%) rename user_guide_src/source/installation/upgrade_views/{ => ci3sample}/001.php (100%) diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index 21ae6101c158..6a9f38069478 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -40,7 +40,7 @@ CodeIgniter Version 3.x Path: **application/config**: -.. literalinclude:: upgrade_configuration/001.php +.. literalinclude:: upgrade_configuration/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_configuration/001.php b/user_guide_src/source/installation/upgrade_configuration/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_configuration/001.php rename to user_guide_src/source/installation/upgrade_configuration/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index fc0bcb4d37d7..3e7521445691 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -43,7 +43,7 @@ CodeIgniter Version 3.x Path: **application/controllers**: -.. literalinclude:: upgrade_controllers/001.php +.. literalinclude:: upgrade_controllers/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_controllers/001.php b/user_guide_src/source/installation/upgrade_controllers/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_controllers/001.php rename to user_guide_src/source/installation/upgrade_controllers/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index 4479c46ff5e8..10b1e6ac1c96 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -46,7 +46,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_database/001.php +.. literalinclude:: upgrade_database/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_database/001.php b/user_guide_src/source/installation/upgrade_database/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_database/001.php rename to user_guide_src/source/installation/upgrade_database/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index 1ece732add8f..af322f2d7c7a 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -28,7 +28,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_emails/001.php +.. literalinclude:: upgrade_emails/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_emails/001.php b/user_guide_src/source/installation/upgrade_emails/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_emails/001.php rename to user_guide_src/source/installation/upgrade_emails/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index fb617a5424d5..9d626d341d5d 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -26,7 +26,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_encryption/001.php +.. literalinclude:: upgrade_encryption/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_encryption/001.php b/user_guide_src/source/installation/upgrade_encryption/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_encryption/001.php rename to user_guide_src/source/installation/upgrade_encryption/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index f0eb3a24c405..ed620bbaeb67 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -27,7 +27,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_file_upload/001.php +.. literalinclude:: upgrade_file_upload/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_file_upload/001.php b/user_guide_src/source/installation/upgrade_file_upload/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_file_upload/001.php rename to user_guide_src/source/installation/upgrade_file_upload/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst index 2a0bbaacd5c7..ae97e8e3baf2 100644 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -27,7 +27,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_html_tables/001.php +.. literalinclude:: upgrade_html_tables/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_html_tables/001.php b/user_guide_src/source/installation/upgrade_html_tables/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_html_tables/001.php rename to user_guide_src/source/installation/upgrade_html_tables/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index 0d1ed53f2ebb..782336334974 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -32,7 +32,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_localization/002.php +.. literalinclude:: upgrade_localization/ci3sample/002.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_localization/002.php b/user_guide_src/source/installation/upgrade_localization/ci3sample/002.php similarity index 100% rename from user_guide_src/source/installation/upgrade_localization/002.php rename to user_guide_src/source/installation/upgrade_localization/ci3sample/002.php diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 07dc32e96675..60f6b8d7b090 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -53,7 +53,7 @@ CodeIgniter Version 3.x Path: **application/migrations**: -.. literalinclude:: upgrade_migrations/001.php +.. literalinclude:: upgrade_migrations/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_migrations/001.php b/user_guide_src/source/installation/upgrade_migrations/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_migrations/001.php rename to user_guide_src/source/installation/upgrade_migrations/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst index ea9928a8f47e..1ffce60151e0 100644 --- a/user_guide_src/source/installation/upgrade_models.rst +++ b/user_guide_src/source/installation/upgrade_models.rst @@ -42,7 +42,7 @@ CodeIgniter Version 3.x Path: **application/models**: -.. literalinclude:: upgrade_models/001.php +.. literalinclude:: upgrade_models/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_models/001.php b/user_guide_src/source/installation/upgrade_models/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_models/001.php rename to user_guide_src/source/installation/upgrade_models/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index c39638682534..6658ae8e4bd7 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -34,7 +34,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_pagination/001.php +.. literalinclude:: upgrade_pagination/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_pagination/001.php b/user_guide_src/source/installation/upgrade_pagination/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_pagination/001.php rename to user_guide_src/source/installation/upgrade_pagination/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index 455e5aa1617c..c6b925d144f1 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -25,7 +25,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_responses/001.php +.. literalinclude:: upgrade_responses/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_responses/001.php b/user_guide_src/source/installation/upgrade_responses/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_responses/001.php rename to user_guide_src/source/installation/upgrade_responses/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 533826babd29..9e6c512ff423 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -30,7 +30,7 @@ CodeIgniter Version 3.x ------------------------ Path: **application/config/routes.php**: -.. literalinclude:: upgrade_routing/001.php +.. literalinclude:: upgrade_routing/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_routing/001.php b/user_guide_src/source/installation/upgrade_routing/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_routing/001.php rename to user_guide_src/source/installation/upgrade_routing/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 9000bea7167a..0a6d615e0841 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -33,7 +33,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_security/002.php +.. literalinclude:: upgrade_security/ci3sample/002.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_security/002.php b/user_guide_src/source/installation/upgrade_security/ci3sample/002.php similarity index 100% rename from user_guide_src/source/installation/upgrade_security/002.php rename to user_guide_src/source/installation/upgrade_security/ci3sample/002.php diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index df5ff7daae85..a309033bc816 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -31,7 +31,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_sessions/001.php +.. literalinclude:: upgrade_sessions/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_sessions/001.php b/user_guide_src/source/installation/upgrade_sessions/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_sessions/001.php rename to user_guide_src/source/installation/upgrade_sessions/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 22dd0a2aff00..3612784ade28 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -73,7 +73,7 @@ Path: **application/views**:: Path: **application/controllers**: -.. literalinclude:: upgrade_validations/002.php +.. literalinclude:: upgrade_validations/ci3sample/002.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_validations/002.php b/user_guide_src/source/installation/upgrade_validations/ci3sample/002.php similarity index 100% rename from user_guide_src/source/installation/upgrade_validations/002.php rename to user_guide_src/source/installation/upgrade_validations/ci3sample/002.php diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index a6faa488471e..5def5e912d5f 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -27,7 +27,7 @@ Code Example CodeIgniter Version 3.x ------------------------ -.. literalinclude:: upgrade_view_parser/001.php +.. literalinclude:: upgrade_view_parser/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_view_parser/001.php b/user_guide_src/source/installation/upgrade_view_parser/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_view_parser/001.php rename to user_guide_src/source/installation/upgrade_view_parser/ci3sample/001.php diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index ac7df48f2844..574de607b42b 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -36,7 +36,7 @@ CodeIgniter Version 3.x Path: **application/views**: -.. literalinclude:: upgrade_views/001.php +.. literalinclude:: upgrade_views/ci3sample/001.php CodeIgniter Version 4.x ----------------------- diff --git a/user_guide_src/source/installation/upgrade_views/001.php b/user_guide_src/source/installation/upgrade_views/ci3sample/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_views/001.php rename to user_guide_src/source/installation/upgrade_views/ci3sample/001.php From 7120a4b762af9b10e181c75d1f26881c95d06904 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 13:46:06 +0900 Subject: [PATCH 1726/2325] docs: change comment style --- .../source/cli/cli_commands/007.php | 8 +++-- .../source/database/query_builder/003.php | 7 ++-- .../source/database/query_builder/006.php | 12 ++++--- .../source/database/query_builder/018.php | 7 ++-- .../source/database/query_builder/074.php | 7 ++-- .../source/database/query_builder/087.php | 11 ++++--- .../source/database/query_builder/088.php | 11 ++++--- .../source/database/query_builder/091.php | 23 ++++++------- .../source/database/query_builder/092.php | 2 +- .../source/database/query_builder/093.php | 9 +++--- .../source/database/query_builder/095.php | 7 ++-- .../source/database/query_builder/097.php | 7 ++-- user_guide_src/source/dbmgmt/forge/004.php | 6 ++-- .../source/helpers/array_helper/011.php | 7 ++-- .../source/helpers/form_helper/010.php | 10 +++--- .../source/helpers/form_helper/011.php | 10 +++--- .../source/helpers/form_helper/012.php | 6 ++-- .../source/helpers/form_helper/014.php | 6 ++-- .../source/helpers/form_helper/017.php | 6 ++-- .../source/helpers/form_helper/018.php | 32 ++++++++----------- .../source/helpers/text_helper/020.php | 14 ++++---- .../source/incoming/incomingrequest/010.php | 12 +++---- .../source/libraries/curlrequest/014.php | 10 +++--- .../source/libraries/validation/009.php | 25 +++++++-------- .../source/libraries/validation/011.php | 15 ++++----- .../source/libraries/validation/026.php | 12 +++---- .../source/libraries/validation/028.2.php | 11 +++---- user_guide_src/source/models/entities/021.php | 1 - .../source/outgoing/response/021.php | 7 ++-- .../source/outgoing/view_parser/016.php | 7 ++-- .../source/testing/benchmark/004.php | 16 ++++------ 31 files changed, 159 insertions(+), 165 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands/007.php b/user_guide_src/source/cli/cli_commands/007.php index 7fcb90ccf083..9f9f47f2a4fb 100644 --- a/user_guide_src/source/cli/cli_commands/007.php +++ b/user_guide_src/source/cli/cli_commands/007.php @@ -6,6 +6,8 @@ CLI::write($tab . CLI::color(str_pad($option, $pad), 'green') . $description, 'yellow'); } -// Output will be -// -n Set migration namespace -// -r override file +/* + Output will be + -n Set migration namespace + -r override file +*/ diff --git a/user_guide_src/source/database/query_builder/003.php b/user_guide_src/source/database/query_builder/003.php index 26a9470fb6ef..b5300a358280 100644 --- a/user_guide_src/source/database/query_builder/003.php +++ b/user_guide_src/source/database/query_builder/003.php @@ -1,6 +1,7 @@ get(10, 20); - -// Executes: SELECT * FROM mytable LIMIT 20, 10 -// (in MySQL. Other databases have slightly different syntax) +/* +Executes: SELECT * FROM mytable LIMIT 20, 10 +(in MySQL. Other databases have slightly different syntax) +*/ diff --git a/user_guide_src/source/database/query_builder/006.php b/user_guide_src/source/database/query_builder/006.php index 2868aaa49fee..2d672d5ce9ce 100644 --- a/user_guide_src/source/database/query_builder/006.php +++ b/user_guide_src/source/database/query_builder/006.php @@ -1,10 +1,12 @@ limit(10,20)->getCompiledSelect(false); - -// Prints string: SELECT * FROM mytable LIMIT 20, 10 -// (in MySQL. Other databases have slightly different syntax) +/* +Prints string: SELECT * FROM mytable LIMIT 20, 10 +(in MySQL. Other databases have slightly different syntax) +*/ echo $builder->select('title, content, date')->getCompiledSelect(); - -// Prints string: SELECT title, content, date FROM mytable LIMIT 20, 10 +/* +Prints string: SELECT title, content, date FROM mytable LIMIT 20, 10 +*/ diff --git a/user_guide_src/source/database/query_builder/018.php b/user_guide_src/source/database/query_builder/018.php index 870a45e638e6..17465bd1cb43 100644 --- a/user_guide_src/source/database/query_builder/018.php +++ b/user_guide_src/source/database/query_builder/018.php @@ -4,6 +4,7 @@ $builder->select('*'); $builder->join('comments', 'comments.id = blogs.id'); $query = $builder->get(); - -// Produces: -// SELECT * FROM blogs JOIN comments ON comments.id = blogs.id +/* +Produces: +SELECT * FROM blogs JOIN comments ON comments.id = blogs.id +*/ diff --git a/user_guide_src/source/database/query_builder/074.php b/user_guide_src/source/database/query_builder/074.php index 20025bc32cee..68fbcbb0bf60 100644 --- a/user_guide_src/source/database/query_builder/074.php +++ b/user_guide_src/source/database/query_builder/074.php @@ -10,6 +10,7 @@ ->groupEnd() ->where('d', 'd') ->get(); - -// Generates: -// SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' +/* +Generates: +SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' +*/ diff --git a/user_guide_src/source/database/query_builder/087.php b/user_guide_src/source/database/query_builder/087.php index 1b99a6196706..3032402a7c32 100644 --- a/user_guide_src/source/database/query_builder/087.php +++ b/user_guide_src/source/database/query_builder/087.php @@ -8,8 +8,9 @@ $builder->where('id', $id); $builder->update($data); -// Produces: -// -// UPDATE mytable -// SET title = '{$title}', name = '{$name}', date = '{$date}' -// WHERE id = $id +/* +Produces: +UPDATE mytable +SET title = '{$title}', name = '{$name}', date = '{$date}' +WHERE id = $id +*/ diff --git a/user_guide_src/source/database/query_builder/088.php b/user_guide_src/source/database/query_builder/088.php index c789d85e02bf..37afb6ce2b46 100644 --- a/user_guide_src/source/database/query_builder/088.php +++ b/user_guide_src/source/database/query_builder/088.php @@ -10,8 +10,9 @@ class Myclass $object = new Myclass; $builder->where('id', $id); $builder->update($object); -// Produces: -// -// UPDATE `mytable` -// SET `title` = '{$title}', `name` = '{$name}', `date` = '{$date}' -// WHERE id = `$id` +/* +Produces: +UPDATE `mytable` +SET `title` = '{$title}', `name` = '{$name}', `date` = '{$date}' +WHERE id = `$id` +*/ diff --git a/user_guide_src/source/database/query_builder/091.php b/user_guide_src/source/database/query_builder/091.php index 545641a98f74..a3943d41cfb9 100644 --- a/user_guide_src/source/database/query_builder/091.php +++ b/user_guide_src/source/database/query_builder/091.php @@ -14,14 +14,15 @@ ]; $builder->updateBatch($data, 'title'); - -// Produces: -// UPDATE `mytable` SET `name` = CASE -// WHEN `title` = 'My title' THEN 'My Name 2' -// WHEN `title` = 'Another title' THEN 'Another Name 2' -// ELSE `name` END, -// `date` = CASE -// WHEN `title` = 'My title' THEN 'My date 2' -// WHEN `title` = 'Another title' THEN 'Another date 2' -// ELSE `date` END -// WHERE `title` IN ('My title','Another title') +/* +Produces: +UPDATE `mytable` SET `name` = CASE +WHEN `title` = 'My title' THEN 'My Name 2' +WHEN `title` = 'Another title' THEN 'Another Name 2' +ELSE `name` END, +`date` = CASE +WHEN `title` = 'My title' THEN 'My date 2' +WHEN `title` = 'Another title' THEN 'Another date 2' +ELSE `date` END +WHERE `title` IN ('My title','Another title') +*/ diff --git a/user_guide_src/source/database/query_builder/092.php b/user_guide_src/source/database/query_builder/092.php index 605d533162bd..ed680a441d98 100644 --- a/user_guide_src/source/database/query_builder/092.php +++ b/user_guide_src/source/database/query_builder/092.php @@ -1,4 +1,4 @@ delete(['id' => $id]); -// Produces: // DELETE FROM mytable // WHERE id = $id +// Produces: DELETE FROM mytable WHERE id = $id diff --git a/user_guide_src/source/database/query_builder/093.php b/user_guide_src/source/database/query_builder/093.php index 6628a09b5056..70e9ed3b7f69 100644 --- a/user_guide_src/source/database/query_builder/093.php +++ b/user_guide_src/source/database/query_builder/093.php @@ -2,7 +2,8 @@ $builder->where('id', $id); $builder->delete(); - -// Produces: -// DELETE FROM mytable -// WHERE id = $id +/* +Produces: +DELETE FROM mytable +WHERE id = $id +*/ diff --git a/user_guide_src/source/database/query_builder/095.php b/user_guide_src/source/database/query_builder/095.php index 0cdf6ef52bfa..c2afc9fe3c2a 100644 --- a/user_guide_src/source/database/query_builder/095.php +++ b/user_guide_src/source/database/query_builder/095.php @@ -1,6 +1,7 @@ truncate(); - -// Produce: -// TRUNCATE mytable +/* +Produce: +TRUNCATE mytable +*/ diff --git a/user_guide_src/source/database/query_builder/097.php b/user_guide_src/source/database/query_builder/097.php index f484292a9d27..ec48b920e406 100644 --- a/user_guide_src/source/database/query_builder/097.php +++ b/user_guide_src/source/database/query_builder/097.php @@ -11,6 +11,7 @@ // ... $data = $builder->get()->getResultArray(); - -// Would execute and return an array of results of the following query: -// SELECT field1, field1 from mytable where field3 = 5; +/* +Would execute and return an array of results of the following query: +SELECT field1, field1 from mytable where field3 = 5; +*/ diff --git a/user_guide_src/source/dbmgmt/forge/004.php b/user_guide_src/source/dbmgmt/forge/004.php index c514b3c0e46a..d793fd8b82d8 100644 --- a/user_guide_src/source/dbmgmt/forge/004.php +++ b/user_guide_src/source/dbmgmt/forge/004.php @@ -1,5 +1,7 @@ createDatabase('my_db', true); -// gives CREATE DATABASE IF NOT EXISTS `my_db` -// or will check if a database exists +/* +gives CREATE DATABASE IF NOT EXISTS `my_db` +or will check if a database exists +*/ diff --git a/user_guide_src/source/helpers/array_helper/011.php b/user_guide_src/source/helpers/array_helper/011.php index 754588747d6c..31ee64387979 100644 --- a/user_guide_src/source/helpers/array_helper/011.php +++ b/user_guide_src/source/helpers/array_helper/011.php @@ -2,12 +2,13 @@ // using the same data from above $flattened = array_flatten_with_dots($arrayToFlatten, 'foo_'); - -// $flattened is now: +/* +$flattened is now: [ 'foo_personal.first_name' => 'john', 'foo_personal.last_name' => 'smith', 'foo_personal.age' => '26', 'foo_personal.address' => 'US', 'foo_other_details' => 'marines officer', -]; +] +*/ diff --git a/user_guide_src/source/helpers/form_helper/010.php b/user_guide_src/source/helpers/form_helper/010.php index 8efbdfdeddf1..401a94c685b1 100644 --- a/user_guide_src/source/helpers/form_helper/010.php +++ b/user_guide_src/source/helpers/form_helper/010.php @@ -7,11 +7,9 @@ ]; echo form_hidden($data); - /* - Would produce: - - - - +Would produce: + + + */ diff --git a/user_guide_src/source/helpers/form_helper/011.php b/user_guide_src/source/helpers/form_helper/011.php index 26641f577429..6e28c61e8352 100644 --- a/user_guide_src/source/helpers/form_helper/011.php +++ b/user_guide_src/source/helpers/form_helper/011.php @@ -7,11 +7,9 @@ ]; echo form_hidden('my_array', $data); - /* - Would produce: - - - - +Would produce: + + + */ diff --git a/user_guide_src/source/helpers/form_helper/012.php b/user_guide_src/source/helpers/form_helper/012.php index 1059821da652..4b232ba110f8 100644 --- a/user_guide_src/source/helpers/form_helper/012.php +++ b/user_guide_src/source/helpers/form_helper/012.php @@ -9,9 +9,7 @@ ]; echo form_input($data); - /* - Would produce: - - +Would produce: + */ diff --git a/user_guide_src/source/helpers/form_helper/014.php b/user_guide_src/source/helpers/form_helper/014.php index 6143aed6eaaf..cf8a20dbadff 100644 --- a/user_guide_src/source/helpers/form_helper/014.php +++ b/user_guide_src/source/helpers/form_helper/014.php @@ -10,9 +10,7 @@ ]; echo form_input($data); - /* - Would produce: - - +Would produce: + */ diff --git a/user_guide_src/source/helpers/form_helper/017.php b/user_guide_src/source/helpers/form_helper/017.php index 0ec6a19ca99f..99106e9b4fa8 100644 --- a/user_guide_src/source/helpers/form_helper/017.php +++ b/user_guide_src/source/helpers/form_helper/017.php @@ -1,9 +1,7 @@ 'Email Address...'], 'email'); - /* - Would produce: - - +Would produce: + */ diff --git a/user_guide_src/source/helpers/form_helper/018.php b/user_guide_src/source/helpers/form_helper/018.php index fc6521be6e06..6e521ed04985 100644 --- a/user_guide_src/source/helpers/form_helper/018.php +++ b/user_guide_src/source/helpers/form_helper/018.php @@ -9,27 +9,23 @@ $shirts_on_sale = ['small', 'large']; echo form_dropdown('shirts', $options, 'large'); - /* - Would produce: - - +Would produce: + */ echo form_dropdown('shirts', $options, $shirts_on_sale); - /* - Would produce: - - +Would produce: + */ diff --git a/user_guide_src/source/helpers/text_helper/020.php b/user_guide_src/source/helpers/text_helper/020.php index 1b235b77497e..4bd123f5ae8a 100644 --- a/user_guide_src/source/helpers/text_helper/020.php +++ b/user_guide_src/source/helpers/text_helper/020.php @@ -2,14 +2,12 @@ $string = "Here is a simple string of text that will help us demonstrate this function."; echo word_wrap($string, 25); - /* - Would produce: - - Here is a simple string - of text that will help us - demonstrate this - function. +Would produce: +Here is a simple string +of text that will help us +demonstrate this +function. - Excessively long words will be split, but URLs will not be. +Excessively long words will be split, but URLs will not be. */ diff --git a/user_guide_src/source/incoming/incomingrequest/010.php b/user_guide_src/source/incoming/incomingrequest/010.php index e223b7772d54..a1dc2ccfb9cd 100644 --- a/user_guide_src/source/incoming/incomingrequest/010.php +++ b/user_guide_src/source/incoming/incomingrequest/010.php @@ -1,13 +1,13 @@ getVar('foo'); diff --git a/user_guide_src/source/libraries/curlrequest/014.php b/user_guide_src/source/libraries/curlrequest/014.php index 9147c8861423..2f7e79cc4be7 100644 --- a/user_guide_src/source/libraries/curlrequest/014.php +++ b/user_guide_src/source/libraries/curlrequest/014.php @@ -1,11 +1,9 @@ request('GET', 'http://example.com', ['allow_redirects' => true]); - /* - Sets the following defaults: - - 'max' => 5, // Maximum number of redirects to follow before stopping - 'strict' => true, // Ensure POST requests stay POST requests through redirects - 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols +Sets the following defaults: +'max' => 5, // Maximum number of redirects to follow before stopping +'strict' => true, // Ensure POST requests stay POST requests through redirects +'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols */ diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php index 8792a8a8f728..6f7ce8b9e992 100644 --- a/user_guide_src/source/libraries/validation/009.php +++ b/user_guide_src/source/libraries/validation/009.php @@ -1,21 +1,20 @@ [ - 'name' => 'Joe Smith', - 'friends' => [ - [ - 'name' => 'Fred Flinstone', - ], - [ - 'name' => 'Wilma', - ], - ] +The data to test: +[ + 'contacts' => [ + 'name' => 'Joe Smith', + 'friends' => [ + [ + 'name' => 'Fred Flinstone', + ], + [ + 'name' => 'Wilma', + ], ] ] +] */ // Joe Smith diff --git a/user_guide_src/source/libraries/validation/011.php b/user_guide_src/source/libraries/validation/011.php index ec6b9c9adbab..fa5cad04369c 100644 --- a/user_guide_src/source/libraries/validation/011.php +++ b/user_guide_src/source/libraries/validation/011.php @@ -1,15 +1,14 @@ [ - 1, - 2, - 3, - ] +The data to test: +[ + 'user_ids' => [ + 1, + 2, + 3, ] +] */ // Rule diff --git a/user_guide_src/source/libraries/validation/026.php b/user_guide_src/source/libraries/validation/026.php index e633f5cdd1e3..4c27f4548b0e 100644 --- a/user_guide_src/source/libraries/validation/026.php +++ b/user_guide_src/source/libraries/validation/026.php @@ -1,12 +1,10 @@ getErrors(); - /* - Produces: - - [ - 'field1' => 'error message', - 'field2' => 'error message', - ] +Produces: +[ + 'field1' => 'error message', + 'field2' => 'error message', +] */ diff --git a/user_guide_src/source/libraries/validation/028.2.php b/user_guide_src/source/libraries/validation/028.2.php index 6ad70098c789..34a4d7edefe3 100644 --- a/user_guide_src/source/libraries/validation/028.2.php +++ b/user_guide_src/source/libraries/validation/028.2.php @@ -1,12 +1,11 @@ 'Error', - 'foo.baz.bar' => 'Error', - ] +For errors: +[ + 'foo.0.bar' => 'Error', + 'foo.baz.bar' => 'Error', +] */ // returns true diff --git a/user_guide_src/source/models/entities/021.php b/user_guide_src/source/models/entities/021.php index 219c437b378c..ceb17247a908 100644 --- a/user_guide_src/source/models/entities/021.php +++ b/user_guide_src/source/models/entities/021.php @@ -11,7 +11,6 @@ public static function get($value, array $params = []) var_dump($params); /* Output: - array(3) { [0]=> string(13) "App\SomeClass" diff --git a/user_guide_src/source/outgoing/response/021.php b/user_guide_src/source/outgoing/response/021.php index 092a758b18db..51abaf76bdbd 100644 --- a/user_guide_src/source/outgoing/response/021.php +++ b/user_guide_src/source/outgoing/response/021.php @@ -1,6 +1,7 @@ noCache(); - -// Sets the following header: -// Cache-Control: no-store, max-age=0, no-cache +/* +Sets the following header: +Cache-Control: no-store, max-age=0, no-cache +*/ diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index 0350043cf4fa..0c71e3f88fbb 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -9,8 +9,11 @@ class View extends BaseView public $plugins = [ 'foo' => '\Some\Class::methodName', ]; + // ... } -// Tag is replaced by the return value of Some\Class::methodName static function. -// {+ foo +} +/* +Tag is replaced by the return value of Some\Class::methodName() static function. +{+ foo +} +*/ diff --git a/user_guide_src/source/testing/benchmark/004.php b/user_guide_src/source/testing/benchmark/004.php index 3048a2851ff3..32dc5df31b1a 100644 --- a/user_guide_src/source/testing/benchmark/004.php +++ b/user_guide_src/source/testing/benchmark/004.php @@ -1,15 +1,13 @@ getTimers(); - /* - Produces: - - [ - 'render view' => [ - 'start' => 1234567890, - 'end' => 1345678920, - 'duration' => 15.4315, // number of seconds - ] +Produces: +[ + 'render view' => [ + 'start' => 1234567890, + 'end' => 1345678920, + 'duration' => 15.4315, // number of seconds ] +] */ From 806d5726011d9dcc04fdf7ac951d5007834d7702 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 13:50:09 +0900 Subject: [PATCH 1727/2325] docs: change comment style --- user_guide_src/source/cli/cli_commands/007.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands/007.php b/user_guide_src/source/cli/cli_commands/007.php index 9f9f47f2a4fb..3365e8afdd0e 100644 --- a/user_guide_src/source/cli/cli_commands/007.php +++ b/user_guide_src/source/cli/cli_commands/007.php @@ -7,7 +7,7 @@ } /* - Output will be - -n Set migration namespace - -r override file +Output will be: +-n Set migration namespace +-r override file */ From fff15ead6010363f5938bec26c3c08409fe03dd9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 12:55:51 +0900 Subject: [PATCH 1728/2325] docs: add empty line in sample code --- user_guide_src/source/concepts/services/007.php | 1 + user_guide_src/source/concepts/services/008.php | 1 + user_guide_src/source/concepts/services/010.php | 1 + user_guide_src/source/database/configuration/006.php | 1 + user_guide_src/source/database/helpers/001.php | 1 - user_guide_src/source/database/helpers/002.php | 1 - user_guide_src/source/database/query_builder/005.php | 1 - user_guide_src/source/database/query_builder/008.php | 1 - user_guide_src/source/database/query_builder/016.php | 1 - user_guide_src/source/database/query_builder/017.php | 1 - user_guide_src/source/database/query_builder/027.php | 2 -- user_guide_src/source/database/query_builder/032.php | 1 - user_guide_src/source/database/query_builder/034.php | 1 - user_guide_src/source/database/query_builder/036.php | 1 - user_guide_src/source/database/query_builder/053.php | 1 - user_guide_src/source/database/query_builder/055.php | 1 - user_guide_src/source/database/query_builder/057.php | 1 - user_guide_src/source/database/query_builder/078.php | 1 - user_guide_src/source/database/query_builder/079.php | 2 -- user_guide_src/source/database/query_builder/081.php | 1 - user_guide_src/source/database/query_builder/098.php | 1 - user_guide_src/source/extending/core_classes/002.php | 1 + user_guide_src/source/general/configuration/008.php | 1 + user_guide_src/source/general/logging/002.php | 1 + user_guide_src/source/general/logging/003.php | 1 + user_guide_src/source/general/logging/004.php | 1 + user_guide_src/source/general/managing_apps/001.php | 1 + user_guide_src/source/incoming/filters/003.php | 1 + user_guide_src/source/incoming/filters/004.php | 1 + user_guide_src/source/incoming/filters/005.php | 1 + user_guide_src/source/incoming/filters/006.php | 1 + user_guide_src/source/incoming/filters/007.php | 1 + user_guide_src/source/incoming/filters/008.php | 1 + user_guide_src/source/incoming/filters/009.php | 1 + user_guide_src/source/incoming/filters/011.php | 1 + user_guide_src/source/libraries/caching/013.php | 2 ++ user_guide_src/source/libraries/caching/014.php | 1 + user_guide_src/source/libraries/curlrequest/001.php | 1 + user_guide_src/source/libraries/encryption/008.php | 1 - user_guide_src/source/libraries/honeypot/001.php | 1 + user_guide_src/source/libraries/pagination/010.php | 1 + user_guide_src/source/libraries/pagination/011.php | 1 + user_guide_src/source/libraries/security/002.php | 1 + user_guide_src/source/libraries/security/003.php | 1 + user_guide_src/source/libraries/security/004.php | 1 + user_guide_src/source/libraries/security/006.php | 1 + user_guide_src/source/libraries/security/007.php | 1 + user_guide_src/source/libraries/security/008.php | 1 + user_guide_src/source/libraries/security/009.php | 1 + user_guide_src/source/libraries/sessions/010.php | 2 -- user_guide_src/source/libraries/sessions/017.php | 2 -- user_guide_src/source/libraries/sessions/038.php | 2 -- user_guide_src/source/libraries/sessions/044.php | 1 + user_guide_src/source/libraries/throttler/003.php | 1 + user_guide_src/source/libraries/throttler/004.php | 1 + user_guide_src/source/libraries/validation/003.php | 1 + user_guide_src/source/libraries/validation/013.php | 1 + user_guide_src/source/libraries/validation/015.php | 2 ++ user_guide_src/source/libraries/validation/031.php | 1 + user_guide_src/source/libraries/validation/032.php | 1 + user_guide_src/source/outgoing/api_responses/003.php | 1 + user_guide_src/source/outgoing/api_responses/004.php | 1 + user_guide_src/source/outgoing/localization/001.php | 1 + user_guide_src/source/outgoing/localization/002.php | 1 + user_guide_src/source/outgoing/localization/003.php | 1 + user_guide_src/source/outgoing/response/011.php | 1 + user_guide_src/source/outgoing/view_decorators/002.php | 1 + user_guide_src/source/outgoing/view_parser/005.php | 1 - user_guide_src/source/outgoing/view_parser/012.php | 1 + user_guide_src/source/outgoing/view_parser/013.php | 1 + user_guide_src/source/outgoing/view_parser/014.php | 1 + user_guide_src/source/outgoing/view_parser/015.php | 1 + user_guide_src/source/outgoing/view_parser/017.php | 1 + user_guide_src/source/outgoing/view_parser/018.php | 1 - user_guide_src/source/outgoing/view_parser/019.php | 1 - user_guide_src/source/outgoing/view_parser/020.php | 1 - user_guide_src/source/testing/controllers/012.php | 1 + user_guide_src/source/testing/overview/007.php | 1 + user_guide_src/source/tutorial/create_news_items/001.php | 1 + 79 files changed, 56 insertions(+), 30 deletions(-) diff --git a/user_guide_src/source/concepts/services/007.php b/user_guide_src/source/concepts/services/007.php index 298b8abd010f..296d8445fefc 100644 --- a/user_guide_src/source/concepts/services/007.php +++ b/user_guide_src/source/concepts/services/007.php @@ -10,5 +10,6 @@ public static function routes() { return new \App\Router\MyRouter(); } + // ... } diff --git a/user_guide_src/source/concepts/services/008.php b/user_guide_src/source/concepts/services/008.php index 52edb387792c..5843b28ab5e2 100644 --- a/user_guide_src/source/concepts/services/008.php +++ b/user_guide_src/source/concepts/services/008.php @@ -10,5 +10,6 @@ public static function renderer($viewPath = APPPATH . 'views/') { return new \CodeIgniter\View\View($viewPath); } + // ... } diff --git a/user_guide_src/source/concepts/services/010.php b/user_guide_src/source/concepts/services/010.php index fd5d3f6c4e35..b74d9c470888 100644 --- a/user_guide_src/source/concepts/services/010.php +++ b/user_guide_src/source/concepts/services/010.php @@ -14,5 +14,6 @@ public static function routes($getShared = false) return static::getSharedInstance('routes'); } + // ... } diff --git a/user_guide_src/source/database/configuration/006.php b/user_guide_src/source/database/configuration/006.php index afc24022c199..4381a0a71fff 100644 --- a/user_guide_src/source/database/configuration/006.php +++ b/user_guide_src/source/database/configuration/006.php @@ -24,5 +24,6 @@ class Database extends Config 'strictOn' => false, 'failover' => [], ]; + // ... } diff --git a/user_guide_src/source/database/helpers/001.php b/user_guide_src/source/database/helpers/001.php index f5dea164c946..e36a3989a74f 100644 --- a/user_guide_src/source/database/helpers/001.php +++ b/user_guide_src/source/database/helpers/001.php @@ -1,5 +1,4 @@ table('my_table')->countAll(); - // Produces an integer, like 25 diff --git a/user_guide_src/source/database/helpers/002.php b/user_guide_src/source/database/helpers/002.php index d43cf8dbc3bc..bca6cfe1b5a8 100644 --- a/user_guide_src/source/database/helpers/002.php +++ b/user_guide_src/source/database/helpers/002.php @@ -1,5 +1,4 @@ table('my_table')->like('title', 'match')->countAllResults(); - // Produces an integer, like 5 diff --git a/user_guide_src/source/database/query_builder/005.php b/user_guide_src/source/database/query_builder/005.php index 38bc63a577e7..7a33f8be2d82 100644 --- a/user_guide_src/source/database/query_builder/005.php +++ b/user_guide_src/source/database/query_builder/005.php @@ -2,5 +2,4 @@ $sql = $builder->getCompiledSelect(); echo $sql; - // Prints string: SELECT * FROM mytable diff --git a/user_guide_src/source/database/query_builder/008.php b/user_guide_src/source/database/query_builder/008.php index e2b594d51865..f9ebd8650717 100644 --- a/user_guide_src/source/database/query_builder/008.php +++ b/user_guide_src/source/database/query_builder/008.php @@ -2,5 +2,4 @@ $builder->select('title, content, date'); $query = $builder->get(); - // Executes: SELECT title, content, date FROM mytable diff --git a/user_guide_src/source/database/query_builder/016.php b/user_guide_src/source/database/query_builder/016.php index e505681ddc57..f00c2dbe47c2 100644 --- a/user_guide_src/source/database/query_builder/016.php +++ b/user_guide_src/source/database/query_builder/016.php @@ -3,5 +3,4 @@ $subquery = $db->table('users'); $builder = $db->table('jobs')->fromSubquery($subquery, 'alias'); $query = $builder->get(); - // Produces: SELECT * FROM `jobs`, (SELECT * FROM `users`) AS `alias` diff --git a/user_guide_src/source/database/query_builder/017.php b/user_guide_src/source/database/query_builder/017.php index 938edc98c72c..965ae956a6af 100644 --- a/user_guide_src/source/database/query_builder/017.php +++ b/user_guide_src/source/database/query_builder/017.php @@ -3,5 +3,4 @@ $subquery = $db->table('users')->select('id, name'); $builder = $db->newQuery()->fromSubquery($subquery, 't'); $query = $builder->get(); - // Produces: SELECT * FROM (SELECT `id`, `name` FROM users) AS `t` diff --git a/user_guide_src/source/database/query_builder/027.php b/user_guide_src/source/database/query_builder/027.php index 7583487da1a2..043b7d9e451b 100644 --- a/user_guide_src/source/database/query_builder/027.php +++ b/user_guide_src/source/database/query_builder/027.php @@ -1,11 +1,9 @@ where('advance_amount <', function (BaseBuilder $builder) { return $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); }); - // Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) // With builder directly diff --git a/user_guide_src/source/database/query_builder/032.php b/user_guide_src/source/database/query_builder/032.php index 07aee709b79c..7a7a44182396 100644 --- a/user_guide_src/source/database/query_builder/032.php +++ b/user_guide_src/source/database/query_builder/032.php @@ -4,7 +4,6 @@ $builder->orWhereIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - // Produces: OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/034.php b/user_guide_src/source/database/query_builder/034.php index e5e366acb069..2316388e16b6 100644 --- a/user_guide_src/source/database/query_builder/034.php +++ b/user_guide_src/source/database/query_builder/034.php @@ -4,7 +4,6 @@ $builder->whereNotIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - // Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/036.php b/user_guide_src/source/database/query_builder/036.php index 8b3087cac1c1..d50bcc113853 100644 --- a/user_guide_src/source/database/query_builder/036.php +++ b/user_guide_src/source/database/query_builder/036.php @@ -4,7 +4,6 @@ $builder->orWhereNotIn('id', function (BaseBuilder $builder) { return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); }); - // Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/053.php b/user_guide_src/source/database/query_builder/053.php index 3bbf43645915..baa936c5df82 100644 --- a/user_guide_src/source/database/query_builder/053.php +++ b/user_guide_src/source/database/query_builder/053.php @@ -4,7 +4,6 @@ $builder->orHavingIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); - // Produces: OR "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/055.php b/user_guide_src/source/database/query_builder/055.php index 2c032a5b1cec..986b3ff24cb9 100644 --- a/user_guide_src/source/database/query_builder/055.php +++ b/user_guide_src/source/database/query_builder/055.php @@ -4,7 +4,6 @@ $builder->havingNotIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); - // Produces: HAVING "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/057.php b/user_guide_src/source/database/query_builder/057.php index 7960a3382f79..85cab6e2eba8 100644 --- a/user_guide_src/source/database/query_builder/057.php +++ b/user_guide_src/source/database/query_builder/057.php @@ -4,7 +4,6 @@ $builder->orHavingNotIn('id', function (BaseBuilder $builder) { return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); }); - // Produces: OR "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/078.php b/user_guide_src/source/database/query_builder/078.php index e4ddf03e6732..ed0e4cb3f7a1 100644 --- a/user_guide_src/source/database/query_builder/078.php +++ b/user_guide_src/source/database/query_builder/078.php @@ -8,5 +8,4 @@ $sql = $builder->set($data)->getCompiledInsert(); echo $sql; - // Produces string: INSERT INTO mytable (`title`, `name`, `date`) VALUES ('My title', 'My name', 'My date') diff --git a/user_guide_src/source/database/query_builder/079.php b/user_guide_src/source/database/query_builder/079.php index 4e095f9e0c72..1807be1d706a 100644 --- a/user_guide_src/source/database/query_builder/079.php +++ b/user_guide_src/source/database/query_builder/079.php @@ -1,9 +1,7 @@ set('title', 'My Title')->getCompiledInsert(false); - // Produces string: INSERT INTO mytable (`title`) VALUES ('My Title') echo $builder->set('content', 'My Content')->getCompiledInsert(); - // Produces string: INSERT INTO mytable (`title`, `content`) VALUES ('My Title', 'My Content') diff --git a/user_guide_src/source/database/query_builder/081.php b/user_guide_src/source/database/query_builder/081.php index bb263a3b4eba..d4bd972f5830 100644 --- a/user_guide_src/source/database/query_builder/081.php +++ b/user_guide_src/source/database/query_builder/081.php @@ -7,5 +7,4 @@ ]; $builder->replace($data); - // Executes: REPLACE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') diff --git a/user_guide_src/source/database/query_builder/098.php b/user_guide_src/source/database/query_builder/098.php index e9be12b58273..a6fb3cc4beed 100644 --- a/user_guide_src/source/database/query_builder/098.php +++ b/user_guide_src/source/database/query_builder/098.php @@ -3,5 +3,4 @@ $subquery = $db->table('countries')->select('name')->where('id', 1); $builder = $db->table('users')->select('name')->selectSubquery($subquery, 'country'); $query = $builder->get(); - // Produces: SELECT `name`, (SELECT `name` FROM `countries` WHERE `id` = 1) AS `country` FROM `users` diff --git a/user_guide_src/source/extending/core_classes/002.php b/user_guide_src/source/extending/core_classes/002.php index 1d0de27ee238..68d22ff508b8 100644 --- a/user_guide_src/source/extending/core_classes/002.php +++ b/user_guide_src/source/extending/core_classes/002.php @@ -14,5 +14,6 @@ public static function routes(bool $getShared = true) return new \App\Libraries\RouteCollection(static::locator(), config('Modules')); } + // ... } diff --git a/user_guide_src/source/general/configuration/008.php b/user_guide_src/source/general/configuration/008.php index 86749331c9c5..752084b65072 100644 --- a/user_guide_src/source/general/configuration/008.php +++ b/user_guide_src/source/general/configuration/008.php @@ -7,5 +7,6 @@ class MyConfig extends BaseConfig public static $registrars = [ SupportingPackageRegistrar::class, ]; + // ... } diff --git a/user_guide_src/source/general/logging/002.php b/user_guide_src/source/general/logging/002.php index 1c27f2410126..7a1e4e97fde5 100644 --- a/user_guide_src/source/general/logging/002.php +++ b/user_guide_src/source/general/logging/002.php @@ -7,5 +7,6 @@ class Logger extends BaseConfig { public $threshold = 5; + // ... } diff --git a/user_guide_src/source/general/logging/003.php b/user_guide_src/source/general/logging/003.php index 170b74457967..926e04a017de 100644 --- a/user_guide_src/source/general/logging/003.php +++ b/user_guide_src/source/general/logging/003.php @@ -8,5 +8,6 @@ class Logger extends BaseConfig { // Log only debug and info type messages public $threshold = [5, 8]; + // ... } diff --git a/user_guide_src/source/general/logging/004.php b/user_guide_src/source/general/logging/004.php index ff5f9511d81f..7691936b3165 100644 --- a/user_guide_src/source/general/logging/004.php +++ b/user_guide_src/source/general/logging/004.php @@ -12,5 +12,6 @@ class Logger extends BaseConfig 'handles' => ['critical', 'alert', 'emergency', 'debug', 'error', 'info', 'notice', 'warning'], ], ]; + // ... } diff --git a/user_guide_src/source/general/managing_apps/001.php b/user_guide_src/source/general/managing_apps/001.php index 2d0690cabc41..c116317678be 100644 --- a/user_guide_src/source/general/managing_apps/001.php +++ b/user_guide_src/source/general/managing_apps/001.php @@ -5,5 +5,6 @@ class Paths { public $appDirectory = '/path/to/your/app'; + // ... } diff --git a/user_guide_src/source/incoming/filters/003.php b/user_guide_src/source/incoming/filters/003.php index 060f5957b5cc..2e7770e88ddd 100644 --- a/user_guide_src/source/incoming/filters/003.php +++ b/user_guide_src/source/incoming/filters/003.php @@ -9,5 +9,6 @@ class Filters extends BaseConfig public $aliases = [ 'csrf' => \CodeIgniter\Filters\CSRF::class, ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/004.php b/user_guide_src/source/incoming/filters/004.php index d39de5a0bee8..c645d9f8191d 100644 --- a/user_guide_src/source/incoming/filters/004.php +++ b/user_guide_src/source/incoming/filters/004.php @@ -12,5 +12,6 @@ class Filters extends BaseConfig \App\Filters\ApiAuth::class, ], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/005.php b/user_guide_src/source/incoming/filters/005.php index 55b7d1fa522b..226db2389c58 100644 --- a/user_guide_src/source/incoming/filters/005.php +++ b/user_guide_src/source/incoming/filters/005.php @@ -12,5 +12,6 @@ class Filters extends BaseConfig ], 'after' => [], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/006.php b/user_guide_src/source/incoming/filters/006.php index ed7ce0a8a120..bfddf66c3c4e 100644 --- a/user_guide_src/source/incoming/filters/006.php +++ b/user_guide_src/source/incoming/filters/006.php @@ -12,5 +12,6 @@ class Filters extends BaseConfig ], 'after' => [], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/007.php b/user_guide_src/source/incoming/filters/007.php index fa79b5bbb7c8..d7f21efa1344 100644 --- a/user_guide_src/source/incoming/filters/007.php +++ b/user_guide_src/source/incoming/filters/007.php @@ -12,5 +12,6 @@ class Filters extends BaseConfig ], 'after' => [], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/008.php b/user_guide_src/source/incoming/filters/008.php index a37967a538c0..1d99d0226a79 100644 --- a/user_guide_src/source/incoming/filters/008.php +++ b/user_guide_src/source/incoming/filters/008.php @@ -10,5 +10,6 @@ class Filters extends BaseConfig 'post' => ['foo', 'bar'], 'get' => ['baz'], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/009.php b/user_guide_src/source/incoming/filters/009.php index bfc7d6176b77..162af6dcbaec 100644 --- a/user_guide_src/source/incoming/filters/009.php +++ b/user_guide_src/source/incoming/filters/009.php @@ -10,5 +10,6 @@ class Filters extends BaseConfig 'foo' => ['before' => ['admin/*'], 'after' => ['users/*']], 'bar' => ['before' => ['api/*', 'admin/*']], ]; + // ... } diff --git a/user_guide_src/source/incoming/filters/011.php b/user_guide_src/source/incoming/filters/011.php index 8b6e24c5fe91..fa12db31a9e7 100644 --- a/user_guide_src/source/incoming/filters/011.php +++ b/user_guide_src/source/incoming/filters/011.php @@ -10,5 +10,6 @@ class Filters extends BaseConfig // ... 'secureheaders' => \App\Filters\SecureHeaders::class, ]; + // ... } diff --git a/user_guide_src/source/libraries/caching/013.php b/user_guide_src/source/libraries/caching/013.php index 3dd8ff740944..84287d5e7bcb 100644 --- a/user_guide_src/source/libraries/caching/013.php +++ b/user_guide_src/source/libraries/caching/013.php @@ -7,11 +7,13 @@ class Cache extends BaseConfig { // ... + public $memcached = [ 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 1, 'raw' => false, ]; + // ... } diff --git a/user_guide_src/source/libraries/caching/014.php b/user_guide_src/source/libraries/caching/014.php index cfb6eeb6698f..6b0012696bf3 100644 --- a/user_guide_src/source/libraries/caching/014.php +++ b/user_guide_src/source/libraries/caching/014.php @@ -15,5 +15,6 @@ class Cache extends BaseConfig 'timeout' => 0, 'database' => 0, ]; + // ... } diff --git a/user_guide_src/source/libraries/curlrequest/001.php b/user_guide_src/source/libraries/curlrequest/001.php index 35486f4e7971..e89e0692462f 100644 --- a/user_guide_src/source/libraries/curlrequest/001.php +++ b/user_guide_src/source/libraries/curlrequest/001.php @@ -7,5 +7,6 @@ class CURLRequest extends BaseConfig { public $shareOptions = false; + // ... } diff --git a/user_guide_src/source/libraries/encryption/008.php b/user_guide_src/source/libraries/encryption/008.php index 506a5d594c4e..0fe44575e8db 100644 --- a/user_guide_src/source/libraries/encryption/008.php +++ b/user_guide_src/source/libraries/encryption/008.php @@ -8,7 +8,6 @@ class Encryption extends BaseConfig { // In Encryption, you may use public $key = 'hex2bin:'; - // or public $key = 'base64:'; // ... diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php index 8463a919d54a..f0dbf7e64d57 100644 --- a/user_guide_src/source/libraries/honeypot/001.php +++ b/user_guide_src/source/libraries/honeypot/001.php @@ -16,5 +16,6 @@ class Filters extends BaseConfig 'honeypot', ], ]; + // ... } diff --git a/user_guide_src/source/libraries/pagination/010.php b/user_guide_src/source/libraries/pagination/010.php index d168163446ee..86947793c132 100644 --- a/user_guide_src/source/libraries/pagination/010.php +++ b/user_guide_src/source/libraries/pagination/010.php @@ -10,5 +10,6 @@ class Pager extends BaseConfig 'default_full' => 'CodeIgniter\Pager\Views\default_full', 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', ]; + // ... } diff --git a/user_guide_src/source/libraries/pagination/011.php b/user_guide_src/source/libraries/pagination/011.php index 4302997f8bff..6c15797754e0 100644 --- a/user_guide_src/source/libraries/pagination/011.php +++ b/user_guide_src/source/libraries/pagination/011.php @@ -11,5 +11,6 @@ class Pager extends BaseConfig 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 'front_full' => 'App\Views\Pagers\foundation_full', ]; + // ... } diff --git a/user_guide_src/source/libraries/security/002.php b/user_guide_src/source/libraries/security/002.php index 39df6fa8d292..d7af0b687f0b 100644 --- a/user_guide_src/source/libraries/security/002.php +++ b/user_guide_src/source/libraries/security/002.php @@ -7,5 +7,6 @@ class Security extends BaseConfig { public $csrfProtection = 'session'; + // ... } diff --git a/user_guide_src/source/libraries/security/003.php b/user_guide_src/source/libraries/security/003.php index 7d8b3241c285..f092196845a4 100644 --- a/user_guide_src/source/libraries/security/003.php +++ b/user_guide_src/source/libraries/security/003.php @@ -7,5 +7,6 @@ class Security extends BaseConfig { public $tokenRandomize = true; + // ... } diff --git a/user_guide_src/source/libraries/security/004.php b/user_guide_src/source/libraries/security/004.php index 7187a1b523c5..ff5c6cca8b06 100644 --- a/user_guide_src/source/libraries/security/004.php +++ b/user_guide_src/source/libraries/security/004.php @@ -7,5 +7,6 @@ class Security extends BaseConfig { public $regenerate = true; + // ... } diff --git a/user_guide_src/source/libraries/security/006.php b/user_guide_src/source/libraries/security/006.php index cc3ef9d162c6..9105bc43dd80 100644 --- a/user_guide_src/source/libraries/security/006.php +++ b/user_guide_src/source/libraries/security/006.php @@ -12,5 +12,6 @@ class Filters extends BaseConfig 'csrf', ], ]; + // ... } diff --git a/user_guide_src/source/libraries/security/007.php b/user_guide_src/source/libraries/security/007.php index 0b099addb52c..437bc7bfbead 100644 --- a/user_guide_src/source/libraries/security/007.php +++ b/user_guide_src/source/libraries/security/007.php @@ -11,5 +11,6 @@ class Filters extends BaseConfig 'csrf' => ['except' => ['api/record/save']], ], ]; + // ... } diff --git a/user_guide_src/source/libraries/security/008.php b/user_guide_src/source/libraries/security/008.php index 370bd2bcedad..8a4a6ef4d430 100644 --- a/user_guide_src/source/libraries/security/008.php +++ b/user_guide_src/source/libraries/security/008.php @@ -11,5 +11,6 @@ class Filters extends BaseConfig 'csrf' => ['except' => ['api/record/[0-9]+']], ], ]; + // ... } diff --git a/user_guide_src/source/libraries/security/009.php b/user_guide_src/source/libraries/security/009.php index d90632e53f1c..bd6bc93cfeb6 100644 --- a/user_guide_src/source/libraries/security/009.php +++ b/user_guide_src/source/libraries/security/009.php @@ -10,5 +10,6 @@ class Filters extends BaseConfig 'get' => ['csrf'], 'post' => ['csrf'], ]; + // ... } diff --git a/user_guide_src/source/libraries/sessions/010.php b/user_guide_src/source/libraries/sessions/010.php index fd3471eba73e..4bbbfb2646db 100644 --- a/user_guide_src/source/libraries/sessions/010.php +++ b/user_guide_src/source/libraries/sessions/010.php @@ -1,7 +1,5 @@ get(); diff --git a/user_guide_src/source/libraries/sessions/017.php b/user_guide_src/source/libraries/sessions/017.php index 66a5f8662b39..2b00df65a034 100644 --- a/user_guide_src/source/libraries/sessions/017.php +++ b/user_guide_src/source/libraries/sessions/017.php @@ -1,9 +1,7 @@ destroy(); diff --git a/user_guide_src/source/libraries/sessions/044.php b/user_guide_src/source/libraries/sessions/044.php index 2cc31e9035db..e5fab8602236 100644 --- a/user_guide_src/source/libraries/sessions/044.php +++ b/user_guide_src/source/libraries/sessions/044.php @@ -9,5 +9,6 @@ class App extends BaseConfig // localhost will be given higher priority (5) here, // compared to 192.0.2.1 with a weight of 1. public $sessionSavePath = 'localhost:11211:5,192.0.2.1:11211:1'; + // ... } diff --git a/user_guide_src/source/libraries/throttler/003.php b/user_guide_src/source/libraries/throttler/003.php index ae13441bb8ad..b365df88fa53 100644 --- a/user_guide_src/source/libraries/throttler/003.php +++ b/user_guide_src/source/libraries/throttler/003.php @@ -10,5 +10,6 @@ class Filters extends BaseConfig // ... 'throttle' => \App\Filters\Throttle::class, ]; + // ... } diff --git a/user_guide_src/source/libraries/throttler/004.php b/user_guide_src/source/libraries/throttler/004.php index 077cb46a66dc..ab4d91257f8f 100644 --- a/user_guide_src/source/libraries/throttler/004.php +++ b/user_guide_src/source/libraries/throttler/004.php @@ -9,5 +9,6 @@ class Filters extends BaseConfig public $methods = [ 'post' => ['throttle'], ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/003.php b/user_guide_src/source/libraries/validation/003.php index fbcbb7690260..d27270810429 100644 --- a/user_guide_src/source/libraries/validation/003.php +++ b/user_guide_src/source/libraries/validation/003.php @@ -10,5 +10,6 @@ class Validation \CodeIgniter\Validation\StrictRules\FormatRules::class, \CodeIgniter\Validation\StrictRules\Rules::class, ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/013.php b/user_guide_src/source/libraries/validation/013.php index 4e2982d7564f..671b5386fe98 100644 --- a/user_guide_src/source/libraries/validation/013.php +++ b/user_guide_src/source/libraries/validation/013.php @@ -10,5 +10,6 @@ class Validation 'pass_confirm' => 'required|matches[password]', 'email' => 'required|valid_email', ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/015.php b/user_guide_src/source/libraries/validation/015.php index 46ef2c4431a1..5815abfaccf4 100644 --- a/user_guide_src/source/libraries/validation/015.php +++ b/user_guide_src/source/libraries/validation/015.php @@ -10,6 +10,7 @@ class Validation 'pass_confirm' => 'required|matches[password]', 'email' => 'required|valid_email', ]; + public $signup_errors = [ 'username' => [ 'required' => 'You must choose a username.', @@ -18,5 +19,6 @@ class Validation 'valid_email' => 'Please check the Email field. It does not appear to be valid.', ], ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php index 7ed5d307b0e2..acec3cfc6ba2 100644 --- a/user_guide_src/source/libraries/validation/031.php +++ b/user_guide_src/source/libraries/validation/031.php @@ -9,5 +9,6 @@ class Validation 'single' => 'CodeIgniter\Validation\Views\single', 'my_list' => '_errors_list', ]; + // ... } diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php index 5f16ca283c1e..890b4c453fc0 100644 --- a/user_guide_src/source/libraries/validation/032.php +++ b/user_guide_src/source/libraries/validation/032.php @@ -15,5 +15,6 @@ class Validation FileRules::class, CreditCardRules::class, ]; + // ... } diff --git a/user_guide_src/source/outgoing/api_responses/003.php b/user_guide_src/source/outgoing/api_responses/003.php index eebb83c43fc1..6e99762ccaed 100644 --- a/user_guide_src/source/outgoing/api_responses/003.php +++ b/user_guide_src/source/outgoing/api_responses/003.php @@ -10,5 +10,6 @@ class Format extends BaseConfig 'application/json', 'application/xml', ]; + // ... } diff --git a/user_guide_src/source/outgoing/api_responses/004.php b/user_guide_src/source/outgoing/api_responses/004.php index 57532911f13b..713d1b314dce 100644 --- a/user_guide_src/source/outgoing/api_responses/004.php +++ b/user_guide_src/source/outgoing/api_responses/004.php @@ -10,5 +10,6 @@ class Format extends BaseConfig 'application/json' => \CodeIgniter\Format\JSONFormatter::class, 'application/xml' => \CodeIgniter\Format\XMLFormatter::class, ]; + // ... } diff --git a/user_guide_src/source/outgoing/localization/001.php b/user_guide_src/source/outgoing/localization/001.php index ebc1e57ef45c..6978e6fb35e7 100644 --- a/user_guide_src/source/outgoing/localization/001.php +++ b/user_guide_src/source/outgoing/localization/001.php @@ -7,5 +7,6 @@ class App extends BaseConfig { public $defaultLocale = 'en'; + // ... } diff --git a/user_guide_src/source/outgoing/localization/002.php b/user_guide_src/source/outgoing/localization/002.php index 6a0cce0ea027..bb4941fd2c14 100644 --- a/user_guide_src/source/outgoing/localization/002.php +++ b/user_guide_src/source/outgoing/localization/002.php @@ -7,5 +7,6 @@ class App extends BaseConfig { public $negotiateLocale = true; + // ... } diff --git a/user_guide_src/source/outgoing/localization/003.php b/user_guide_src/source/outgoing/localization/003.php index 81aa073152a0..36ccb2344557 100644 --- a/user_guide_src/source/outgoing/localization/003.php +++ b/user_guide_src/source/outgoing/localization/003.php @@ -7,5 +7,6 @@ class App extends BaseConfig { public $supportedLocales = ['en', 'es', 'fr-FR']; + // ... } diff --git a/user_guide_src/source/outgoing/response/011.php b/user_guide_src/source/outgoing/response/011.php index 2ad152a51755..4a21b5c29078 100644 --- a/user_guide_src/source/outgoing/response/011.php +++ b/user_guide_src/source/outgoing/response/011.php @@ -7,5 +7,6 @@ class App extends BaseConfig { public $CSPEnabled = true; + // ... } diff --git a/user_guide_src/source/outgoing/view_decorators/002.php b/user_guide_src/source/outgoing/view_decorators/002.php index 6bd050126f90..ba56ea1e80ad 100644 --- a/user_guide_src/source/outgoing/view_decorators/002.php +++ b/user_guide_src/source/outgoing/view_decorators/002.php @@ -9,5 +9,6 @@ class View extends BaseView public array $decorators = [ 'App\Views\Decorators\MyDecorator', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/005.php b/user_guide_src/source/outgoing/view_parser/005.php index 6681b588d74e..e77c54268648 100644 --- a/user_guide_src/source/outgoing/view_parser/005.php +++ b/user_guide_src/source/outgoing/view_parser/005.php @@ -4,5 +4,4 @@ $data = ['blog_title' => 'My ramblings']; echo $parser->setData($data)->renderString($template); - // Result: My ramblings diff --git a/user_guide_src/source/outgoing/view_parser/012.php b/user_guide_src/source/outgoing/view_parser/012.php index a006a51d5c33..000642837149 100644 --- a/user_guide_src/source/outgoing/view_parser/012.php +++ b/user_guide_src/source/outgoing/view_parser/012.php @@ -10,5 +10,6 @@ class View extends BaseView 'abs' => '\CodeIgniter\View\Filters::abs', 'capitalize' => '\CodeIgniter\View\Filters::capitalize', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/013.php b/user_guide_src/source/outgoing/view_parser/013.php index c45a72b89bde..e5546bdda272 100644 --- a/user_guide_src/source/outgoing/view_parser/013.php +++ b/user_guide_src/source/outgoing/view_parser/013.php @@ -9,5 +9,6 @@ class View extends BaseView public $filters = [ 'str_repeat' => '\str_repeat', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/014.php b/user_guide_src/source/outgoing/view_parser/014.php index 866a547e3b28..5153c4ee6757 100644 --- a/user_guide_src/source/outgoing/view_parser/014.php +++ b/user_guide_src/source/outgoing/view_parser/014.php @@ -9,5 +9,6 @@ class View extends BaseView public $plugins = [ 'foo' => '\Some\Class::methodName', ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/015.php b/user_guide_src/source/outgoing/view_parser/015.php index ecfafffbf97a..e499e9805416 100644 --- a/user_guide_src/source/outgoing/view_parser/015.php +++ b/user_guide_src/source/outgoing/view_parser/015.php @@ -16,5 +16,6 @@ public function __construct() parent::__construct(); } + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/017.php b/user_guide_src/source/outgoing/view_parser/017.php index 1042665a0fcf..d9427bde4bf4 100644 --- a/user_guide_src/source/outgoing/view_parser/017.php +++ b/user_guide_src/source/outgoing/view_parser/017.php @@ -9,6 +9,7 @@ class View extends BaseView public $plugins = [ 'foo' => ['\Some\Class::methodName'], ]; + // ... } diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php index cd9ca09109b9..64101a6a8cfa 100644 --- a/user_guide_src/source/outgoing/view_parser/018.php +++ b/user_guide_src/source/outgoing/view_parser/018.php @@ -8,5 +8,4 @@ ]; echo $parser->setData($data) ->renderString($template); - // Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php index dfce0c26ccb4..2570076b3018 100644 --- a/user_guide_src/source/outgoing/view_parser/019.php +++ b/user_guide_src/source/outgoing/view_parser/019.php @@ -8,5 +8,4 @@ ]; echo $parser->setData($data) ->renderString($template); - // Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php index 371fa9a21f14..a7966a9c2bfd 100644 --- a/user_guide_src/source/outgoing/view_parser/020.php +++ b/user_guide_src/source/outgoing/view_parser/020.php @@ -12,5 +12,4 @@ ]; echo $parser->setData($data) ->renderString($template); - // Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/testing/controllers/012.php b/user_guide_src/source/testing/controllers/012.php index 620bdb363c6e..e94476c6364a 100644 --- a/user_guide_src/source/testing/controllers/012.php +++ b/user_guide_src/source/testing/controllers/012.php @@ -15,5 +15,6 @@ protected function testFilterFailsOnAdminRoute() $this->assertHasFilters('unfiltered/route', 'before'); } + // ... } diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php index dec488ef2e5e..6193eb88bf50 100644 --- a/user_guide_src/source/testing/overview/007.php +++ b/user_guide_src/source/testing/overview/007.php @@ -7,6 +7,7 @@ protected function setUpAuthTrait() $user = $this->createFakeUser(); $this->logInUser($user); } + // ... } diff --git a/user_guide_src/source/tutorial/create_news_items/001.php b/user_guide_src/source/tutorial/create_news_items/001.php index c63e033af0bf..4e6615b6bbda 100644 --- a/user_guide_src/source/tutorial/create_news_items/001.php +++ b/user_guide_src/source/tutorial/create_news_items/001.php @@ -9,5 +9,6 @@ class Filters extends BaseConfig public $methods = [ 'post' => ['csrf'], ]; + // ... } From 2854d99655d74450bb23d66daf78a42e724d36b8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 17:00:23 +0900 Subject: [PATCH 1729/2325] docs: change comment style to `*` each line --- .../source/cli/cli_commands/007.php | 9 +++--- user_guide_src/source/cli/cli_library/007.php | 15 ++++----- user_guide_src/source/cli/cli_library/008.php | 15 ++++----- .../source/database/query_builder/003.php | 6 ++-- .../source/database/query_builder/006.php | 10 +++--- .../source/database/query_builder/018.php | 6 ++-- .../source/database/query_builder/074.php | 6 ++-- .../source/database/query_builder/087.php | 10 +++--- .../source/database/query_builder/088.php | 10 +++--- .../source/database/query_builder/091.php | 22 ++++++------- .../source/database/query_builder/093.php | 8 ++--- .../source/database/query_builder/095.php | 6 ++-- .../source/database/query_builder/097.php | 6 ++-- user_guide_src/source/dbmgmt/forge/004.php | 6 ++-- .../source/helpers/array_helper/011.php | 18 +++++------ .../source/helpers/form_helper/010.php | 10 +++--- .../source/helpers/form_helper/011.php | 10 +++--- .../source/helpers/form_helper/012.php | 6 ++-- .../source/helpers/form_helper/014.php | 6 ++-- .../source/helpers/form_helper/017.php | 6 ++-- .../source/helpers/form_helper/018.php | 32 +++++++++---------- .../source/helpers/text_helper/020.php | 16 +++++----- .../source/incoming/controllers/005.php | 5 ++- .../source/incoming/incomingrequest/010.php | 16 +++++----- .../source/incoming/incomingrequest/013.php | 13 ++++---- .../source/incoming/incomingrequest/015.php | 15 ++++----- .../source/incoming/message/003.php | 27 +++++++--------- .../source/incoming/message/005.php | 7 ++-- .../source/libraries/curlrequest/014.php | 10 +++--- user_guide_src/source/libraries/uri/026.php | 15 ++++----- .../source/libraries/validation/009.php | 30 ++++++++--------- .../source/libraries/validation/011.php | 18 +++++------ .../source/libraries/validation/026.php | 12 +++---- .../source/libraries/validation/028.2.php | 12 +++---- user_guide_src/source/models/entities/021.php | 20 ++++++------ .../source/outgoing/response/021.php | 6 ++-- .../source/outgoing/view_parser/016.php | 6 ++-- .../source/testing/benchmark/004.php | 18 +++++------ .../source/testing/response/030.php | 17 ++++------ .../source/testing/response/032.php | 11 +++---- 40 files changed, 241 insertions(+), 256 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands/007.php b/user_guide_src/source/cli/cli_commands/007.php index 3365e8afdd0e..76150e4d4e5c 100644 --- a/user_guide_src/source/cli/cli_commands/007.php +++ b/user_guide_src/source/cli/cli_commands/007.php @@ -5,9 +5,8 @@ foreach ($this->options as $option => $description) { CLI::write($tab . CLI::color(str_pad($option, $pad), 'green') . $description, 'yellow'); } - /* -Output will be: --n Set migration namespace --r override file -*/ + * Output will be: + * -n Set migration namespace + * -r override file + */ diff --git a/user_guide_src/source/cli/cli_library/007.php b/user_guide_src/source/cli/cli_library/007.php index 6d77ee91e4a0..0c9d257b1ecd 100644 --- a/user_guide_src/source/cli/cli_library/007.php +++ b/user_guide_src/source/cli/cli_library/007.php @@ -1,12 +1,11 @@ 'The plump orange', 'banana' => 'The ripe banana' ]); - /* -These are your choices: - [apple] The red apple - [orange] The plump orange - [banana] The ripe banana - -Which would you like? [apple, orange, banana]: -*/ + * These are your choices: + * [apple] The red apple + * [orange] The plump orange + * [banana] The ripe banana + * + * Which would you like? [apple, orange, banana]: + */ diff --git a/user_guide_src/source/database/query_builder/003.php b/user_guide_src/source/database/query_builder/003.php index b5300a358280..faad112895ba 100644 --- a/user_guide_src/source/database/query_builder/003.php +++ b/user_guide_src/source/database/query_builder/003.php @@ -2,6 +2,6 @@ $query = $builder->get(10, 20); /* -Executes: SELECT * FROM mytable LIMIT 20, 10 -(in MySQL. Other databases have slightly different syntax) -*/ + * Executes: SELECT * FROM mytable LIMIT 20, 10 + * (in MySQL. Other databases have slightly different syntax) + */ diff --git a/user_guide_src/source/database/query_builder/006.php b/user_guide_src/source/database/query_builder/006.php index 2d672d5ce9ce..78a92e7b7b9d 100644 --- a/user_guide_src/source/database/query_builder/006.php +++ b/user_guide_src/source/database/query_builder/006.php @@ -2,11 +2,11 @@ echo $builder->limit(10,20)->getCompiledSelect(false); /* -Prints string: SELECT * FROM mytable LIMIT 20, 10 -(in MySQL. Other databases have slightly different syntax) -*/ + * Prints string: SELECT * FROM mytable LIMIT 20, 10 + * (in MySQL. Other databases have slightly different syntax) + */ echo $builder->select('title, content, date')->getCompiledSelect(); /* -Prints string: SELECT title, content, date FROM mytable LIMIT 20, 10 -*/ + * Prints string: SELECT title, content, date FROM mytable LIMIT 20, 10 + */ diff --git a/user_guide_src/source/database/query_builder/018.php b/user_guide_src/source/database/query_builder/018.php index 17465bd1cb43..159f88e4a984 100644 --- a/user_guide_src/source/database/query_builder/018.php +++ b/user_guide_src/source/database/query_builder/018.php @@ -5,6 +5,6 @@ $builder->join('comments', 'comments.id = blogs.id'); $query = $builder->get(); /* -Produces: -SELECT * FROM blogs JOIN comments ON comments.id = blogs.id -*/ + * Produces: + * SELECT * FROM blogs JOIN comments ON comments.id = blogs.id + */ diff --git a/user_guide_src/source/database/query_builder/074.php b/user_guide_src/source/database/query_builder/074.php index 68fbcbb0bf60..d858451993a2 100644 --- a/user_guide_src/source/database/query_builder/074.php +++ b/user_guide_src/source/database/query_builder/074.php @@ -11,6 +11,6 @@ ->where('d', 'd') ->get(); /* -Generates: -SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' -*/ + * Generates: + * SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' + */ diff --git a/user_guide_src/source/database/query_builder/087.php b/user_guide_src/source/database/query_builder/087.php index 3032402a7c32..7869b4b4d966 100644 --- a/user_guide_src/source/database/query_builder/087.php +++ b/user_guide_src/source/database/query_builder/087.php @@ -9,8 +9,8 @@ $builder->where('id', $id); $builder->update($data); /* -Produces: -UPDATE mytable -SET title = '{$title}', name = '{$name}', date = '{$date}' -WHERE id = $id -*/ + * Produces: + * UPDATE mytable + * SET title = '{$title}', name = '{$name}', date = '{$date}' + * WHERE id = $id + */ diff --git a/user_guide_src/source/database/query_builder/088.php b/user_guide_src/source/database/query_builder/088.php index 37afb6ce2b46..ce38024e558d 100644 --- a/user_guide_src/source/database/query_builder/088.php +++ b/user_guide_src/source/database/query_builder/088.php @@ -11,8 +11,8 @@ class Myclass $builder->where('id', $id); $builder->update($object); /* -Produces: -UPDATE `mytable` -SET `title` = '{$title}', `name` = '{$name}', `date` = '{$date}' -WHERE id = `$id` -*/ + * Produces: + * UPDATE `mytable` + * SET `title` = '{$title}', `name` = '{$name}', `date` = '{$date}' + * WHERE id = `$id` + */ diff --git a/user_guide_src/source/database/query_builder/091.php b/user_guide_src/source/database/query_builder/091.php index a3943d41cfb9..56f04036cd6f 100644 --- a/user_guide_src/source/database/query_builder/091.php +++ b/user_guide_src/source/database/query_builder/091.php @@ -15,14 +15,14 @@ $builder->updateBatch($data, 'title'); /* -Produces: -UPDATE `mytable` SET `name` = CASE -WHEN `title` = 'My title' THEN 'My Name 2' -WHEN `title` = 'Another title' THEN 'Another Name 2' -ELSE `name` END, -`date` = CASE -WHEN `title` = 'My title' THEN 'My date 2' -WHEN `title` = 'Another title' THEN 'Another date 2' -ELSE `date` END -WHERE `title` IN ('My title','Another title') -*/ + * Produces: + * UPDATE `mytable` SET `name` = CASE + * WHEN `title` = 'My title' THEN 'My Name 2' + * WHEN `title` = 'Another title' THEN 'Another Name 2' + * ELSE `name` END, + * `date` = CASE + * WHEN `title` = 'My title' THEN 'My date 2' + * WHEN `title` = 'Another title' THEN 'Another date 2' + * ELSE `date` END + * WHERE `title` IN ('My title','Another title') + */ diff --git a/user_guide_src/source/database/query_builder/093.php b/user_guide_src/source/database/query_builder/093.php index 70e9ed3b7f69..f1ba27e29ef2 100644 --- a/user_guide_src/source/database/query_builder/093.php +++ b/user_guide_src/source/database/query_builder/093.php @@ -3,7 +3,7 @@ $builder->where('id', $id); $builder->delete(); /* -Produces: -DELETE FROM mytable -WHERE id = $id -*/ + * Produces: + * DELETE FROM mytable + * WHERE id = $id + */ diff --git a/user_guide_src/source/database/query_builder/095.php b/user_guide_src/source/database/query_builder/095.php index c2afc9fe3c2a..a6c0ab4fc069 100644 --- a/user_guide_src/source/database/query_builder/095.php +++ b/user_guide_src/source/database/query_builder/095.php @@ -2,6 +2,6 @@ $builder->truncate(); /* -Produce: -TRUNCATE mytable -*/ + * Produce: + * TRUNCATE mytable + */ diff --git a/user_guide_src/source/database/query_builder/097.php b/user_guide_src/source/database/query_builder/097.php index ec48b920e406..30c4d0c4526a 100644 --- a/user_guide_src/source/database/query_builder/097.php +++ b/user_guide_src/source/database/query_builder/097.php @@ -12,6 +12,6 @@ $data = $builder->get()->getResultArray(); /* -Would execute and return an array of results of the following query: -SELECT field1, field1 from mytable where field3 = 5; -*/ + * Would execute and return an array of results of the following query: + * SELECT field1, field1 from mytable where field3 = 5; + */ diff --git a/user_guide_src/source/dbmgmt/forge/004.php b/user_guide_src/source/dbmgmt/forge/004.php index d793fd8b82d8..6c44a8e553a0 100644 --- a/user_guide_src/source/dbmgmt/forge/004.php +++ b/user_guide_src/source/dbmgmt/forge/004.php @@ -2,6 +2,6 @@ $forge->createDatabase('my_db', true); /* -gives CREATE DATABASE IF NOT EXISTS `my_db` -or will check if a database exists -*/ + * gives CREATE DATABASE IF NOT EXISTS `my_db` + * or will check if a database exists + */ diff --git a/user_guide_src/source/helpers/array_helper/011.php b/user_guide_src/source/helpers/array_helper/011.php index 31ee64387979..c80dc01e0caa 100644 --- a/user_guide_src/source/helpers/array_helper/011.php +++ b/user_guide_src/source/helpers/array_helper/011.php @@ -3,12 +3,12 @@ // using the same data from above $flattened = array_flatten_with_dots($arrayToFlatten, 'foo_'); /* -$flattened is now: -[ - 'foo_personal.first_name' => 'john', - 'foo_personal.last_name' => 'smith', - 'foo_personal.age' => '26', - 'foo_personal.address' => 'US', - 'foo_other_details' => 'marines officer', -] -*/ + * $flattened is now: + * [ + * 'foo_personal.first_name' => 'john', + * 'foo_personal.last_name' => 'smith', + * 'foo_personal.age' => '26', + * 'foo_personal.address' => 'US', + * 'foo_other_details' => 'marines officer', + * ] + */ diff --git a/user_guide_src/source/helpers/form_helper/010.php b/user_guide_src/source/helpers/form_helper/010.php index 401a94c685b1..4edb9a0922c6 100644 --- a/user_guide_src/source/helpers/form_helper/010.php +++ b/user_guide_src/source/helpers/form_helper/010.php @@ -8,8 +8,8 @@ echo form_hidden($data); /* -Would produce: - - - -*/ + * Would produce: + * + * + * + */ diff --git a/user_guide_src/source/helpers/form_helper/011.php b/user_guide_src/source/helpers/form_helper/011.php index 6e28c61e8352..472793162640 100644 --- a/user_guide_src/source/helpers/form_helper/011.php +++ b/user_guide_src/source/helpers/form_helper/011.php @@ -8,8 +8,8 @@ echo form_hidden('my_array', $data); /* -Would produce: - - - -*/ + * Would produce: + * + * + * + */ diff --git a/user_guide_src/source/helpers/form_helper/012.php b/user_guide_src/source/helpers/form_helper/012.php index 4b232ba110f8..2d781ad3effd 100644 --- a/user_guide_src/source/helpers/form_helper/012.php +++ b/user_guide_src/source/helpers/form_helper/012.php @@ -10,6 +10,6 @@ echo form_input($data); /* -Would produce: - -*/ + * Would produce: + * + */ diff --git a/user_guide_src/source/helpers/form_helper/014.php b/user_guide_src/source/helpers/form_helper/014.php index cf8a20dbadff..d194b318d2dd 100644 --- a/user_guide_src/source/helpers/form_helper/014.php +++ b/user_guide_src/source/helpers/form_helper/014.php @@ -11,6 +11,6 @@ echo form_input($data); /* -Would produce: - -*/ + * Would produce: + * + */ diff --git a/user_guide_src/source/helpers/form_helper/017.php b/user_guide_src/source/helpers/form_helper/017.php index 99106e9b4fa8..fb73d427ba63 100644 --- a/user_guide_src/source/helpers/form_helper/017.php +++ b/user_guide_src/source/helpers/form_helper/017.php @@ -2,6 +2,6 @@ echo form_input('email', 'joe@example.com', ['placeholder' => 'Email Address...'], 'email'); /* -Would produce: - -*/ + * Would produce: + * + */ diff --git a/user_guide_src/source/helpers/form_helper/018.php b/user_guide_src/source/helpers/form_helper/018.php index 6e521ed04985..9177e4d3435d 100644 --- a/user_guide_src/source/helpers/form_helper/018.php +++ b/user_guide_src/source/helpers/form_helper/018.php @@ -10,22 +10,22 @@ $shirts_on_sale = ['small', 'large']; echo form_dropdown('shirts', $options, 'large'); /* -Would produce: - -*/ + * Would produce: + * + */ echo form_dropdown('shirts', $options, $shirts_on_sale); /* -Would produce: - -*/ + * Would produce: + * + */ diff --git a/user_guide_src/source/helpers/text_helper/020.php b/user_guide_src/source/helpers/text_helper/020.php index 4bd123f5ae8a..2a4f595f3655 100644 --- a/user_guide_src/source/helpers/text_helper/020.php +++ b/user_guide_src/source/helpers/text_helper/020.php @@ -3,11 +3,11 @@ $string = "Here is a simple string of text that will help us demonstrate this function."; echo word_wrap($string, 25); /* -Would produce: -Here is a simple string -of text that will help us -demonstrate this -function. - -Excessively long words will be split, but URLs will not be. -*/ + * Would produce: + * Here is a simple string + * of text that will help us + * demonstrate this + * function. + * + * Excessively long words will be split, but URLs will not be. + */ diff --git a/user_guide_src/source/incoming/controllers/005.php b/user_guide_src/source/incoming/controllers/005.php index 84b910be2507..efaecbb8f400 100644 --- a/user_guide_src/source/incoming/controllers/005.php +++ b/user_guide_src/source/incoming/controllers/005.php @@ -1,9 +1,8 @@ (\)*\ + * Folder and file structure: + * \(\)*\ */ $routes->get('helloworld', '\App\Controllers\HelloWorld::index'); diff --git a/user_guide_src/source/incoming/incomingrequest/010.php b/user_guide_src/source/incoming/incomingrequest/010.php index a1dc2ccfb9cd..a199c91bffe2 100644 --- a/user_guide_src/source/incoming/incomingrequest/010.php +++ b/user_guide_src/source/incoming/incomingrequest/010.php @@ -1,14 +1,14 @@ getVar('foo'); // $data = "bar" diff --git a/user_guide_src/source/incoming/incomingrequest/013.php b/user_guide_src/source/incoming/incomingrequest/013.php index bdb8b43b5206..483662cbfaf7 100644 --- a/user_guide_src/source/incoming/incomingrequest/013.php +++ b/user_guide_src/source/incoming/incomingrequest/013.php @@ -3,10 +3,9 @@ var_dump($request->getRawInput()); /* - Outputs: - - [ - 'Param1' => 'Value1', - 'Param2' => 'Value2', - ] -*/ + * Outputs: + * [ + * 'Param1' => 'Value1', + * 'Param2' => 'Value2', + * ] + */ diff --git a/user_guide_src/source/incoming/incomingrequest/015.php b/user_guide_src/source/incoming/incomingrequest/015.php index 95d483206211..81043ae80587 100644 --- a/user_guide_src/source/incoming/incomingrequest/015.php +++ b/user_guide_src/source/incoming/incomingrequest/015.php @@ -3,11 +3,10 @@ var_dump($request->headers()); /* - Outputs: - - [ - 'Host' => CodeIgniter\HTTP\Header, - 'Cache-Control' => CodeIgniter\HTTP\Header, - 'Accept' => CodeIgniter\HTTP\Header, - ] -*/ + * Outputs: + * [ + * 'Host' => CodeIgniter\HTTP\Header, + * 'Cache-Control' => CodeIgniter\HTTP\Header, + * 'Accept' => CodeIgniter\HTTP\Header, + * ] + */ diff --git a/user_guide_src/source/incoming/message/003.php b/user_guide_src/source/incoming/message/003.php index 41aa837fb49f..9d51f9a183ab 100644 --- a/user_guide_src/source/incoming/message/003.php +++ b/user_guide_src/source/incoming/message/003.php @@ -1,25 +1,22 @@ header('Accept-Language'); - /* - Outputs something like: - 'Accept-Language: en,en-US' -*/ + * Outputs something like: + * 'Accept-Language: en,en-US' + */ echo $message->header('Accept-Language')->getValue(); - /* - Outputs something like: - [ - 'en', - 'en-US' - ] -*/ + * Outputs something like: + * [ + * 'en', + * 'en-US', + * ] + */ echo $message->header('Accept-Language')->getValueLine(); - /* - Outputs something like: - 'en,en-US' -*/ + * Outputs something like: + * en,en-US' + */ diff --git a/user_guide_src/source/incoming/message/005.php b/user_guide_src/source/incoming/message/005.php index b67851a9258a..5c450073a340 100644 --- a/user_guide_src/source/incoming/message/005.php +++ b/user_guide_src/source/incoming/message/005.php @@ -1,8 +1,7 @@ getHeaderLine('Accept-Language'); - /* - Outputs: - 'en,en-US' -*/ + * Outputs: + * 'en,en-US' + */ diff --git a/user_guide_src/source/libraries/curlrequest/014.php b/user_guide_src/source/libraries/curlrequest/014.php index 2f7e79cc4be7..410ed9980e34 100644 --- a/user_guide_src/source/libraries/curlrequest/014.php +++ b/user_guide_src/source/libraries/curlrequest/014.php @@ -2,8 +2,8 @@ $client->request('GET', 'http://example.com', ['allow_redirects' => true]); /* -Sets the following defaults: -'max' => 5, // Maximum number of redirects to follow before stopping -'strict' => true, // Ensure POST requests stay POST requests through redirects -'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols -*/ + * Sets the following defaults: + * 'max' => 5, // Maximum number of redirects to follow before stopping + * 'strict' => true, // Ensure POST requests stay POST requests through redirects + * 'protocols' => ['http', 'https'] // Restrict redirects to one or more protocols + */ diff --git a/user_guide_src/source/libraries/uri/026.php b/user_guide_src/source/libraries/uri/026.php index 60c076bc13cf..f2d8bb72553f 100644 --- a/user_guide_src/source/libraries/uri/026.php +++ b/user_guide_src/source/libraries/uri/026.php @@ -3,11 +3,10 @@ $segments = $uri->getSegments(); /* - Produces: - - [ - 0 => 'users', - 1 => '15', - 2 => 'profile', - ] -*/ + * Produces: + * [ + * 0 => 'users', + * 1 => '15', + * 2 => 'profile', + * ] + */ diff --git a/user_guide_src/source/libraries/validation/009.php b/user_guide_src/source/libraries/validation/009.php index 6f7ce8b9e992..58f0749a0c5d 100644 --- a/user_guide_src/source/libraries/validation/009.php +++ b/user_guide_src/source/libraries/validation/009.php @@ -1,21 +1,21 @@ [ - 'name' => 'Joe Smith', - 'friends' => [ - [ - 'name' => 'Fred Flinstone', - ], - [ - 'name' => 'Wilma', - ], - ] - ] -] -*/ + * The data to test: + * [ + * 'contacts' => [ + * 'name' => 'Joe Smith', + * 'friends' => [ + * [ + * 'name' => 'Fred Flinstone', + * ], + * [ + * 'name' => 'Wilma', + * ], + * ] + * ] + * ] + */ // Joe Smith $validation->setRules([ diff --git a/user_guide_src/source/libraries/validation/011.php b/user_guide_src/source/libraries/validation/011.php index fa5cad04369c..2754c41ac933 100644 --- a/user_guide_src/source/libraries/validation/011.php +++ b/user_guide_src/source/libraries/validation/011.php @@ -1,15 +1,15 @@ [ - 1, - 2, - 3, - ] -] -*/ + * The data to test: + * [ + * 'user_ids' => [ + * 1, + * 2, + * 3, + * ] + * ] + */ // Rule $validation->setRules([ diff --git a/user_guide_src/source/libraries/validation/026.php b/user_guide_src/source/libraries/validation/026.php index 4c27f4548b0e..4488f2a6be57 100644 --- a/user_guide_src/source/libraries/validation/026.php +++ b/user_guide_src/source/libraries/validation/026.php @@ -2,9 +2,9 @@ $errors = $validation->getErrors(); /* -Produces: -[ - 'field1' => 'error message', - 'field2' => 'error message', -] -*/ + * Produces: + * [ + * 'field1' => 'error message', + * 'field2' => 'error message', + * ] + */ diff --git a/user_guide_src/source/libraries/validation/028.2.php b/user_guide_src/source/libraries/validation/028.2.php index 34a4d7edefe3..5470a1eecea6 100644 --- a/user_guide_src/source/libraries/validation/028.2.php +++ b/user_guide_src/source/libraries/validation/028.2.php @@ -1,12 +1,12 @@ 'Error', - 'foo.baz.bar' => 'Error', -] -*/ + * For errors: + * [ + * 'foo.0.bar' => 'Error', + * 'foo.baz.bar' => 'Error', + * ] + */ // returns true $validation->hasError('foo.*.bar'); diff --git a/user_guide_src/source/models/entities/021.php b/user_guide_src/source/models/entities/021.php index ceb17247a908..1ea3a26de623 100644 --- a/user_guide_src/source/models/entities/021.php +++ b/user_guide_src/source/models/entities/021.php @@ -10,15 +10,15 @@ public static function get($value, array $params = []) { var_dump($params); /* - Output: - array(3) { - [0]=> - string(13) "App\SomeClass" - [1]=> - string(6) "param2" - [2]=> - string(6) "param3" - } - */ + * Output: + * array(3) { + * [0]=> + * string(13) "App\SomeClass" + * [1]=> + * string(6) "param2" + * [2]=> + * string(6) "param3" + * } + */ } } diff --git a/user_guide_src/source/outgoing/response/021.php b/user_guide_src/source/outgoing/response/021.php index 51abaf76bdbd..d5275cfb734e 100644 --- a/user_guide_src/source/outgoing/response/021.php +++ b/user_guide_src/source/outgoing/response/021.php @@ -2,6 +2,6 @@ $response->noCache(); /* -Sets the following header: -Cache-Control: no-store, max-age=0, no-cache -*/ + * Sets the following header: + * Cache-Control: no-store, max-age=0, no-cache + */ diff --git a/user_guide_src/source/outgoing/view_parser/016.php b/user_guide_src/source/outgoing/view_parser/016.php index 0c71e3f88fbb..5120c1eebf27 100644 --- a/user_guide_src/source/outgoing/view_parser/016.php +++ b/user_guide_src/source/outgoing/view_parser/016.php @@ -14,6 +14,6 @@ class View extends BaseView } /* -Tag is replaced by the return value of Some\Class::methodName() static function. -{+ foo +} -*/ + * Tag is replaced by the return value of Some\Class::methodName() static function. + * {+ foo +} + */ diff --git a/user_guide_src/source/testing/benchmark/004.php b/user_guide_src/source/testing/benchmark/004.php index 32dc5df31b1a..8a5c4d248837 100644 --- a/user_guide_src/source/testing/benchmark/004.php +++ b/user_guide_src/source/testing/benchmark/004.php @@ -2,12 +2,12 @@ $timers = $benchmark->getTimers(); /* -Produces: -[ - 'render view' => [ - 'start' => 1234567890, - 'end' => 1345678920, - 'duration' => 15.4315, // number of seconds - ] -] -*/ + * Produces: + * [ + * 'render view' => [ + * 'start' => 1234567890, + * 'end' => 1345678920, + * 'duration' => 15.4315, // number of seconds + * ] + * ] + */ diff --git a/user_guide_src/source/testing/response/030.php b/user_guide_src/source/testing/response/030.php index 060f5c551a87..47e480c6081f 100644 --- a/user_guide_src/source/testing/response/030.php +++ b/user_guide_src/source/testing/response/030.php @@ -1,17 +1,14 @@ 'bar'] -*/ + * Response body is this: + * ['foo' => 'bar'] + */ $json = $result->getJSON(); - /* - $json is this: - - { - "foo": "bar" - } + * $json is this: + * { + * "foo": "bar" + * } `*/ diff --git a/user_guide_src/source/testing/response/032.php b/user_guide_src/source/testing/response/032.php index 6de63a9cfce8..14f13f1942f5 100644 --- a/user_guide_src/source/testing/response/032.php +++ b/user_guide_src/source/testing/response/032.php @@ -1,12 +1,11 @@ ['key-a', 'key-b'], - ] -*/ + * Response body is this: + * [ + * 'config' => ['key-a', 'key-b'], + * ] + */ // Is true $result->assertJSONFragment(['config' => ['key-a']]); From a1e4f09527bb8b484e1a55a3b53e7319bb425316 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 19:11:27 +0900 Subject: [PATCH 1730/2325] docs: fix parent classname --- user_guide_src/source/outgoing/localization/005.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/localization/005.php b/user_guide_src/source/outgoing/localization/005.php index be23e05fac89..fa115d6cf3db 100644 --- a/user_guide_src/source/outgoing/localization/005.php +++ b/user_guide_src/source/outgoing/localization/005.php @@ -2,7 +2,7 @@ namespace App\Controllers; -class UserController extends \Controller +class UserController extends BaseController { public function index() { From 3ef6925e4f9fc7424e0f12b11bb0fa361457715d Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 19:11:49 +0900 Subject: [PATCH 1731/2325] docs: add return type void --- user_guide_src/source/testing/database/002.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/testing/database/002.php b/user_guide_src/source/testing/database/002.php index 4702f22d35ba..4b75aa739784 100644 --- a/user_guide_src/source/testing/database/002.php +++ b/user_guide_src/source/testing/database/002.php @@ -9,14 +9,14 @@ class MyTests extends CIUnitTestCase { use DatabaseTestTrait; - public function setUp() + public function setUp(): void { parent::setUp(); // Do something here.... } - public function tearDown() + public function tearDown(): void { parent::tearDown(); From 861f5100c89daa7c7b5a2332b68e8bec79b0cd4c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 5 Mar 2022 08:37:53 +0900 Subject: [PATCH 1732/2325] docs: run php-cs-fixer php-cs-fixer fix --verbose --diff --config=.user-guide.php-cs-fixer.dist.php --- user_guide_src/source/cli/cli_library/004.php | 2 +- user_guide_src/source/cli/cli_library/008.php | 4 +-- user_guide_src/source/cli/cli_library/013.php | 2 +- user_guide_src/source/cli/cli_library/015.php | 2 +- user_guide_src/source/cli/cli_library/021.php | 2 +- .../source/concepts/autoloader/003.php | 2 +- .../source/database/call_function/004.php | 2 +- .../source/database/configuration/001.php | 2 +- .../source/database/configuration/005.php | 2 +- .../source/database/examples/006.php | 2 +- .../source/database/examples/008.php | 2 +- .../source/database/metadata/007.php | 2 +- .../source/database/queries/003.php | 4 +-- .../source/database/queries/009.php | 2 +- .../source/database/queries/011.php | 2 +- .../source/database/queries/012.php | 2 +- .../source/database/queries/013.php | 2 +- .../source/database/queries/014.php | 2 +- .../source/database/queries/016.php | 4 +-- .../source/database/queries/017.php | 4 +-- .../source/database/queries/018.php | 4 +-- .../source/database/queries/019.php | 4 +-- .../source/database/query_builder/006.php | 6 ++-- .../source/database/query_builder/016.php | 2 +- .../source/database/query_builder/017.php | 2 +- .../source/database/query_builder/026.php | 2 +- .../source/database/query_builder/027.php | 4 +-- .../source/database/query_builder/030.php | 4 +-- .../source/database/query_builder/032.php | 4 +-- .../source/database/query_builder/034.php | 4 +-- .../source/database/query_builder/036.php | 4 +-- .../source/database/query_builder/044.php | 2 +- .../source/database/query_builder/045.php | 2 +- .../source/database/query_builder/047.php | 2 +- .../source/database/query_builder/049.php | 4 +-- .../source/database/query_builder/051.php | 4 +-- .../source/database/query_builder/053.php | 6 ++-- .../source/database/query_builder/055.php | 6 ++-- .../source/database/query_builder/057.php | 6 ++-- .../source/database/query_builder/074.php | 12 +++---- .../source/database/query_builder/076.php | 2 +- .../source/database/query_builder/086.php | 2 +- .../source/database/query_builder/088.php | 2 +- .../source/database/query_builder/089.php | 2 +- .../source/database/query_builder/091.php | 20 ++++++------ .../source/database/query_builder/096.php | 6 ++-- .../source/database/query_builder/097.php | 6 ++-- .../source/database/query_builder/098.php | 2 +- .../source/database/results/001.php | 2 +- .../source/database/results/002.php | 2 +- .../source/database/results/003.php | 2 +- .../source/database/results/004.php | 2 +- .../source/database/results/005.php | 2 +- .../source/database/results/007.php | 4 +-- .../source/database/results/008.php | 2 +- .../source/database/results/010.php | 2 +- .../source/database/results/011.php | 7 ++-- .../source/database/results/013.php | 4 +-- .../source/database/results/014.php | 2 +- .../source/database/results/015.php | 2 +- .../source/database/utilities/001.php | 6 ++-- user_guide_src/source/dbmgmt/forge/007.php | 32 +++++++++---------- user_guide_src/source/dbmgmt/forge/022.php | 2 +- user_guide_src/source/dbmgmt/forge/023.php | 4 +-- .../source/dbmgmt/migration/001.php | 4 +-- .../source/dbmgmt/migration/002.php | 2 +- .../source/dbmgmt/migration/005.php | 3 +- user_guide_src/source/dbmgmt/seeds/001.php | 4 +-- .../source/extending/events/002.php | 3 +- .../source/extending/events/006.php | 2 +- .../source/general/common_functions/001.php | 2 +- .../source/general/common_functions/008.php | 4 +-- .../source/general/configuration/006.php | 4 +-- .../source/general/configuration/009.php | 4 +-- .../source/general/configuration/011.php | 2 +- user_guide_src/source/general/errors/001.php | 2 +- user_guide_src/source/general/errors/002.php | 2 +- user_guide_src/source/general/helpers/005.php | 2 +- user_guide_src/source/general/logging/005.php | 4 +-- user_guide_src/source/general/modules/001.php | 2 +- user_guide_src/source/general/modules/002.php | 2 +- user_guide_src/source/general/modules/003.php | 2 +- user_guide_src/source/general/modules/004.php | 2 +- user_guide_src/source/general/modules/007.php | 2 +- .../source/helpers/array_helper/002.php | 4 +-- .../source/helpers/array_helper/008.php | 6 ++-- .../source/helpers/filesystem_helper/010.php | 2 +- .../source/helpers/filesystem_helper/011.php | 2 +- .../source/helpers/form_helper/020.php | 2 +- .../source/helpers/form_helper/022.php | 4 +-- .../source/helpers/form_helper/025.php | 2 +- .../source/helpers/form_helper/029.php | 2 +- .../source/helpers/form_helper/031.php | 2 +- .../source/helpers/html_helper/011.php | 2 +- .../source/helpers/html_helper/013.php | 8 ++--- .../source/helpers/html_helper/014.php | 17 +++++----- .../source/helpers/html_helper/017.php | 2 +- .../source/helpers/text_helper/006.php | 2 +- .../source/helpers/text_helper/007.php | 4 +-- .../source/helpers/text_helper/008.php | 2 +- .../source/helpers/text_helper/009.php | 4 +-- .../source/helpers/text_helper/010.php | 4 +-- .../source/helpers/text_helper/011.php | 2 +- .../source/helpers/text_helper/012.php | 2 +- .../source/helpers/text_helper/013.php | 2 +- .../source/helpers/text_helper/014.php | 2 +- .../source/helpers/text_helper/019.php | 4 +-- .../source/helpers/text_helper/020.php | 2 +- .../source/incoming/filters/001.php | 2 +- .../source/incoming/incomingrequest/007.php | 2 +- .../source/incoming/incomingrequest/018.php | 2 +- .../source/incoming/incomingrequest/019.php | 2 +- .../source/incoming/restful/001.php | 14 ++++---- .../source/incoming/restful/002.php | 2 +- .../source/incoming/restful/003.php | 2 +- .../source/incoming/restful/009.php | 16 +++++----- .../source/incoming/restful/011.php | 2 +- .../source/incoming/restful/015.php | 1 - .../source/incoming/routing/002.php | 2 +- .../source/incoming/routing/016.php | 2 +- .../source/incoming/routing/019.php | 2 +- .../source/incoming/routing/020.php | 2 +- .../source/incoming/routing/021.php | 2 +- .../source/incoming/routing/022.php | 4 +-- .../source/incoming/routing/024.php | 2 +- .../source/incoming/routing/025.php | 2 +- .../source/incoming/routing/026.php | 2 +- .../source/incoming/routing/029.php | 2 +- .../source/incoming/routing/030.php | 2 +- .../source/incoming/routing/032.php | 2 +- .../source/incoming/routing/033.php | 2 +- .../source/incoming/routing/047.php | 3 +- .../installation/troubleshooting/001.php | 4 +-- .../installation/upgrade_database/002.php | 6 ++-- .../installation/upgrade_encryption/002.php | 2 +- .../installation/upgrade_file_upload/002.php | 8 ++--- .../installation/upgrade_localization/001.php | 4 +-- .../installation/upgrade_validations/001.php | 2 +- .../installation/upgrade_view_parser/002.php | 2 +- .../source/libraries/cookies/003.php | 2 +- .../source/libraries/curlrequest/003.php | 2 +- .../source/libraries/curlrequest/010.php | 2 +- .../source/libraries/curlrequest/015.php | 2 +- .../source/libraries/curlrequest/017.php | 2 +- user_guide_src/source/libraries/email/013.php | 5 ++- user_guide_src/source/libraries/email/022.php | 2 +- .../source/libraries/encryption/002.php | 2 +- .../source/libraries/encryption/005.php | 2 +- user_guide_src/source/libraries/files/004.php | 2 +- .../source/libraries/images/011.php | 2 +- .../source/libraries/images/014.php | 2 +- .../source/libraries/pagination/005.php | 2 +- .../source/libraries/publisher/005.php | 3 +- .../source/libraries/publisher/009.php | 2 -- .../source/libraries/publisher/010.php | 1 + .../source/libraries/sessions/014.php | 2 +- .../source/libraries/sessions/016.php | 2 +- .../source/libraries/sessions/029.php | 4 +-- user_guide_src/source/libraries/time/030.php | 2 +- .../source/libraries/uploaded_files/002.php | 7 ++-- .../source/libraries/uploaded_files/009.php | 2 +- user_guide_src/source/libraries/uri/023.php | 2 +- .../source/libraries/validation/002.php | 2 +- .../source/libraries/validation/004.php | 2 +- .../source/libraries/validation/021.php | 2 +- .../source/libraries/validation/023.php | 5 +-- .../source/libraries/validation/024.php | 5 +-- .../source/libraries/validation/025.php | 3 +- .../source/libraries/validation/030.php | 2 +- .../source/libraries/validation/033.php | 2 +- .../source/libraries/validation/036.php | 4 +-- .../source/libraries/validation/037.php | 8 ++--- user_guide_src/source/models/entities/003.php | 2 +- user_guide_src/source/models/entities/017.php | 2 +- user_guide_src/source/models/model/001.php | 2 +- user_guide_src/source/models/model/007.php | 2 +- user_guide_src/source/models/model/010.php | 2 +- user_guide_src/source/models/model/012.php | 2 +- user_guide_src/source/models/model/018.php | 2 +- user_guide_src/source/models/model/020.php | 4 +-- user_guide_src/source/models/model/022.php | 2 +- user_guide_src/source/models/model/024.php | 2 +- user_guide_src/source/models/model/028.php | 2 +- user_guide_src/source/models/model/029.php | 2 +- user_guide_src/source/models/model/030.php | 2 +- user_guide_src/source/models/model/039.php | 4 +-- user_guide_src/source/models/model/042.php | 4 +-- user_guide_src/source/models/model/045.php | 4 +-- user_guide_src/source/models/model/049.php | 2 +- .../source/outgoing/api_responses/007.php | 1 + .../source/outgoing/api_responses/008.php | 1 + .../source/outgoing/api_responses/009.php | 1 + .../source/outgoing/localization/007.php | 2 +- .../source/outgoing/localization/012.php | 2 +- .../source/outgoing/response/003.php | 2 +- .../source/outgoing/response/004.php | 2 +- .../source/outgoing/response/005.php | 2 +- .../source/outgoing/response/007.php | 1 + .../source/outgoing/response/010.php | 2 +- .../source/outgoing/response/013.php | 2 +- .../source/outgoing/response/016.php | 2 +- .../source/outgoing/response/023.php | 16 +++++----- user_guide_src/source/outgoing/table/005.php | 2 +- user_guide_src/source/outgoing/table/006.php | 32 +++++++++---------- user_guide_src/source/outgoing/table/007.php | 2 +- user_guide_src/source/outgoing/table/008.php | 2 +- user_guide_src/source/outgoing/table/016.php | 2 +- user_guide_src/source/outgoing/table/017.php | 2 +- .../source/outgoing/view_parser/003.php | 2 +- .../source/outgoing/view_parser/006.php | 2 +- .../source/outgoing/view_parser/007.php | 4 +-- .../source/outgoing/view_parser/008.php | 2 +- .../source/outgoing/view_parser/010.php | 4 +-- .../source/outgoing/view_parser/011.php | 2 +- .../source/outgoing/view_parser/015.php | 4 +-- .../source/outgoing/view_parser/018.php | 6 ++-- .../source/outgoing/view_parser/019.php | 4 +-- .../source/outgoing/view_parser/020.php | 4 +-- .../source/outgoing/view_parser/021.php | 10 +++--- .../source/outgoing/view_parser/025.php | 2 +- .../source/outgoing/view_parser/026.php | 2 +- .../source/outgoing/view_renderer/003.php | 4 +-- .../source/outgoing/view_renderer/007.php | 2 +- .../source/outgoing/view_renderer/008.php | 2 +- .../source/testing/benchmark/007.php | 6 ++-- .../source/testing/controllers/001.php | 5 +-- .../source/testing/controllers/002.php | 9 +++--- .../source/testing/controllers/004.php | 2 +- .../source/testing/controllers/005.php | 6 ++-- .../source/testing/controllers/006.php | 4 +-- .../source/testing/controllers/007.php | 4 +-- .../source/testing/controllers/008.php | 6 ++-- .../source/testing/controllers/009.php | 4 +-- .../source/testing/controllers/010.php | 4 +-- .../source/testing/database/002.php | 4 +-- .../source/testing/database/003.php | 2 +- .../source/testing/debugging/006.php | 2 +- .../source/testing/fabricator/009.php | 12 +++---- .../source/testing/fabricator/012.php | 16 +++++----- .../source/testing/fabricator/016.php | 24 +++++++------- .../source/testing/fabricator/018.php | 24 +++++++------- user_guide_src/source/testing/feature/001.php | 3 +- user_guide_src/source/testing/feature/002.php | 2 +- .../source/testing/overview/009.php | 2 +- .../source/testing/overview/010.php | 2 +- .../source/testing/overview/011.php | 2 +- 246 files changed, 442 insertions(+), 464 deletions(-) diff --git a/user_guide_src/source/cli/cli_library/004.php b/user_guide_src/source/cli/cli_library/004.php index 10a92407bcbd..7fae108cd3e7 100644 --- a/user_guide_src/source/cli/cli_library/004.php +++ b/user_guide_src/source/cli/cli_library/004.php @@ -1,3 +1,3 @@ 'The red apple', + 'apple' => 'The red apple', 'orange' => 'The plump orange', - 'banana' => 'The ripe banana' + 'banana' => 'The ripe banana', ]); /* * These are your choices: diff --git a/user_guide_src/source/cli/cli_library/013.php b/user_guide_src/source/cli/cli_library/013.php index cfbeb34a3ffa..64c5ad14f457 100644 --- a/user_guide_src/source/cli/cli_library/013.php +++ b/user_guide_src/source/cli/cli_library/013.php @@ -1,3 +1,3 @@ APPPATH . 'third_party/markdown.php' + 'Markdown' => APPPATH . 'third_party/markdown.php', ]; diff --git a/user_guide_src/source/database/call_function/004.php b/user_guide_src/source/database/call_function/004.php index 2739752f852d..0a8afc4199ef 100644 --- a/user_guide_src/source/database/call_function/004.php +++ b/user_guide_src/source/database/call_function/004.php @@ -1,5 +1,5 @@ query("SOME QUERY"); +$query = $db->query('SOME QUERY'); $query->resultID; diff --git a/user_guide_src/source/database/configuration/001.php b/user_guide_src/source/database/configuration/001.php index 5631cf7faede..eae7a19f2dab 100644 --- a/user_guide_src/source/database/configuration/001.php +++ b/user_guide_src/source/database/configuration/001.php @@ -24,6 +24,6 @@ class Database extends Config 'strictOn' => false, 'failover' => [], ]; - + // ... } diff --git a/user_guide_src/source/database/configuration/005.php b/user_guide_src/source/database/configuration/005.php index acc4a7b8db70..7e2da93f95d3 100644 --- a/user_guide_src/source/database/configuration/005.php +++ b/user_guide_src/source/database/configuration/005.php @@ -32,5 +32,5 @@ 'encrypt' => false, 'compress' => false, 'strictOn' => false, - ] + ], ]; diff --git a/user_guide_src/source/database/examples/006.php b/user_guide_src/source/database/examples/006.php index 1f7ac810d441..5f8843348c60 100644 --- a/user_guide_src/source/database/examples/006.php +++ b/user_guide_src/source/database/examples/006.php @@ -1,5 +1,5 @@ escape($title).", ".$db->escape($name).")"; +$sql = 'INSERT INTO mytable (title, name) VALUES (' . $db->escape($title) . ', ' . $db->escape($name) . ')'; $db->query($sql); echo $db->affectedRows(); diff --git a/user_guide_src/source/database/examples/008.php b/user_guide_src/source/database/examples/008.php index 00ed0b27dbfc..76e35e0e0932 100644 --- a/user_guide_src/source/database/examples/008.php +++ b/user_guide_src/source/database/examples/008.php @@ -3,7 +3,7 @@ $data = [ 'title' => $title, 'name' => $name, - 'date' => $date + 'date' => $date, ]; $db->table('mytable')->insert($data); diff --git a/user_guide_src/source/database/metadata/007.php b/user_guide_src/source/database/metadata/007.php index fdac8c74ffec..2c68fc14b5f4 100644 --- a/user_guide_src/source/database/metadata/007.php +++ b/user_guide_src/source/database/metadata/007.php @@ -1,4 +1,4 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); $fields = $query->fieldData(); diff --git a/user_guide_src/source/database/queries/003.php b/user_guide_src/source/database/queries/003.php index 9980b5d1701e..f414f829b39e 100644 --- a/user_guide_src/source/database/queries/003.php +++ b/user_guide_src/source/database/queries/003.php @@ -1,7 +1,7 @@ simpleQuery('YOUR QUERY')) { - echo "Success!"; + echo 'Success!'; } else { - echo "Query failed!"; + echo 'Query failed!'; } diff --git a/user_guide_src/source/database/queries/009.php b/user_guide_src/source/database/queries/009.php index e93ca2da877c..24961e75db6e 100644 --- a/user_guide_src/source/database/queries/009.php +++ b/user_guide_src/source/database/queries/009.php @@ -1,3 +1,3 @@ escape($title) . ")"; +$sql = 'INSERT INTO table (title) VALUES(' . $db->escape($title) . ')'; diff --git a/user_guide_src/source/database/queries/011.php b/user_guide_src/source/database/queries/011.php index 4b4e40660456..e3b1f9033bc9 100644 --- a/user_guide_src/source/database/queries/011.php +++ b/user_guide_src/source/database/queries/011.php @@ -1,5 +1,5 @@ escapeLikeString($search) . "%' ESCAPE '!'"; diff --git a/user_guide_src/source/database/queries/012.php b/user_guide_src/source/database/queries/012.php index 5aebc0688a14..11f1035c0ef7 100644 --- a/user_guide_src/source/database/queries/012.php +++ b/user_guide_src/source/database/queries/012.php @@ -1,4 +1,4 @@ query($sql, [3, 'live', 'Rick']); diff --git a/user_guide_src/source/database/queries/013.php b/user_guide_src/source/database/queries/013.php index 572886ee41b8..1e6afe7861a5 100644 --- a/user_guide_src/source/database/queries/013.php +++ b/user_guide_src/source/database/queries/013.php @@ -1,4 +1,4 @@ query($sql, [[3, 6], 'live', 'Rick']); diff --git a/user_guide_src/source/database/queries/014.php b/user_guide_src/source/database/queries/014.php index 6fadb198fd45..63d156cc6d13 100644 --- a/user_guide_src/source/database/queries/014.php +++ b/user_guide_src/source/database/queries/014.php @@ -1,6 +1,6 @@ query($sql, [ 'id' => 3, 'status' => 'live', diff --git a/user_guide_src/source/database/queries/016.php b/user_guide_src/source/database/queries/016.php index b614183dfa83..f674f7c7ccce 100644 --- a/user_guide_src/source/database/queries/016.php +++ b/user_guide_src/source/database/queries/016.php @@ -1,9 +1,9 @@ prepare(function ($db) { +$pQuery = $db->prepare(static function ($db) { return $db->table('user')->insert([ 'name' => 'x', 'email' => 'y', - 'country' => 'US' + 'country' => 'US', ]); }); diff --git a/user_guide_src/source/database/queries/017.php b/user_guide_src/source/database/queries/017.php index 3862d566dd3f..308412f64653 100644 --- a/user_guide_src/source/database/queries/017.php +++ b/user_guide_src/source/database/queries/017.php @@ -2,8 +2,8 @@ use CodeIgniter\Database\Query; -$pQuery = $db->prepare(function ($db) { - $sql = "INSERT INTO user (name, email, country) VALUES (?, ?, ?)"; +$pQuery = $db->prepare(static function ($db) { + $sql = 'INSERT INTO user (name, email, country) VALUES (?, ?, ?)'; return (new Query($db))->setQuery($sql); }); diff --git a/user_guide_src/source/database/queries/018.php b/user_guide_src/source/database/queries/018.php index ddf8aa0dd58f..a6df9b8d6dbe 100644 --- a/user_guide_src/source/database/queries/018.php +++ b/user_guide_src/source/database/queries/018.php @@ -2,8 +2,8 @@ use CodeIgniter\Database\Query; -$pQuery = $db->prepare(function ($db) { - $sql = "INSERT INTO user (name, email, country) VALUES (?, ?, ?)"; +$pQuery = $db->prepare(static function ($db) { + $sql = 'INSERT INTO user (name, email, country) VALUES (?, ?, ?)'; return (new Query($db))->setQuery($sql); }, $options); diff --git a/user_guide_src/source/database/queries/019.php b/user_guide_src/source/database/queries/019.php index 73467a9394e5..28729f2e484a 100644 --- a/user_guide_src/source/database/queries/019.php +++ b/user_guide_src/source/database/queries/019.php @@ -1,11 +1,11 @@ prepare(function ($db) { +$pQuery = $db->prepare(static function ($db) { return $db->table('user')->insert([ 'name' => 'x', 'email' => 'y', - 'country' => 'US' + 'country' => 'US', ]); }); diff --git a/user_guide_src/source/database/query_builder/006.php b/user_guide_src/source/database/query_builder/006.php index 78a92e7b7b9d..52af6d2a4913 100644 --- a/user_guide_src/source/database/query_builder/006.php +++ b/user_guide_src/source/database/query_builder/006.php @@ -1,12 +1,10 @@ limit(10,20)->getCompiledSelect(false); +echo $builder->limit(10, 20)->getCompiledSelect(false); /* * Prints string: SELECT * FROM mytable LIMIT 20, 10 * (in MySQL. Other databases have slightly different syntax) */ echo $builder->select('title, content, date')->getCompiledSelect(); -/* - * Prints string: SELECT title, content, date FROM mytable LIMIT 20, 10 - */ +// Prints string: SELECT title, content, date FROM mytable LIMIT 20, 10 diff --git a/user_guide_src/source/database/query_builder/016.php b/user_guide_src/source/database/query_builder/016.php index f00c2dbe47c2..1ad1c917ff57 100644 --- a/user_guide_src/source/database/query_builder/016.php +++ b/user_guide_src/source/database/query_builder/016.php @@ -2,5 +2,5 @@ $subquery = $db->table('users'); $builder = $db->table('jobs')->fromSubquery($subquery, 'alias'); -$query = $builder->get(); +$query = $builder->get(); // Produces: SELECT * FROM `jobs`, (SELECT * FROM `users`) AS `alias` diff --git a/user_guide_src/source/database/query_builder/017.php b/user_guide_src/source/database/query_builder/017.php index 965ae956a6af..b33dd475b6f8 100644 --- a/user_guide_src/source/database/query_builder/017.php +++ b/user_guide_src/source/database/query_builder/017.php @@ -2,5 +2,5 @@ $subquery = $db->table('users')->select('id, name'); $builder = $db->newQuery()->fromSubquery($subquery, 't'); -$query = $builder->get(); +$query = $builder->get(); // Produces: SELECT * FROM (SELECT `id`, `name` FROM users) AS `t` diff --git a/user_guide_src/source/database/query_builder/026.php b/user_guide_src/source/database/query_builder/026.php index d4e93699151c..ed45b84bf363 100644 --- a/user_guide_src/source/database/query_builder/026.php +++ b/user_guide_src/source/database/query_builder/026.php @@ -1,5 +1,5 @@ db->escape('Joe'); +$name = $builder->db->escape('Joe'); $where = "name={$name} AND status='boss' OR status='active'"; $builder->where($where); diff --git a/user_guide_src/source/database/query_builder/027.php b/user_guide_src/source/database/query_builder/027.php index 043b7d9e451b..019386718cd1 100644 --- a/user_guide_src/source/database/query_builder/027.php +++ b/user_guide_src/source/database/query_builder/027.php @@ -1,9 +1,7 @@ where('advance_amount <', function (BaseBuilder $builder) { - return $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2); -}); +$builder->where('advance_amount <', static fn (BaseBuilder $builder) => $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2)); // Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) // With builder directly diff --git a/user_guide_src/source/database/query_builder/030.php b/user_guide_src/source/database/query_builder/030.php index 7f80507b4435..5aa7619c0dc8 100644 --- a/user_guide_src/source/database/query_builder/030.php +++ b/user_guide_src/source/database/query_builder/030.php @@ -1,9 +1,7 @@ whereIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); -}); +$builder->whereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); // Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/032.php b/user_guide_src/source/database/query_builder/032.php index 7a7a44182396..ae8ddb7ce7a4 100644 --- a/user_guide_src/source/database/query_builder/032.php +++ b/user_guide_src/source/database/query_builder/032.php @@ -1,9 +1,7 @@ orWhereIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); -}); +$builder->orWhereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); // Produces: OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/034.php b/user_guide_src/source/database/query_builder/034.php index 2316388e16b6..02904a3962f3 100644 --- a/user_guide_src/source/database/query_builder/034.php +++ b/user_guide_src/source/database/query_builder/034.php @@ -1,9 +1,7 @@ whereNotIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); -}); +$builder->whereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); // Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/036.php b/user_guide_src/source/database/query_builder/036.php index d50bcc113853..f5668aa1a30d 100644 --- a/user_guide_src/source/database/query_builder/036.php +++ b/user_guide_src/source/database/query_builder/036.php @@ -1,9 +1,7 @@ orWhereNotIn('id', function (BaseBuilder $builder) { - return $builder->select('job_id')->from('users_jobs')->where('user_id', 3); -}); +$builder->orWhereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); // Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/044.php b/user_guide_src/source/database/query_builder/044.php index 1c0a0e15991d..ffe4786baaae 100644 --- a/user_guide_src/source/database/query_builder/044.php +++ b/user_guide_src/source/database/query_builder/044.php @@ -1,4 +1,4 @@ groupBy("title"); +$builder->groupBy('title'); // Produces: GROUP BY title diff --git a/user_guide_src/source/database/query_builder/045.php b/user_guide_src/source/database/query_builder/045.php index 5758e29187be..0872996afe9f 100644 --- a/user_guide_src/source/database/query_builder/045.php +++ b/user_guide_src/source/database/query_builder/045.php @@ -1,4 +1,4 @@ groupBy(["title", "date"]); +$builder->groupBy(['title', 'date']); // Produces: GROUP BY title, date diff --git a/user_guide_src/source/database/query_builder/047.php b/user_guide_src/source/database/query_builder/047.php index cf439e52d0fb..87f435064238 100644 --- a/user_guide_src/source/database/query_builder/047.php +++ b/user_guide_src/source/database/query_builder/047.php @@ -1,4 +1,4 @@ having('user_id = 45'); // Produces: HAVING user_id = 45 -$builder->having('user_id', 45); // Produces: HAVING user_id = 45 +$builder->having('user_id', 45); // Produces: HAVING user_id = 45 diff --git a/user_guide_src/source/database/query_builder/049.php b/user_guide_src/source/database/query_builder/049.php index 4a22eccffc4d..b044b821f388 100644 --- a/user_guide_src/source/database/query_builder/049.php +++ b/user_guide_src/source/database/query_builder/049.php @@ -1,4 +1,4 @@ having('user_id', 45); // Produces: HAVING `user_id` = 45 in some databases such as MySQL -$builder->having('user_id', 45, false); // Produces: HAVING user_id = 45 +$builder->having('user_id', 45); // Produces: HAVING `user_id` = 45 in some databases such as MySQL +$builder->having('user_id', 45, false); // Produces: HAVING user_id = 45 diff --git a/user_guide_src/source/database/query_builder/051.php b/user_guide_src/source/database/query_builder/051.php index 325e99679082..1f5736243866 100644 --- a/user_guide_src/source/database/query_builder/051.php +++ b/user_guide_src/source/database/query_builder/051.php @@ -1,9 +1,7 @@ havingIn('id', function (BaseBuilder $builder) { - return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); -}); +$builder->havingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); // Produces: HAVING "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/053.php b/user_guide_src/source/database/query_builder/053.php index baa936c5df82..8a19ff4ac7d8 100644 --- a/user_guide_src/source/database/query_builder/053.php +++ b/user_guide_src/source/database/query_builder/053.php @@ -1,9 +1,7 @@ orHavingIn('id', function (BaseBuilder $builder) { - return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); -}); +// With closure +$builder->orHavingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); // Produces: OR "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/055.php b/user_guide_src/source/database/query_builder/055.php index 986b3ff24cb9..67a54f87f7bc 100644 --- a/user_guide_src/source/database/query_builder/055.php +++ b/user_guide_src/source/database/query_builder/055.php @@ -1,9 +1,7 @@ havingNotIn('id', function (BaseBuilder $builder) { - return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); -}); +// With closure +$builder->havingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); // Produces: HAVING "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/057.php b/user_guide_src/source/database/query_builder/057.php index 85cab6e2eba8..8a92da5725b2 100644 --- a/user_guide_src/source/database/query_builder/057.php +++ b/user_guide_src/source/database/query_builder/057.php @@ -1,9 +1,7 @@ orHavingNotIn('id', function (BaseBuilder $builder) { - return $builder->select('user_id')->from('users_jobs')->where('group_id', 3); -}); +// With closure +$builder->orHavingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); // Produces: OR "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) // With builder directly diff --git a/user_guide_src/source/database/query_builder/074.php b/user_guide_src/source/database/query_builder/074.php index d858451993a2..1ce884db6e6a 100644 --- a/user_guide_src/source/database/query_builder/074.php +++ b/user_guide_src/source/database/query_builder/074.php @@ -2,14 +2,14 @@ $builder->select('*')->from('my_table') ->groupStart() - ->where('a', 'a') - ->orGroupStart() - ->where('b', 'b') - ->where('c', 'c') - ->groupEnd() + ->where('a', 'a') + ->orGroupStart() + ->where('b', 'b') + ->where('c', 'c') + ->groupEnd() ->groupEnd() ->where('d', 'd') -->get(); + ->get(); /* * Generates: * SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' diff --git a/user_guide_src/source/database/query_builder/076.php b/user_guide_src/source/database/query_builder/076.php index cdacf0a53df5..ba38d99ff43b 100644 --- a/user_guide_src/source/database/query_builder/076.php +++ b/user_guide_src/source/database/query_builder/076.php @@ -7,6 +7,6 @@ class Myclass public $date = 'My Date'; } -$object = new Myclass; +$object = new Myclass(); $builder->insert($object); // Produces: INSERT INTO mytable (title, content, date) VALUES ('My Title', 'My Content', 'My Date') diff --git a/user_guide_src/source/database/query_builder/086.php b/user_guide_src/source/database/query_builder/086.php index c7dcd01aa071..d395bc3b8ea9 100644 --- a/user_guide_src/source/database/query_builder/086.php +++ b/user_guide_src/source/database/query_builder/086.php @@ -7,6 +7,6 @@ class Myclass public $date = 'My Date'; } -$object = new Myclass; +$object = new Myclass(); $builder->set($object); $builder->insert(); diff --git a/user_guide_src/source/database/query_builder/088.php b/user_guide_src/source/database/query_builder/088.php index ce38024e558d..445e53716041 100644 --- a/user_guide_src/source/database/query_builder/088.php +++ b/user_guide_src/source/database/query_builder/088.php @@ -7,7 +7,7 @@ class Myclass public $date = 'My Date'; } -$object = new Myclass; +$object = new Myclass(); $builder->where('id', $id); $builder->update($object); /* diff --git a/user_guide_src/source/database/query_builder/089.php b/user_guide_src/source/database/query_builder/089.php index 2a4a01cc6346..d2ed79d26832 100644 --- a/user_guide_src/source/database/query_builder/089.php +++ b/user_guide_src/source/database/query_builder/089.php @@ -1,3 +1,3 @@ update($data, "id = 4"); +$builder->update($data, 'id = 4'); diff --git a/user_guide_src/source/database/query_builder/091.php b/user_guide_src/source/database/query_builder/091.php index 56f04036cd6f..e60b9ee6b486 100644 --- a/user_guide_src/source/database/query_builder/091.php +++ b/user_guide_src/source/database/query_builder/091.php @@ -1,16 +1,16 @@ 'My title' , - 'name' => 'My Name 2' , - 'date' => 'My date 2', - ], - [ - 'title' => 'Another title' , - 'name' => 'Another Name 2' , - 'date' => 'Another date 2', - ], + [ + 'title' => 'My title', + 'name' => 'My Name 2', + 'date' => 'My date 2', + ], + [ + 'title' => 'Another title', + 'name' => 'Another Name 2', + 'date' => 'Another date 2', + ], ]; $builder->updateBatch($data, 'title'); diff --git a/user_guide_src/source/database/query_builder/096.php b/user_guide_src/source/database/query_builder/096.php index 78b57dd13df5..5a05f70d8070 100644 --- a/user_guide_src/source/database/query_builder/096.php +++ b/user_guide_src/source/database/query_builder/096.php @@ -1,6 +1,6 @@ select('title') - ->where('id', $id) - ->limit(10, 20) - ->get(); + ->where('id', $id) + ->limit(10, 20) + ->get(); diff --git a/user_guide_src/source/database/query_builder/097.php b/user_guide_src/source/database/query_builder/097.php index 30c4d0c4526a..50d274d63a54 100644 --- a/user_guide_src/source/database/query_builder/097.php +++ b/user_guide_src/source/database/query_builder/097.php @@ -1,9 +1,9 @@ select(['field1','field2']) - ->where('field3',5) - ->getCompiledSelect(false); +$sql = $builder->select(['field1', 'field2']) + ->where('field3', 5) + ->getCompiledSelect(false); // ... // Do something crazy with the SQL code... like add it to a cron script for diff --git a/user_guide_src/source/database/query_builder/098.php b/user_guide_src/source/database/query_builder/098.php index a6fb3cc4beed..b3890e978005 100644 --- a/user_guide_src/source/database/query_builder/098.php +++ b/user_guide_src/source/database/query_builder/098.php @@ -2,5 +2,5 @@ $subquery = $db->table('countries')->select('name')->where('id', 1); $builder = $db->table('users')->select('name')->selectSubquery($subquery, 'country'); -$query = $builder->get(); +$query = $builder->get(); // Produces: SELECT `name`, (SELECT `name` FROM `countries` WHERE `id` = 1) AS `country` FROM `users` diff --git a/user_guide_src/source/database/results/001.php b/user_guide_src/source/database/results/001.php index 0cbecfb88ba9..af0b6117f689 100644 --- a/user_guide_src/source/database/results/001.php +++ b/user_guide_src/source/database/results/001.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); foreach ($query->getResult() as $row) { echo $row->title; diff --git a/user_guide_src/source/database/results/002.php b/user_guide_src/source/database/results/002.php index 8b702c8e1150..2ab6e0535a3a 100644 --- a/user_guide_src/source/database/results/002.php +++ b/user_guide_src/source/database/results/002.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); foreach ($query->getResult('array') as $row) { echo $row['title']; diff --git a/user_guide_src/source/database/results/003.php b/user_guide_src/source/database/results/003.php index 1ad7d7dcb9fe..da55c19717c1 100644 --- a/user_guide_src/source/database/results/003.php +++ b/user_guide_src/source/database/results/003.php @@ -1,6 +1,6 @@ query("SELECT * FROM users;"); +$query = $db->query('SELECT * FROM users;'); foreach ($query->getResult('User') as $user) { echo $user->name; // access attributes diff --git a/user_guide_src/source/database/results/004.php b/user_guide_src/source/database/results/004.php index e8e9acecdcdc..66c537b57344 100644 --- a/user_guide_src/source/database/results/004.php +++ b/user_guide_src/source/database/results/004.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); foreach ($query->getResultArray() as $row) { echo $row['title']; diff --git a/user_guide_src/source/database/results/005.php b/user_guide_src/source/database/results/005.php index af79170b8b89..bd0e2ed47050 100644 --- a/user_guide_src/source/database/results/005.php +++ b/user_guide_src/source/database/results/005.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); $row = $query->getRow(); diff --git a/user_guide_src/source/database/results/007.php b/user_guide_src/source/database/results/007.php index 4b46945c285e..6a6c309efb4f 100644 --- a/user_guide_src/source/database/results/007.php +++ b/user_guide_src/source/database/results/007.php @@ -1,7 +1,7 @@ query("SELECT * FROM users LIMIT 1;"); -$row = $query->getRow(0, 'User'); +$query = $db->query('SELECT * FROM users LIMIT 1;'); +$row = $query->getRow(0, 'User'); echo $row->name; // access attributes echo $row->reverse_name(); // or methods defined on the 'User' class diff --git a/user_guide_src/source/database/results/008.php b/user_guide_src/source/database/results/008.php index 8b576d1d3117..9925567c5a01 100644 --- a/user_guide_src/source/database/results/008.php +++ b/user_guide_src/source/database/results/008.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); $row = $query->getRowArray(); diff --git a/user_guide_src/source/database/results/010.php b/user_guide_src/source/database/results/010.php index ad0b4c326d0f..072c511f89bd 100644 --- a/user_guide_src/source/database/results/010.php +++ b/user_guide_src/source/database/results/010.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); while ($row = $query->getUnbufferedRow()) { echo $row->title; diff --git a/user_guide_src/source/database/results/011.php b/user_guide_src/source/database/results/011.php index f57aa21a2504..b33681cd74b4 100644 --- a/user_guide_src/source/database/results/011.php +++ b/user_guide_src/source/database/results/011.php @@ -2,14 +2,13 @@ $db->resultMode = MYSQLI_USE_RESULT; // for unbuffered results -$query = $db->query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); -$file = new \CodeIgniter\Files\File(WRITEPATH.'data.csv'); +$file = new \CodeIgniter\Files\File(WRITEPATH . 'data.csv'); $csv = $file->openFile('w'); -while ($row = $query->getUnbufferedRow('array')) -{ +while ($row = $query->getUnbufferedRow('array')) { $csv->fputcsv($row); } diff --git a/user_guide_src/source/database/results/013.php b/user_guide_src/source/database/results/013.php index 6c47fe5bf256..380945848ebb 100644 --- a/user_guide_src/source/database/results/013.php +++ b/user_guide_src/source/database/results/013.php @@ -22,8 +22,8 @@ public function __set($name, $value) public function __get($name) { - if (isset($this->$name)) { - return $this->$name; + if (isset($this->{$name})) { + return $this->{$name}; } } } diff --git a/user_guide_src/source/database/results/014.php b/user_guide_src/source/database/results/014.php index df6073c5ed79..f0845bf55ac3 100644 --- a/user_guide_src/source/database/results/014.php +++ b/user_guide_src/source/database/results/014.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); $rows = $query->getCustomResultObject('User'); diff --git a/user_guide_src/source/database/results/015.php b/user_guide_src/source/database/results/015.php index a57dddfa42d0..247d5d8b5313 100644 --- a/user_guide_src/source/database/results/015.php +++ b/user_guide_src/source/database/results/015.php @@ -1,6 +1,6 @@ query("YOUR QUERY"); +$query = $db->query('YOUR QUERY'); $row = $query->getCustomRowObject(0, 'User'); diff --git a/user_guide_src/source/database/utilities/001.php b/user_guide_src/source/database/utilities/001.php index 9b0e88d70753..697e6a786930 100644 --- a/user_guide_src/source/database/utilities/001.php +++ b/user_guide_src/source/database/utilities/001.php @@ -1,12 +1,10 @@ db; -}, null, $model)($model); +$db = \Closure::bind(static fn ($model) => $model->db, null, $model)($model); $util = (new \CodeIgniter\Database\Database())->loadUtils($db); echo $util->getXMLFromResult($model->get()); diff --git a/user_guide_src/source/dbmgmt/forge/007.php b/user_guide_src/source/dbmgmt/forge/007.php index 5150dd8495ef..182ea8347633 100644 --- a/user_guide_src/source/dbmgmt/forge/007.php +++ b/user_guide_src/source/dbmgmt/forge/007.php @@ -1,29 +1,29 @@ [ + 'id' => [ 'type' => 'INT', 'constraint' => 5, 'unsigned' => true, - 'auto_increment' => true + 'auto_increment' => true, ], - 'title' => [ - 'type' => 'VARCHAR', - 'constraint' => '100', - 'unique' => true, + 'title' => [ + 'type' => 'VARCHAR', + 'constraint' => '100', + 'unique' => true, ], - 'author' => [ - 'type' =>'VARCHAR', - 'constraint' => 100, - 'default' => 'King of Town', + 'author' => [ + 'type' => 'VARCHAR', + 'constraint' => 100, + 'default' => 'King of Town', ], 'description' => [ - 'type' => 'TEXT', - 'null' => true, + 'type' => 'TEXT', + 'null' => true, ], - 'status' => [ - 'type' => 'ENUM', - 'constraint' => ['publish', 'pending', 'draft'], - 'default' => 'pending', + 'status' => [ + 'type' => 'ENUM', + 'constraint' => ['publish', 'pending', 'draft'], + 'default' => 'pending', ], ]; diff --git a/user_guide_src/source/dbmgmt/forge/022.php b/user_guide_src/source/dbmgmt/forge/022.php index 22b335fc992c..80b0b9f5e098 100644 --- a/user_guide_src/source/dbmgmt/forge/022.php +++ b/user_guide_src/source/dbmgmt/forge/022.php @@ -1,7 +1,7 @@ ['type' => 'TEXT'] + 'preferences' => ['type' => 'TEXT'], ]; $forge->addColumn('table_name', $fields); // Executes: ALTER TABLE `table_name` ADD `preferences` TEXT diff --git a/user_guide_src/source/dbmgmt/forge/023.php b/user_guide_src/source/dbmgmt/forge/023.php index 50a5bc799909..957d9a37dafc 100644 --- a/user_guide_src/source/dbmgmt/forge/023.php +++ b/user_guide_src/source/dbmgmt/forge/023.php @@ -2,10 +2,10 @@ // Will place the new column after the `another_field` column: $fields = [ - 'preferences' => ['type' => 'TEXT', 'after' => 'another_field'] + 'preferences' => ['type' => 'TEXT', 'after' => 'another_field'], ]; // Will place the new column at the start of the table definition: $fields = [ - 'preferences' => ['type' => 'TEXT', 'first' => true] + 'preferences' => ['type' => 'TEXT', 'first' => true], ]; diff --git a/user_guide_src/source/dbmgmt/migration/001.php b/user_guide_src/source/dbmgmt/migration/001.php index 0d08e2b44308..3f73906231f1 100644 --- a/user_guide_src/source/dbmgmt/migration/001.php +++ b/user_guide_src/source/dbmgmt/migration/001.php @@ -9,13 +9,13 @@ class AddBlog extends Migration public function up() { $this->forge->addField([ - 'blog_id' => [ + 'blog_id' => [ 'type' => 'INT', 'constraint' => 5, 'unsigned' => true, 'auto_increment' => true, ], - 'blog_title' => [ + 'blog_title' => [ 'type' => 'VARCHAR', 'constraint' => '100', ], diff --git a/user_guide_src/source/dbmgmt/migration/002.php b/user_guide_src/source/dbmgmt/migration/002.php index b324f22003a7..ec555bb81cd6 100644 --- a/user_guide_src/source/dbmgmt/migration/002.php +++ b/user_guide_src/source/dbmgmt/migration/002.php @@ -11,7 +11,7 @@ public function up() $this->db->disableForeignKeyChecks(); // Migration rules would go here.. - + $this->db->enableForeignKeyChecks(); } } diff --git a/user_guide_src/source/dbmgmt/migration/005.php b/user_guide_src/source/dbmgmt/migration/005.php index 958aff859e9d..e9b4c2ad37fe 100644 --- a/user_guide_src/source/dbmgmt/migration/005.php +++ b/user_guide_src/source/dbmgmt/migration/005.php @@ -3,6 +3,7 @@ namespace App\Controllers; use CodeIgniter\Controller; +use Throwable; class Migrate extends Controller { @@ -12,7 +13,7 @@ public function index() try { $migrate->latest(); - } catch (\Throwable $e) { + } catch (Throwable $e) { // Do something with the error here... } } diff --git a/user_guide_src/source/dbmgmt/seeds/001.php b/user_guide_src/source/dbmgmt/seeds/001.php index 627f554fc515..b65b92182611 100644 --- a/user_guide_src/source/dbmgmt/seeds/001.php +++ b/user_guide_src/source/dbmgmt/seeds/001.php @@ -10,11 +10,11 @@ public function run() { $data = [ 'username' => 'darth', - 'email' => 'darth@theempire.com' + 'email' => 'darth@theempire.com', ]; // Simple Queries - $this->db->query("INSERT INTO users (username, email) VALUES(:username:, :email:)", $data); + $this->db->query('INSERT INTO users (username, email) VALUES(:username:, :email:)', $data); // Using Query Builder $this->db->table('users')->insert($data); diff --git a/user_guide_src/source/extending/events/002.php b/user_guide_src/source/extending/events/002.php index 1c28aa8dc471..00fa912bd45a 100644 --- a/user_guide_src/source/extending/events/002.php +++ b/user_guide_src/source/extending/events/002.php @@ -11,7 +11,6 @@ Events::on('pre_system', 'SomeClass::someMethod'); // Use a Closure -Events::on('pre_system', function (...$params) -{ +Events::on('pre_system', static function (...$params) { // ... }); diff --git a/user_guide_src/source/extending/events/006.php b/user_guide_src/source/extending/events/006.php index 5233c94e1808..bceef2866e9e 100644 --- a/user_guide_src/source/extending/events/006.php +++ b/user_guide_src/source/extending/events/006.php @@ -2,6 +2,6 @@ \CodeIgniter\Events\Events::trigger('some_events', $foo, $bar, $baz); -Events::on('some_event', function ($foo, $bar, $baz) { +Events::on('some_event', static function ($foo, $bar, $baz) { // ... }); diff --git a/user_guide_src/source/general/common_functions/001.php b/user_guide_src/source/general/common_functions/001.php index f4d4e1521fff..eeb8da7c2069 100644 --- a/user_guide_src/source/general/common_functions/001.php +++ b/user_guide_src/source/general/common_functions/001.php @@ -1,4 +1,4 @@ find($id); } catch (\Exception $e) { - die($e->getMessage()); + exit($e->getMessage()); } diff --git a/user_guide_src/source/general/helpers/005.php b/user_guide_src/source/general/helpers/005.php index 8d58b073035b..13a7f3015387 100644 --- a/user_guide_src/source/general/helpers/005.php +++ b/user_guide_src/source/general/helpers/005.php @@ -1 +1 @@ - + $user->id, - 'ip_address' => $this->request->getIPAddress() + 'id' => $user->id, + 'ip_address' => $this->request->getIPAddress(), ]; log_message('info', 'User {id} logged into the system from {ip_address}', $info); diff --git a/user_guide_src/source/general/modules/001.php b/user_guide_src/source/general/modules/001.php index c8d49bd4d362..4ced75497590 100644 --- a/user_guide_src/source/general/modules/001.php +++ b/user_guide_src/source/general/modules/001.php @@ -11,6 +11,6 @@ class Autoload extends AutoloadConfig 'Config' => APPPATH . 'Config', 'Acme' => ROOTPATH . 'acme', ]; - + // ... } diff --git a/user_guide_src/source/general/modules/002.php b/user_guide_src/source/general/modules/002.php index 1ee3a742d9aa..c23c48890b32 100644 --- a/user_guide_src/source/general/modules/002.php +++ b/user_guide_src/source/general/modules/002.php @@ -13,6 +13,6 @@ class Autoload extends AutoloadConfig 'path/to/my/constants.php', 'path/to/my/bootstrap.php', ]; - + // ... } diff --git a/user_guide_src/source/general/modules/003.php b/user_guide_src/source/general/modules/003.php index 24accb0c737b..93601b2f1d66 100644 --- a/user_guide_src/source/general/modules/003.php +++ b/user_guide_src/source/general/modules/003.php @@ -11,6 +11,6 @@ class Autoload extends AutoloadConfig 'Config' => APPPATH . 'Config', 'Acme\Blog' => ROOTPATH . 'acme/Blog', // Change ]; - + // ... } diff --git a/user_guide_src/source/general/modules/004.php b/user_guide_src/source/general/modules/004.php index 33bbe70b086f..47a4b1bad712 100644 --- a/user_guide_src/source/general/modules/004.php +++ b/user_guide_src/source/general/modules/004.php @@ -7,6 +7,6 @@ class Modules extends BaseModules { public $discoverInComposer = false; - + // ... } diff --git a/user_guide_src/source/general/modules/007.php b/user_guide_src/source/general/modules/007.php index 06038f690a8c..0030a0885214 100644 --- a/user_guide_src/source/general/modules/007.php +++ b/user_guide_src/source/general/modules/007.php @@ -1,5 +1,5 @@ group('blog', ['namespace' => 'Acme\Blog\Controllers'], function ($routes) { +$routes->group('blog', ['namespace' => 'Acme\Blog\Controllers'], static function ($routes) { $routes->get('/', 'Blog::index'); }); diff --git a/user_guide_src/source/helpers/array_helper/002.php b/user_guide_src/source/helpers/array_helper/002.php index 50ce70084c86..8dde5d7a181b 100644 --- a/user_guide_src/source/helpers/array_helper/002.php +++ b/user_guide_src/source/helpers/array_helper/002.php @@ -7,6 +7,6 @@ ], 'bar' => [ 'baz' => 23, - ] - ] + ], + ], ]; diff --git a/user_guide_src/source/helpers/array_helper/008.php b/user_guide_src/source/helpers/array_helper/008.php index 14c6213b8410..64342dc6da9b 100644 --- a/user_guide_src/source/helpers/array_helper/008.php +++ b/user_guide_src/source/helpers/array_helper/008.php @@ -6,7 +6,7 @@ 'team_id' => 5, 'position' => 1, 'team' => [ - 'id' => 5, + 'id' => 5, 'order' => 1, ], ], @@ -15,7 +15,7 @@ 'team_id' => 5, 'position' => 4, 'team' => [ - 'id' => 5, + 'id' => 5, 'order' => 1, ], ], @@ -24,7 +24,7 @@ 'team_id' => 2, 'position' => 3, 'team' => [ - 'id' => 1, + 'id' => 1, 'order' => 2, ], ], diff --git a/user_guide_src/source/helpers/filesystem_helper/010.php b/user_guide_src/source/helpers/filesystem_helper/010.php index 9c703479fe68..51db194b6d63 100644 --- a/user_guide_src/source/helpers/filesystem_helper/010.php +++ b/user_guide_src/source/helpers/filesystem_helper/010.php @@ -1,3 +1,3 @@ 'shirts', - 'onChange' => 'some_function();' + 'onChange' => 'some_function();', ]; echo form_dropdown('shirts', $options, 'large', $js); diff --git a/user_guide_src/source/helpers/form_helper/022.php b/user_guide_src/source/helpers/form_helper/022.php index a8ca201db3e3..77fea178b64c 100644 --- a/user_guide_src/source/helpers/form_helper/022.php +++ b/user_guide_src/source/helpers/form_helper/022.php @@ -2,7 +2,7 @@ $attributes = [ 'id' => 'address_info', - 'class' => 'address_info' + 'class' => 'address_info', ]; echo form_fieldset('Address Information', $attributes); @@ -11,7 +11,7 @@ ?> - +
    Address Information

    form content here

    diff --git a/user_guide_src/source/helpers/form_helper/025.php b/user_guide_src/source/helpers/form_helper/025.php index d889aab62591..3929501e40fb 100644 --- a/user_guide_src/source/helpers/form_helper/025.php +++ b/user_guide_src/source/helpers/form_helper/025.php @@ -5,7 +5,7 @@ 'id' => 'newsletter', 'value' => 'accept', 'checked' => true, - 'style' => 'margin:10px' + 'style' => 'margin:10px', ]; echo form_checkbox($data); diff --git a/user_guide_src/source/helpers/form_helper/029.php b/user_guide_src/source/helpers/form_helper/029.php index c05370129514..9344463584f6 100644 --- a/user_guide_src/source/helpers/form_helper/029.php +++ b/user_guide_src/source/helpers/form_helper/029.php @@ -2,7 +2,7 @@ $attributes = [ 'class' => 'mycustomclass', - 'style' => 'color: #000;' + 'style' => 'color: #000;', ]; echo form_label('What is your Name', 'username', $attributes); diff --git a/user_guide_src/source/helpers/form_helper/031.php b/user_guide_src/source/helpers/form_helper/031.php index 671a69fcf6d8..c95d783fc985 100644 --- a/user_guide_src/source/helpers/form_helper/031.php +++ b/user_guide_src/source/helpers/form_helper/031.php @@ -1,4 +1,4 @@ Content diff --git a/user_guide_src/source/helpers/html_helper/011.php b/user_guide_src/source/helpers/html_helper/011.php index 0d15fc0e6c69..126fd86c4952 100644 --- a/user_guide_src/source/helpers/html_helper/011.php +++ b/user_guide_src/source/helpers/html_helper/011.php @@ -1,6 +1,6 @@ 'js/printer.js']; +$script = ['src' => 'js/printer.js']; echo script_tag($script); // diff --git a/user_guide_src/source/helpers/html_helper/013.php b/user_guide_src/source/helpers/html_helper/013.php index 435ebc5535d2..113ecbbaf6c6 100644 --- a/user_guide_src/source/helpers/html_helper/013.php +++ b/user_guide_src/source/helpers/html_helper/013.php @@ -20,9 +20,9 @@ 'sphere', ], ], - 'moods' => [ + 'moods' => [ 'happy', - 'upset' => [ + 'upset' => [ 'defeated' => [ 'dejected', 'disheartened', @@ -31,8 +31,8 @@ 'annoyed', 'cross', 'angry', - ] - ] + ], + ], ]; echo ul($list, $attributes); diff --git a/user_guide_src/source/helpers/html_helper/014.php b/user_guide_src/source/helpers/html_helper/014.php index 505b771d5f1b..e61c2db89e12 100644 --- a/user_guide_src/source/helpers/html_helper/014.php +++ b/user_guide_src/source/helpers/html_helper/014.php @@ -2,7 +2,7 @@ $tracks = [ track('subtitles_no.vtt', 'subtitles', 'no', 'Norwegian No'), - track('subtitles_yes.vtt', 'subtitles', 'yes', 'Norwegian Yes') + track('subtitles_yes.vtt', 'subtitles', 'yes', 'Norwegian Yes'), ]; echo video('test.mp4', 'Your browser does not support the video tag.', 'controls'); @@ -14,13 +14,14 @@ $tracks ); -echo video([ - source('movie.mp4', 'video/mp4', 'class="test"'), - source('movie.ogg', 'video/ogg'), - source('movie.mov', 'video/quicktime'), - source('movie.ogv', 'video/ogv; codecs=dirac, speex') -], +echo video( + [ + source('movie.mp4', 'video/mp4', 'class="test"'), + source('movie.ogg', 'video/ogg'), + source('movie.mov', 'video/quicktime'), + source('movie.ogv', 'video/ogv; codecs=dirac, speex'), + ], 'Your browser does not support the video tag.', 'class="test" controls', $tracks - ); +); diff --git a/user_guide_src/source/helpers/html_helper/017.php b/user_guide_src/source/helpers/html_helper/017.php index a0b38b79e672..1ff7fb45ba01 100644 --- a/user_guide_src/source/helpers/html_helper/017.php +++ b/user_guide_src/source/helpers/html_helper/017.php @@ -8,6 +8,6 @@ 'class="test"', [ param('foo', 'bar', 'ref', 'class="test"'), - param('hello', 'world', 'ref', 'class="test"') + param('hello', 'world', 'ref', 'class="test"'), ] ); diff --git a/user_guide_src/source/helpers/text_helper/006.php b/user_guide_src/source/helpers/text_helper/006.php index 4c564c6da0f6..3327d2e2176d 100644 --- a/user_guide_src/source/helpers/text_helper/006.php +++ b/user_guide_src/source/helpers/text_helper/006.php @@ -1,4 +1,4 @@ "Is your name O\'reilly?", - 'answer' => "No, my name is O\'connor." + 'question' => "Is your name O\\'reilly?", + 'answer' => "No, my name is O\\'connor.", ]; $str = strip_slashes($str); diff --git a/user_guide_src/source/helpers/text_helper/008.php b/user_guide_src/source/helpers/text_helper/008.php index 073f97ff0046..c4cd2f1c53ca 100644 --- a/user_guide_src/source/helpers/text_helper/008.php +++ b/user_guide_src/source/helpers/text_helper/008.php @@ -2,5 +2,5 @@ [ 'question' => "Is your name O'reilly?", - 'answer' => "No, my name is O'connor." + 'answer' => "No, my name is O'connor.", ]; diff --git a/user_guide_src/source/helpers/text_helper/009.php b/user_guide_src/source/helpers/text_helper/009.php index 8081482f17eb..60f35bc49ead 100644 --- a/user_guide_src/source/helpers/text_helper/009.php +++ b/user_guide_src/source/helpers/text_helper/009.php @@ -1,4 +1,4 @@ ', ''); +$string = 'Here is a nice text string about nothing in particular.'; +echo highlight_phrase($string, 'nice text', '', ''); diff --git a/user_guide_src/source/helpers/text_helper/020.php b/user_guide_src/source/helpers/text_helper/020.php index 2a4f595f3655..8b2606aea1bf 100644 --- a/user_guide_src/source/helpers/text_helper/020.php +++ b/user_guide_src/source/helpers/text_helper/020.php @@ -1,6 +1,6 @@ getHeaderLine('accept-encoding'); +echo 'Accept-Encoding: ' . $request->getHeaderLine('accept-encoding'); diff --git a/user_guide_src/source/incoming/incomingrequest/019.php b/user_guide_src/source/incoming/incomingrequest/019.php index 14e917083397..a31ffd384853 100644 --- a/user_guide_src/source/incoming/incomingrequest/019.php +++ b/user_guide_src/source/incoming/incomingrequest/019.php @@ -1,3 +1,3 @@ resource('photos'); // Equivalent to the following: -$routes->get('photos/new', 'Photos::new'); -$routes->post('photos', 'Photos::create'); -$routes->get('photos', 'Photos::index'); -$routes->get('photos/(:segment)', 'Photos::show/$1'); +$routes->get('photos/new', 'Photos::new'); +$routes->post('photos', 'Photos::create'); +$routes->get('photos', 'Photos::index'); +$routes->get('photos/(:segment)', 'Photos::show/$1'); $routes->get('photos/(:segment)/edit', 'Photos::edit/$1'); -$routes->put('photos/(:segment)', 'Photos::update/$1'); -$routes->patch('photos/(:segment)', 'Photos::update/$1'); -$routes->delete('photos/(:segment)', 'Photos::delete/$1'); +$routes->put('photos/(:segment)', 'Photos::update/$1'); +$routes->patch('photos/(:segment)', 'Photos::update/$1'); +$routes->delete('photos/(:segment)', 'Photos::delete/$1'); diff --git a/user_guide_src/source/incoming/restful/002.php b/user_guide_src/source/incoming/restful/002.php index cc879a2ab667..67ce23393964 100644 --- a/user_guide_src/source/incoming/restful/002.php +++ b/user_guide_src/source/incoming/restful/002.php @@ -4,4 +4,4 @@ // The following equivalent routes are created: $routes->post('photos/(:segment)/delete', 'Photos::delete/$1'); -$routes->post('photos/(:segment)', 'Photos::update/$1'); +$routes->post('photos/(:segment)', 'Photos::update/$1'); diff --git a/user_guide_src/source/incoming/restful/003.php b/user_guide_src/source/incoming/restful/003.php index 1485f3c4edea..6610555f0a5f 100644 --- a/user_guide_src/source/incoming/restful/003.php +++ b/user_guide_src/source/incoming/restful/003.php @@ -1,6 +1,6 @@ resource('photos', ['controller' =>'App\Gallery']); +$routes->resource('photos', ['controller' => 'App\Gallery']); // Would create routes like: $routes->get('photos', 'App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/009.php b/user_guide_src/source/incoming/restful/009.php index 5918a044fab5..25e069258781 100644 --- a/user_guide_src/source/incoming/restful/009.php +++ b/user_guide_src/source/incoming/restful/009.php @@ -3,13 +3,13 @@ $routes->presenter('photos'); // Equivalent to the following: -$routes->get('photos/new', 'Photos::new'); -$routes->post('photos/create', 'Photos::create'); -$routes->post('photos', 'Photos::create'); // alias -$routes->get('photos', 'Photos::index'); -$routes->get('photos/show/(:segment)', 'Photos::show/$1'); -$routes->get('photos/(:segment)', 'Photos::show/$1'); // alias -$routes->get('photos/edit/(:segment)', 'Photos::edit/$1'); +$routes->get('photos/new', 'Photos::new'); +$routes->post('photos/create', 'Photos::create'); +$routes->post('photos', 'Photos::create'); // alias +$routes->get('photos', 'Photos::index'); +$routes->get('photos/show/(:segment)', 'Photos::show/$1'); +$routes->get('photos/(:segment)', 'Photos::show/$1'); // alias +$routes->get('photos/edit/(:segment)', 'Photos::edit/$1'); $routes->post('photos/update/(:segment)', 'Photos::update/$1'); -$routes->get('photos/remove/(:segment)', 'Photos::remove/$1'); +$routes->get('photos/remove/(:segment)', 'Photos::remove/$1'); $routes->post('photos/delete/(:segment)', 'Photos::delete/$1'); diff --git a/user_guide_src/source/incoming/restful/011.php b/user_guide_src/source/incoming/restful/011.php index 5c949d80cc29..cbb6f13bdf85 100644 --- a/user_guide_src/source/incoming/restful/011.php +++ b/user_guide_src/source/incoming/restful/011.php @@ -1,6 +1,6 @@ presenter('photos', ['controller' =>'App\Gallery']); +$routes->presenter('photos', ['controller' => 'App\Gallery']); // Would create routes like: $routes->get('photos', 'App\Gallery::index'); diff --git a/user_guide_src/source/incoming/restful/015.php b/user_guide_src/source/incoming/restful/015.php index fc5713b20d61..0600f7c686ef 100644 --- a/user_guide_src/source/incoming/restful/015.php +++ b/user_guide_src/source/incoming/restful/015.php @@ -6,7 +6,6 @@ class Photos extends ResourcePresenter { - protected $modelName = 'App\Models\Photos'; public function index() diff --git a/user_guide_src/source/incoming/routing/002.php b/user_guide_src/source/incoming/routing/002.php index 4ddfd31abaed..030ac6d25045 100644 --- a/user_guide_src/source/incoming/routing/002.php +++ b/user_guide_src/source/incoming/routing/002.php @@ -4,4 +4,4 @@ $routes->get('users', 'Users::list'); // Calls $Users->list(1, 23) -$routes->get('users/1/23', 'Users::list/1/23'); \ No newline at end of file +$routes->get('users/1/23', 'Users::list/1/23'); diff --git a/user_guide_src/source/incoming/routing/016.php b/user_guide_src/source/incoming/routing/016.php index 2d0f48cb284e..e4fc5bde4a68 100644 --- a/user_guide_src/source/incoming/routing/016.php +++ b/user_guide_src/source/incoming/routing/016.php @@ -1,6 +1,6 @@ get('feed', function () { +$routes->get('feed', static function () { $rss = new RSSFeeder(); return $rss->feed('general'); diff --git a/user_guide_src/source/incoming/routing/019.php b/user_guide_src/source/incoming/routing/019.php index 8c770fd05f24..6f08c319c551 100644 --- a/user_guide_src/source/incoming/routing/019.php +++ b/user_guide_src/source/incoming/routing/019.php @@ -1,6 +1,6 @@ group('admin', function ($routes) { +$routes->group('admin', static function ($routes) { $routes->get('users', 'Admin\Users::index'); $routes->get('blog', 'Admin\Blog::index'); }); diff --git a/user_guide_src/source/incoming/routing/020.php b/user_guide_src/source/incoming/routing/020.php index 678e90700e74..7c66c3b693dd 100644 --- a/user_guide_src/source/incoming/routing/020.php +++ b/user_guide_src/source/incoming/routing/020.php @@ -1,5 +1,5 @@ group('api', ['namespace' => 'App\API\v1'], function ($routes) { +$routes->group('api', ['namespace' => 'App\API\v1'], static function ($routes) { $routes->resource('users'); }); diff --git a/user_guide_src/source/incoming/routing/021.php b/user_guide_src/source/incoming/routing/021.php index 395ddfe6c8c8..75cec09100cb 100644 --- a/user_guide_src/source/incoming/routing/021.php +++ b/user_guide_src/source/incoming/routing/021.php @@ -1,5 +1,5 @@ group('api', ['filter' => 'api-auth'], function ($routes) { +$routes->group('api', ['filter' => 'api-auth'], static function ($routes) { $routes->resource('users'); }); diff --git a/user_guide_src/source/incoming/routing/022.php b/user_guide_src/source/incoming/routing/022.php index 08169acec275..1ed2a8a96ee6 100644 --- a/user_guide_src/source/incoming/routing/022.php +++ b/user_guide_src/source/incoming/routing/022.php @@ -1,7 +1,7 @@ group('admin', function ($routes) { - $routes->group('users', function ($routes) { +$routes->group('admin', static function ($routes) { + $routes->group('users', static function ($routes) { $routes->get('list', 'Admin\Users::list'); }); }); diff --git a/user_guide_src/source/incoming/routing/024.php b/user_guide_src/source/incoming/routing/024.php index 69a4c184ab36..53921b33f5eb 100644 --- a/user_guide_src/source/incoming/routing/024.php +++ b/user_guide_src/source/incoming/routing/024.php @@ -1,5 +1,5 @@ environment('development', function ($routes) { +$routes->environment('development', static function ($routes) { $routes->get('builder', 'Tools\Builder::index'); }); diff --git a/user_guide_src/source/incoming/routing/025.php b/user_guide_src/source/incoming/routing/025.php index 3379179f4be1..e6bc6bdfb65f 100644 --- a/user_guide_src/source/incoming/routing/025.php +++ b/user_guide_src/source/incoming/routing/025.php @@ -5,6 +5,6 @@ ?> - + View Gallery diff --git a/user_guide_src/source/incoming/routing/026.php b/user_guide_src/source/incoming/routing/026.php index 604e9f95b26e..1c1c629893e3 100644 --- a/user_guide_src/source/incoming/routing/026.php +++ b/user_guide_src/source/incoming/routing/026.php @@ -5,6 +5,6 @@ ?> - + View Gallery diff --git a/user_guide_src/source/incoming/routing/029.php b/user_guide_src/source/incoming/routing/029.php index fad1213d3f22..ff7e995a1526 100644 --- a/user_guide_src/source/incoming/routing/029.php +++ b/user_guide_src/source/incoming/routing/029.php @@ -11,4 +11,4 @@ $routes->match(['get', 'put'], 'from', 'to', $options); $routes->resource('photos', $options); $routes->map($array, $options); -$routes->group('name', $options, function (){}); +$routes->group('name', $options, static function () {}); diff --git a/user_guide_src/source/incoming/routing/030.php b/user_guide_src/source/incoming/routing/030.php index ca1121e0786d..2515937bb02a 100644 --- a/user_guide_src/source/incoming/routing/030.php +++ b/user_guide_src/source/incoming/routing/030.php @@ -1,3 +1,3 @@ get('admin',' AdminController::index', ['filter' => 'admin-auth']); +$routes->get('admin', ' AdminController::index', ['filter' => 'admin-auth']); diff --git a/user_guide_src/source/incoming/routing/032.php b/user_guide_src/source/incoming/routing/032.php index 14d5142de2f0..dd6cd63ba61d 100644 --- a/user_guide_src/source/incoming/routing/032.php +++ b/user_guide_src/source/incoming/routing/032.php @@ -1,3 +1,3 @@ get('admin',' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); +$routes->get('admin', ' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); diff --git a/user_guide_src/source/incoming/routing/033.php b/user_guide_src/source/incoming/routing/033.php index 24cf6c5dbc2d..94ae43246897 100644 --- a/user_guide_src/source/incoming/routing/033.php +++ b/user_guide_src/source/incoming/routing/033.php @@ -1,3 +1,3 @@ get('admin',' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); +$routes->get('admin', ' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); diff --git a/user_guide_src/source/incoming/routing/047.php b/user_guide_src/source/incoming/routing/047.php index 1f3758e244d4..dddd067f0f26 100644 --- a/user_guide_src/source/incoming/routing/047.php +++ b/user_guide_src/source/incoming/routing/047.php @@ -4,7 +4,6 @@ $routes->set404Override('App\Errors::show404'); // Will display a custom view -$routes->set404Override(function () -{ +$routes->set404Override(static function () { echo view('my_errors/not_found.html'); }); diff --git a/user_guide_src/source/installation/troubleshooting/001.php b/user_guide_src/source/installation/troubleshooting/001.php index 65f74aae9efc..54f5c279f554 100644 --- a/user_guide_src/source/installation/troubleshooting/001.php +++ b/user_guide_src/source/installation/troubleshooting/001.php @@ -7,8 +7,8 @@ class App extends BaseConfig { // ... - + public $indexPage = 'index.php'; - + // ... } diff --git a/user_guide_src/source/installation/upgrade_database/002.php b/user_guide_src/source/installation/upgrade_database/002.php index 65fdc4c24d1b..18a1e627fe80 100644 --- a/user_guide_src/source/installation/upgrade_database/002.php +++ b/user_guide_src/source/installation/upgrade_database/002.php @@ -3,6 +3,6 @@ $builder = $db->table('mytable'); $query = $builder->select('title') - ->where('id', $id) - ->limit(10, 20) - ->get(); + ->where('id', $id) + ->limit(10, 20) + ->get(); diff --git a/user_guide_src/source/installation/upgrade_encryption/002.php b/user_guide_src/source/installation/upgrade_encryption/002.php index 91b00ee54e83..695d69e24a28 100644 --- a/user_guide_src/source/installation/upgrade_encryption/002.php +++ b/user_guide_src/source/installation/upgrade_encryption/002.php @@ -2,7 +2,7 @@ $encrypter = service('encrypter'); -$plainText = 'This is a plain-text message!'; +$plainText = 'This is a plain-text message!'; $ciphertext = $encrypter->encrypt($plainText); // Outputs: This is a plain-text message! diff --git a/user_guide_src/source/installation/upgrade_file_upload/002.php b/user_guide_src/source/installation/upgrade_file_upload/002.php index 29de4bf665dc..6a4e6c88e250 100644 --- a/user_guide_src/source/installation/upgrade_file_upload/002.php +++ b/user_guide_src/source/installation/upgrade_file_upload/002.php @@ -2,8 +2,8 @@ namespace App\Controllers; -class Upload extends BaseController { - +class Upload extends BaseController +{ public function index() { echo view('upload_form', ['error' => ' ']); @@ -14,13 +14,13 @@ public function do_upload() $this->validate([ 'userfile' => 'uploaded[userfile]|max_size[userfile,100]' . '|mime_in[userfile,image/png,image/jpg,image/gif]' - . '|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]' + . '|ext_in[userfile,png,jpg,gif]|max_dims[userfile,1024,768]', ]); $file = $this->request->getFile('userfile'); if (! $path = $file->store()) { - echo view('upload_form', ['error' => "upload failed"]); + echo view('upload_form', ['error' => 'upload failed']); } else { $data = ['upload_file_path' => $path]; diff --git a/user_guide_src/source/installation/upgrade_localization/001.php b/user_guide_src/source/installation/upgrade_localization/001.php index 731d1c5f2430..7248a03e3c72 100644 --- a/user_guide_src/source/installation/upgrade_localization/001.php +++ b/user_guide_src/source/installation/upgrade_localization/001.php @@ -7,8 +7,8 @@ class App extends BaseConfig { // ... - + public $defaultLocale = 'en'; - + // ... } diff --git a/user_guide_src/source/installation/upgrade_validations/001.php b/user_guide_src/source/installation/upgrade_validations/001.php index f9730b8f3e3f..36ec03941532 100644 --- a/user_guide_src/source/installation/upgrade_validations/001.php +++ b/user_guide_src/source/installation/upgrade_validations/001.php @@ -3,5 +3,5 @@ $isValid = $this->validate([ 'name' => 'required|min_length[3]', 'email' => 'required|valid_email', - 'phone' => 'required|numeric|max_length[10]' + 'phone' => 'required|numeric|max_length[10]', ]); diff --git a/user_guide_src/source/installation/upgrade_view_parser/002.php b/user_guide_src/source/installation/upgrade_view_parser/002.php index 2f4607092635..6bef47ef69ec 100644 --- a/user_guide_src/source/installation/upgrade_view_parser/002.php +++ b/user_guide_src/source/installation/upgrade_view_parser/002.php @@ -4,7 +4,7 @@ $data = [ 'blog_title' => 'My Blog Title', - 'blog_heading' => 'My Blog Heading' + 'blog_heading' => 'My Blog Heading', ]; echo $parser->setData($data) diff --git a/user_guide_src/source/libraries/cookies/003.php b/user_guide_src/source/libraries/cookies/003.php index 2b41c1e4209f..f878ff8592d1 100644 --- a/user_guide_src/source/libraries/cookies/003.php +++ b/user_guide_src/source/libraries/cookies/003.php @@ -4,7 +4,7 @@ use Config\Cookie as CookieConfig; $oldDefaults = Cookie::setDefaults(new CookieConfig()); -$cookie = new Cookie('my_token', 'muffins'); +$cookie = new Cookie('my_token', 'muffins'); // return the old defaults Cookie::setDefaults($oldDefaults); diff --git a/user_guide_src/source/libraries/curlrequest/003.php b/user_guide_src/source/libraries/curlrequest/003.php index 9eb5d0d1e591..5f02e4f18c00 100644 --- a/user_guide_src/source/libraries/curlrequest/003.php +++ b/user_guide_src/source/libraries/curlrequest/003.php @@ -2,6 +2,6 @@ $options = [ 'baseURI' => 'http://example.com/api/v1/', - 'timeout' => 3, + 'timeout' => 3, ]; $client = \Config\Services::curlrequest($options); diff --git a/user_guide_src/source/libraries/curlrequest/010.php b/user_guide_src/source/libraries/curlrequest/010.php index e13fa1c5e7e3..12e892980beb 100644 --- a/user_guide_src/source/libraries/curlrequest/010.php +++ b/user_guide_src/source/libraries/curlrequest/010.php @@ -5,5 +5,5 @@ // Get all headers foreach ($response->getHeaders() as $name => $value) { - echo $name .': '. $response->getHeaderLine($name) ."\n"; + echo $name . ': ' . $response->getHeaderLine($name) . "\n"; } diff --git a/user_guide_src/source/libraries/curlrequest/015.php b/user_guide_src/source/libraries/curlrequest/015.php index c8c85ee7f116..136a6ca13286 100644 --- a/user_guide_src/source/libraries/curlrequest/015.php +++ b/user_guide_src/source/libraries/curlrequest/015.php @@ -2,5 +2,5 @@ $client->request('GET', 'http://example.com', ['allow_redirects' => [ 'max' => 10, - 'protocols' => ['https'] // Force HTTPS domains only. + 'protocols' => ['https'], // Force HTTPS domains only. ]]); diff --git a/user_guide_src/source/libraries/curlrequest/017.php b/user_guide_src/source/libraries/curlrequest/017.php index fbc6302a68ec..3f6012cfb70b 100644 --- a/user_guide_src/source/libraries/curlrequest/017.php +++ b/user_guide_src/source/libraries/curlrequest/017.php @@ -1,3 +1,3 @@ setBody($body) ->request('put', 'http://example.com'); +$client->setBody($body)->request('put', 'http://example.com'); diff --git a/user_guide_src/source/libraries/email/013.php b/user_guide_src/source/libraries/email/013.php index 744360f49cc1..60147e305d34 100644 --- a/user_guide_src/source/libraries/email/013.php +++ b/user_guide_src/source/libraries/email/013.php @@ -1,12 +1,11 @@ $address) -{ +foreach ($list as $name => $address) { $email->clear(); $email->setTo($address); $email->setFrom('your@example.com'); - $email->setSubject('Here is your info '.$name); + $email->setSubject('Here is your info ' . $name); $email->setMessage('Hi ' . $name . ' Here is the info you requested.'); $email->send(); } diff --git a/user_guide_src/source/libraries/email/022.php b/user_guide_src/source/libraries/email/022.php index a6d9bfadeb70..80dcaf8d85ce 100644 --- a/user_guide_src/source/libraries/email/022.php +++ b/user_guide_src/source/libraries/email/022.php @@ -6,6 +6,6 @@ foreach ($list as $address) { $email->setTo($address); $cid = $email->setAttachmentCID($filename); - $email->setMessage('photo1'); + $email->setMessage('photo1'); $email->send(); } diff --git a/user_guide_src/source/libraries/encryption/002.php b/user_guide_src/source/libraries/encryption/002.php index c7dccced0797..62061dbd928d 100644 --- a/user_guide_src/source/libraries/encryption/002.php +++ b/user_guide_src/source/libraries/encryption/002.php @@ -1,6 +1,6 @@ encrypt($plainText); // Outputs: This is a plain-text message! diff --git a/user_guide_src/source/libraries/encryption/005.php b/user_guide_src/source/libraries/encryption/005.php index cbc92a5d1be1..df42a88d3a08 100644 --- a/user_guide_src/source/libraries/encryption/005.php +++ b/user_guide_src/source/libraries/encryption/005.php @@ -7,6 +7,6 @@ class Encryption extends BaseConfig { public $key = 'YOUR KEY'; - + // ... } diff --git a/user_guide_src/source/libraries/files/004.php b/user_guide_src/source/libraries/files/004.php index e73de3b6cd74..e3998d56af19 100644 --- a/user_guide_src/source/libraries/files/004.php +++ b/user_guide_src/source/libraries/files/004.php @@ -1,3 +1,3 @@ getSize(); // 256901 +$size = $file->getSize(); // 256901 diff --git a/user_guide_src/source/libraries/images/011.php b/user_guide_src/source/libraries/images/011.php index c72932893af8..f18fb55545a1 100644 --- a/user_guide_src/source/libraries/images/011.php +++ b/user_guide_src/source/libraries/images/011.php @@ -7,5 +7,5 @@ \Config\Services::image('imagick') ->withFile('/path/to/image/mypic.png') - ->flatten(25,25,112) + ->flatten(25, 25, 112) ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/images/014.php b/user_guide_src/source/libraries/images/014.php index 4afd1e12d420..32943ed142c6 100644 --- a/user_guide_src/source/libraries/images/014.php +++ b/user_guide_src/source/libraries/images/014.php @@ -8,6 +8,6 @@ 'withShadow' => true, 'hAlign' => 'center', 'vAlign' => 'bottom', - 'fontSize' => 20 + 'fontSize' => 20, ]) ->save('/path/to/new/image.jpg'); diff --git a/user_guide_src/source/libraries/pagination/005.php b/user_guide_src/source/libraries/pagination/005.php index 149f369b321c..dec2c3161e76 100644 --- a/user_guide_src/source/libraries/pagination/005.php +++ b/user_guide_src/source/libraries/pagination/005.php @@ -1,6 +1,6 @@ paginate(10, 'group1', $page); diff --git a/user_guide_src/source/libraries/publisher/005.php b/user_guide_src/source/libraries/publisher/005.php index 5d598c3f7d1c..d369073dd6df 100644 --- a/user_guide_src/source/libraries/publisher/005.php +++ b/user_guide_src/source/libraries/publisher/005.php @@ -3,8 +3,7 @@ use CodeIgniter\CLI\CLI; use CodeIgniter\Publisher\Publisher; -foreach (Publisher::discover() as $publisher) -{ +foreach (Publisher::discover() as $publisher) { $result = $publisher->publish(); if ($result === false) { diff --git a/user_guide_src/source/libraries/publisher/009.php b/user_guide_src/source/libraries/publisher/009.php index 4756956740bd..1e840ce9da2c 100644 --- a/user_guide_src/source/libraries/publisher/009.php +++ b/user_guide_src/source/libraries/publisher/009.php @@ -27,8 +27,6 @@ class BootstrapPublisher extends Publisher /** * Use the "publish" method to indicate that this * class is ready to be discovered and automated. - * - * @return boolean */ public function publish(): bool { diff --git a/user_guide_src/source/libraries/publisher/010.php b/user_guide_src/source/libraries/publisher/010.php index 3ea9c40e24b6..652322fd0bcb 100644 --- a/user_guide_src/source/libraries/publisher/010.php +++ b/user_guide_src/source/libraries/publisher/010.php @@ -28,6 +28,7 @@ public function run(array $params) ])->merge(false); // Be careful not to overwrite anything } catch (Throwable $e) { $this->showError($e); + return; } diff --git a/user_guide_src/source/libraries/sessions/014.php b/user_guide_src/source/libraries/sessions/014.php index 50b76d2409b5..45bce58b5e06 100644 --- a/user_guide_src/source/libraries/sessions/014.php +++ b/user_guide_src/source/libraries/sessions/014.php @@ -2,6 +2,6 @@ // returns false if the 'some_name' item doesn't exist or is null, // true otherwise: -if(isset($_SESSION['some_name'])) { +if (isset($_SESSION['some_name'])) { // ... } diff --git a/user_guide_src/source/libraries/sessions/016.php b/user_guide_src/source/libraries/sessions/016.php index ef48af6552cc..e80a0177905a 100644 --- a/user_guide_src/source/libraries/sessions/016.php +++ b/user_guide_src/source/libraries/sessions/016.php @@ -1,3 +1,3 @@ push('hobbies', ['sport'=>'tennis']); +$session->push('hobbies', ['sport' => 'tennis']); diff --git a/user_guide_src/source/libraries/sessions/029.php b/user_guide_src/source/libraries/sessions/029.php index 978341190b52..fd8d241ad069 100644 --- a/user_guide_src/source/libraries/sessions/029.php +++ b/user_guide_src/source/libraries/sessions/029.php @@ -6,6 +6,6 @@ // 'item' will be erased after 300 seconds, while 'item2' // will do so after only 240 seconds $session->markAsTempdata([ - 'item' => 300, - 'item2' => 240, + 'item' => 300, + 'item2' => 240, ]); diff --git a/user_guide_src/source/libraries/time/030.php b/user_guide_src/source/libraries/time/030.php index 929a9f272e28..243416cbbdb5 100644 --- a/user_guide_src/source/libraries/time/030.php +++ b/user_guide_src/source/libraries/time/030.php @@ -1,6 +1,6 @@ setTimestamp(strtotime('April 1, 2017')); echo $time->toDateTimeString(); // 2017-05-10 00:00:00 diff --git a/user_guide_src/source/libraries/uploaded_files/002.php b/user_guide_src/source/libraries/uploaded_files/002.php index f186d517fd96..11c6b18698d4 100644 --- a/user_guide_src/source/libraries/uploaded_files/002.php +++ b/user_guide_src/source/libraries/uploaded_files/002.php @@ -39,10 +39,9 @@ public function upload() $data = ['uploaded_flleinfo' => new File($filepath)]; return view('upload_success', $data); - } else { - $data = ['errors' => 'The file has already been moved.']; - - return view('upload_form', $data); } + $data = ['errors' => 'The file has already been moved.']; + + return view('upload_form', $data); } } diff --git a/user_guide_src/source/libraries/uploaded_files/009.php b/user_guide_src/source/libraries/uploaded_files/009.php index f37491c04821..f0be5ba1aafb 100644 --- a/user_guide_src/source/libraries/uploaded_files/009.php +++ b/user_guide_src/source/libraries/uploaded_files/009.php @@ -1,7 +1,7 @@ request->getFiles()) { - foreach($imagefile['images'] as $img) { + foreach ($imagefile['images'] as $img) { if ($img->isValid() && ! $img->hasMoved()) { $newName = $img->getRandomName(); $img->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/uri/023.php b/user_guide_src/source/libraries/uri/023.php index 8c611f066c28..34e8764cd045 100644 --- a/user_guide_src/source/libraries/uri/023.php +++ b/user_guide_src/source/libraries/uri/023.php @@ -3,6 +3,6 @@ // URI = http://example.com/users/15/profile // Prints '15' -if ($uri->getSegment(1) == 'users') { +if ($uri->getSegment(1) === 'users') { echo $uri->getSegment(2); } diff --git a/user_guide_src/source/libraries/validation/002.php b/user_guide_src/source/libraries/validation/002.php index 1cc4b9e188ab..30b845e20701 100644 --- a/user_guide_src/source/libraries/validation/002.php +++ b/user_guide_src/source/libraries/validation/002.php @@ -4,7 +4,7 @@ 'username' => 'required', 'password' => 'required|min_length[10]', 'passconf' => 'required|matches[password]', - 'email' => 'required|valid_email', + 'email' => 'required|valid_email', ])) { // ... } diff --git a/user_guide_src/source/libraries/validation/004.php b/user_guide_src/source/libraries/validation/004.php index 60b31dec6d82..01e5f9b648bd 100644 --- a/user_guide_src/source/libraries/validation/004.php +++ b/user_guide_src/source/libraries/validation/004.php @@ -1,3 +1,3 @@ 4, + 'id' => 4, 'email' => 'foo@example.com', ]; diff --git a/user_guide_src/source/libraries/validation/023.php b/user_guide_src/source/libraries/validation/023.php index 5d0618b338ee..f9ba86d1f60c 100644 --- a/user_guide_src/source/libraries/validation/023.php +++ b/user_guide_src/source/libraries/validation/023.php @@ -1,8 +1,9 @@ setRules([ +$validation->setRules( + [ 'username' => 'required|is_unique[users.username]', - 'password' => 'required|min_length[10]' + 'password' => 'required|min_length[10]', ], [ // Errors 'username' => [ diff --git a/user_guide_src/source/libraries/validation/024.php b/user_guide_src/source/libraries/validation/024.php index b6b7c7464a5d..84478a772271 100644 --- a/user_guide_src/source/libraries/validation/024.php +++ b/user_guide_src/source/libraries/validation/024.php @@ -1,6 +1,7 @@ setRules([ +$validation->setRules( + [ 'username' => [ 'label' => 'Username', 'rules' => 'required|is_unique[users.username]', @@ -14,6 +15,6 @@ 'errors' => [ 'min_length' => 'Your {field} is too short. You want to get hacked?', ], - ] + ], ] ); diff --git a/user_guide_src/source/libraries/validation/025.php b/user_guide_src/source/libraries/validation/025.php index 50bd0147aaf2..f04a161f4f47 100644 --- a/user_guide_src/source/libraries/validation/025.php +++ b/user_guide_src/source/libraries/validation/025.php @@ -1,6 +1,7 @@ setRules([ +$validation->setRules( + [ 'username' => [ 'label' => 'Rules.username', 'rules' => 'required|is_unique[users.username]', diff --git a/user_guide_src/source/libraries/validation/030.php b/user_guide_src/source/libraries/validation/030.php index 0da86ca2d054..abac67b15dec 100644 --- a/user_guide_src/source/libraries/validation/030.php +++ b/user_guide_src/source/libraries/validation/030.php @@ -2,5 +2,5 @@ $errors = [ 'username' => 'The username field must be unique.', - 'email' => 'You must provide a valid email address.' + 'email' => 'You must provide a valid email address.', ]; diff --git a/user_guide_src/source/libraries/validation/033.php b/user_guide_src/source/libraries/validation/033.php index d7a10b5071cd..282bef9aabbc 100644 --- a/user_guide_src/source/libraries/validation/033.php +++ b/user_guide_src/source/libraries/validation/033.php @@ -4,6 +4,6 @@ class MyRules { public function even(string $str): bool { - return (int) $str % 2 == 0; + return (int) $str % 2 === 0; } } diff --git a/user_guide_src/source/libraries/validation/036.php b/user_guide_src/source/libraries/validation/036.php index 491c528e87e4..9e13c663b0d7 100644 --- a/user_guide_src/source/libraries/validation/036.php +++ b/user_guide_src/source/libraries/validation/036.php @@ -28,9 +28,7 @@ public function required_with($str, string $fields, array $data): bool // Remove any keys with empty values since, that means they // weren't truly there, as far as this is concerned. - $requiredFields = array_filter($requiredFields, static function ($item) use ($data) { - return ! empty($data[$item]); - }); + $requiredFields = array_filter($requiredFields, static fn ($item) => ! empty($data[$item])); return empty($requiredFields); } diff --git a/user_guide_src/source/libraries/validation/037.php b/user_guide_src/source/libraries/validation/037.php index 089b0eeaf465..f37307b0ae07 100644 --- a/user_guide_src/source/libraries/validation/037.php +++ b/user_guide_src/source/libraries/validation/037.php @@ -3,8 +3,8 @@ // is_unique[table.field,ignore_field,ignore_value] $validation->setRules([ - 'name' => "is_unique[supplier.name,uuid, $uuid]", // is not ok - 'name' => "is_unique[supplier.name,uuid,$uuid ]", // is not ok - 'name' => "is_unique[supplier.name,uuid,$uuid]", // is ok - 'name' => "is_unique[supplier.name,uuid,{uuid}]", // is ok - see "Validation Placeholders" + 'name' => "is_unique[supplier.name,uuid, {$uuid}]", // is not ok + 'name' => "is_unique[supplier.name,uuid,{$uuid} ]", // is not ok + 'name' => "is_unique[supplier.name,uuid,{$uuid}]", // is ok + 'name' => 'is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" ]); diff --git a/user_guide_src/source/models/entities/003.php b/user_guide_src/source/models/entities/003.php index c8cfd58c14db..3b50b6691d0d 100644 --- a/user_guide_src/source/models/entities/003.php +++ b/user_guide_src/source/models/entities/003.php @@ -16,7 +16,7 @@ $userModel->save($user); // Create -$user = new \App\Entities\User(); +$user = new \App\Entities\User(); $user->username = 'foo'; $user->email = 'foo@example.com'; $userModel->save($user); diff --git a/user_guide_src/source/models/entities/017.php b/user_guide_src/source/models/entities/017.php index 422a28cd1c37..cfbd01207678 100644 --- a/user_guide_src/source/models/entities/017.php +++ b/user_guide_src/source/models/entities/017.php @@ -9,7 +9,7 @@ class CastBase64 extends BaseCast { public static function get($value, array $params = []) { - return base64_decode($value); + return base64_decode($value, true); } public static function set($value, array $params = []) diff --git a/user_guide_src/source/models/model/001.php b/user_guide_src/source/models/model/001.php index ac8ede5c3dec..c9074ddda6cd 100644 --- a/user_guide_src/source/models/model/001.php +++ b/user_guide_src/source/models/model/001.php @@ -12,5 +12,5 @@ // Create shared instance with a supplied database connection // When no namespace is given, it will search through all namespaces // the system knows about and attempt to located the UserModel class. -$db = db_connect('custom'); +$db = db_connect('custom'); $userModel = model('UserModel', true, $db); diff --git a/user_guide_src/source/models/model/007.php b/user_guide_src/source/models/model/007.php index 1c5d65b7d93e..312575c09578 100644 --- a/user_guide_src/source/models/model/007.php +++ b/user_guide_src/source/models/model/007.php @@ -1,3 +1,3 @@ find([1,2,3]); +$users = $userModel->find([1, 2, 3]); diff --git a/user_guide_src/source/models/model/010.php b/user_guide_src/source/models/model/010.php index bc654f2703c9..cdb8fe06588d 100644 --- a/user_guide_src/source/models/model/010.php +++ b/user_guide_src/source/models/model/010.php @@ -1,4 +1,4 @@ where('active', 1) - ->findAll(); + ->findAll(); diff --git a/user_guide_src/source/models/model/012.php b/user_guide_src/source/models/model/012.php index 117771f78ca8..f00b70258b05 100644 --- a/user_guide_src/source/models/model/012.php +++ b/user_guide_src/source/models/model/012.php @@ -1,4 +1,4 @@ where('deleted', 0) - ->first(); + ->first(); diff --git a/user_guide_src/source/models/model/018.php b/user_guide_src/source/models/model/018.php index 8c13a5a85e2a..a5f03a2118dc 100644 --- a/user_guide_src/source/models/model/018.php +++ b/user_guide_src/source/models/model/018.php @@ -1,6 +1,6 @@ whereIn('id', [1,2,3]) + ->whereIn('id', [1, 2, 3]) ->set(['active' => 1]) ->update(); diff --git a/user_guide_src/source/models/model/020.php b/user_guide_src/source/models/model/020.php index ebc37ee608c1..7d659c7fcd36 100644 --- a/user_guide_src/source/models/model/020.php +++ b/user_guide_src/source/models/model/020.php @@ -11,14 +11,14 @@ class Job public function __get($key) { if (property_exists($this, $key)) { - return $this->$key; + return $this->{$key}; } } public function __set($key, $value) { if (property_exists($this, $key)) { - $this->$key = $value; + $this->{$key} = $value; } } } diff --git a/user_guide_src/source/models/model/022.php b/user_guide_src/source/models/model/022.php index e1137c8fa845..0df2b39c0c66 100644 --- a/user_guide_src/source/models/model/022.php +++ b/user_guide_src/source/models/model/022.php @@ -4,7 +4,7 @@ $job = $model->find(15); // Make some changes -$job->name = "Foobar"; +$job->name = 'Foobar'; // Save the changes $model->save($job); diff --git a/user_guide_src/source/models/model/024.php b/user_guide_src/source/models/model/024.php index f6769f061142..cdac096377b2 100644 --- a/user_guide_src/source/models/model/024.php +++ b/user_guide_src/source/models/model/024.php @@ -1,3 +1,3 @@ delete([1,2,3]); +$userModel->delete([1, 2, 3]); diff --git a/user_guide_src/source/models/model/028.php b/user_guide_src/source/models/model/028.php index c9bea660de81..acffbf22be01 100644 --- a/user_guide_src/source/models/model/028.php +++ b/user_guide_src/source/models/model/028.php @@ -1,6 +1,6 @@ setValidationRule($fieldName, $fieldRules); diff --git a/user_guide_src/source/models/model/029.php b/user_guide_src/source/models/model/029.php index 15221f2505a6..b7876797a6e2 100644 --- a/user_guide_src/source/models/model/029.php +++ b/user_guide_src/source/models/model/029.php @@ -2,7 +2,7 @@ $validationRules = [ 'username' => 'required|alpha_numeric_space|min_length[3]', - 'email' => [ + 'email' => [ 'rules' => 'required|valid_email|is_unique[users.email]', 'errors' => [ 'required' => 'We really need your email.', diff --git a/user_guide_src/source/models/model/030.php b/user_guide_src/source/models/model/030.php index deca0d44f722..251f9bade2cd 100644 --- a/user_guide_src/source/models/model/030.php +++ b/user_guide_src/source/models/model/030.php @@ -1,6 +1,6 @@ 'Your name is required here', ]; diff --git a/user_guide_src/source/models/model/039.php b/user_guide_src/source/models/model/039.php index 00ab7df2a766..fa1b37d0f839 100644 --- a/user_guide_src/source/models/model/039.php +++ b/user_guide_src/source/models/model/039.php @@ -1,6 +1,6 @@ 4, - 'email' => 'foo@example.com' + 'id' => 4, + 'email' => 'foo@example.com', ]; diff --git a/user_guide_src/source/models/model/042.php b/user_guide_src/source/models/model/042.php index a3742c451104..7688fa03057f 100644 --- a/user_guide_src/source/models/model/042.php +++ b/user_guide_src/source/models/model/042.php @@ -1,5 +1,5 @@ protect(false) - ->insert($data) - ->protect(true); + ->insert($data) + ->protect(true); diff --git a/user_guide_src/source/models/model/045.php b/user_guide_src/source/models/model/045.php index 9b064dd4fbff..e4d005fb3acc 100644 --- a/user_guide_src/source/models/model/045.php +++ b/user_guide_src/source/models/model/045.php @@ -1,5 +1,5 @@ where('status', 'active') - ->orderBy('last_login', 'asc') - ->findAll(); + ->orderBy('last_login', 'asc') + ->findAll(); diff --git a/user_guide_src/source/models/model/049.php b/user_guide_src/source/models/model/049.php index 0aace6d0fc28..92493d8e47d5 100644 --- a/user_guide_src/source/models/model/049.php +++ b/user_guide_src/source/models/model/049.php @@ -1,6 +1,6 @@ chunk(100, function ($data) { +$userModel->chunk(100, static function ($data) { // do something. // $data is a single row of data. }); diff --git a/user_guide_src/source/outgoing/api_responses/007.php b/user_guide_src/source/outgoing/api_responses/007.php index 568075938d3a..4e30f3e6b6ac 100644 --- a/user_guide_src/source/outgoing/api_responses/007.php +++ b/user_guide_src/source/outgoing/api_responses/007.php @@ -1,4 +1,5 @@ insert($data); + return $this->respondCreated($user); diff --git a/user_guide_src/source/outgoing/api_responses/008.php b/user_guide_src/source/outgoing/api_responses/008.php index 5c1fe47efb65..abbd2322bcda 100644 --- a/user_guide_src/source/outgoing/api_responses/008.php +++ b/user_guide_src/source/outgoing/api_responses/008.php @@ -1,4 +1,5 @@ delete($id); + return $this->respondDeleted(['id' => $id]); diff --git a/user_guide_src/source/outgoing/api_responses/009.php b/user_guide_src/source/outgoing/api_responses/009.php index e7672d94a610..8eea1b15dfaf 100644 --- a/user_guide_src/source/outgoing/api_responses/009.php +++ b/user_guide_src/source/outgoing/api_responses/009.php @@ -1,4 +1,5 @@ respondNoContent(); diff --git a/user_guide_src/source/outgoing/localization/007.php b/user_guide_src/source/outgoing/localization/007.php index adc24e5d6242..035d13bcfb64 100644 --- a/user_guide_src/source/outgoing/localization/007.php +++ b/user_guide_src/source/outgoing/localization/007.php @@ -1,5 +1,5 @@ 'The actual message to be shown.' + 'languageKey' => 'The actual message to be shown.', ]; diff --git a/user_guide_src/source/outgoing/localization/012.php b/user_guide_src/source/outgoing/localization/012.php index 7e3990788c5b..ab4564fece6d 100644 --- a/user_guide_src/source/outgoing/localization/012.php +++ b/user_guide_src/source/outgoing/localization/012.php @@ -8,4 +8,4 @@ ]; // Displays "I have 3 apples." -echo lang('Tests.apples', [ 3 ]); +echo lang('Tests.apples', [3]); diff --git a/user_guide_src/source/outgoing/response/003.php b/user_guide_src/source/outgoing/response/003.php index e8d671f81739..e5bff8cabf2f 100644 --- a/user_guide_src/source/outgoing/response/003.php +++ b/user_guide_src/source/outgoing/response/003.php @@ -2,7 +2,7 @@ $data = [ 'success' => true, - 'id' => 123, + 'id' => 123, ]; return $this->response->setJSON($data); diff --git a/user_guide_src/source/outgoing/response/004.php b/user_guide_src/source/outgoing/response/004.php index 2777aea2795b..0497dea06e58 100644 --- a/user_guide_src/source/outgoing/response/004.php +++ b/user_guide_src/source/outgoing/response/004.php @@ -1,4 +1,4 @@ setHeader('Location', 'http://example.com') - ->setHeader('WWW-Authenticate', 'Negotiate'); + ->setHeader('WWW-Authenticate', 'Negotiate'); diff --git a/user_guide_src/source/outgoing/response/005.php b/user_guide_src/source/outgoing/response/005.php index acc3254fa49a..39276d3f80f1 100644 --- a/user_guide_src/source/outgoing/response/005.php +++ b/user_guide_src/source/outgoing/response/005.php @@ -1,4 +1,4 @@ setHeader('Cache-Control', 'no-cache') - ->appendHeader('Cache-Control', 'must-revalidate'); + ->appendHeader('Cache-Control', 'must-revalidate'); diff --git a/user_guide_src/source/outgoing/response/007.php b/user_guide_src/source/outgoing/response/007.php index c8e545831e00..9f80218ee669 100644 --- a/user_guide_src/source/outgoing/response/007.php +++ b/user_guide_src/source/outgoing/response/007.php @@ -2,4 +2,5 @@ $data = 'Here is some text!'; $name = 'mytext.txt'; + return $response->download($name, $data); diff --git a/user_guide_src/source/outgoing/response/010.php b/user_guide_src/source/outgoing/response/010.php index 724c1fb213a1..93acf62e99fa 100644 --- a/user_guide_src/source/outgoing/response/010.php +++ b/user_guide_src/source/outgoing/response/010.php @@ -3,6 +3,6 @@ $options = [ 'max-age' => 300, 's-maxage' => 900, - 'etag' => 'abcde' + 'etag' => 'abcde', ]; $this->response->setCache($options); diff --git a/user_guide_src/source/outgoing/response/013.php b/user_guide_src/source/outgoing/response/013.php index 8cebd2451096..273d72c29a1d 100644 --- a/user_guide_src/source/outgoing/response/013.php +++ b/user_guide_src/source/outgoing/response/013.php @@ -3,4 +3,4 @@ $response->addChildSrc('https://youtube.com'); // allowed $response->reportOnly(true); $response->addChildSrc('https://metube.com'); // allowed but reported -$response->addChildSrc('https://ourtube.com',false); // allowed +$response->addChildSrc('https://ourtube.com', false); // allowed diff --git a/user_guide_src/source/outgoing/response/016.php b/user_guide_src/source/outgoing/response/016.php index 38d6a8e3b690..31a4990eb9ee 100644 --- a/user_guide_src/source/outgoing/response/016.php +++ b/user_guide_src/source/outgoing/response/016.php @@ -1,3 +1,3 @@ setStatusCode(230, "Tardis initiated"); +$response->setStatusCode(230, 'Tardis initiated'); diff --git a/user_guide_src/source/outgoing/response/023.php b/user_guide_src/source/outgoing/response/023.php index 35d072f354d9..3d0855739e96 100644 --- a/user_guide_src/source/outgoing/response/023.php +++ b/user_guide_src/source/outgoing/response/023.php @@ -1,15 +1,15 @@ 'The Cookie Name', - 'value' => 'The Value', - 'expire' => '86500', - 'domain' => '.some-domain.com', - 'path' => '/', - 'prefix' => 'myprefix_', - 'secure' => true, + 'name' => 'The Cookie Name', + 'value' => 'The Value', + 'expire' => '86500', + 'domain' => '.some-domain.com', + 'path' => '/', + 'prefix' => 'myprefix_', + 'secure' => true, 'httponly' => false, - 'samesite' => 'Lax' + 'samesite' => 'Lax', ]; $response->setCookie($cookie); diff --git a/user_guide_src/source/outgoing/table/005.php b/user_guide_src/source/outgoing/table/005.php index 06eaf75d9f8d..08d6dabb1850 100644 --- a/user_guide_src/source/outgoing/table/005.php +++ b/user_guide_src/source/outgoing/table/005.php @@ -2,7 +2,7 @@ $table = new \CodeIgniter\View\Table(); -$table->setHeading(array('Name', 'Color', 'Size')); +$table->setHeading(['Name', 'Color', 'Size']); $table->addRow(['Fred', 'Blue', 'Small']); $table->addRow(['Mary', 'Red', 'Large']); diff --git a/user_guide_src/source/outgoing/table/006.php b/user_guide_src/source/outgoing/table/006.php index 2bc38b546950..a5955aa5704b 100644 --- a/user_guide_src/source/outgoing/table/006.php +++ b/user_guide_src/source/outgoing/table/006.php @@ -1,38 +1,38 @@ '', + 'table_open' => '
    ', - 'thead_open' => '', - 'thead_close' => '', + 'thead_open' => '', + 'thead_close' => '', 'heading_row_start' => '', 'heading_row_end' => '', 'heading_cell_start' => '', - 'tfoot_open' => '', - 'tfoot_close' => '', + 'tfoot_open' => '', + 'tfoot_close' => '', 'footing_row_start' => '', 'footing_row_end' => '', 'footing_cell_start' => '', - 'tbody_open' => '', - 'tbody_close' => '', + 'tbody_open' => '', + 'tbody_close' => '', - 'row_start' => '', - 'row_end' => '', - 'cell_start' => '', + 'row_start' => '', + 'row_end' => '', + 'cell_start' => '', - 'row_alt_start' => '', - 'row_alt_end' => '', - 'cell_alt_start' => '', + 'row_alt_start' => '', + 'row_alt_end' => '', + 'cell_alt_start' => '', - 'table_close' => '
    ', 'heading_cell_end' => '
    ', 'footing_cell_end' => '
    ', - 'cell_end' => '
    ', + 'cell_end' => '
    ', - 'cell_alt_end' => '
    ', + 'cell_alt_end' => '
    ' + 'table_close' => '', ]; $table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/007.php b/user_guide_src/source/outgoing/table/007.php index 307d2e9a6c26..022abfc296ad 100644 --- a/user_guide_src/source/outgoing/table/007.php +++ b/user_guide_src/source/outgoing/table/007.php @@ -1,7 +1,7 @@ '' + 'table_open' => '
    ', ]; $table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/008.php b/user_guide_src/source/outgoing/table/008.php index 9d6dbddd40c6..99f12f2b2fcd 100644 --- a/user_guide_src/source/outgoing/table/008.php +++ b/user_guide_src/source/outgoing/table/008.php @@ -1,7 +1,7 @@ '
    ' + 'table_open' => '
    ', ]; $table = new \CodeIgniter\View\Table($customSettings); diff --git a/user_guide_src/source/outgoing/table/016.php b/user_guide_src/source/outgoing/table/016.php index 307d2e9a6c26..022abfc296ad 100644 --- a/user_guide_src/source/outgoing/table/016.php +++ b/user_guide_src/source/outgoing/table/016.php @@ -1,7 +1,7 @@ '
    ' + 'table_open' => '
    ', ]; $table->setTemplate($template); diff --git a/user_guide_src/source/outgoing/table/017.php b/user_guide_src/source/outgoing/table/017.php index 41ecff5926c7..8f7b203a3344 100644 --- a/user_guide_src/source/outgoing/table/017.php +++ b/user_guide_src/source/outgoing/table/017.php @@ -1,3 +1,3 @@ setEmpty(" "); +$table->setEmpty(' '); diff --git a/user_guide_src/source/outgoing/view_parser/003.php b/user_guide_src/source/outgoing/view_parser/003.php index 0eefa68d2781..1ee48b997ae6 100644 --- a/user_guide_src/source/outgoing/view_parser/003.php +++ b/user_guide_src/source/outgoing/view_parser/003.php @@ -6,4 +6,4 @@ ]; echo $parser->setData($data) - ->render('blog_template'); + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/006.php b/user_guide_src/source/outgoing/view_parser/006.php index 1bedecc07c0a..6b1409c46c1d 100644 --- a/user_guide_src/source/outgoing/view_parser/006.php +++ b/user_guide_src/source/outgoing/view_parser/006.php @@ -13,4 +13,4 @@ ]; echo $parser->setData($data) - ->render('blog_template'); + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/007.php b/user_guide_src/source/outgoing/view_parser/007.php index 8932712a7835..032f9d55f268 100644 --- a/user_guide_src/source/outgoing/view_parser/007.php +++ b/user_guide_src/source/outgoing/view_parser/007.php @@ -1,6 +1,6 @@ query("SELECT * FROM blog"); +$query = $db->query('SELECT * FROM blog'); $data = [ 'blog_title' => 'My Blog Title', @@ -9,4 +9,4 @@ ]; echo $parser->setData($data) - ->render('blog_template'); + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/008.php b/user_guide_src/source/outgoing/view_parser/008.php index ef502cf5e3af..62be126a407d 100644 --- a/user_guide_src/source/outgoing/view_parser/008.php +++ b/user_guide_src/source/outgoing/view_parser/008.php @@ -10,4 +10,4 @@ ]; echo $parser->setData($data) - ->render('blog_template'); + ->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/010.php b/user_guide_src/source/outgoing/view_parser/010.php index 33439f861407..7fcd5bafbfec 100644 --- a/user_guide_src/source/outgoing/view_parser/010.php +++ b/user_guide_src/source/outgoing/view_parser/010.php @@ -7,8 +7,8 @@ 'location' => ['city' => 'Red City', 'planet' => 'Mars'], ]; -echo $parser->setData($data)->renderString($template, ['cascadeData'=>false]); +echo $parser->setData($data)->renderString($template, ['cascadeData' => false]); // Result: {name} lives in Red City on Mars. -echo $parser->setData($data)->renderString($template, ['cascadeData'=>true]); +echo $parser->setData($data)->renderString($template, ['cascadeData' => true]); // Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/011.php b/user_guide_src/source/outgoing/view_parser/011.php index 8030f44e8883..88e2060b1ed5 100644 --- a/user_guide_src/source/outgoing/view_parser/011.php +++ b/user_guide_src/source/outgoing/view_parser/011.php @@ -1,3 +1,3 @@ - +

    Welcome, Admin!

    diff --git a/user_guide_src/source/outgoing/view_parser/015.php b/user_guide_src/source/outgoing/view_parser/015.php index e499e9805416..c0aa68b3381f 100644 --- a/user_guide_src/source/outgoing/view_parser/015.php +++ b/user_guide_src/source/outgoing/view_parser/015.php @@ -10,9 +10,7 @@ class View extends BaseView public function __construct() { - $this->plugins['bar'] = static function (array $params = []) { - return $params[0] ?? ''; - }; + $this->plugins['bar'] = static fn (array $params = []) => $params[0] ?? ''; parent::__construct(); } diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php index 64101a6a8cfa..4e039f02a08c 100644 --- a/user_guide_src/source/outgoing/view_parser/018.php +++ b/user_guide_src/source/outgoing/view_parser/018.php @@ -1,11 +1,11 @@ 'Mr', 'firstname' => 'John', - 'lastname' => 'Doe' + 'lastname' => 'Doe', ]; echo $parser->setData($data) - ->renderString($template); + ->renderString($template); // Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php index 2570076b3018..16621ef2f190 100644 --- a/user_guide_src/source/outgoing/view_parser/019.php +++ b/user_guide_src/source/outgoing/view_parser/019.php @@ -1,11 +1,11 @@ 'Mr', 'firstname' => 'John', 'lastname' => 'Doe', ]; echo $parser->setData($data) - ->renderString($template); + ->renderString($template); // Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php index a7966a9c2bfd..9226793f280d 100644 --- a/user_guide_src/source/outgoing/view_parser/020.php +++ b/user_guide_src/source/outgoing/view_parser/020.php @@ -1,7 +1,7 @@ 'Mr', 'firstname' => 'John', 'lastname' => 'Doe', @@ -11,5 +11,5 @@ ], ]; echo $parser->setData($data) - ->renderString($template); + ->renderString($template); // Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php index 6dce1f1316e2..3c9982437a19 100644 --- a/user_guide_src/source/outgoing/view_parser/021.php +++ b/user_guide_src/source/outgoing/view_parser/021.php @@ -1,19 +1,19 @@ {title}'; -$data1 = [ +$data1 = [ ['title' => 'First Link', 'link' => '/first'], ['title' => 'Second Link', 'link' => '/second'], ]; -foreach ($data1 as $menuItem){ +foreach ($data1 as $menuItem) { $temp .= $parser->setData($menuItem)->renderString($template1); } $template2 = '
      {menuitems}
    '; -$data = [ +$data = [ 'menuitems' => $temp, ]; echo $parser->setData($data) - ->renderString($template2); + ->renderString($template2); diff --git a/user_guide_src/source/outgoing/view_parser/025.php b/user_guide_src/source/outgoing/view_parser/025.php index 76ba0b537f96..8fa85f4faa98 100644 --- a/user_guide_src/source/outgoing/view_parser/025.php +++ b/user_guide_src/source/outgoing/view_parser/025.php @@ -1,3 +1,3 @@ setVar('name','Joe','html'); +$renderer->setVar('name', 'Joe', 'html'); diff --git a/user_guide_src/source/outgoing/view_parser/026.php b/user_guide_src/source/outgoing/view_parser/026.php index a8633d5717c7..46cfd9afd818 100644 --- a/user_guide_src/source/outgoing/view_parser/026.php +++ b/user_guide_src/source/outgoing/view_parser/026.php @@ -1,3 +1,3 @@ setDelimiters('[',']'); +$renderer->setDelimiters('[', ']'); diff --git a/user_guide_src/source/outgoing/view_renderer/003.php b/user_guide_src/source/outgoing/view_renderer/003.php index c4609b018c58..04e8c18a3ca4 100644 --- a/user_guide_src/source/outgoing/view_renderer/003.php +++ b/user_guide_src/source/outgoing/view_renderer/003.php @@ -1,5 +1,5 @@ setVar('one', $one) - ->setVar('two', $two) - ->render('myView'); + ->setVar('two', $two) + ->render('myView'); diff --git a/user_guide_src/source/outgoing/view_renderer/007.php b/user_guide_src/source/outgoing/view_renderer/007.php index 1b45fef3dca5..99080056b1bc 100644 --- a/user_guide_src/source/outgoing/view_renderer/007.php +++ b/user_guide_src/source/outgoing/view_renderer/007.php @@ -1,3 +1,3 @@ setData(['name'=>'George', 'position'=>'Boss']); +$view->setData(['name' => 'George', 'position' => 'Boss']); diff --git a/user_guide_src/source/outgoing/view_renderer/008.php b/user_guide_src/source/outgoing/view_renderer/008.php index 284b58caf6be..f0b868b54bca 100644 --- a/user_guide_src/source/outgoing/view_renderer/008.php +++ b/user_guide_src/source/outgoing/view_renderer/008.php @@ -1,3 +1,3 @@ setVar('name','Joe','html'); +$view->setVar('name', 'Joe', 'html'); diff --git a/user_guide_src/source/testing/benchmark/007.php b/user_guide_src/source/testing/benchmark/007.php index c126ed4a9670..13a95ec66e29 100644 --- a/user_guide_src/source/testing/benchmark/007.php +++ b/user_guide_src/source/testing/benchmark/007.php @@ -3,11 +3,11 @@ $iterator = new \CodeIgniter\Benchmark\Iterator(); // Add a new task -$iterator->add('single_concat', function () { - $str = 'Some basic'.'little'.'string concatenation test.'; +$iterator->add('single_concat', static function () { + $str = 'Some basic' . 'little' . 'string concatenation test.'; }); // Add another task -$iterator->add('double', function ($a = 'little') { +$iterator->add('double', static function ($a = 'little') { $str = "Some basic {$little} string test."; }); diff --git a/user_guide_src/source/testing/controllers/001.php b/user_guide_src/source/testing/controllers/001.php index 9c31d5b62d00..9162fa0aeabd 100644 --- a/user_guide_src/source/testing/controllers/001.php +++ b/user_guide_src/source/testing/controllers/001.php @@ -2,11 +2,12 @@ namespace CodeIgniter; -use CodeIgniter\Test\ControllerTestTrait; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\ControllerTestTrait; use CodeIgniter\Test\DatabaseTestTrait; class TestControllerA extends CIUnitTestCase { - use ControllerTestTrait, DatabaseTestTrait; + use ControllerTestTrait; + use DatabaseTestTrait; } diff --git a/user_guide_src/source/testing/controllers/002.php b/user_guide_src/source/testing/controllers/002.php index 708f7761afbf..a21362e952a2 100644 --- a/user_guide_src/source/testing/controllers/002.php +++ b/user_guide_src/source/testing/controllers/002.php @@ -2,19 +2,20 @@ namespace CodeIgniter; -use CodeIgniter\Test\ControllerTestTrait; use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\ControllerTestTrait; use CodeIgniter\Test\DatabaseTestTrait; class TestControllerA extends CIUnitTestCase { - use ControllerTestTrait, DatabaseTestTrait; + use ControllerTestTrait; + use DatabaseTestTrait; public function testShowCategories() { $result = $this->withURI('http://example.com/categories') - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); $this->assertTrue($result->isOK()); } diff --git a/user_guide_src/source/testing/controllers/004.php b/user_guide_src/source/testing/controllers/004.php index d06bb51768c3..17b5f42590ce 100644 --- a/user_guide_src/source/testing/controllers/004.php +++ b/user_guide_src/source/testing/controllers/004.php @@ -1,4 +1,4 @@ controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/005.php b/user_guide_src/source/testing/controllers/005.php index bffc4c9c8f95..7d2864f5fcbf 100644 --- a/user_guide_src/source/testing/controllers/005.php +++ b/user_guide_src/source/testing/controllers/005.php @@ -1,8 +1,8 @@ appTimezone = 'America/Chicago'; $results = $this->withConfig($config) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/006.php b/user_guide_src/source/testing/controllers/006.php index aef7e41e071e..0fc7670487de 100644 --- a/user_guide_src/source/testing/controllers/006.php +++ b/user_guide_src/source/testing/controllers/006.php @@ -4,5 +4,5 @@ $request->setLocale($locale); $results = $this->withRequest($request) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/007.php b/user_guide_src/source/testing/controllers/007.php index 73b1d4e122c2..8f7d55448035 100644 --- a/user_guide_src/source/testing/controllers/007.php +++ b/user_guide_src/source/testing/controllers/007.php @@ -3,5 +3,5 @@ $response = new \CodeIgniter\HTTP\Response(new \Config\App()); $results = $this->withResponse($response) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/008.php b/user_guide_src/source/testing/controllers/008.php index 4ea1c84dee20..641a7f92f68b 100644 --- a/user_guide_src/source/testing/controllers/008.php +++ b/user_guide_src/source/testing/controllers/008.php @@ -3,6 +3,6 @@ $logger = new \CodeIgniter\Log\Handlers\FileHandler(); $results = $this->withResponse($response) - ->withLogger($logger) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->withLogger($logger) + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/009.php b/user_guide_src/source/testing/controllers/009.php index 4559dd8f4711..711d947b4267 100644 --- a/user_guide_src/source/testing/controllers/009.php +++ b/user_guide_src/source/testing/controllers/009.php @@ -1,5 +1,5 @@ withURI('http://example.com/forums/categories') - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/controllers/010.php b/user_guide_src/source/testing/controllers/010.php index 2cf6d9919c31..e257dcbc4928 100644 --- a/user_guide_src/source/testing/controllers/010.php +++ b/user_guide_src/source/testing/controllers/010.php @@ -3,5 +3,5 @@ $body = json_encode(['foo' => 'bar']); $results = $this->withBody($body) - ->controller(\App\Controllers\ForumController::class) - ->execute('showCategories'); + ->controller(\App\Controllers\ForumController::class) + ->execute('showCategories'); diff --git a/user_guide_src/source/testing/database/002.php b/user_guide_src/source/testing/database/002.php index 4b75aa739784..be357858ae62 100644 --- a/user_guide_src/source/testing/database/002.php +++ b/user_guide_src/source/testing/database/002.php @@ -9,14 +9,14 @@ class MyTests extends CIUnitTestCase { use DatabaseTestTrait; - public function setUp(): void + protected function setUp(): void { parent::setUp(); // Do something here.... } - public function tearDown(): void + protected function tearDown(): void { parent::tearDown(); diff --git a/user_guide_src/source/testing/database/003.php b/user_guide_src/source/testing/database/003.php index d293cce95f81..399ddfb04425 100644 --- a/user_guide_src/source/testing/database/003.php +++ b/user_guide_src/source/testing/database/003.php @@ -12,4 +12,4 @@ class MyTests extends CIUnitTestCase protected $refresh = true; protected $seed = 'TestSeeder'; protected $basePath = 'path/to/database/files'; -} \ No newline at end of file +} diff --git a/user_guide_src/source/testing/debugging/006.php b/user_guide_src/source/testing/debugging/006.php index 3140ea7e4a81..3ad25be67894 100644 --- a/user_guide_src/source/testing/debugging/006.php +++ b/user_guide_src/source/testing/debugging/006.php @@ -9,4 +9,4 @@ 'foo' => 'bar', 'bar' => 'baz', ], - ]; +]; diff --git a/user_guide_src/source/testing/fabricator/009.php b/user_guide_src/source/testing/fabricator/009.php index 9c8d366d8684..a82d6063213e 100644 --- a/user_guide_src/source/testing/fabricator/009.php +++ b/user_guide_src/source/testing/fabricator/009.php @@ -1,9 +1,9 @@ "Maynard", - 'email' => "king.alford@example.org", - 'phone' => "201-886-0269 x3767", - 'avatar' => "http://lorempixel.com/800/400/", +[ + 'first' => 'Maynard', + 'email' => 'king.alford@example.org', + 'phone' => '201-886-0269 x3767', + 'avatar' => 'http://lorempixel.com/800/400/', 'login' => null, -); +]; diff --git a/user_guide_src/source/testing/fabricator/012.php b/user_guide_src/source/testing/fabricator/012.php index 89731845f145..98e83b610318 100644 --- a/user_guide_src/source/testing/fabricator/012.php +++ b/user_guide_src/source/testing/fabricator/012.php @@ -1,12 +1,12 @@ 1, - 'first' => "Rachel", - 'email' => "bradley72@gmail.com", - 'phone' => "741-241-2356", - 'avatar' => "http://lorempixel.com/800/400/", + 'first' => 'Rachel', + 'email' => 'bradley72@gmail.com', + 'phone' => '741-241-2356', + 'avatar' => 'http://lorempixel.com/800/400/', 'login' => null, - 'created_at' => "2020-05-08 14:52:10", - 'updated_at' => "2020-05-08 14:52:10", -); + 'created_at' => '2020-05-08 14:52:10', + 'updated_at' => '2020-05-08 14:52:10', +]; diff --git a/user_guide_src/source/testing/fabricator/016.php b/user_guide_src/source/testing/fabricator/016.php index eb9edc657239..8b3f9513280d 100644 --- a/user_guide_src/source/testing/fabricator/016.php +++ b/user_guide_src/source/testing/fabricator/016.php @@ -1,17 +1,17 @@ "Bobby", - 'email' => "latta.kindel@company.org", - 'phone' => "251-806-2169", - 'avatar' => "http://lorempixel.com/800/400/", +[ + 'first' => 'Bobby', + 'email' => 'latta.kindel@company.org', + 'phone' => '251-806-2169', + 'avatar' => 'http://lorempixel.com/800/400/', 'login' => null, -); +]; -array( - 'first' => "Bobby", - 'email' => "melissa.strike@fabricon.us", - 'phone' => "525-214-2656 x23546", - 'avatar' => "http://lorempixel.com/800/400/", +[ + 'first' => 'Bobby', + 'email' => 'melissa.strike@fabricon.us', + 'phone' => '525-214-2656 x23546', + 'avatar' => 'http://lorempixel.com/800/400/', 'login' => null, -); +]; diff --git a/user_guide_src/source/testing/fabricator/018.php b/user_guide_src/source/testing/fabricator/018.php index 60599b602f6e..9eb1dbf0334d 100644 --- a/user_guide_src/source/testing/fabricator/018.php +++ b/user_guide_src/source/testing/fabricator/018.php @@ -1,17 +1,17 @@ "Bobby", - 'email' => "belingadon142@example.org", - 'phone' => "741-857-1933 x1351", - 'avatar' => "http://lorempixel.com/800/400/", +[ + 'first' => 'Bobby', + 'email' => 'belingadon142@example.org', + 'phone' => '741-857-1933 x1351', + 'avatar' => 'http://lorempixel.com/800/400/', 'login' => null, -); +]; -array( - 'first' => "Hans", - 'email' => "hoppifur@metraxalon.com", - 'phone' => "487-235-7006", - 'avatar' => "http://lorempixel.com/800/400/", +[ + 'first' => 'Hans', + 'email' => 'hoppifur@metraxalon.com', + 'phone' => '487-235-7006', + 'avatar' => 'http://lorempixel.com/800/400/', 'login' => null, -); +]; diff --git a/user_guide_src/source/testing/feature/001.php b/user_guide_src/source/testing/feature/001.php index 5449332fe266..0ab640465052 100644 --- a/user_guide_src/source/testing/feature/001.php +++ b/user_guide_src/source/testing/feature/001.php @@ -7,7 +7,8 @@ class TestFoo extends CIUnitTestCase { - use DatabaseTestTrait, FeatureTestTrait; + use DatabaseTestTrait; + use FeatureTestTrait; protected function setUp(): void { diff --git a/user_guide_src/source/testing/feature/002.php b/user_guide_src/source/testing/feature/002.php index 553aaa0bfd03..8af5fda7b7c6 100644 --- a/user_guide_src/source/testing/feature/002.php +++ b/user_guide_src/source/testing/feature/002.php @@ -6,5 +6,5 @@ // Submit a form $result = $this->call('post', 'contact', [ 'name' => 'Fred Flintstone', - 'email' => 'flintyfred@example.com' + 'email' => 'flintyfred@example.com', ]); diff --git a/user_guide_src/source/testing/overview/009.php b/user_guide_src/source/testing/overview/009.php index 115cf6bda9e4..5d69c01c16d5 100644 --- a/user_guide_src/source/testing/overview/009.php +++ b/user_guide_src/source/testing/overview/009.php @@ -1,6 +1,6 @@ response->send(); $output = ob_get_clean(); // in case you want to check the actual body -$this->assertHeaderEmitted("Set-Cookie: foo=bar"); +$this->assertHeaderEmitted('Set-Cookie: foo=bar'); diff --git a/user_guide_src/source/testing/overview/011.php b/user_guide_src/source/testing/overview/011.php index a2aa11c7bb64..10e9d4a0d31b 100644 --- a/user_guide_src/source/testing/overview/011.php +++ b/user_guide_src/source/testing/overview/011.php @@ -6,4 +6,4 @@ $this->response->send(); $output = ob_get_clean(); // in case you want to check the actual body -$this->assertHeaderNotEmitted("Set-Cookie: banana"); +$this->assertHeaderNotEmitted('Set-Cookie: banana'); From e8202c2baa7e325ae85387cf75656596081f8954 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 5 Mar 2022 08:48:32 +0900 Subject: [PATCH 1733/2325] docs: add dummy HTML tags --- user_guide_src/source/general/helpers/005.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/general/helpers/005.php b/user_guide_src/source/general/helpers/005.php index 13a7f3015387..0602338d208b 100644 --- a/user_guide_src/source/general/helpers/005.php +++ b/user_guide_src/source/general/helpers/005.php @@ -1 +1,3 @@ - + + From 170faa1f8f3491ffeb2bbdcfbc268fbafd5af187 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 6 Mar 2022 08:41:56 +0900 Subject: [PATCH 1734/2325] docs: revert method chaining indentation --- user_guide_src/source/database/query_builder/074.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/database/query_builder/074.php b/user_guide_src/source/database/query_builder/074.php index 1ce884db6e6a..3ea4d947f4a7 100644 --- a/user_guide_src/source/database/query_builder/074.php +++ b/user_guide_src/source/database/query_builder/074.php @@ -2,11 +2,11 @@ $builder->select('*')->from('my_table') ->groupStart() - ->where('a', 'a') - ->orGroupStart() - ->where('b', 'b') - ->where('c', 'c') - ->groupEnd() + ->where('a', 'a') + ->orGroupStart() + ->where('b', 'b') + ->where('c', 'c') + ->groupEnd() ->groupEnd() ->where('d', 'd') ->get(); From f8d29aeed1837bf584ba637f2fc55a74e5c48768 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 6 Mar 2022 09:46:28 +0900 Subject: [PATCH 1735/2325] docs: update @param comments --- system/Database/BaseConnection.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 134a50517ae6..6d7170dc5bb3 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -962,8 +962,9 @@ public function getConnectDuration(int $decimals = 6): string * the correct identifiers. * * @param array|string $item - * @param bool $prefixSingle Prefix an item with no segments? - * @param bool $fieldExists Supplied $item contains a field name? + * @param bool $prefixSingle Prefix a table name with no segments? + * @param bool $protectIdentifiers Protect table or column names? + * @param bool $fieldExists Supplied $item contains a column name? * * @return array|string */ From 30bc414a9e22bf886c1d186691ddce9539e5f974 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 7 Mar 2022 08:25:02 +0900 Subject: [PATCH 1736/2325] fix: table name is double prefixed when LIKE clause --- system/Database/BaseBuilder.php | 4 ++-- tests/system/Database/Builder/LikeTest.php | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 79bdf08ffb43..1d0c241903e8 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -1051,7 +1051,7 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri $bind = $this->setBind($k, "%{$v}%", $escape); } - $likeStatement = $this->_like_statement($prefix, $this->db->protectIdentifiers($k, false, $escape), $not, $bind, $insensitiveSearch); + $likeStatement = $this->_like_statement($prefix, $k, $not, $bind, $insensitiveSearch); // some platforms require an escape sequence definition for LIKE wildcards if ($escape === true && $this->db->likeEscapeStr !== '') { @@ -1073,7 +1073,7 @@ protected function _like($field, string $match = '', string $type = 'AND ', stri protected function _like_statement(?string $prefix, string $column, ?string $not, string $bind, bool $insensitiveSearch = false): string { if ($insensitiveSearch === true) { - return "{$prefix} LOWER({$column}) {$not} LIKE :{$bind}:"; + return "{$prefix} LOWER(" . $this->db->escapeIdentifiers($column) . ") {$not} LIKE :{$bind}:"; } return "{$prefix} {$column} {$not} LIKE :{$bind}:"; diff --git a/tests/system/Database/Builder/LikeTest.php b/tests/system/Database/Builder/LikeTest.php index ba7c176b7c90..2d81db2b90fa 100644 --- a/tests/system/Database/Builder/LikeTest.php +++ b/tests/system/Database/Builder/LikeTest.php @@ -183,4 +183,27 @@ public function testCaseInsensitiveLike() $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); $this->assertSame($expectedBinds, $builder->getBinds()); } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5775 + */ + public function testDBPrefixAndCoulmnWithTablename() + { + $this->db = new MockConnection(['DBPrefix' => 'db_']); + $builder = new BaseBuilder('test', $this->db); + + $builder->like('test.field', 'string'); + + $expectedSQL = <<<'SQL' + SELECT * FROM "db_test" WHERE "db_test"."field" LIKE '%string%' ESCAPE '!' + SQL; + $expectedBinds = [ + 'test.field' => [ + '%string%', + true, + ], + ]; + $this->assertSame($expectedSQL, str_replace("\n", ' ', $builder->getCompiledSelect())); + $this->assertSame($expectedBinds, $builder->getBinds()); + } } From 7509003826079c0d1056300e17796fd68a176efe Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 7 Mar 2022 08:25:33 +0900 Subject: [PATCH 1737/2325] refactor: revert unneeded workaround from #5361 --- system/Database/BaseConnection.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 6d7170dc5bb3..4f54c1980830 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -1022,8 +1022,7 @@ public function protectIdentifiers($item, bool $prefixSingle = false, ?bool $pro // // NOTE: The ! empty() condition prevents this method // from breaking when QB isn't enabled. - $firstSegment = trim($parts[0], $this->escapeChar); - if (! empty($this->aliasedTables) && in_array($firstSegment, $this->aliasedTables, true)) { + if (! empty($this->aliasedTables) && in_array($parts[0], $this->aliasedTables, true)) { if ($protectIdentifiers === true) { foreach ($parts as $key => $val) { if (! in_array($val, $this->reservedIdentifiers, true)) { From 3e52f412d024f0d50f0041d676e7c56197f5a5c0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 7 Mar 2022 08:43:59 +0900 Subject: [PATCH 1738/2325] fix: app/Config/Routes.php is loaded twice on Windows system/Config/Routes.php is loaded in app/Config/Routes.php --- system/Router/RouteCollection.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 7eded3411b7f..65bf4f4985af 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -357,9 +357,14 @@ protected function discoverRoutes() if ($this->moduleConfig->shouldDiscover('routes')) { $files = $this->fileLocator->search('Config/Routes.php'); + $excludes = [ + APPPATH . 'Config' . DIRECTORY_SEPARATOR . 'Routes.php', + SYSTEMPATH . 'Config' . DIRECTORY_SEPARATOR . 'Routes.php', + ]; + foreach ($files as $file) { // Don't include our main file again... - if ($file === APPPATH . 'Config/Routes.php') { + if (in_array($file, $excludes, true)) { continue; } From 539cdd7f7925d8f99254542cf65ddb55aa08090d Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 8 Mar 2022 01:09:50 +0000 Subject: [PATCH 1739/2325] Add User Guide deploy script --- .github/scripts/deploy-userguide | 36 ++++++++++++++++ .github/workflows/deploy-userguide.yml | 59 ++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100755 .github/scripts/deploy-userguide create mode 100644 .github/workflows/deploy-userguide.yml diff --git a/.github/scripts/deploy-userguide b/.github/scripts/deploy-userguide new file mode 100755 index 000000000000..abbb768a5017 --- /dev/null +++ b/.github/scripts/deploy-userguide @@ -0,0 +1,36 @@ +#!/bin/bash + +## Deploy codeigniter4/userguide + +# Setup variables +SOURCE=$1 +TARGET=$2 +RELEASE=$3 +VERSION=`echo "$RELEASE" | cut -c 2-` + +echo "Preparing for version $3" +echo "Merging files from $1 to $2" + +# Prepare the source +cd $SOURCE +git checkout master +cd user_guide_src +make html +make epub + +# Prepare the target +cd $TARGET +git checkout master +rm -rf docs + +# Copy files +cp -Rf ${SOURCE}/user_guide_src/build/html ./docs +cp -Rf ${SOURCE}/user_guide_src/build/epub/CodeIgniter.epub ./CodeIgniter${VERSION}.epub + +# Ensure underscore prefixed files are published +touch ${TARGET}/docs/.nojekyll + +# Commit the changes +git add . +git commit -m "Release ${RELEASE}" +git push diff --git a/.github/workflows/deploy-userguide.yml b/.github/workflows/deploy-userguide.yml new file mode 100644 index 000000000000..384eeef5186f --- /dev/null +++ b/.github/workflows/deploy-userguide.yml @@ -0,0 +1,59 @@ +# When a new Release is created, deploy relevant +# files to each of the generated repos. +name: Deploy User Guide + +on: + release: + types: [published] + +jobs: + framework: + name: Deploy to userguide + if: (github.repository == 'codeigniter4/CodeIgniter4') + runs-on: ubuntu-latest + steps: + - name: Identify + run: | + git config --global user.email "action@github.com" + git config --global user.name "${GITHUB_ACTOR}" + + - name: Checkout source + uses: actions/checkout@v3 + with: + path: source + + - name: Checkout target + uses: actions/checkout@v3 + with: + repository: codeigniter4/userguide + token: ${{ secrets.ACCESS_TOKEN }} + path: userguide + + - name: Install Sphinx + run: | + sudo apt install python3-sphinx + sudo pip3 install sphinxcontrib-phpdomain + sudo pip3 install sphinx_rtd_theme + + - name: Chmod + run: chmod +x ./source/.github/scripts/deploy-userguide + + - name: Deploy + run: ./source/.github/scripts/deploy-userguide ${GITHUB_WORKSPACE}/source ${GITHUB_WORKSPACE}/userguide ${GITHUB_REF##*/} + + - name: Release + uses: actions/github-script@v6 + with: + github-token: ${{secrets.ACCESS_TOKEN}} + script: | + const release = await github.rest.repos.getLatestRelease({ + owner: context.repo.owner, + repo: context.repo.repo + }) + github.rest.repos.createRelease({ + owner: context.repo.owner, + repo: 'userguide', + tag_name: release.data.tag_name, + name: release.data.name, + body: release.data.body + }) From 3cc2ea9ea2255a8300d20a6532f31c0d076f6128 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 8 Mar 2022 15:30:27 +0900 Subject: [PATCH 1740/2325] chore: fix php-cs-fixer version to 3.6 --- 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 42ca449ddf3c..03d3965770ba 100644 --- a/admin/framework/composer.json +++ b/admin/framework/composer.json @@ -17,7 +17,7 @@ "require-dev": { "codeigniter/coding-standard": "^1.1", "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "^3.6", + "friendsofphp/php-cs-fixer": "3.6.*", "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "phpunit/phpunit": "^9.1", diff --git a/composer.json b/composer.json index 945e9d30e723..d31045882d31 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,7 @@ "require-dev": { "codeigniter/coding-standard": "^1.1", "fakerphp/faker": "^1.9", - "friendsofphp/php-cs-fixer": "^3.6", + "friendsofphp/php-cs-fixer": "3.6.*", "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "nexusphp/tachycardia": "^1.0", From 848a72318537da4a88b5118554c478c3284d5020 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 3 Mar 2022 15:58:41 +0900 Subject: [PATCH 1741/2325] chore: add .user-guide.php-cs-fixer.dist.php and update composer cs-fix --- .php-cs-fixer.dist.php | 1 + .user-guide.php-cs-fixer.dist.php | 48 +++++++++++++++++++++++++++++++ composer.json | 2 ++ 3 files changed, 51 insertions(+) create mode 100644 .user-guide.php-cs-fixer.dist.php diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index ec0ceaeb0172..7caeaec1035c 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -30,6 +30,7 @@ ->append([ __FILE__, __DIR__ . '/.no-header.php-cs-fixer.dist.php', + __DIR__ . '/.user-guide.php-cs-fixer.dist.php', __DIR__ . '/rector.php', __DIR__ . '/spark', __DIR__ . '/user_guide_src/renumerate.php', diff --git a/.user-guide.php-cs-fixer.dist.php b/.user-guide.php-cs-fixer.dist.php new file mode 100644 index 000000000000..ba33baaf409d --- /dev/null +++ b/.user-guide.php-cs-fixer.dist.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +use CodeIgniter\CodingStandard\CodeIgniter4; +use Nexus\CsConfig\Factory; +use Nexus\CsConfig\Fixer\Comment\NoCodeSeparatorCommentFixer; +use Nexus\CsConfig\Fixer\Comment\SpaceAfterCommentStartFixer; +use Nexus\CsConfig\FixerGenerator; +use PhpCsFixer\Finder; + +$finder = Finder::create() + ->files() + ->in([ + __DIR__ . '/user_guide_src/source', + ]) + ->notPath([ + 'ci3sample/', + 'libraries/sessions/017.php', + ]); + +$overrides = [ + 'echo_tag_syntax' => false, + 'php_unit_internal_class' => false, + 'no_unused_imports' => false, + 'class_attributes_separation' => false, +]; + +$options = [ + 'cacheFile' => 'build/.user-guide.php-cs-fixer.cache', + 'finder' => $finder, + 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), + 'customRules' => [ + NoCodeSeparatorCommentFixer::name() => true, + SpaceAfterCommentStartFixer::name() => true, + ], +]; + +return Factory::create(new CodeIgniter4(), $overrides, $options)->forProjects(); diff --git a/composer.json b/composer.json index d31045882d31..ed6ff59ccad4 100644 --- a/composer.json +++ b/composer.json @@ -62,10 +62,12 @@ "analyze": "phpstan analyse", "test": "phpunit", "cs": [ + "php-cs-fixer fix --verbose --dry-run --diff --config=.user-guide.php-cs-fixer.dist.php", "php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php", "php-cs-fixer fix --verbose --dry-run --diff" ], "cs-fix": [ + "php-cs-fixer fix --verbose --diff --config=.user-guide.php-cs-fixer.dist.php", "php-cs-fixer fix --verbose --diff --config=.no-header.php-cs-fixer.dist.php", "php-cs-fixer fix --verbose --diff" ] From e7095469ef365ad6cd50a19c83352110078ff478 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 4 Mar 2022 09:36:15 +0900 Subject: [PATCH 1742/2325] chore: add checking on user guide PHP coding style --- admin/pre-commit | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/admin/pre-commit b/admin/pre-commit index 4f1e7d11f544..e8fdcff64499 100644 --- a/admin/pre-commit +++ b/admin/pre-commit @@ -63,6 +63,18 @@ if [ "$FILES" != "" ]; then echo "Files in system, tests, utils, or root are not following the coding standards. Please fix them before commit." exit 1 fi + + # Next, run on user_guide_src/source PHP files + if [ -d /proc/cygdrive ]; then + ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.user-guide.php-cs-fixer.dist.php + else + php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.user-guide.php-cs-fixer.dist.php + fi + + if [ $? != 0 ]; then + echo "Files in user_guide_src/source are not following the coding standards. Please fix them before commit." + exit 1 + fi fi if [ "$STAGED_RST_FILES" != "" ]; then From 24b2210fdc1596a5e4e867f84175fd70d85048b7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 6 Mar 2022 08:45:27 +0900 Subject: [PATCH 1743/2325] docs: add file to exclude very special method chaining --- .user-guide.php-cs-fixer.dist.php | 1 + 1 file changed, 1 insertion(+) diff --git a/.user-guide.php-cs-fixer.dist.php b/.user-guide.php-cs-fixer.dist.php index ba33baaf409d..7a48f922f1d7 100644 --- a/.user-guide.php-cs-fixer.dist.php +++ b/.user-guide.php-cs-fixer.dist.php @@ -26,6 +26,7 @@ ->notPath([ 'ci3sample/', 'libraries/sessions/017.php', + 'database/query_builder/074.php', ]); $overrides = [ From 03354eed49cd344dbecfc2e141d47d06fd2f28eb Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 8 Mar 2022 18:52:43 +0900 Subject: [PATCH 1744/2325] chore: add coding style check for user_guide/ in GitHub Action --- .github/workflows/test-coding-standards.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-coding-standards.yml b/.github/workflows/test-coding-standards.yml index 4e9509f4fb2e..c966d9e1e603 100644 --- a/.github/workflows/test-coding-standards.yml +++ b/.github/workflows/test-coding-standards.yml @@ -56,3 +56,6 @@ jobs: - name: Run lint on `system/`, `tests`, `utils/`, and root PHP files run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --using-cache=no --diff + + - name: Run lint on `user_guide_src/source/` + run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --config=.user-guide.php-cs-fixer.dist.php --using-cache=no --diff From 5307ec4642c60f51b6427b2d6fbc51c6a06f25e0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 9 Mar 2022 09:10:01 +0900 Subject: [PATCH 1745/2325] docs: add TOC --- user_guide_src/source/extending/basecontroller.rst | 4 ++++ user_guide_src/source/extending/core_classes.rst | 4 ++++ user_guide_src/source/extending/events.rst | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/user_guide_src/source/extending/basecontroller.rst b/user_guide_src/source/extending/basecontroller.rst index 790eac099060..cdd3710a3c24 100644 --- a/user_guide_src/source/extending/basecontroller.rst +++ b/user_guide_src/source/extending/basecontroller.rst @@ -8,6 +8,10 @@ advantage of preloaded components and any additional functionality you provide: .. literalinclude:: basecontroller/001.php +.. contents:: + :local: + :depth: 2 + Preloading Components ===================== diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index fc06e2c305f8..2de8de4d961b 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -12,6 +12,10 @@ who would like to significantly alter the CodeIgniter core.** .. note:: Messing with a core system class has a lot of implications, so make sure you know what you are doing before attempting it. +.. contents:: + :local: + :depth: 2 + System Class List ================= diff --git a/user_guide_src/source/extending/events.rst b/user_guide_src/source/extending/events.rst index cf15415813a4..c14f56a11022 100644 --- a/user_guide_src/source/extending/events.rst +++ b/user_guide_src/source/extending/events.rst @@ -11,6 +11,10 @@ Events work on a *publish/subscribe* pattern, where an event, is triggered at so Other scripts can "subscribe" to that event by registering with the Events class to let it know they want to perform an action when that event is triggered. +.. contents:: + :local: + :depth: 2 + Enabling Events =============== From e234e9f734a7ba4ac889e598394edf58a06598aa Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 9 Mar 2022 09:10:29 +0900 Subject: [PATCH 1746/2325] docs: update System Class List --- user_guide_src/source/extending/core_classes.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index 2de8de4d961b..7695c55ac38d 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -21,13 +21,16 @@ System Class List The following is a list of the core system files that are invoked every time CodeIgniter runs: -* Config\\Services * CodeIgniter\\Autoloader\\Autoloader +* CodeIgniter\\CodeIgniter * CodeIgniter\\Config\\DotEnv +* CodeIgniter\\Config\\Services * CodeIgniter\\Controller * CodeIgniter\\Debug\\Exceptions * CodeIgniter\\Debug\\Timer * CodeIgniter\\Events\\Events +* CodeIgniter\\Filters\\Filters +* CodeIgniter\\HTTP\\ContentSecurityPolicy * CodeIgniter\\HTTP\\CLIRequest (if launched from command line only) * CodeIgniter\\HTTP\\IncomingRequest (if launched over HTTP) * CodeIgniter\\HTTP\\Request @@ -39,9 +42,7 @@ The following is a list of the core system files that are invoked every time Cod * CodeIgniter\\Log\\Handlers\\FileHandler * CodeIgniter\\Router\\RouteCollection * CodeIgniter\\Router\\Router -* CodeIgniter\\Security\\Security * CodeIgniter\\View\\View -* CodeIgniter\\View\\Escaper Replacing Core Classes ====================== From 43cd7c99e59993f02ebcf7d16f85ef47da2a3613 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 9 Mar 2022 09:18:07 +0900 Subject: [PATCH 1747/2325] docs: decorate classnames with '``' --- .../source/extending/core_classes.rst | 46 +++++++++---------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index 7695c55ac38d..5530421f24c5 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -21,28 +21,28 @@ System Class List The following is a list of the core system files that are invoked every time CodeIgniter runs: -* CodeIgniter\\Autoloader\\Autoloader -* CodeIgniter\\CodeIgniter -* CodeIgniter\\Config\\DotEnv -* CodeIgniter\\Config\\Services -* CodeIgniter\\Controller -* CodeIgniter\\Debug\\Exceptions -* CodeIgniter\\Debug\\Timer -* CodeIgniter\\Events\\Events -* CodeIgniter\\Filters\\Filters -* CodeIgniter\\HTTP\\ContentSecurityPolicy -* CodeIgniter\\HTTP\\CLIRequest (if launched from command line only) -* CodeIgniter\\HTTP\\IncomingRequest (if launched over HTTP) -* CodeIgniter\\HTTP\\Request -* CodeIgniter\\HTTP\\Response -* CodeIgniter\\HTTP\\Message -* CodeIgniter\\HTTP\\URI -* CodeIgniter\\Log\\Logger -* CodeIgniter\\Log\\Handlers\\BaseHandler -* CodeIgniter\\Log\\Handlers\\FileHandler -* CodeIgniter\\Router\\RouteCollection -* CodeIgniter\\Router\\Router -* CodeIgniter\\View\\View +* ``CodeIgniter\Autoloader\Autoloader`` +* ``CodeIgniter\CodeIgniter`` +* ``CodeIgniter\Config\DotEnv`` +* ``CodeIgniter\Config\Services`` +* ``CodeIgniter\Controller`` +* ``CodeIgniter\Debug\Exceptions`` +* ``CodeIgniter\Debug\Timer`` +* ``CodeIgniter\Events\Events`` +* ``CodeIgniter\Filters\Filters`` +* ``CodeIgniter\HTTP\ContentSecurityPolicy`` +* ``CodeIgniter\HTTP\CLIRequest`` (if launched from command line only) +* ``CodeIgniter\HTTP\IncomingRequest`` (if launched over HTTP) +* ``CodeIgniter\HTTP\Request`` +* ``CodeIgniter\HTTP\Response`` +* ``CodeIgniter\HTTP\Message`` +* ``CodeIgniter\HTTP\URI`` +* ``CodeIgniter\Log\Logger`` +* ``CodeIgniter\Log\Handlers\BaseHandler`` +* ``CodeIgniter\Log\Handlers\FileHandler`` +* ``CodeIgniter\Router\RouteCollection`` +* ``CodeIgniter\Router\Router`` +* ``CodeIgniter\View\View`` Replacing Core Classes ====================== @@ -69,7 +69,7 @@ identical to replacing a class with one exception: * The class declaration must extend the parent class. -For example, to extend the native RouteCollection class, you would declare your class with: +For example, to extend the native ``RouteCollection`` class, you would declare your class with: .. literalinclude:: core_classes/003.php From caa5d62484d759d3c1befab536d1ea657713c487 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 9 Mar 2022 09:18:44 +0900 Subject: [PATCH 1748/2325] docs: fix words --- user_guide_src/source/extending/core_classes.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/extending/core_classes.rst b/user_guide_src/source/extending/core_classes.rst index 5530421f24c5..8f923a2e14bd 100644 --- a/user_guide_src/source/extending/core_classes.rst +++ b/user_guide_src/source/extending/core_classes.rst @@ -19,7 +19,7 @@ who would like to significantly alter the CodeIgniter core.** System Class List ================= -The following is a list of the core system files that are invoked every time CodeIgniter runs: +The following is a list of the core system classes that are invoked every time CodeIgniter runs: * ``CodeIgniter\Autoloader\Autoloader`` * ``CodeIgniter\CodeIgniter`` @@ -48,7 +48,7 @@ Replacing Core Classes ====================== To use one of your own system classes instead of a default one, ensure that the :doc:`Autoloader <../concepts/autoloader>` -can find your class, that your new class extends the appropriate interface, and modify the appropriate +can find your class, that your new class implements the appropriate interface, and modify the appropriate :doc:`Service <../concepts/services>` to load your class in place of the core class. For example, if you have a new ``App\Libraries\RouteCollection`` class that you would like to use in place of From e80d3b9933ecf5073c11127f7917c6e253030ca5 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Tue, 8 Mar 2022 22:23:25 -0600 Subject: [PATCH 1749/2325] Extend Validation from BaseConfig so Registrars can add rules. --- app/Config/Validation.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/Config/Validation.php b/app/Config/Validation.php index 1cff0424f4de..a254c1850015 100644 --- a/app/Config/Validation.php +++ b/app/Config/Validation.php @@ -2,12 +2,13 @@ namespace Config; +use CodeIgniter\Config\BaseConfig; use CodeIgniter\Validation\CreditCardRules; use CodeIgniter\Validation\FileRules; use CodeIgniter\Validation\FormatRules; use CodeIgniter\Validation\Rules; -class Validation +class Validation extends BaseConfig { //-------------------------------------------------------------------- // Setup From 6804486d254ec67e16fa862c69422d26891bba68 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 10 Mar 2022 09:00:42 +0900 Subject: [PATCH 1750/2325] docs: fix incorrect directory name --- user_guide_src/source/extending/common.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/extending/common.rst b/user_guide_src/source/extending/common.rst index 5c5bf9c999e0..e85ca6c56ef8 100644 --- a/user_guide_src/source/extending/common.rst +++ b/user_guide_src/source/extending/common.rst @@ -4,9 +4,9 @@ Replacing Common Functions There are quite a few functions necessary to CodeIgniter that need to be loaded early for use in the core classes and thus cannot be placed into a helper. While most users will never have any need to do this, but the option to replace -these functions does exist for those who would like to significantly alter the CodeIgniter core. In the ``App\`` -directory there is a file ``Common.php``, and any functions defined in there will take precedence over the versions -found in ``system/Common.php``. This is also an opportunity to create globally-available functions you intend to +these functions does exist for those who would like to significantly alter the CodeIgniter core. In the **app/** +directory there is a file **Common.php**, and any functions defined in there will take precedence over the versions +found in **system/Common.php**. This is also an opportunity to create globally-available functions you intend to use throughout the framework. .. note:: Messing with a core system class has a lot of implications, so make sure you know what you are doing before From a4d777bdcea8a959d984c4362acc40d979a06e2a Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 10 Mar 2022 09:03:40 +0900 Subject: [PATCH 1751/2325] docs: fix incorrect event name and method name --- user_guide_src/source/extending/events.rst | 4 ++-- user_guide_src/source/extending/events/001.php | 2 +- user_guide_src/source/extending/events/002.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/extending/events.rst b/user_guide_src/source/extending/events.rst index c14f56a11022..439aaffd4718 100644 --- a/user_guide_src/source/extending/events.rst +++ b/user_guide_src/source/extending/events.rst @@ -29,8 +29,8 @@ a callable that will be run when that event is triggered: .. literalinclude:: events/001.php -In this example, whenever the **pre_controller** event is executed, an instance of ``MyClass`` is created and the -``MyFunction`` method is run. Note that the second parameter can be *any* form of +In this example, whenever the ``pre_system`` event is executed, an instance of ``MyClass`` is created and the +``myFunction()`` method is run. Note that the second parameter can be *any* form of `callable `_ that PHP recognizes: .. literalinclude:: events/002.php diff --git a/user_guide_src/source/extending/events/001.php b/user_guide_src/source/extending/events/001.php index 2a3ee317e594..3702ec7518c2 100644 --- a/user_guide_src/source/extending/events/001.php +++ b/user_guide_src/source/extending/events/001.php @@ -2,4 +2,4 @@ use CodeIgniter\Events\Events; -Events::on('pre_system', ['MyClass', 'MyFunction']); +Events::on('pre_system', ['MyClass', 'myFunction']); diff --git a/user_guide_src/source/extending/events/002.php b/user_guide_src/source/extending/events/002.php index 00fa912bd45a..ca9bf0074209 100644 --- a/user_guide_src/source/extending/events/002.php +++ b/user_guide_src/source/extending/events/002.php @@ -5,7 +5,7 @@ // Call on an instance method $user = new User(); -Events::on('pre_system', [$user, 'some_method']); +Events::on('pre_system', [$user, 'someMethod']); // Call on a static method Events::on('pre_system', 'SomeClass::someMethod'); From d8b3ed4fb47172677665b47757703fb65a9eee81 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 10 Mar 2022 09:04:50 +0900 Subject: [PATCH 1752/2325] docs: decorate classname with '``' --- 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 439aaffd4718..1b2c53a918cd 100644 --- a/user_guide_src/source/extending/events.rst +++ b/user_guide_src/source/extending/events.rst @@ -24,7 +24,7 @@ Defining an Event ================= Most events are defined within the **app/Config/Events.php** file. You can subscribe an action to an event with -the Events class' ``on()`` method. The first parameter is the name of the event to subscribe to. The second parameter is +the ``Events`` class' ``on()`` method. The first parameter is the name of the event to subscribe to. The second parameter is a callable that will be run when that event is triggered: .. literalinclude:: events/001.php From 7ea657bdff71b9ae7fbe33a5dc0e3635d8a7598e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 11 Mar 2022 08:49:34 +0900 Subject: [PATCH 1753/2325] docs: fix RST format --- user_guide_src/source/libraries/publisher.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index af683bc0afe2..55e68adc5847 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -80,6 +80,7 @@ In order to prevent modules from injecting malicious code into your projects, `` that defines which directories and file patterns are allowed as destinations. By default, files may only be published to your project (to prevent access to the rest of the filesystem), and the **public/** folder (``FCPATH``) will only receive files with the following extensions: + * Web assets: css, scss, js, map * Non-executable web files: htm, html, xml, json, webmanifest * Fonts: tff, eot, woff From 1f6e857b89fd3a81435f881a7c1b23738aba2ea3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 11 Mar 2022 08:49:52 +0900 Subject: [PATCH 1754/2325] docs: add config file path --- user_guide_src/source/libraries/publisher.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 55e68adc5847..9acf7ec48011 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -86,7 +86,7 @@ receive files with the following extensions: * Fonts: tff, eot, woff * Images: gif, jpg, jpeg, tiff, png, webp, bmp, ico, svg -If you need to add or adjust the security for your project then alter the ``$restrictions`` property of ``Config\Publisher``. +If you need to add or adjust the security for your project then alter the ``$restrictions`` property of ``Config\Publisher`` in **app/Config/Publisher.php**. ******** Examples From 7ff85e66362b2f5da8503ab2d78d40322629cdfe Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 11 Mar 2022 08:56:24 +0900 Subject: [PATCH 1755/2325] docs: add .tif --- user_guide_src/source/libraries/publisher.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 9acf7ec48011..69de79bd7464 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -84,7 +84,7 @@ receive files with the following extensions: * Web assets: css, scss, js, map * Non-executable web files: htm, html, xml, json, webmanifest * Fonts: tff, eot, woff -* Images: gif, jpg, jpeg, tiff, png, webp, bmp, ico, svg +* Images: gif, jpg, jpeg, tif, tiff, png, webp, bmp, ico, svg If you need to add or adjust the security for your project then alter the ``$restrictions`` property of ``Config\Publisher`` in **app/Config/Publisher.php**. From 43ad9b8148d42c014f890434f6febbcad64fe55d Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 11 Mar 2022 08:58:23 +0900 Subject: [PATCH 1756/2325] fix: regex for file extentions to FCPATH --- app/Config/Publisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php index f3768bc577b4..4f7cf11037f5 100644 --- a/app/Config/Publisher.php +++ b/app/Config/Publisher.php @@ -23,6 +23,6 @@ class Publisher extends BasePublisher */ public $restrictions = [ ROOTPATH => '*', - FCPATH => '#\.(?css|js|map|htm?|xml|json|webmanifest|tff|eot|woff?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|tff|eot|woff|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', ]; } From 81c588bacf1f6488e6fbe51a3d799c09390b789c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 11 Mar 2022 09:05:01 +0900 Subject: [PATCH 1757/2325] test: fix classname in comment --- tests/system/Publisher/PublisherRestrictionsTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Publisher/PublisherRestrictionsTest.php b/tests/system/Publisher/PublisherRestrictionsTest.php index a3750f1427ad..9353c1d6ccfd 100644 --- a/tests/system/Publisher/PublisherRestrictionsTest.php +++ b/tests/system/Publisher/PublisherRestrictionsTest.php @@ -25,7 +25,7 @@ final class PublisherRestrictionsTest extends CIUnitTestCase { /** - * @see Tests\Support\Config\Registrars::Publisher() + * @see \Tests\Support\Config\Registrar::Publisher() */ public function testRegistrarsNotAllowed() { From 3a0d78b664417408ed339b3b7533bba38be1e20c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 11 Mar 2022 09:05:35 +0900 Subject: [PATCH 1758/2325] test: refactor dataProvider --- tests/system/Publisher/PublisherRestrictionsTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/system/Publisher/PublisherRestrictionsTest.php b/tests/system/Publisher/PublisherRestrictionsTest.php index 9353c1d6ccfd..620a74dcf224 100644 --- a/tests/system/Publisher/PublisherRestrictionsTest.php +++ b/tests/system/Publisher/PublisherRestrictionsTest.php @@ -69,11 +69,11 @@ public function testDefaultPublicRestrictions(string $path) public function fileProvider() { - yield 'php' => ['index.php']; - - yield 'exe' => ['cat.exe']; - - yield 'flat' => ['banana']; + yield from [ + 'php' => ['index.php'], + 'exe' => ['cat.exe'], + 'flat' => ['banana'], + ]; } /** From 608fa4251ade74f87164e3656b3e245d1151e79e Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Fri, 11 Mar 2022 17:32:44 +0100 Subject: [PATCH 1759/2325] Renumerate examples. --- user_guide_src/{renumerate => renumerate.php} | 0 .../source/database/query_builder.rst | 168 +++++++++--------- .../source/database/query_builder/015.php | 9 +- .../source/database/query_builder/016.php | 9 +- .../source/database/query_builder/017.php | 6 +- .../source/database/query_builder/018.php | 12 +- .../source/database/query_builder/019.php | 10 +- .../source/database/query_builder/020.php | 4 +- .../source/database/query_builder/021.php | 4 +- .../source/database/query_builder/022.php | 7 +- .../source/database/query_builder/023.php | 6 +- .../source/database/query_builder/024.php | 3 +- .../source/database/query_builder/025.php | 4 +- .../source/database/query_builder/026.php | 3 +- .../source/database/query_builder/027.php | 10 +- .../source/database/query_builder/028.php | 10 +- .../source/database/query_builder/029.php | 6 +- .../source/database/query_builder/030.php | 10 +- .../source/database/query_builder/031.php | 10 +- .../source/database/query_builder/032.php | 10 +- .../source/database/query_builder/033.php | 10 +- .../source/database/query_builder/034.php | 10 +- .../source/database/query_builder/035.php | 10 +- .../source/database/query_builder/036.php | 10 +- .../source/database/query_builder/037.php | 9 +- .../source/database/query_builder/038.php | 3 +- .../source/database/query_builder/039.php | 6 +- .../source/database/query_builder/040.php | 6 +- .../source/database/query_builder/041.php | 5 +- .../source/database/query_builder/042.php | 3 +- .../source/database/query_builder/043.php | 4 +- .../source/database/query_builder/044.php | 5 +- .../source/database/query_builder/045.php | 4 +- .../source/database/query_builder/046.php | 5 +- .../source/database/query_builder/047.php | 5 +- .../source/database/query_builder/048.php | 4 +- .../source/database/query_builder/049.php | 4 +- .../source/database/query_builder/050.php | 5 +- .../source/database/query_builder/051.php | 10 +- .../source/database/query_builder/052.php | 10 +- .../source/database/query_builder/053.php | 10 +- .../source/database/query_builder/054.php | 10 +- .../source/database/query_builder/055.php | 10 +- .../source/database/query_builder/056.php | 10 +- .../source/database/query_builder/057.php | 10 +- .../source/database/query_builder/058.php | 9 +- .../source/database/query_builder/059.php | 3 +- .../source/database/query_builder/060.php | 6 +- .../source/database/query_builder/061.php | 6 +- .../source/database/query_builder/062.php | 5 +- .../source/database/query_builder/063.php | 4 +- .../source/database/query_builder/064.php | 5 +- .../source/database/query_builder/065.php | 5 +- .../source/database/query_builder/066.php | 4 +- .../source/database/query_builder/067.php | 3 +- .../source/database/query_builder/068.php | 8 +- .../source/database/query_builder/069.php | 7 +- .../source/database/query_builder/070.php | 4 +- .../source/database/query_builder/071.php | 6 +- .../source/database/query_builder/072.php | 5 +- .../source/database/query_builder/073.php | 2 +- .../source/database/query_builder/074.php | 15 +- .../source/database/query_builder/075.php | 22 ++- .../source/database/query_builder/076.php | 16 +- .../source/database/query_builder/077.php | 16 +- .../source/database/query_builder/078.php | 5 +- .../source/database/query_builder/079.php | 12 +- .../source/database/query_builder/080.php | 18 +- .../source/database/query_builder/081.php | 17 +- .../source/database/query_builder/082.php | 11 +- .../source/database/query_builder/083.php | 3 +- .../source/database/query_builder/084.php | 13 +- .../source/database/query_builder/085.php | 15 +- .../source/database/query_builder/086.php | 14 +- .../source/database/query_builder/087.php | 22 +-- .../source/database/query_builder/088.php | 20 +-- .../source/database/query_builder/089.php | 17 +- .../source/database/query_builder/090.php | 2 +- .../source/database/query_builder/091.php | 27 +-- .../source/database/query_builder/092.php | 28 ++- .../source/database/query_builder/093.php | 9 +- .../source/database/query_builder/094.php | 9 +- .../source/database/query_builder/095.php | 7 +- .../source/database/query_builder/096.php | 9 +- .../source/database/query_builder/097.php | 19 +- .../source/database/query_builder/098.php | 19 +- .../source/incoming/controllers.rst | 38 ++-- .../source/incoming/controllers/001.php | 7 +- .../source/incoming/controllers/002.php | 7 +- .../source/incoming/controllers/003.php | 7 +- .../source/incoming/controllers/004.php | 16 +- .../source/incoming/controllers/005.php | 19 +- .../source/incoming/controllers/006.php | 23 ++- .../source/incoming/controllers/007.php | 5 +- .../source/incoming/controllers/008.php | 10 +- .../source/incoming/controllers/009.php | 7 +- .../source/incoming/controllers/010.php | 7 +- .../source/incoming/controllers/011.php | 11 +- .../source/incoming/controllers/012.php | 19 +- .../source/incoming/controllers/013.php | 11 +- .../source/incoming/controllers/014.php | 11 +- .../source/incoming/controllers/015.php | 4 +- .../source/incoming/controllers/016.php | 7 +- .../source/incoming/controllers/017.php | 15 +- .../source/incoming/controllers/018.php | 12 +- .../source/incoming/controllers/019.php | 20 +-- user_guide_src/source/incoming/routing.rst | 80 ++++----- .../source/incoming/routing/004_1.php | 3 - .../source/incoming/routing/004_2.php | 5 - .../source/incoming/routing/004_3.php | 8 - .../source/incoming/routing/004_4.php | 8 - .../source/incoming/routing/013.php | 3 +- .../source/incoming/routing/014.php | 4 +- .../source/incoming/routing/015.php | 7 +- .../source/incoming/routing/016.php | 9 +- .../source/incoming/routing/017.php | 8 +- .../source/incoming/routing/018.php | 7 +- .../source/incoming/routing/019.php | 5 +- .../source/incoming/routing/020.php | 6 +- .../source/incoming/routing/021.php | 9 +- .../source/incoming/routing/022.php | 11 +- .../source/incoming/routing/023.php | 7 +- .../source/incoming/routing/024.php | 4 +- .../source/incoming/routing/025.php | 11 +- .../source/incoming/routing/026.php | 13 +- .../source/incoming/routing/027.php | 6 +- .../source/incoming/routing/028.php | 4 +- .../source/incoming/routing/029.php | 20 +-- .../source/incoming/routing/030.php | 9 +- .../source/incoming/routing/031.php | 2 +- .../source/incoming/routing/032.php | 2 +- .../source/incoming/routing/033.php | 13 +- .../source/incoming/routing/034.php | 3 +- .../source/incoming/routing/035.php | 2 +- .../source/incoming/routing/036.php | 3 +- .../source/incoming/routing/037.php | 3 +- .../source/incoming/routing/038.php | 6 +- .../source/incoming/routing/039.php | 11 +- .../source/incoming/routing/040.php | 3 +- .../source/incoming/routing/041.php | 9 +- .../source/incoming/routing/042.php | 9 +- .../source/incoming/routing/043.php | 12 +- .../source/incoming/routing/044.php | 2 +- .../source/incoming/routing/045.php | 8 +- .../source/incoming/routing/046.php | 8 +- .../source/incoming/routing/047.php | 9 +- .../source/incoming/routing/048.php | 6 +- .../source/incoming/routing/049.php | 3 + .../source/incoming/routing/050.php | 3 + .../source/incoming/routing/051.php | 9 + .../source/incoming/routing/052.php | 7 + user_guide_src/source/libraries/sessions.rst | 84 ++++----- .../source/libraries/sessions/002.php | 3 + .../source/libraries/sessions/003.php | 2 +- .../source/libraries/sessions/004.php | 2 +- .../source/libraries/sessions/005.php | 2 +- .../source/libraries/sessions/006.php | 2 +- .../source/libraries/sessions/007.php | 2 +- .../source/libraries/sessions/008.php | 10 +- .../source/libraries/sessions/009.php | 10 +- .../source/libraries/sessions/010.php | 4 +- .../source/libraries/sessions/011.php | 8 +- .../source/libraries/sessions/012.php | 8 +- .../source/libraries/sessions/013.php | 6 +- .../source/libraries/sessions/014.php | 6 +- .../source/libraries/sessions/015.php | 2 +- .../source/libraries/sessions/016.php | 7 +- .../source/libraries/sessions/017.php | 7 +- .../source/libraries/sessions/018.php | 3 +- .../source/libraries/sessions/019.php | 3 +- .../source/libraries/sessions/020.php | 2 +- .../source/libraries/sessions/021.php | 3 +- .../source/libraries/sessions/022.php | 3 +- .../source/libraries/sessions/023.php | 2 +- .../source/libraries/sessions/024.php | 2 +- .../source/libraries/sessions/025.php | 2 +- .../source/libraries/sessions/026.php | 3 +- .../source/libraries/sessions/027.php | 4 +- .../source/libraries/sessions/028.php | 11 +- .../source/libraries/sessions/029.php | 11 +- .../source/libraries/sessions/030.php | 3 +- .../source/libraries/sessions/031.php | 3 +- .../source/libraries/sessions/032.php | 3 +- .../source/libraries/sessions/033.php | 2 +- .../source/libraries/sessions/034.php | 2 +- .../source/libraries/sessions/035.php | 2 +- .../source/libraries/sessions/036.php | 2 +- .../source/libraries/sessions/037.php | 4 +- .../source/libraries/sessions/038.php | 4 +- .../source/libraries/sessions/039.php | 11 +- .../source/libraries/sessions/040.php | 3 +- .../source/libraries/sessions/041.php | 3 +- .../source/libraries/sessions/042.php | 4 +- .../source/libraries/sessions/043.php | 6 +- .../source/libraries/sessions/044.php | 14 -- .../source/libraries/uploaded_files.rst | 34 ++-- .../source/libraries/uploaded_files/004.php | 3 + .../source/libraries/uploaded_files/005.php | 3 + .../source/libraries/uploaded_files/006.php | 10 ++ .../source/libraries/uploaded_files/007.php | 3 +- .../source/libraries/uploaded_files/008.php | 2 +- .../source/libraries/uploaded_files/009.php | 10 +- .../source/libraries/uploaded_files/010.php | 5 +- .../source/libraries/uploaded_files/011.php | 2 +- .../source/libraries/uploaded_files/012.php | 3 +- .../source/libraries/uploaded_files/013.php | 4 +- .../source/libraries/uploaded_files/014.php | 2 +- .../source/libraries/uploaded_files/015.php | 4 +- .../source/libraries/uploaded_files/016.php | 2 +- .../source/libraries/uploaded_files/017.php | 3 +- .../source/libraries/uploaded_files/018.php | 6 +- .../source/libraries/uploaded_files/019.php | 2 +- .../source/libraries/uploaded_files/020.php | 3 +- .../source/libraries/uploaded_files/021.php | 5 - .../source/libraries/uploaded_files/022.php | 3 - .../source/libraries/uploaded_files/023.php | 3 - .../source/libraries/validation.rst | 20 +-- .../source/libraries/validation/028.2.php | 12 -- .../source/libraries/validation/029.php | 19 +- .../source/libraries/validation/030.php | 13 +- .../source/libraries/validation/031.php | 16 +- .../source/libraries/validation/032.php | 14 +- .../source/libraries/validation/033.php | 21 ++- .../source/libraries/validation/034.php | 10 +- .../source/libraries/validation/035.php | 16 +- .../source/libraries/validation/036.php | 36 +--- .../source/libraries/validation/037.php | 41 ++++- .../source/libraries/validation/038.php | 10 ++ user_guide_src/source/testing/overview.rst | 32 ++-- .../source/testing/overview/003.php | 14 ++ .../source/testing/overview/004.php | 10 +- .../source/testing/overview/005.php | 11 +- .../source/testing/overview/006.php | 22 ++- .../source/testing/overview/007.php | 22 +-- .../source/testing/overview/008.php | 10 +- .../source/testing/overview/009.php | 10 +- .../source/testing/overview/010.php | 2 +- .../source/testing/overview/011.php | 10 +- .../source/testing/overview/012.php | 2 +- .../source/testing/overview/013.php | 11 +- .../source/testing/overview/014.php | 7 +- .../source/testing/overview/015.php | 6 +- .../source/testing/overview/016.php | 17 +- .../source/testing/overview/017.php | 10 +- .../source/testing/overview/018.php | 16 +- .../source/testing/overview/019.php | 24 --- 246 files changed, 1209 insertions(+), 1209 deletions(-) rename user_guide_src/{renumerate => renumerate.php} (100%) delete mode 100644 user_guide_src/source/incoming/routing/004_1.php delete mode 100644 user_guide_src/source/incoming/routing/004_2.php delete mode 100644 user_guide_src/source/incoming/routing/004_3.php delete mode 100644 user_guide_src/source/incoming/routing/004_4.php create mode 100644 user_guide_src/source/incoming/routing/049.php create mode 100644 user_guide_src/source/incoming/routing/050.php create mode 100644 user_guide_src/source/incoming/routing/051.php create mode 100644 user_guide_src/source/incoming/routing/052.php create mode 100644 user_guide_src/source/libraries/sessions/002.php delete mode 100644 user_guide_src/source/libraries/sessions/044.php create mode 100644 user_guide_src/source/libraries/uploaded_files/004.php create mode 100644 user_guide_src/source/libraries/uploaded_files/005.php create mode 100644 user_guide_src/source/libraries/uploaded_files/006.php delete mode 100644 user_guide_src/source/libraries/uploaded_files/021.php delete mode 100644 user_guide_src/source/libraries/uploaded_files/022.php delete mode 100644 user_guide_src/source/libraries/uploaded_files/023.php delete mode 100644 user_guide_src/source/libraries/validation/028.2.php create mode 100644 user_guide_src/source/libraries/validation/038.php create mode 100644 user_guide_src/source/testing/overview/003.php delete mode 100644 user_guide_src/source/testing/overview/019.php diff --git a/user_guide_src/renumerate b/user_guide_src/renumerate.php similarity index 100% rename from user_guide_src/renumerate rename to user_guide_src/renumerate.php diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index 2df0d3a03084..d6e5b27aac36 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -159,7 +159,7 @@ the resulting field. Adds a subquery to the SELECT section. -.. literalinclude:: query_builder/098.php +.. literalinclude:: query_builder/015.php :lines: 2- From @@ -169,7 +169,7 @@ From Permits you to write the **FROM** portion of your query: -.. literalinclude:: query_builder/015.php +.. literalinclude:: query_builder/016.php .. note:: As shown earlier, the **FROM** portion of your query can be specified in the ``$db->table()`` method. Additional calls to ``from()`` will add more tables @@ -186,11 +186,11 @@ Permits you to write part of a **FROM** query as a subquery. This is where we add a subquery to an existing table: -.. literalinclude:: query_builder/016.php +.. literalinclude:: query_builder/017.php Use the ``$db->newQuery()`` method to make a subquery the main table: -.. literalinclude:: query_builder/017.php +.. literalinclude:: query_builder/018.php Join ==== @@ -199,7 +199,7 @@ Join Permits you to write the **JOIN** portion of your query: -.. literalinclude:: query_builder/018.php +.. literalinclude:: query_builder/019.php Multiple method calls can be made if you need several joins in one query. @@ -208,7 +208,7 @@ If you need a specific type of **JOIN** you can specify it via the third parameter of the method. Options are: ``left``, ``right``, ``outer``, ``inner``, ``left outer``, and ``right outer``. -.. literalinclude:: query_builder/019.php +.. literalinclude:: query_builder/020.php ************************* Looking for Specific Data @@ -227,97 +227,97 @@ methods: #. **Simple key/value method:** - .. literalinclude:: query_builder/020.php + .. literalinclude:: query_builder/021.php Notice that the equal sign is added for you. If you use multiple method calls they will be chained together with **AND** between them: - .. literalinclude:: query_builder/021.php + .. literalinclude:: query_builder/022.php #. **Custom key/value method:** You can include an operator in the first parameter in order to control the comparison: - .. literalinclude:: query_builder/022.php + .. literalinclude:: query_builder/023.php #. **Associative array method:** - .. literalinclude:: query_builder/023.php + .. literalinclude:: query_builder/024.php You can include your own operators using this method as well: - .. literalinclude:: query_builder/024.php + .. literalinclude:: query_builder/025.php #. **Custom string:** You can write your own clauses manually: - .. literalinclude:: query_builder/025.php + .. literalinclude:: query_builder/026.php .. warning:: If you are using user-supplied data within the string, you MUST escape the data manually. Failure to do so could result in SQL injections. - .. literalinclude:: query_builder/026.php + .. literalinclude:: query_builder/027.php .. _query-builder-where-subquery: 5. **Subqueries:** - .. literalinclude:: query_builder/027.php + .. literalinclude:: query_builder/028.php **$builder->orWhere()** This method is identical to the one above, except that multiple instances are joined by **OR**: -.. literalinclude:: query_builder/028.php +.. literalinclude:: query_builder/029.php **$builder->whereIn()** Generates a **WHERE** field IN ('item', 'item') SQL query joined with **AND** if appropriate: -.. literalinclude:: query_builder/029.php +.. literalinclude:: query_builder/030.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/030.php +.. literalinclude:: query_builder/031.php **$builder->orWhereIn()** Generates a **WHERE field IN ('item', 'item')** SQL query joined with **OR** if appropriate: -.. literalinclude:: query_builder/031.php +.. literalinclude:: query_builder/032.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/032.php +.. literalinclude:: query_builder/033.php **$builder->whereNotIn()** Generates a **WHERE field NOT IN ('item', 'item')** SQL query joined with **AND** if appropriate: -.. literalinclude:: query_builder/033.php +.. literalinclude:: query_builder/034.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/034.php +.. literalinclude:: query_builder/035.php **$builder->orWhereNotIn()** Generates a **WHERE field NOT IN ('item', 'item')** SQL query joined with **OR** if appropriate: -.. literalinclude:: query_builder/035.php +.. literalinclude:: query_builder/036.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/036.php +.. literalinclude:: query_builder/037.php ************************ Looking for Similar Data @@ -337,76 +337,76 @@ searches. #. **Simple key/value method:** - .. literalinclude:: query_builder/037.php + .. literalinclude:: query_builder/038.php If you use multiple method calls they will be chained together with **AND** between them: - .. literalinclude:: query_builder/038.php + .. literalinclude:: query_builder/039.php If you want to control where the wildcard (**%**) is placed, you can use an optional third argument. Your options are ``before``, ``after`` and ``both`` (which is the default). - .. literalinclude:: query_builder/039.php + .. literalinclude:: query_builder/040.php #. **Associative array method:** - .. literalinclude:: query_builder/040.php + .. literalinclude:: query_builder/041.php **$builder->orLike()** This method is identical to the one above, except that multiple instances are joined by **OR**: -.. literalinclude:: query_builder/041.php +.. literalinclude:: query_builder/042.php **$builder->notLike()** This method is identical to ``like()``, except that it generates **NOT LIKE** statements: -.. literalinclude:: query_builder/042.php +.. literalinclude:: query_builder/043.php **$builder->orNotLike()** This method is identical to ``notLike()``, except that multiple instances are joined by **OR**: -.. literalinclude:: query_builder/043.php +.. literalinclude:: query_builder/044.php **$builder->groupBy()** Permits you to write the **GROUP BY** portion of your query: -.. literalinclude:: query_builder/044.php +.. literalinclude:: query_builder/045.php You can also pass an array of multiple values as well: -.. literalinclude:: query_builder/045.php +.. literalinclude:: query_builder/046.php **$builder->distinct()** Adds the **DISTINCT** keyword to a query -.. literalinclude:: query_builder/046.php +.. literalinclude:: query_builder/047.php **$builder->having()** Permits you to write the **HAVING** portion of your query. There are 2 possible syntaxes, 1 argument or 2: -.. literalinclude:: query_builder/047.php +.. literalinclude:: query_builder/048.php You can also pass an array of multiple values as well: -.. literalinclude:: query_builder/048.php +.. literalinclude:: query_builder/049.php If you are using a database that CodeIgniter escapes queries for, you can prevent escaping content by passing an optional third argument, and setting it to ``false``. -.. literalinclude:: query_builder/049.php +.. literalinclude:: query_builder/050.php **$builder->orHaving()** @@ -417,44 +417,44 @@ Identical to ``having()``, only separates multiple clauses with **OR**. Generates a **HAVING field IN ('item', 'item')** SQL query joined with **AND** if appropriate: -.. literalinclude:: query_builder/050.php +.. literalinclude:: query_builder/051.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/051.php +.. literalinclude:: query_builder/052.php **$builder->orHavingIn()** Generates a **HAVING field IN ('item', 'item')** SQL query joined with **OR** if appropriate -.. literalinclude:: query_builder/052.php +.. literalinclude:: query_builder/053.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/053.php +.. literalinclude:: query_builder/054.php **$builder->havingNotIn()** Generates a **HAVING field NOT IN ('item', 'item')** SQL query joined with **AND** if appropriate -.. literalinclude:: query_builder/054.php +.. literalinclude:: query_builder/055.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/055.php +.. literalinclude:: query_builder/056.php **$builder->orHavingNotIn()** Generates a **HAVING field NOT IN ('item', 'item')** SQL query joined with **OR** if appropriate -.. literalinclude:: query_builder/056.php +.. literalinclude:: query_builder/057.php You can use subqueries instead of an array of values: -.. literalinclude:: query_builder/057.php +.. literalinclude:: query_builder/058.php **$builder->havingLike()** @@ -470,43 +470,43 @@ searches. #. **Simple key/value method:** - .. literalinclude:: query_builder/058.php + .. literalinclude:: query_builder/059.php If you use multiple method calls they will be chained together with **AND** between them: - .. literalinclude:: query_builder/059.php + .. literalinclude:: query_builder/060.php If you want to control where the wildcard (**%**) is placed, you can use an optional third argument. Your options are ``before``, ``after`` and ``both`` (which is the default). - .. literalinclude:: query_builder/060.php + .. literalinclude:: query_builder/061.php #. **Associative array method:** - .. literalinclude:: query_builder/061.php + .. literalinclude:: query_builder/062.php **$builder->orHavingLike()** This method is identical to the one above, except that multiple instances are joined by **OR**: -.. literalinclude:: query_builder/062.php +.. literalinclude:: query_builder/063.php **$builder->notHavingLike()** This method is identical to ``havingLike()``, except that it generates **NOT LIKE** statements: -.. literalinclude:: query_builder/063.php +.. literalinclude:: query_builder/064.php **$builder->orNotHavingLike()** This method is identical to ``notHavingLike()``, except that multiple instances are joined by **OR**: -.. literalinclude:: query_builder/064.php +.. literalinclude:: query_builder/065.php **************** Ordering Results @@ -521,20 +521,20 @@ The first parameter contains the name of the column you would like to order by. The second parameter lets you set the direction of the result. Options are ``ASC``, ``DESC`` AND ``RANDOM``. -.. literalinclude:: query_builder/065.php +.. literalinclude:: query_builder/066.php You can also pass your own string in the first parameter: -.. literalinclude:: query_builder/066.php +.. literalinclude:: query_builder/067.php Or multiple method calls can be made if you need multiple fields. -.. literalinclude:: query_builder/067.php +.. literalinclude:: query_builder/068.php If you choose the ``RANDOM`` direction option, then the first parameters will be ignored, unless you specify a numeric seed value. -.. literalinclude:: query_builder/068.php +.. literalinclude:: query_builder/069.php **************************** Limiting or Counting Results @@ -544,11 +544,11 @@ Limiting or Counting Results Lets you limit the number of rows you would like returned by the query: -.. literalinclude:: query_builder/069.php +.. literalinclude:: query_builder/070.php The second parameter lets you set a result offset. -.. literalinclude:: query_builder/070.php +.. literalinclude:: query_builder/071.php **$builder->countAllResults()** @@ -556,20 +556,20 @@ Permits you to determine the number of rows in a particular Query Builder query. Queries will accept Query Builder restrictors such as ``where()``, ``orWhere()``, ``like()``, ``orLike()``, etc. Example: -.. literalinclude:: query_builder/071.php +.. literalinclude:: query_builder/072.php However, this method also resets any field values that you may have passed to ``select()``. If you need to keep them, you can pass ``false`` as the first parameter. -.. literalinclude:: query_builder/072.php +.. literalinclude:: query_builder/073.php **$builder->countAll()** Permits you to determine the number of rows in a particular table. Example: -.. literalinclude:: query_builder/073.php +.. literalinclude:: query_builder/074.php As is in ``countAllResult()`` method, this method resets any field values that you may have passed to ``select()`` as well. If you need to keep them, you can pass ``false`` as the @@ -582,7 +582,7 @@ Query grouping Query grouping allows you to create groups of **WHERE** clauses by enclosing them in parentheses. This will allow you to create queries with complex **WHERE** clauses. Nested groups are supported. Example: -.. literalinclude:: query_builder/074.php +.. literalinclude:: query_builder/075.php .. note:: Groups need to be balanced, make sure every ``groupStart()`` is matched by a ``groupEnd()``. @@ -636,13 +636,13 @@ Generates an insert string based on the data you supply, and runs the query. You can either pass an **array** or an **object** to the method. Here is an example using an array: -.. literalinclude:: query_builder/075.php +.. literalinclude:: query_builder/076.php The first parameter is an associative array of values. Here is an example using an object: -.. literalinclude:: query_builder/076.php +.. literalinclude:: query_builder/077.php The first parameter is an object. @@ -654,7 +654,7 @@ 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: -.. literalinclude:: query_builder/077.php +.. literalinclude:: query_builder/078.php **$builder->getCompiledInsert()** @@ -663,12 +663,12 @@ Compiles the insertion query just like ``$builder->insert()`` but does not Example: -.. literalinclude:: query_builder/078.php +.. literalinclude:: query_builder/079.php The first parameter enables you to set whether or not the query builder query will be reset (by default it will be--just like ``$builder->insert()``): -.. literalinclude:: query_builder/079.php +.. literalinclude:: query_builder/080.php The reason the second query worked is that the query has not been executed using ``$builder->insert()`` which resets values or reset directly using @@ -682,7 +682,7 @@ Generates an insert string based on the data you supply, and runs the query. You can either pass an **array** or an **object** to the method. Here is an example using an array: -.. literalinclude:: query_builder/080.php +.. literalinclude:: query_builder/081.php The first parameter is an associative array of values. @@ -703,7 +703,7 @@ logics with different combinations of ``select()``, ``update()``, Example: -.. literalinclude:: query_builder/081.php +.. literalinclude:: query_builder/082.php In the above example, if we assume that the ``title`` field is our primary key, then if a row containing ``My title`` as the ``title`` value, that row @@ -719,27 +719,27 @@ This method enables you to set values for inserts or updates. **It can be used instead of passing a data array directly to the insert() or update() methods:** -.. literalinclude:: query_builder/082.php +.. literalinclude:: query_builder/083.php If you use multiple method called they will be assembled properly based on whether you are doing an insert or an update: -.. literalinclude:: query_builder/083.php +.. literalinclude:: query_builder/084.php ``set()`` will also accept an optional third parameter (``$escape``), that will prevent data from being escaped if set to ``false``. To illustrate the difference, here is ``set()`` used both with and without the escape parameter. -.. literalinclude:: query_builder/084.php +.. literalinclude:: query_builder/085.php You can also pass an associative array to this method: -.. literalinclude:: query_builder/085.php +.. literalinclude:: query_builder/086.php Or an object: -.. literalinclude:: query_builder/086.php +.. literalinclude:: query_builder/087.php **$builder->update()** @@ -747,11 +747,11 @@ Generates an update string and runs the query based on the data you supply. You can pass an **array** or an **object** to the method. Here is an example using an array: -.. literalinclude:: query_builder/087.php +.. literalinclude:: query_builder/088.php Or you can supply an object: -.. literalinclude:: query_builder/088.php +.. literalinclude:: query_builder/089.php .. note:: All values are escaped automatically producing safer queries. @@ -759,11 +759,11 @@ You'll notice the use of the ``$builder->where()`` method, enabling you to set the **WHERE** clause. You can optionally pass this information directly into the ``update()`` method as a string: -.. literalinclude:: query_builder/089.php +.. literalinclude:: query_builder/090.php Or as an array: -.. literalinclude:: query_builder/090.php +.. literalinclude:: query_builder/091.php You may also use the ``$builder->set()`` method described above when performing updates. @@ -774,7 +774,7 @@ Generates an update string based on the data you supply, and runs the query. You can either pass an **array** or an **object** to the method. Here is an example using an array: -.. literalinclude:: query_builder/091.php +.. literalinclude:: query_builder/092.php The first parameter is an associative array of values, the second parameter is the where key. @@ -801,13 +801,13 @@ Deleting Data Generates a **DELETE** SQL string and runs the query. -.. literalinclude:: query_builder/092.php +.. literalinclude:: query_builder/093.php The first parameter is the where clause. You can also use the ``where()`` or ``or_where()`` methods instead of passing the data to the first parameter of the method: -.. literalinclude:: query_builder/093.php +.. literalinclude:: query_builder/094.php If you want to delete all data from a table, you can use the ``truncate()`` method, or ``emptyTable()``. @@ -817,13 +817,13 @@ method, or ``emptyTable()``. Generates a **DELETE** SQL string and runs the query: -.. literalinclude:: query_builder/094.php +.. literalinclude:: query_builder/095.php **$builder->truncate()** Generates a **TRUNCATE** SQL string and runs the query. -.. literalinclude:: query_builder/095.php +.. literalinclude:: query_builder/096.php .. note:: If the TRUNCATE command isn't available, ``truncate()`` will execute as "DELETE FROM table". @@ -842,7 +842,7 @@ Method Chaining Method chaining allows you to simplify your syntax by connecting multiple methods. Consider this example: -.. literalinclude:: query_builder/096.php +.. literalinclude:: query_builder/097.php .. _ar-caching: @@ -859,7 +859,7 @@ This is useful in situations where you are using Query Builder to generate SQL (e.g., ``$builder->getCompiledSelect()``) but then choose to, for instance, run the query: -.. literalinclude:: query_builder/097.php +.. literalinclude:: query_builder/098.php *************** Class Reference diff --git a/user_guide_src/source/database/query_builder/015.php b/user_guide_src/source/database/query_builder/015.php index 727a7e5bd3e8..b3890e978005 100644 --- a/user_guide_src/source/database/query_builder/015.php +++ b/user_guide_src/source/database/query_builder/015.php @@ -1,7 +1,6 @@ table('users'); -$builder->select('title, content, date'); -$builder->from('mytable'); -$query = $builder->get(); -// Produces: SELECT title, content, date FROM users, mytable +$subquery = $db->table('countries')->select('name')->where('id', 1); +$builder = $db->table('users')->select('name')->selectSubquery($subquery, 'country'); +$query = $builder->get(); +// Produces: SELECT `name`, (SELECT `name` FROM `countries` WHERE `id` = 1) AS `country` FROM `users` diff --git a/user_guide_src/source/database/query_builder/016.php b/user_guide_src/source/database/query_builder/016.php index 1ad1c917ff57..727a7e5bd3e8 100644 --- a/user_guide_src/source/database/query_builder/016.php +++ b/user_guide_src/source/database/query_builder/016.php @@ -1,6 +1,7 @@ table('users'); -$builder = $db->table('jobs')->fromSubquery($subquery, 'alias'); -$query = $builder->get(); -// Produces: SELECT * FROM `jobs`, (SELECT * FROM `users`) AS `alias` +$builder = $db->table('users'); +$builder->select('title, content, date'); +$builder->from('mytable'); +$query = $builder->get(); +// Produces: SELECT title, content, date FROM users, mytable diff --git a/user_guide_src/source/database/query_builder/017.php b/user_guide_src/source/database/query_builder/017.php index b33dd475b6f8..1ad1c917ff57 100644 --- a/user_guide_src/source/database/query_builder/017.php +++ b/user_guide_src/source/database/query_builder/017.php @@ -1,6 +1,6 @@ table('users')->select('id, name'); -$builder = $db->newQuery()->fromSubquery($subquery, 't'); +$subquery = $db->table('users'); +$builder = $db->table('jobs')->fromSubquery($subquery, 'alias'); $query = $builder->get(); -// Produces: SELECT * FROM (SELECT `id`, `name` FROM users) AS `t` +// Produces: SELECT * FROM `jobs`, (SELECT * FROM `users`) AS `alias` diff --git a/user_guide_src/source/database/query_builder/018.php b/user_guide_src/source/database/query_builder/018.php index 159f88e4a984..b33dd475b6f8 100644 --- a/user_guide_src/source/database/query_builder/018.php +++ b/user_guide_src/source/database/query_builder/018.php @@ -1,10 +1,6 @@ table('blogs'); -$builder->select('*'); -$builder->join('comments', 'comments.id = blogs.id'); -$query = $builder->get(); -/* - * Produces: - * SELECT * FROM blogs JOIN comments ON comments.id = blogs.id - */ +$subquery = $db->table('users')->select('id, name'); +$builder = $db->newQuery()->fromSubquery($subquery, 't'); +$query = $builder->get(); +// Produces: SELECT * FROM (SELECT `id`, `name` FROM users) AS `t` diff --git a/user_guide_src/source/database/query_builder/019.php b/user_guide_src/source/database/query_builder/019.php index 428451dfb822..159f88e4a984 100644 --- a/user_guide_src/source/database/query_builder/019.php +++ b/user_guide_src/source/database/query_builder/019.php @@ -1,4 +1,10 @@ join('comments', 'comments.id = blogs.id', 'left'); -// Produces: LEFT JOIN comments ON comments.id = blogs.id +$builder = $db->table('blogs'); +$builder->select('*'); +$builder->join('comments', 'comments.id = blogs.id'); +$query = $builder->get(); +/* + * Produces: + * SELECT * FROM blogs JOIN comments ON comments.id = blogs.id + */ diff --git a/user_guide_src/source/database/query_builder/020.php b/user_guide_src/source/database/query_builder/020.php index cf0ce1b24ff2..428451dfb822 100644 --- a/user_guide_src/source/database/query_builder/020.php +++ b/user_guide_src/source/database/query_builder/020.php @@ -1,4 +1,4 @@ where('name', $name); -// Produces: WHERE name = 'Joe' +$builder->join('comments', 'comments.id = blogs.id', 'left'); +// Produces: LEFT JOIN comments ON comments.id = blogs.id diff --git a/user_guide_src/source/database/query_builder/021.php b/user_guide_src/source/database/query_builder/021.php index 08d3c63f40d5..cf0ce1b24ff2 100644 --- a/user_guide_src/source/database/query_builder/021.php +++ b/user_guide_src/source/database/query_builder/021.php @@ -1,6 +1,4 @@ where('name', $name); -$builder->where('title', $title); -$builder->where('status', $status); -// WHERE name = 'Joe' AND title = 'boss' AND status = 'active' +// Produces: WHERE name = 'Joe' diff --git a/user_guide_src/source/database/query_builder/022.php b/user_guide_src/source/database/query_builder/022.php index e6950008ff68..08d3c63f40d5 100644 --- a/user_guide_src/source/database/query_builder/022.php +++ b/user_guide_src/source/database/query_builder/022.php @@ -1,5 +1,6 @@ where('name !=', $name); -$builder->where('id <', $id); -// Produces: WHERE name != 'Joe' AND id < 45 +$builder->where('name', $name); +$builder->where('title', $title); +$builder->where('status', $status); +// WHERE name = 'Joe' AND title = 'boss' AND status = 'active' diff --git a/user_guide_src/source/database/query_builder/023.php b/user_guide_src/source/database/query_builder/023.php index 36fdf370be96..e6950008ff68 100644 --- a/user_guide_src/source/database/query_builder/023.php +++ b/user_guide_src/source/database/query_builder/023.php @@ -1,5 +1,5 @@ $name, 'title' => $title, 'status' => $status]; -$builder->where($array); -// Produces: WHERE name = 'Joe' AND title = 'boss' AND status = 'active' +$builder->where('name !=', $name); +$builder->where('id <', $id); +// Produces: WHERE name != 'Joe' AND id < 45 diff --git a/user_guide_src/source/database/query_builder/024.php b/user_guide_src/source/database/query_builder/024.php index d136a85683a9..36fdf370be96 100644 --- a/user_guide_src/source/database/query_builder/024.php +++ b/user_guide_src/source/database/query_builder/024.php @@ -1,4 +1,5 @@ $name, 'id <' => $id, 'date >' => $date]; +$array = ['name' => $name, 'title' => $title, 'status' => $status]; $builder->where($array); +// Produces: WHERE name = 'Joe' AND title = 'boss' AND status = 'active' diff --git a/user_guide_src/source/database/query_builder/025.php b/user_guide_src/source/database/query_builder/025.php index 10175cc40a71..d136a85683a9 100644 --- a/user_guide_src/source/database/query_builder/025.php +++ b/user_guide_src/source/database/query_builder/025.php @@ -1,4 +1,4 @@ where($where); +$array = ['name !=' => $name, 'id <' => $id, 'date >' => $date]; +$builder->where($array); diff --git a/user_guide_src/source/database/query_builder/026.php b/user_guide_src/source/database/query_builder/026.php index ed45b84bf363..10175cc40a71 100644 --- a/user_guide_src/source/database/query_builder/026.php +++ b/user_guide_src/source/database/query_builder/026.php @@ -1,5 +1,4 @@ db->escape('Joe'); -$where = "name={$name} AND status='boss' OR status='active'"; +$where = "name='Joe' AND status='boss' OR status='active'"; $builder->where($where); diff --git a/user_guide_src/source/database/query_builder/027.php b/user_guide_src/source/database/query_builder/027.php index 019386718cd1..ed45b84bf363 100644 --- a/user_guide_src/source/database/query_builder/027.php +++ b/user_guide_src/source/database/query_builder/027.php @@ -1,9 +1,5 @@ where('advance_amount <', static fn (BaseBuilder $builder) => $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2)); -// Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) - -// With builder directly -$subQuery = $db->table('orders')->select('MAX(advance_amount)', false)->where('id >', 2); -$builder->where('advance_amount <', $subQuery); +$name = $builder->db->escape('Joe'); +$where = "name={$name} AND status='boss' OR status='active'"; +$builder->where($where); diff --git a/user_guide_src/source/database/query_builder/028.php b/user_guide_src/source/database/query_builder/028.php index d925a347e428..019386718cd1 100644 --- a/user_guide_src/source/database/query_builder/028.php +++ b/user_guide_src/source/database/query_builder/028.php @@ -1,5 +1,9 @@ where('name !=', $name); -$builder->orWhere('id >', $id); -// Produces: WHERE name != 'Joe' OR id > 50 +// With closure +$builder->where('advance_amount <', static fn (BaseBuilder $builder) => $builder->select('MAX(advance_amount)', false)->from('orders')->where('id >', 2)); +// Produces: WHERE "advance_amount" < (SELECT MAX(advance_amount) FROM "orders" WHERE "id" > 2) + +// With builder directly +$subQuery = $db->table('orders')->select('MAX(advance_amount)', false)->where('id >', 2); +$builder->where('advance_amount <', $subQuery); diff --git a/user_guide_src/source/database/query_builder/029.php b/user_guide_src/source/database/query_builder/029.php index 6683a842eb99..d925a347e428 100644 --- a/user_guide_src/source/database/query_builder/029.php +++ b/user_guide_src/source/database/query_builder/029.php @@ -1,5 +1,5 @@ whereIn('username', $names); -// Produces: WHERE username IN ('Frank', 'Todd', 'James') +$builder->where('name !=', $name); +$builder->orWhere('id >', $id); +// Produces: WHERE name != 'Joe' OR id > 50 diff --git a/user_guide_src/source/database/query_builder/030.php b/user_guide_src/source/database/query_builder/030.php index 5aa7619c0dc8..6683a842eb99 100644 --- a/user_guide_src/source/database/query_builder/030.php +++ b/user_guide_src/source/database/query_builder/030.php @@ -1,9 +1,5 @@ whereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); -// Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); -$builder->whereIn('id', $subQuery); +$names = ['Frank', 'Todd', 'James']; +$builder->whereIn('username', $names); +// Produces: WHERE username IN ('Frank', 'Todd', 'James') diff --git a/user_guide_src/source/database/query_builder/031.php b/user_guide_src/source/database/query_builder/031.php index b1fea4626937..5aa7619c0dc8 100644 --- a/user_guide_src/source/database/query_builder/031.php +++ b/user_guide_src/source/database/query_builder/031.php @@ -1,5 +1,9 @@ orWhereIn('username', $names); -// Produces: OR username IN ('Frank', 'Todd', 'James') +// With closure +$builder->whereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +// Produces: WHERE "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); +$builder->whereIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/032.php b/user_guide_src/source/database/query_builder/032.php index ae8ddb7ce7a4..b1fea4626937 100644 --- a/user_guide_src/source/database/query_builder/032.php +++ b/user_guide_src/source/database/query_builder/032.php @@ -1,9 +1,5 @@ orWhereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); -// Produces: OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); -$builder->orWhereIn('id', $subQuery); +$names = ['Frank', 'Todd', 'James']; +$builder->orWhereIn('username', $names); +// Produces: OR username IN ('Frank', 'Todd', 'James') diff --git a/user_guide_src/source/database/query_builder/033.php b/user_guide_src/source/database/query_builder/033.php index 46b196764e71..ae8ddb7ce7a4 100644 --- a/user_guide_src/source/database/query_builder/033.php +++ b/user_guide_src/source/database/query_builder/033.php @@ -1,5 +1,9 @@ whereNotIn('username', $names); -// Produces: WHERE username NOT IN ('Frank', 'Todd', 'James') +// With closure +$builder->orWhereIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +// Produces: OR "id" IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); +$builder->orWhereIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/034.php b/user_guide_src/source/database/query_builder/034.php index 02904a3962f3..46b196764e71 100644 --- a/user_guide_src/source/database/query_builder/034.php +++ b/user_guide_src/source/database/query_builder/034.php @@ -1,9 +1,5 @@ whereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); -// Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); -$builder->whereNotIn('id', $subQuery); +$names = ['Frank', 'Todd', 'James']; +$builder->whereNotIn('username', $names); +// Produces: WHERE username NOT IN ('Frank', 'Todd', 'James') diff --git a/user_guide_src/source/database/query_builder/035.php b/user_guide_src/source/database/query_builder/035.php index d37209c5efd8..02904a3962f3 100644 --- a/user_guide_src/source/database/query_builder/035.php +++ b/user_guide_src/source/database/query_builder/035.php @@ -1,5 +1,9 @@ orWhereNotIn('username', $names); -// Produces: OR username NOT IN ('Frank', 'Todd', 'James') +// With closure +$builder->whereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +// Produces: WHERE "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); +$builder->whereNotIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/036.php b/user_guide_src/source/database/query_builder/036.php index f5668aa1a30d..d37209c5efd8 100644 --- a/user_guide_src/source/database/query_builder/036.php +++ b/user_guide_src/source/database/query_builder/036.php @@ -1,9 +1,5 @@ orWhereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); -// Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); -$builder->orWhereNotIn('id', $subQuery); +$names = ['Frank', 'Todd', 'James']; +$builder->orWhereNotIn('username', $names); +// Produces: OR username NOT IN ('Frank', 'Todd', 'James') diff --git a/user_guide_src/source/database/query_builder/037.php b/user_guide_src/source/database/query_builder/037.php index d5218d2f8f59..f5668aa1a30d 100644 --- a/user_guide_src/source/database/query_builder/037.php +++ b/user_guide_src/source/database/query_builder/037.php @@ -1,4 +1,9 @@ like('title', 'match'); -// Produces: WHERE `title` LIKE '%match%' ESCAPE '!' +// With closure +$builder->orWhereNotIn('id', static fn (BaseBuilder $builder) => $builder->select('job_id')->from('users_jobs')->where('user_id', 3)); +// Produces: OR "id" NOT IN (SELECT "job_id" FROM "users_jobs" WHERE "user_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('job_id')->where('user_id', 3); +$builder->orWhereNotIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/038.php b/user_guide_src/source/database/query_builder/038.php index a8ae3efa1d27..d5218d2f8f59 100644 --- a/user_guide_src/source/database/query_builder/038.php +++ b/user_guide_src/source/database/query_builder/038.php @@ -1,5 +1,4 @@ like('title', 'match'); -$builder->like('body', 'match'); -// WHERE `title` LIKE '%match%' ESCAPE '!' AND `body` LIKE '%match%' ESCAPE '!' +// Produces: WHERE `title` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/039.php b/user_guide_src/source/database/query_builder/039.php index 519686f9e4d9..a8ae3efa1d27 100644 --- a/user_guide_src/source/database/query_builder/039.php +++ b/user_guide_src/source/database/query_builder/039.php @@ -1,5 +1,5 @@ like('title', 'match', 'before'); // Produces: WHERE `title` LIKE '%match' ESCAPE '!' -$builder->like('title', 'match', 'after'); // Produces: WHERE `title` LIKE 'match%' ESCAPE '!' -$builder->like('title', 'match', 'both'); // Produces: WHERE `title` LIKE '%match%' ESCAPE '!' +$builder->like('title', 'match'); +$builder->like('body', 'match'); +// WHERE `title` LIKE '%match%' ESCAPE '!' AND `body` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/040.php b/user_guide_src/source/database/query_builder/040.php index 0583a2a79187..519686f9e4d9 100644 --- a/user_guide_src/source/database/query_builder/040.php +++ b/user_guide_src/source/database/query_builder/040.php @@ -1,5 +1,5 @@ $match, 'page1' => $match, 'page2' => $match]; -$builder->like($array); -// WHERE `title` LIKE '%match%' ESCAPE '!' AND `page1` LIKE '%match%' ESCAPE '!' AND `page2` LIKE '%match%' ESCAPE '!' +$builder->like('title', 'match', 'before'); // Produces: WHERE `title` LIKE '%match' ESCAPE '!' +$builder->like('title', 'match', 'after'); // Produces: WHERE `title` LIKE 'match%' ESCAPE '!' +$builder->like('title', 'match', 'both'); // Produces: WHERE `title` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/041.php b/user_guide_src/source/database/query_builder/041.php index 7c9935e4f356..0583a2a79187 100644 --- a/user_guide_src/source/database/query_builder/041.php +++ b/user_guide_src/source/database/query_builder/041.php @@ -1,4 +1,5 @@ like('title', 'match'); $builder->orLike('body', $match); -// WHERE `title` LIKE '%match%' ESCAPE '!' OR `body` LIKE '%match%' ESCAPE '!' +$array = ['title' => $match, 'page1' => $match, 'page2' => $match]; +$builder->like($array); +// WHERE `title` LIKE '%match%' ESCAPE '!' AND `page1` LIKE '%match%' ESCAPE '!' AND `page2` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/042.php b/user_guide_src/source/database/query_builder/042.php index 983068b45fef..7c9935e4f356 100644 --- a/user_guide_src/source/database/query_builder/042.php +++ b/user_guide_src/source/database/query_builder/042.php @@ -1,3 +1,4 @@ notLike('title', 'match'); // WHERE `title` NOT LIKE '%match% ESCAPE '!' +$builder->like('title', 'match'); $builder->orLike('body', $match); +// WHERE `title` LIKE '%match%' ESCAPE '!' OR `body` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/043.php b/user_guide_src/source/database/query_builder/043.php index f0f442dfeb78..983068b45fef 100644 --- a/user_guide_src/source/database/query_builder/043.php +++ b/user_guide_src/source/database/query_builder/043.php @@ -1,5 +1,3 @@ like('title', 'match'); -$builder->orNotLike('body', 'match'); -// WHERE `title` LIKE '%match% OR `body` NOT LIKE '%match%' ESCAPE '!' +$builder->notLike('title', 'match'); // WHERE `title` NOT LIKE '%match% ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/044.php b/user_guide_src/source/database/query_builder/044.php index ffe4786baaae..f0f442dfeb78 100644 --- a/user_guide_src/source/database/query_builder/044.php +++ b/user_guide_src/source/database/query_builder/044.php @@ -1,4 +1,5 @@ groupBy('title'); -// Produces: GROUP BY title +$builder->like('title', 'match'); +$builder->orNotLike('body', 'match'); +// WHERE `title` LIKE '%match% OR `body` NOT LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/045.php b/user_guide_src/source/database/query_builder/045.php index 0872996afe9f..ffe4786baaae 100644 --- a/user_guide_src/source/database/query_builder/045.php +++ b/user_guide_src/source/database/query_builder/045.php @@ -1,4 +1,4 @@ groupBy(['title', 'date']); -// Produces: GROUP BY title, date +$builder->groupBy('title'); +// Produces: GROUP BY title diff --git a/user_guide_src/source/database/query_builder/046.php b/user_guide_src/source/database/query_builder/046.php index 0e6f6415d6f7..0872996afe9f 100644 --- a/user_guide_src/source/database/query_builder/046.php +++ b/user_guide_src/source/database/query_builder/046.php @@ -1,5 +1,4 @@ distinct(); -$builder->get(); -// Produces: SELECT DISTINCT * FROM mytable +$builder->groupBy(['title', 'date']); +// Produces: GROUP BY title, date diff --git a/user_guide_src/source/database/query_builder/047.php b/user_guide_src/source/database/query_builder/047.php index 87f435064238..0e6f6415d6f7 100644 --- a/user_guide_src/source/database/query_builder/047.php +++ b/user_guide_src/source/database/query_builder/047.php @@ -1,4 +1,5 @@ having('user_id = 45'); // Produces: HAVING user_id = 45 -$builder->having('user_id', 45); // Produces: HAVING user_id = 45 +$builder->distinct(); +$builder->get(); +// Produces: SELECT DISTINCT * FROM mytable diff --git a/user_guide_src/source/database/query_builder/048.php b/user_guide_src/source/database/query_builder/048.php index e911e5e87302..87f435064238 100644 --- a/user_guide_src/source/database/query_builder/048.php +++ b/user_guide_src/source/database/query_builder/048.php @@ -1,4 +1,4 @@ having(['title =' => 'My Title', 'id <' => $id]); -// Produces: HAVING title = 'My Title', id < 45 +$builder->having('user_id = 45'); // Produces: HAVING user_id = 45 +$builder->having('user_id', 45); // Produces: HAVING user_id = 45 diff --git a/user_guide_src/source/database/query_builder/049.php b/user_guide_src/source/database/query_builder/049.php index b044b821f388..e911e5e87302 100644 --- a/user_guide_src/source/database/query_builder/049.php +++ b/user_guide_src/source/database/query_builder/049.php @@ -1,4 +1,4 @@ having('user_id', 45); // Produces: HAVING `user_id` = 45 in some databases such as MySQL -$builder->having('user_id', 45, false); // Produces: HAVING user_id = 45 +$builder->having(['title =' => 'My Title', 'id <' => $id]); +// Produces: HAVING title = 'My Title', id < 45 diff --git a/user_guide_src/source/database/query_builder/050.php b/user_guide_src/source/database/query_builder/050.php index bc6f5a3e1412..b044b821f388 100644 --- a/user_guide_src/source/database/query_builder/050.php +++ b/user_guide_src/source/database/query_builder/050.php @@ -1,5 +1,4 @@ havingIn('group_id', $groups); -// Produces: HAVING group_id IN (1, 2, 3) +$builder->having('user_id', 45); // Produces: HAVING `user_id` = 45 in some databases such as MySQL +$builder->having('user_id', 45, false); // Produces: HAVING user_id = 45 diff --git a/user_guide_src/source/database/query_builder/051.php b/user_guide_src/source/database/query_builder/051.php index 1f5736243866..bc6f5a3e1412 100644 --- a/user_guide_src/source/database/query_builder/051.php +++ b/user_guide_src/source/database/query_builder/051.php @@ -1,9 +1,5 @@ havingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); -// Produces: HAVING "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); -$builder->havingIn('id', $subQuery); +$groups = [1, 2, 3]; +$builder->havingIn('group_id', $groups); +// Produces: HAVING group_id IN (1, 2, 3) diff --git a/user_guide_src/source/database/query_builder/052.php b/user_guide_src/source/database/query_builder/052.php index aa07cad01be9..1f5736243866 100644 --- a/user_guide_src/source/database/query_builder/052.php +++ b/user_guide_src/source/database/query_builder/052.php @@ -1,5 +1,9 @@ orHavingIn('group_id', $groups); -// Produces: OR group_id IN (1, 2, 3) +// With closure +$builder->havingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +// Produces: HAVING "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); +$builder->havingIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/053.php b/user_guide_src/source/database/query_builder/053.php index 8a19ff4ac7d8..aa07cad01be9 100644 --- a/user_guide_src/source/database/query_builder/053.php +++ b/user_guide_src/source/database/query_builder/053.php @@ -1,9 +1,5 @@ orHavingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); -// Produces: OR "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); -$builder->orHavingIn('id', $subQuery); +$groups = [1, 2, 3]; +$builder->orHavingIn('group_id', $groups); +// Produces: OR group_id IN (1, 2, 3) diff --git a/user_guide_src/source/database/query_builder/054.php b/user_guide_src/source/database/query_builder/054.php index 875a2afcbfe4..8a19ff4ac7d8 100644 --- a/user_guide_src/source/database/query_builder/054.php +++ b/user_guide_src/source/database/query_builder/054.php @@ -1,5 +1,9 @@ havingNotIn('group_id', $groups); -// Produces: HAVING group_id NOT IN (1, 2, 3) +// With closure +$builder->orHavingIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +// Produces: OR "id" IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); +$builder->orHavingIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/055.php b/user_guide_src/source/database/query_builder/055.php index 67a54f87f7bc..875a2afcbfe4 100644 --- a/user_guide_src/source/database/query_builder/055.php +++ b/user_guide_src/source/database/query_builder/055.php @@ -1,9 +1,5 @@ havingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); -// Produces: HAVING "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); -$builder->havingNotIn('id', $subQuery); +$groups = [1, 2, 3]; +$builder->havingNotIn('group_id', $groups); +// Produces: HAVING group_id NOT IN (1, 2, 3) diff --git a/user_guide_src/source/database/query_builder/056.php b/user_guide_src/source/database/query_builder/056.php index 6d5a27ad2b95..67a54f87f7bc 100644 --- a/user_guide_src/source/database/query_builder/056.php +++ b/user_guide_src/source/database/query_builder/056.php @@ -1,5 +1,9 @@ havingNotIn('group_id', $groups); -// Produces: OR group_id NOT IN (1, 2, 3) +// With closure +$builder->havingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +// Produces: HAVING "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); +$builder->havingNotIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/057.php b/user_guide_src/source/database/query_builder/057.php index 8a92da5725b2..6d5a27ad2b95 100644 --- a/user_guide_src/source/database/query_builder/057.php +++ b/user_guide_src/source/database/query_builder/057.php @@ -1,9 +1,5 @@ orHavingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); -// Produces: OR "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) - -// With builder directly -$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); -$builder->orHavingNotIn('id', $subQuery); +$groups = [1, 2, 3]; +$builder->havingNotIn('group_id', $groups); +// Produces: OR group_id NOT IN (1, 2, 3) diff --git a/user_guide_src/source/database/query_builder/058.php b/user_guide_src/source/database/query_builder/058.php index e24f2ed0ef45..8a92da5725b2 100644 --- a/user_guide_src/source/database/query_builder/058.php +++ b/user_guide_src/source/database/query_builder/058.php @@ -1,4 +1,9 @@ havingLike('title', 'match'); -// Produces: HAVING `title` LIKE '%match%' ESCAPE '!' +// With closure +$builder->orHavingNotIn('id', static fn (BaseBuilder $builder) => $builder->select('user_id')->from('users_jobs')->where('group_id', 3)); +// Produces: OR "id" NOT IN (SELECT "user_id" FROM "users_jobs" WHERE "group_id" = 3) + +// With builder directly +$subQuery = $db->table('users_jobs')->select('user_id')->where('group_id', 3); +$builder->orHavingNotIn('id', $subQuery); diff --git a/user_guide_src/source/database/query_builder/059.php b/user_guide_src/source/database/query_builder/059.php index 9ef7f263e19f..e24f2ed0ef45 100644 --- a/user_guide_src/source/database/query_builder/059.php +++ b/user_guide_src/source/database/query_builder/059.php @@ -1,5 +1,4 @@ havingLike('title', 'match'); -$builder->havingLike('body', 'match'); -// HAVING `title` LIKE '%match%' ESCAPE '!' AND `body` LIKE '%match% ESCAPE '!' +// Produces: HAVING `title` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/060.php b/user_guide_src/source/database/query_builder/060.php index 3acc5d4f0fd4..9ef7f263e19f 100644 --- a/user_guide_src/source/database/query_builder/060.php +++ b/user_guide_src/source/database/query_builder/060.php @@ -1,5 +1,5 @@ havingLike('title', 'match', 'before'); // Produces: HAVING `title` LIKE '%match' ESCAPE '!' -$builder->havingLike('title', 'match', 'after'); // Produces: HAVING `title` LIKE 'match%' ESCAPE '!' -$builder->havingLike('title', 'match', 'both'); // Produces: HAVING `title` LIKE '%match%' ESCAPE '!' +$builder->havingLike('title', 'match'); +$builder->havingLike('body', 'match'); +// HAVING `title` LIKE '%match%' ESCAPE '!' AND `body` LIKE '%match% ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/061.php b/user_guide_src/source/database/query_builder/061.php index ba1767f6706e..3acc5d4f0fd4 100644 --- a/user_guide_src/source/database/query_builder/061.php +++ b/user_guide_src/source/database/query_builder/061.php @@ -1,5 +1,5 @@ $match, 'page1' => $match, 'page2' => $match]; -$builder->havingLike($array); -// HAVING `title` LIKE '%match%' ESCAPE '!' AND `page1` LIKE '%match%' ESCAPE '!' AND `page2` LIKE '%match%' ESCAPE '!' +$builder->havingLike('title', 'match', 'before'); // Produces: HAVING `title` LIKE '%match' ESCAPE '!' +$builder->havingLike('title', 'match', 'after'); // Produces: HAVING `title` LIKE 'match%' ESCAPE '!' +$builder->havingLike('title', 'match', 'both'); // Produces: HAVING `title` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/062.php b/user_guide_src/source/database/query_builder/062.php index 0b7543273430..ba1767f6706e 100644 --- a/user_guide_src/source/database/query_builder/062.php +++ b/user_guide_src/source/database/query_builder/062.php @@ -1,4 +1,5 @@ havingLike('title', 'match'); $builder->orHavingLike('body', $match); -// HAVING `title` LIKE '%match%' ESCAPE '!' OR `body` LIKE '%match%' ESCAPE '!' +$array = ['title' => $match, 'page1' => $match, 'page2' => $match]; +$builder->havingLike($array); +// HAVING `title` LIKE '%match%' ESCAPE '!' AND `page1` LIKE '%match%' ESCAPE '!' AND `page2` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/063.php b/user_guide_src/source/database/query_builder/063.php index a5c028d78e2c..0b7543273430 100644 --- a/user_guide_src/source/database/query_builder/063.php +++ b/user_guide_src/source/database/query_builder/063.php @@ -1,4 +1,4 @@ notHavingLike('title', 'match'); -// HAVING `title` NOT LIKE '%match% ESCAPE '!' +$builder->havingLike('title', 'match'); $builder->orHavingLike('body', $match); +// HAVING `title` LIKE '%match%' ESCAPE '!' OR `body` LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/064.php b/user_guide_src/source/database/query_builder/064.php index 194a382baa13..a5c028d78e2c 100644 --- a/user_guide_src/source/database/query_builder/064.php +++ b/user_guide_src/source/database/query_builder/064.php @@ -1,5 +1,4 @@ havingLike('title', 'match'); -$builder->orNotHavingLike('body', 'match'); -// HAVING `title` LIKE '%match% OR `body` NOT LIKE '%match%' ESCAPE '!' +$builder->notHavingLike('title', 'match'); +// HAVING `title` NOT LIKE '%match% ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/065.php b/user_guide_src/source/database/query_builder/065.php index f36b6af2b449..194a382baa13 100644 --- a/user_guide_src/source/database/query_builder/065.php +++ b/user_guide_src/source/database/query_builder/065.php @@ -1,4 +1,5 @@ orderBy('title', 'DESC'); -// Produces: ORDER BY `title` DESC +$builder->havingLike('title', 'match'); +$builder->orNotHavingLike('body', 'match'); +// HAVING `title` LIKE '%match% OR `body` NOT LIKE '%match%' ESCAPE '!' diff --git a/user_guide_src/source/database/query_builder/066.php b/user_guide_src/source/database/query_builder/066.php index 01ef14c9a1c3..f36b6af2b449 100644 --- a/user_guide_src/source/database/query_builder/066.php +++ b/user_guide_src/source/database/query_builder/066.php @@ -1,4 +1,4 @@ orderBy('title DESC, name ASC'); -// Produces: ORDER BY `title` DESC, `name` ASC +$builder->orderBy('title', 'DESC'); +// Produces: ORDER BY `title` DESC diff --git a/user_guide_src/source/database/query_builder/067.php b/user_guide_src/source/database/query_builder/067.php index 6ba7dc157b59..01ef14c9a1c3 100644 --- a/user_guide_src/source/database/query_builder/067.php +++ b/user_guide_src/source/database/query_builder/067.php @@ -1,5 +1,4 @@ orderBy('title', 'DESC'); -$builder->orderBy('name', 'ASC'); +$builder->orderBy('title DESC, name ASC'); // Produces: ORDER BY `title` DESC, `name` ASC diff --git a/user_guide_src/source/database/query_builder/068.php b/user_guide_src/source/database/query_builder/068.php index f038c3e67184..6ba7dc157b59 100644 --- a/user_guide_src/source/database/query_builder/068.php +++ b/user_guide_src/source/database/query_builder/068.php @@ -1,7 +1,5 @@ orderBy('title', 'RANDOM'); -// Produces: ORDER BY RAND() - -$builder->orderBy(42, 'RANDOM'); -// Produces: ORDER BY RAND(42) +$builder->orderBy('title', 'DESC'); +$builder->orderBy('name', 'ASC'); +// Produces: ORDER BY `title` DESC, `name` ASC diff --git a/user_guide_src/source/database/query_builder/069.php b/user_guide_src/source/database/query_builder/069.php index dadbdc5dea19..f038c3e67184 100644 --- a/user_guide_src/source/database/query_builder/069.php +++ b/user_guide_src/source/database/query_builder/069.php @@ -1,4 +1,7 @@ limit(10); -// Produces: LIMIT 10 +$builder->orderBy('title', 'RANDOM'); +// Produces: ORDER BY RAND() + +$builder->orderBy(42, 'RANDOM'); +// Produces: ORDER BY RAND(42) diff --git a/user_guide_src/source/database/query_builder/070.php b/user_guide_src/source/database/query_builder/070.php index 0bfcab7b1fcf..dadbdc5dea19 100644 --- a/user_guide_src/source/database/query_builder/070.php +++ b/user_guide_src/source/database/query_builder/070.php @@ -1,4 +1,4 @@ limit(10, 20); -// Produces: LIMIT 20, 10 (in MySQL. Other databases have slightly different syntax) +$builder->limit(10); +// Produces: LIMIT 10 diff --git a/user_guide_src/source/database/query_builder/071.php b/user_guide_src/source/database/query_builder/071.php index 4b1c33356b7e..0bfcab7b1fcf 100644 --- a/user_guide_src/source/database/query_builder/071.php +++ b/user_guide_src/source/database/query_builder/071.php @@ -1,6 +1,4 @@ countAllResults(); // Produces an integer, like 25 -$builder->like('title', 'match'); -$builder->from('my_table'); -echo $builder->countAllResults(); // Produces an integer, like 17 +$builder->limit(10, 20); +// Produces: LIMIT 20, 10 (in MySQL. Other databases have slightly different syntax) diff --git a/user_guide_src/source/database/query_builder/072.php b/user_guide_src/source/database/query_builder/072.php index bb3a9c4d4b63..4b1c33356b7e 100644 --- a/user_guide_src/source/database/query_builder/072.php +++ b/user_guide_src/source/database/query_builder/072.php @@ -1,3 +1,6 @@ countAllResults(false); // Produces an integer, like 17 +echo $builder->countAllResults(); // Produces an integer, like 25 +$builder->like('title', 'match'); +$builder->from('my_table'); +echo $builder->countAllResults(); // Produces an integer, like 17 diff --git a/user_guide_src/source/database/query_builder/073.php b/user_guide_src/source/database/query_builder/073.php index 11bc5421cb42..bb3a9c4d4b63 100644 --- a/user_guide_src/source/database/query_builder/073.php +++ b/user_guide_src/source/database/query_builder/073.php @@ -1,3 +1,3 @@ countAll(); // Produces an integer, like 25 +echo $builder->countAllResults(false); // Produces an integer, like 17 diff --git a/user_guide_src/source/database/query_builder/074.php b/user_guide_src/source/database/query_builder/074.php index 3ea4d947f4a7..11bc5421cb42 100644 --- a/user_guide_src/source/database/query_builder/074.php +++ b/user_guide_src/source/database/query_builder/074.php @@ -1,16 +1,3 @@ select('*')->from('my_table') - ->groupStart() - ->where('a', 'a') - ->orGroupStart() - ->where('b', 'b') - ->where('c', 'c') - ->groupEnd() - ->groupEnd() - ->where('d', 'd') - ->get(); -/* - * Generates: - * SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' - */ +echo $builder->countAll(); // Produces an integer, like 25 diff --git a/user_guide_src/source/database/query_builder/075.php b/user_guide_src/source/database/query_builder/075.php index 2e87e8345dd0..3ea4d947f4a7 100644 --- a/user_guide_src/source/database/query_builder/075.php +++ b/user_guide_src/source/database/query_builder/075.php @@ -1,10 +1,16 @@ 'My title', - 'name' => 'My Name', - 'date' => 'My date', -]; - -$builder->insert($data); -// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') +$builder->select('*')->from('my_table') + ->groupStart() + ->where('a', 'a') + ->orGroupStart() + ->where('b', 'b') + ->where('c', 'c') + ->groupEnd() + ->groupEnd() + ->where('d', 'd') + ->get(); +/* + * Generates: + * SELECT * FROM (`my_table`) WHERE ( `a` = 'a' OR ( `b` = 'b' AND `c` = 'c' ) ) AND `d` = 'd' + */ diff --git a/user_guide_src/source/database/query_builder/076.php b/user_guide_src/source/database/query_builder/076.php index ba38d99ff43b..2e87e8345dd0 100644 --- a/user_guide_src/source/database/query_builder/076.php +++ b/user_guide_src/source/database/query_builder/076.php @@ -1,12 +1,10 @@ 'My title', + 'name' => 'My Name', + 'date' => 'My date', +]; -$object = new Myclass(); -$builder->insert($object); -// Produces: INSERT INTO mytable (title, content, date) VALUES ('My Title', 'My Content', 'My Date') +$builder->insert($data); +// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') diff --git a/user_guide_src/source/database/query_builder/077.php b/user_guide_src/source/database/query_builder/077.php index bb07bc8bdd9c..ba38d99ff43b 100644 --- a/user_guide_src/source/database/query_builder/077.php +++ b/user_guide_src/source/database/query_builder/077.php @@ -1,10 +1,12 @@ 'My title', - 'name' => 'My Name', - 'date' => 'My date', -]; +class Myclass +{ + public $title = 'My Title'; + public $content = 'My Content'; + public $date = 'My Date'; +} -$builder->ignore(true)->insert($data); -// Produces: INSERT OR IGNORE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') +$object = new Myclass(); +$builder->insert($object); +// Produces: INSERT INTO mytable (title, content, date) VALUES ('My Title', 'My Content', 'My Date') diff --git a/user_guide_src/source/database/query_builder/078.php b/user_guide_src/source/database/query_builder/078.php index ed0e4cb3f7a1..bb07bc8bdd9c 100644 --- a/user_guide_src/source/database/query_builder/078.php +++ b/user_guide_src/source/database/query_builder/078.php @@ -6,6 +6,5 @@ 'date' => 'My date', ]; -$sql = $builder->set($data)->getCompiledInsert(); -echo $sql; -// Produces string: INSERT INTO mytable (`title`, `name`, `date`) VALUES ('My title', 'My name', 'My date') +$builder->ignore(true)->insert($data); +// Produces: INSERT OR IGNORE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') diff --git a/user_guide_src/source/database/query_builder/079.php b/user_guide_src/source/database/query_builder/079.php index 1807be1d706a..ed0e4cb3f7a1 100644 --- a/user_guide_src/source/database/query_builder/079.php +++ b/user_guide_src/source/database/query_builder/079.php @@ -1,7 +1,11 @@ set('title', 'My Title')->getCompiledInsert(false); -// Produces string: INSERT INTO mytable (`title`) VALUES ('My Title') +$data = [ + 'title' => 'My title', + 'name' => 'My Name', + 'date' => 'My date', +]; -echo $builder->set('content', 'My Content')->getCompiledInsert(); -// Produces string: INSERT INTO mytable (`title`, `content`) VALUES ('My Title', 'My Content') +$sql = $builder->set($data)->getCompiledInsert(); +echo $sql; +// Produces string: INSERT INTO mytable (`title`, `name`, `date`) VALUES ('My title', 'My name', 'My date') diff --git a/user_guide_src/source/database/query_builder/080.php b/user_guide_src/source/database/query_builder/080.php index 0f263005c18e..1807be1d706a 100644 --- a/user_guide_src/source/database/query_builder/080.php +++ b/user_guide_src/source/database/query_builder/080.php @@ -1,17 +1,7 @@ 'My title', - 'name' => 'My Name', - 'date' => 'My date', - ], - [ - 'title' => 'Another title', - 'name' => 'Another Name', - 'date' => 'Another date', - ], -]; +echo $builder->set('title', 'My Title')->getCompiledInsert(false); +// Produces string: INSERT INTO mytable (`title`) VALUES ('My Title') -$builder->insertBatch($data); -// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date') +echo $builder->set('content', 'My Content')->getCompiledInsert(); +// Produces string: INSERT INTO mytable (`title`, `content`) VALUES ('My Title', 'My Content') diff --git a/user_guide_src/source/database/query_builder/081.php b/user_guide_src/source/database/query_builder/081.php index d4bd972f5830..0f263005c18e 100644 --- a/user_guide_src/source/database/query_builder/081.php +++ b/user_guide_src/source/database/query_builder/081.php @@ -1,10 +1,17 @@ 'My title', - 'name' => 'My Name', - 'date' => 'My date', + [ + 'title' => 'My title', + 'name' => 'My Name', + 'date' => 'My date', + ], + [ + 'title' => 'Another title', + 'name' => 'Another Name', + 'date' => 'Another date', + ], ]; -$builder->replace($data); -// Executes: REPLACE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') +$builder->insertBatch($data); +// Produces: INSERT INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date'), ('Another title', 'Another name', 'Another date') diff --git a/user_guide_src/source/database/query_builder/082.php b/user_guide_src/source/database/query_builder/082.php index 59d14e130215..d4bd972f5830 100644 --- a/user_guide_src/source/database/query_builder/082.php +++ b/user_guide_src/source/database/query_builder/082.php @@ -1,5 +1,10 @@ set('name', $name); -$builder->insert(); -// Produces: INSERT INTO mytable (`name`) VALUES ('{$name}') +$data = [ + 'title' => 'My title', + 'name' => 'My Name', + 'date' => 'My date', +]; + +$builder->replace($data); +// Executes: REPLACE INTO mytable (title, name, date) VALUES ('My title', 'My name', 'My date') diff --git a/user_guide_src/source/database/query_builder/083.php b/user_guide_src/source/database/query_builder/083.php index 8e2fbe2fabe5..59d14e130215 100644 --- a/user_guide_src/source/database/query_builder/083.php +++ b/user_guide_src/source/database/query_builder/083.php @@ -1,6 +1,5 @@ set('name', $name); -$builder->set('title', $title); -$builder->set('status', $status); $builder->insert(); +// Produces: INSERT INTO mytable (`name`) VALUES ('{$name}') diff --git a/user_guide_src/source/database/query_builder/084.php b/user_guide_src/source/database/query_builder/084.php index 2e76bea9e5d5..8e2fbe2fabe5 100644 --- a/user_guide_src/source/database/query_builder/084.php +++ b/user_guide_src/source/database/query_builder/084.php @@ -1,11 +1,6 @@ set('field', 'field+1', false); -$builder->where('id', 2); -$builder->update(); -// gives UPDATE mytable SET field = field+1 WHERE `id` = 2 - -$builder->set('field', 'field+1'); -$builder->where('id', 2); -$builder->update(); -// gives UPDATE `mytable` SET `field` = 'field+1' WHERE `id` = 2 +$builder->set('name', $name); +$builder->set('title', $title); +$builder->set('status', $status); +$builder->insert(); diff --git a/user_guide_src/source/database/query_builder/085.php b/user_guide_src/source/database/query_builder/085.php index 319e29a88142..2e76bea9e5d5 100644 --- a/user_guide_src/source/database/query_builder/085.php +++ b/user_guide_src/source/database/query_builder/085.php @@ -1,10 +1,11 @@ $name, - 'title' => $title, - 'status' => $status, -]; +$builder->set('field', 'field+1', false); +$builder->where('id', 2); +$builder->update(); +// gives UPDATE mytable SET field = field+1 WHERE `id` = 2 -$builder->set($array); -$builder->insert(); +$builder->set('field', 'field+1'); +$builder->where('id', 2); +$builder->update(); +// gives UPDATE `mytable` SET `field` = 'field+1' WHERE `id` = 2 diff --git a/user_guide_src/source/database/query_builder/086.php b/user_guide_src/source/database/query_builder/086.php index d395bc3b8ea9..319e29a88142 100644 --- a/user_guide_src/source/database/query_builder/086.php +++ b/user_guide_src/source/database/query_builder/086.php @@ -1,12 +1,10 @@ $name, + 'title' => $title, + 'status' => $status, +]; -$object = new Myclass(); -$builder->set($object); +$builder->set($array); $builder->insert(); diff --git a/user_guide_src/source/database/query_builder/087.php b/user_guide_src/source/database/query_builder/087.php index 7869b4b4d966..d395bc3b8ea9 100644 --- a/user_guide_src/source/database/query_builder/087.php +++ b/user_guide_src/source/database/query_builder/087.php @@ -1,16 +1,12 @@ $title, - 'name' => $name, - 'date' => $date, -]; +class Myclass +{ + public $title = 'My Title'; + public $content = 'My Content'; + public $date = 'My Date'; +} -$builder->where('id', $id); -$builder->update($data); -/* - * Produces: - * UPDATE mytable - * SET title = '{$title}', name = '{$name}', date = '{$date}' - * WHERE id = $id - */ +$object = new Myclass(); +$builder->set($object); +$builder->insert(); diff --git a/user_guide_src/source/database/query_builder/088.php b/user_guide_src/source/database/query_builder/088.php index 445e53716041..7869b4b4d966 100644 --- a/user_guide_src/source/database/query_builder/088.php +++ b/user_guide_src/source/database/query_builder/088.php @@ -1,18 +1,16 @@ $title, + 'name' => $name, + 'date' => $date, +]; -$object = new Myclass(); $builder->where('id', $id); -$builder->update($object); +$builder->update($data); /* * Produces: - * UPDATE `mytable` - * SET `title` = '{$title}', `name` = '{$name}', `date` = '{$date}' - * WHERE id = `$id` + * UPDATE mytable + * SET title = '{$title}', name = '{$name}', date = '{$date}' + * WHERE id = $id */ diff --git a/user_guide_src/source/database/query_builder/089.php b/user_guide_src/source/database/query_builder/089.php index d2ed79d26832..445e53716041 100644 --- a/user_guide_src/source/database/query_builder/089.php +++ b/user_guide_src/source/database/query_builder/089.php @@ -1,3 +1,18 @@ update($data, 'id = 4'); +class Myclass +{ + public $title = 'My Title'; + public $content = 'My Content'; + public $date = 'My Date'; +} + +$object = new Myclass(); +$builder->where('id', $id); +$builder->update($object); +/* + * Produces: + * UPDATE `mytable` + * SET `title` = '{$title}', `name` = '{$name}', `date` = '{$date}' + * WHERE id = `$id` + */ diff --git a/user_guide_src/source/database/query_builder/090.php b/user_guide_src/source/database/query_builder/090.php index 66a1ee575cee..d2ed79d26832 100644 --- a/user_guide_src/source/database/query_builder/090.php +++ b/user_guide_src/source/database/query_builder/090.php @@ -1,3 +1,3 @@ update($data, ['id' => $id]); +$builder->update($data, 'id = 4'); diff --git a/user_guide_src/source/database/query_builder/091.php b/user_guide_src/source/database/query_builder/091.php index e60b9ee6b486..66a1ee575cee 100644 --- a/user_guide_src/source/database/query_builder/091.php +++ b/user_guide_src/source/database/query_builder/091.php @@ -1,28 +1,3 @@ 'My title', - 'name' => 'My Name 2', - 'date' => 'My date 2', - ], - [ - 'title' => 'Another title', - 'name' => 'Another Name 2', - 'date' => 'Another date 2', - ], -]; - -$builder->updateBatch($data, 'title'); -/* - * Produces: - * UPDATE `mytable` SET `name` = CASE - * WHEN `title` = 'My title' THEN 'My Name 2' - * WHEN `title` = 'Another title' THEN 'Another Name 2' - * ELSE `name` END, - * `date` = CASE - * WHEN `title` = 'My title' THEN 'My date 2' - * WHEN `title` = 'Another title' THEN 'Another date 2' - * ELSE `date` END - * WHERE `title` IN ('My title','Another title') - */ +$builder->update($data, ['id' => $id]); diff --git a/user_guide_src/source/database/query_builder/092.php b/user_guide_src/source/database/query_builder/092.php index ed680a441d98..e60b9ee6b486 100644 --- a/user_guide_src/source/database/query_builder/092.php +++ b/user_guide_src/source/database/query_builder/092.php @@ -1,4 +1,28 @@ delete(['id' => $id]); -// Produces: DELETE FROM mytable WHERE id = $id +$data = [ + [ + 'title' => 'My title', + 'name' => 'My Name 2', + 'date' => 'My date 2', + ], + [ + 'title' => 'Another title', + 'name' => 'Another Name 2', + 'date' => 'Another date 2', + ], +]; + +$builder->updateBatch($data, 'title'); +/* + * Produces: + * UPDATE `mytable` SET `name` = CASE + * WHEN `title` = 'My title' THEN 'My Name 2' + * WHEN `title` = 'Another title' THEN 'Another Name 2' + * ELSE `name` END, + * `date` = CASE + * WHEN `title` = 'My title' THEN 'My date 2' + * WHEN `title` = 'Another title' THEN 'Another date 2' + * ELSE `date` END + * WHERE `title` IN ('My title','Another title') + */ diff --git a/user_guide_src/source/database/query_builder/093.php b/user_guide_src/source/database/query_builder/093.php index f1ba27e29ef2..ed680a441d98 100644 --- a/user_guide_src/source/database/query_builder/093.php +++ b/user_guide_src/source/database/query_builder/093.php @@ -1,9 +1,4 @@ where('id', $id); -$builder->delete(); -/* - * Produces: - * DELETE FROM mytable - * WHERE id = $id - */ +$builder->delete(['id' => $id]); +// Produces: DELETE FROM mytable WHERE id = $id diff --git a/user_guide_src/source/database/query_builder/094.php b/user_guide_src/source/database/query_builder/094.php index 0251fe47031d..f1ba27e29ef2 100644 --- a/user_guide_src/source/database/query_builder/094.php +++ b/user_guide_src/source/database/query_builder/094.php @@ -1,4 +1,9 @@ emptyTable('mytable'); -// Produces: DELETE FROM mytable +$builder->where('id', $id); +$builder->delete(); +/* + * Produces: + * DELETE FROM mytable + * WHERE id = $id + */ diff --git a/user_guide_src/source/database/query_builder/095.php b/user_guide_src/source/database/query_builder/095.php index a6c0ab4fc069..0251fe47031d 100644 --- a/user_guide_src/source/database/query_builder/095.php +++ b/user_guide_src/source/database/query_builder/095.php @@ -1,7 +1,4 @@ truncate(); -/* - * Produce: - * TRUNCATE mytable - */ +$builder->emptyTable('mytable'); +// Produces: DELETE FROM mytable diff --git a/user_guide_src/source/database/query_builder/096.php b/user_guide_src/source/database/query_builder/096.php index 5a05f70d8070..a6c0ab4fc069 100644 --- a/user_guide_src/source/database/query_builder/096.php +++ b/user_guide_src/source/database/query_builder/096.php @@ -1,6 +1,7 @@ select('title') - ->where('id', $id) - ->limit(10, 20) - ->get(); +$builder->truncate(); +/* + * Produce: + * TRUNCATE mytable + */ diff --git a/user_guide_src/source/database/query_builder/097.php b/user_guide_src/source/database/query_builder/097.php index 50d274d63a54..5a05f70d8070 100644 --- a/user_guide_src/source/database/query_builder/097.php +++ b/user_guide_src/source/database/query_builder/097.php @@ -1,17 +1,6 @@ select(['field1', 'field2']) - ->where('field3', 5) - ->getCompiledSelect(false); - -// ... -// Do something crazy with the SQL code... like add it to a cron script for -// later execution or something... -// ... - -$data = $builder->get()->getResultArray(); -/* - * Would execute and return an array of results of the following query: - * SELECT field1, field1 from mytable where field3 = 5; - */ +$query = $builder->select('title') + ->where('id', $id) + ->limit(10, 20) + ->get(); diff --git a/user_guide_src/source/database/query_builder/098.php b/user_guide_src/source/database/query_builder/098.php index b3890e978005..50d274d63a54 100644 --- a/user_guide_src/source/database/query_builder/098.php +++ b/user_guide_src/source/database/query_builder/098.php @@ -1,6 +1,17 @@ table('countries')->select('name')->where('id', 1); -$builder = $db->table('users')->select('name')->selectSubquery($subquery, 'country'); -$query = $builder->get(); -// Produces: SELECT `name`, (SELECT `name` FROM `countries` WHERE `id` = 1) AS `country` FROM `users` +// Note that the second parameter of the ``get_compiled_select`` method is false +$sql = $builder->select(['field1', 'field2']) + ->where('field3', 5) + ->getCompiledSelect(false); + +// ... +// Do something crazy with the SQL code... like add it to a cron script for +// later execution or something... +// ... + +$data = $builder->get()->getResultArray(); +/* + * Would execute and return an array of results of the following query: + * SELECT field1, field1 from mytable where field3 = 5; + */ diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 5ade052c563a..037710255100 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -41,7 +41,7 @@ You can define an array of helper files as a class property. Whenever the contro these helper files will be automatically loaded into memory so that you can use their methods anywhere inside the controller: -.. literalinclude:: controllers/016.php +.. literalinclude:: controllers/001.php .. _controllers-validating-data: @@ -51,13 +51,13 @@ forceHTTPS A convenience method for forcing a method to be accessed via HTTPS is available within all controllers: -.. literalinclude:: controllers/014.php +.. literalinclude:: controllers/002.php By default, and in modern browsers that support the HTTP Strict Transport Security header, this call should force the browser to convert non-HTTPS calls to HTTPS calls for one year. You can modify this by passing the duration (in seconds) as the first parameter: -.. literalinclude:: controllers/015.php +.. literalinclude:: controllers/003.php .. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. @@ -75,12 +75,12 @@ if the items are not valid. Internally, this uses the controller's The :doc:`Validation Library docs ` have details on rule and message array formats, as well as available rules: -.. literalinclude:: controllers/017.php +.. literalinclude:: controllers/004.php If you find it simpler to keep the rules in the configuration file, you can replace the ``$rules`` array with the name of the group as defined in ``Config\Validation.php``: -.. literalinclude:: controllers/018.php +.. literalinclude:: controllers/005.php .. note:: Validation can also be handled automatically in the model, but sometimes it's easier to do it in the controller. Where is up to you. @@ -91,7 +91,7 @@ Sometimes you may want to check the controller method parameters or other custom In that case, you can use the ``$this->validateData()`` method. The method accepts an array of data to validate in the first parameter: -.. literalinclude:: controllers/019.php +.. literalinclude:: controllers/006.php Private methods *************** @@ -101,7 +101,7 @@ To achieve this, simply declare the method as ``private`` or ``protected``. That will prevent it from being served by a URL request. For example, if you were to define a method like this for the ``Helloworld`` controller: -.. literalinclude:: controllers/013.php +.. literalinclude:: controllers/007.php then trying to access it using the following URL will not work:: @@ -141,7 +141,7 @@ controllers. You can extend this class in any new controller. For security reasons be sure to declare any new utility methods as ``protected`` or ``private``: -.. literalinclude:: controllers/001.php +.. literalinclude:: controllers/008.php Then save the file to your **/app/Controllers/** directory. @@ -159,15 +159,15 @@ If you did it right you should see:: This is valid: -.. literalinclude:: controllers/002.php +.. literalinclude:: controllers/009.php This is **not** valid: -.. literalinclude:: controllers/003.php +.. literalinclude:: controllers/010.php This is **not** valid: -.. literalinclude:: controllers/004.php +.. literalinclude:: controllers/011.php Also, always make sure your controller extends the parent controller class so that it can inherit all its methods. @@ -181,7 +181,7 @@ class so that it can inherit all its methods. Here is an example based on PSR-4 Autoloader: - .. literalinclude:: controllers/005.php + .. literalinclude:: controllers/012.php Methods ======= @@ -197,7 +197,7 @@ controller gets called.** Let's try it. Add a new method to your controller: -.. literalinclude:: controllers/006.php +.. literalinclude:: controllers/013.php Now load the following URL to see the comment method:: @@ -217,7 +217,7 @@ For example, let's say you have a URI like this:: Your method will be passed URI segments 3 and 4 (``'sandals'`` and ``'123'``): -.. literalinclude:: controllers/007.php +.. literalinclude:: controllers/014.php .. important:: If you are using the :doc:`URI Routing ` feature, the segments passed to your method will be the re-routed @@ -233,13 +233,13 @@ with the ``Helloworld`` controller. To specify a default controller open your **app/Config/Routes.php** file and set this variable: -.. literalinclude:: controllers/008.php +.. literalinclude:: controllers/015.php Where ``Helloworld`` is the name of the controller class you want to be used. A few lines further down **Routes.php** in the "Route Definitions" section, comment out the line: -.. literalinclude:: controllers/009.php +.. literalinclude:: controllers/016.php If you now browse to your site without specifying any URI segments you'll see the "Hello World" message. @@ -288,7 +288,7 @@ As noted above, the second segment of the URI typically determines which method in the controller gets called. CodeIgniter permits you to override this behavior through the use of the ``_remap()`` method: -.. literalinclude:: controllers/010.php +.. literalinclude:: controllers/017.php .. important:: If your controller contains a method named ``_remap()``, it will **always** get called regardless of what your URI contains. It @@ -298,14 +298,14 @@ this behavior through the use of the ``_remap()`` method: The overridden method call (typically the second segment of the URI) will be passed as a parameter to the ``_remap()`` method: -.. literalinclude:: controllers/011.php +.. literalinclude:: controllers/018.php Any extra segments after the method name are passed into ``_remap()``. These parameters can be passed to the method to emulate CodeIgniter's default behavior. Example: -.. literalinclude:: controllers/012.php +.. literalinclude:: controllers/019.php Extending the Controller ************************ diff --git a/user_guide_src/source/incoming/controllers/001.php b/user_guide_src/source/incoming/controllers/001.php index 926de1e9fbdf..ff3ab9edfcf1 100644 --- a/user_guide_src/source/incoming/controllers/001.php +++ b/user_guide_src/source/incoming/controllers/001.php @@ -2,10 +2,7 @@ namespace App\Controllers; -class Helloworld extends BaseController +class MyController extends BaseController { - public function index() - { - echo 'Hello World!'; - } + protected $helpers = ['url', 'form']; } diff --git a/user_guide_src/source/incoming/controllers/002.php b/user_guide_src/source/incoming/controllers/002.php index 20fe63dc2d69..9414addbb81a 100644 --- a/user_guide_src/source/incoming/controllers/002.php +++ b/user_guide_src/source/incoming/controllers/002.php @@ -1,8 +1,5 @@ request->isSecure()) { + $this->forceHTTPS(); } diff --git a/user_guide_src/source/incoming/controllers/003.php b/user_guide_src/source/incoming/controllers/003.php index 5248ba4b2bdd..c3309ddbf201 100644 --- a/user_guide_src/source/incoming/controllers/003.php +++ b/user_guide_src/source/incoming/controllers/003.php @@ -1,8 +1,5 @@ request->isSecure()) { + $this->forceHTTPS(31536000); // one year } diff --git a/user_guide_src/source/incoming/controllers/004.php b/user_guide_src/source/incoming/controllers/004.php index 7615eecaeba0..65b1c77f8014 100644 --- a/user_guide_src/source/incoming/controllers/004.php +++ b/user_guide_src/source/incoming/controllers/004.php @@ -2,7 +2,19 @@ namespace App\Controllers; -class HelloWorld extends BaseController +class UserController extends BaseController { - // ... + public function updateUser(int $userID) + { + if (! $this->validate([ + 'email' => "required|is_unique[users.email,id,{$userID}]", + 'name' => 'required|alpha_numeric_spaces', + ])) { + return view('users/update', [ + 'errors' => $this->validator->getErrors(), + ]); + } + + // do something here if successful... + } } diff --git a/user_guide_src/source/incoming/controllers/005.php b/user_guide_src/source/incoming/controllers/005.php index efaecbb8f400..48e936b60595 100644 --- a/user_guide_src/source/incoming/controllers/005.php +++ b/user_guide_src/source/incoming/controllers/005.php @@ -1,8 +1,17 @@ (\)*\ - */ +namespace App\Controllers; -$routes->get('helloworld', '\App\Controllers\HelloWorld::index'); +class UserController extends BaseController +{ + public function updateUser(int $userID) + { + if (! $this->validate('userRules')) { + return view('users/update', [ + 'errors' => $this->validator->getErrors(), + ]); + } + + // do something here if successful... + } +} diff --git a/user_guide_src/source/incoming/controllers/006.php b/user_guide_src/source/incoming/controllers/006.php index e43c3e4f2b34..1ae78e5791ff 100644 --- a/user_guide_src/source/incoming/controllers/006.php +++ b/user_guide_src/source/incoming/controllers/006.php @@ -2,15 +2,24 @@ namespace App\Controllers; -class Helloworld extends BaseController +class StoreController extends BaseController { - public function index() + public function product(int $id) { - echo 'Hello World!'; - } + $data = [ + 'id' => $id, + 'name' => $this->request->getVar('name'), + ]; - public function comment() - { - echo 'I am not flat!'; + $rule = [ + 'id' => 'integer', + 'name' => 'required|max_length[255]', + ]; + + if (! $this->validateData($data, $rule)) { + // ... + } + + // ... } } diff --git a/user_guide_src/source/incoming/controllers/007.php b/user_guide_src/source/incoming/controllers/007.php index 319fd8471a7b..7c2e9b7091ea 100644 --- a/user_guide_src/source/incoming/controllers/007.php +++ b/user_guide_src/source/incoming/controllers/007.php @@ -4,9 +4,8 @@ class Products extends BaseController { - public function shoes($sandals, $id) + protected function utility() { - echo $sandals; - echo $id; + // some code } } diff --git a/user_guide_src/source/incoming/controllers/008.php b/user_guide_src/source/incoming/controllers/008.php index 2de1b716d040..926de1e9fbdf 100644 --- a/user_guide_src/source/incoming/controllers/008.php +++ b/user_guide_src/source/incoming/controllers/008.php @@ -1,3 +1,11 @@ setDefaultController('Helloworld'); +namespace App\Controllers; + +class Helloworld extends BaseController +{ + public function index() + { + echo 'Hello World!'; + } +} diff --git a/user_guide_src/source/incoming/controllers/009.php b/user_guide_src/source/incoming/controllers/009.php index d799d1cf0fb5..20fe63dc2d69 100644 --- a/user_guide_src/source/incoming/controllers/009.php +++ b/user_guide_src/source/incoming/controllers/009.php @@ -1,3 +1,8 @@ get('/', 'Home::index'); +namespace App\Controllers; + +class Helloworld extends BaseController +{ + // ... +} diff --git a/user_guide_src/source/incoming/controllers/010.php b/user_guide_src/source/incoming/controllers/010.php index 8bcb6a2b00f9..5248ba4b2bdd 100644 --- a/user_guide_src/source/incoming/controllers/010.php +++ b/user_guide_src/source/incoming/controllers/010.php @@ -2,10 +2,7 @@ namespace App\Controllers; -class Products extends BaseController +class helloworld extends BaseController { - public function _remap() - { - // Some code here... - } + // ... } diff --git a/user_guide_src/source/incoming/controllers/011.php b/user_guide_src/source/incoming/controllers/011.php index 159009b6b855..7615eecaeba0 100644 --- a/user_guide_src/source/incoming/controllers/011.php +++ b/user_guide_src/source/incoming/controllers/011.php @@ -2,14 +2,7 @@ namespace App\Controllers; -class Products extends BaseController +class HelloWorld extends BaseController { - public function _remap($method) - { - if ($method === 'some_method') { - return $this->{$method}(); - } - - return $this->default_method(); - } + // ... } diff --git a/user_guide_src/source/incoming/controllers/012.php b/user_guide_src/source/incoming/controllers/012.php index 4bfdb1393d02..efaecbb8f400 100644 --- a/user_guide_src/source/incoming/controllers/012.php +++ b/user_guide_src/source/incoming/controllers/012.php @@ -1,17 +1,8 @@ (\)*\ + */ -class Products extends BaseController -{ - public function _remap($method, ...$params) - { - $method = 'process_' . $method; - - if (method_exists($this, $method)) { - return $this->{$method}(...$params); - } - - throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); - } -} +$routes->get('helloworld', '\App\Controllers\HelloWorld::index'); diff --git a/user_guide_src/source/incoming/controllers/013.php b/user_guide_src/source/incoming/controllers/013.php index 7c2e9b7091ea..e43c3e4f2b34 100644 --- a/user_guide_src/source/incoming/controllers/013.php +++ b/user_guide_src/source/incoming/controllers/013.php @@ -2,10 +2,15 @@ namespace App\Controllers; -class Products extends BaseController +class Helloworld extends BaseController { - protected function utility() + public function index() { - // some code + echo 'Hello World!'; + } + + public function comment() + { + echo 'I am not flat!'; } } diff --git a/user_guide_src/source/incoming/controllers/014.php b/user_guide_src/source/incoming/controllers/014.php index 9414addbb81a..319fd8471a7b 100644 --- a/user_guide_src/source/incoming/controllers/014.php +++ b/user_guide_src/source/incoming/controllers/014.php @@ -1,5 +1,12 @@ request->isSecure()) { - $this->forceHTTPS(); +namespace App\Controllers; + +class Products extends BaseController +{ + public function shoes($sandals, $id) + { + echo $sandals; + echo $id; + } } diff --git a/user_guide_src/source/incoming/controllers/015.php b/user_guide_src/source/incoming/controllers/015.php index c3309ddbf201..2de1b716d040 100644 --- a/user_guide_src/source/incoming/controllers/015.php +++ b/user_guide_src/source/incoming/controllers/015.php @@ -1,5 +1,3 @@ request->isSecure()) { - $this->forceHTTPS(31536000); // one year -} +$routes->setDefaultController('Helloworld'); diff --git a/user_guide_src/source/incoming/controllers/016.php b/user_guide_src/source/incoming/controllers/016.php index ff3ab9edfcf1..d799d1cf0fb5 100644 --- a/user_guide_src/source/incoming/controllers/016.php +++ b/user_guide_src/source/incoming/controllers/016.php @@ -1,8 +1,3 @@ get('/', 'Home::index'); diff --git a/user_guide_src/source/incoming/controllers/017.php b/user_guide_src/source/incoming/controllers/017.php index 65b1c77f8014..8bcb6a2b00f9 100644 --- a/user_guide_src/source/incoming/controllers/017.php +++ b/user_guide_src/source/incoming/controllers/017.php @@ -2,19 +2,10 @@ namespace App\Controllers; -class UserController extends BaseController +class Products extends BaseController { - public function updateUser(int $userID) + public function _remap() { - if (! $this->validate([ - 'email' => "required|is_unique[users.email,id,{$userID}]", - 'name' => 'required|alpha_numeric_spaces', - ])) { - return view('users/update', [ - 'errors' => $this->validator->getErrors(), - ]); - } - - // do something here if successful... + // Some code here... } } diff --git a/user_guide_src/source/incoming/controllers/018.php b/user_guide_src/source/incoming/controllers/018.php index 48e936b60595..159009b6b855 100644 --- a/user_guide_src/source/incoming/controllers/018.php +++ b/user_guide_src/source/incoming/controllers/018.php @@ -2,16 +2,14 @@ namespace App\Controllers; -class UserController extends BaseController +class Products extends BaseController { - public function updateUser(int $userID) + public function _remap($method) { - if (! $this->validate('userRules')) { - return view('users/update', [ - 'errors' => $this->validator->getErrors(), - ]); + if ($method === 'some_method') { + return $this->{$method}(); } - // do something here if successful... + return $this->default_method(); } } diff --git a/user_guide_src/source/incoming/controllers/019.php b/user_guide_src/source/incoming/controllers/019.php index 1ae78e5791ff..4bfdb1393d02 100644 --- a/user_guide_src/source/incoming/controllers/019.php +++ b/user_guide_src/source/incoming/controllers/019.php @@ -2,24 +2,16 @@ namespace App\Controllers; -class StoreController extends BaseController +class Products extends BaseController { - public function product(int $id) + public function _remap($method, ...$params) { - $data = [ - 'id' => $id, - 'name' => $this->request->getVar('name'), - ]; + $method = 'process_' . $method; - $rule = [ - 'id' => 'integer', - 'name' => 'required|max_length[255]', - ]; - - if (! $this->validateData($data, $rule)) { - // ... + if (method_exists($this, $method)) { + return $this->{$method}(...$params); } - // ... + throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound(); } } diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 83cb4cc95e6d..eb7d57370015 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -118,23 +118,23 @@ Array Callable Syntax Since v4.2.0, you can use array callable syntax to specify the controller: -.. literalinclude:: routing/004_1.php +.. literalinclude:: routing/013.php :lines: 2- Or using ``use`` keyword: -.. literalinclude:: routing/004_2.php +.. literalinclude:: routing/014.php :lines: 2- If there are placeholders, it will automatically set the parameters in the specified order: -.. literalinclude:: routing/004_3.php +.. literalinclude:: routing/015.php :lines: 2- But the auto-configured parameters may not be correct if you use regular expressions in routes. In such a case, you can specify the parameters manually: -.. literalinclude:: routing/004_4.php +.. literalinclude:: routing/016.php :lines: 2- Custom Placeholders @@ -147,7 +147,7 @@ You add new placeholders with the ``addPlaceholder()`` method. The first paramet the placeholder. The second parameter is the Regular Expression pattern it should be replaced with. This must be called before you add the route: -.. literalinclude:: routing/013.php +.. literalinclude:: routing/017.php Regular Expressions =================== @@ -158,7 +158,7 @@ is allowed, as are back-references. .. important:: Note: If you use back-references you must use the dollar syntax rather than the double backslash syntax. A typical RegEx route might look something like this: - .. literalinclude:: routing/014.php + .. literalinclude:: routing/018.php In the above example, a URI similar to **products/shirts/123** would instead call the ``show`` method of the ``Products`` controller class, with the original first and second segment passed as arguments to it. @@ -169,7 +169,7 @@ represent the delimiter between multiple segments. For example, if a user accesses a password protected area of your web application and you wish to be able to redirect them back to the same page after they log in, you may find this example useful: -.. literalinclude:: routing/015.php +.. literalinclude:: routing/019.php For those of you who don't know regular expressions and want to learn more about them, `regular-expressions.info `_ might be a good starting point. @@ -183,7 +183,7 @@ You can use an anonymous function, or Closure, as the destination that a route m executed when the user visits that URI. This is handy for quickly executing small tasks, or even just showing a simple view: -.. literalinclude:: routing/016.php +.. literalinclude:: routing/020.php Mapping multiple routes ======================= @@ -192,7 +192,7 @@ While the ``add()`` method is simple to use, it is often handier to work with mu the ``map()`` method. Instead of calling the ``add()`` method for each route that you need to add, you can define an array of routes and then pass it as the first parameter to the ``map()`` method: -.. literalinclude:: routing/017.php +.. literalinclude:: routing/021.php Redirecting Routes ================== @@ -203,7 +203,7 @@ second parameter is either the new URI to redirect to, or the name of a named ro the HTTP status code that should be sent along with the redirect. The default value is ``302`` which is a temporary redirect and is recommended in most cases: -.. literalinclude:: routing/018.php +.. literalinclude:: routing/022.php If a redirect route is matched during a page load, the user will be immediately redirected to the new page before a controller can be loaded. @@ -215,26 +215,26 @@ You can group your routes under a common name with the ``group()`` method. The g appears prior to the routes defined inside of the group. This allows you to reduce the typing needed to build out an extensive set of routes that all share the opening string, like when building an admin area: -.. literalinclude:: routing/019.php +.. literalinclude:: routing/023.php This would prefix the **users** and **blog** URIs with **admin**, handling URLs like **admin/users** and **admin/blog**. If you need to assign options to a group, like a :ref:`assigning-namespace`, do it before the callback: -.. literalinclude:: routing/020.php +.. literalinclude:: routing/024.php This would handle a resource route to the ``App\API\v1\Users`` controller with the **api/users** URI. You can also use a specific :doc:`filter ` for a group of routes. This will always run the filter before or after the controller. This is especially handy during authentication or api logging: -.. literalinclude:: routing/021.php +.. literalinclude:: routing/025.php The value for the filter must match one of the aliases defined within **app/Config/Filters.php**. It is possible to nest groups within groups for finer organization if you need it: -.. literalinclude:: routing/022.php +.. literalinclude:: routing/026.php This would handle the URL at **admin/users/list**. @@ -245,7 +245,7 @@ config options like namespace, subdomain, etc. Without necessarily needing to ad an empty string in place of the prefix and the routes in the group will be routed as though the group never existed but with the given route config options: -.. literalinclude:: routing/023.php +.. literalinclude:: routing/027.php Environment Restrictions ======================== @@ -255,7 +255,7 @@ tools that only the developer can use on their local machines that are not reach This can be done with the ``environment()`` method. The first parameter is the name of the environment. Any routes defined within this closure are only accessible from the given environment: -.. literalinclude:: routing/024.php +.. literalinclude:: routing/028.php Reverse Routing =============== @@ -269,7 +269,7 @@ function to get the current route that should be used. The first parameter is th separated by a double colon (``::``), much like you would use when writing the initial route itself. Any parameters that should be passed to the route are passed in next: -.. literalinclude:: routing/025.php +.. literalinclude:: routing/029.php Using Named Routes ================== @@ -279,7 +279,7 @@ later, and even if the route definition changes, all of the links in your applic will still work without you having to make any changes. A route is named by passing in the ``as`` option with the name of the route: -.. literalinclude:: routing/026.php +.. literalinclude:: routing/030.php This has the added benefit of making the views more readable, too. @@ -289,7 +289,7 @@ Routes with any HTTP verbs It is possible to define a route with any HTTP verbs. You can use the ``add()`` method: -.. literalinclude:: routing/027.php +.. literalinclude:: routing/031.php .. warning:: While the ``add()`` method seems to be convenient, it is recommended to always use the HTTP-verb-based routes, described above, as it is more secure. If you use the :doc:`CSRF protection `, it does not protect **GET** @@ -310,7 +310,7 @@ You can create routes that work only from the command-line, and are inaccessible route methods will also be inaccessible from the CLI, but routes created by the ``add()`` method will still be available from the command line: -.. literalinclude:: routing/028.php +.. literalinclude:: routing/032.php .. warning:: If you don't disable auto-routing and place the command file in **app/Controllers**, anyone could access the command with the help of auto-routing via HTTP. @@ -321,7 +321,7 @@ Global Options All of the methods for creating a route (add, get, post, :doc:`resource ` etc) can take an array of options that can modify the generated routes, or further restrict them. The ``$options`` array is always the last parameter: -.. literalinclude:: routing/029.php +.. literalinclude:: routing/033.php .. _applying-filters: @@ -347,17 +347,17 @@ See :doc:`Controller filters ` for more information on setting up filte You specify an alias defined in **app/Config/Filters.php** for the filter value: -.. literalinclude:: routing/030.php +.. literalinclude:: routing/034.php You may also supply arguments to be passed to the alias filter's ``before()`` and ``after()`` methods: -.. literalinclude:: routing/031.php +.. literalinclude:: routing/035.php **Classname filter** You specify a filter classname for the filter value: -.. literalinclude:: routing/032.php +.. literalinclude:: routing/036.php **Multiple filters** @@ -365,7 +365,7 @@ You specify a filter classname for the filter value: You specify an array for the filter value: -.. literalinclude:: routing/033.php +.. literalinclude:: routing/037.php .. _assigning-namespace: @@ -376,7 +376,7 @@ While a default namespace will be prepended to the generated controllers (see be a different namespace to be used in any options array, with the ``namespace`` option. The value should be the namespace you want modified: -.. literalinclude:: routing/034.php +.. literalinclude:: routing/038.php The new namespace is only applied during that call for any methods that create a single route, like get, post, etc. For any methods that create multiple routes, the new namespace is attached to all routes generated by that function @@ -388,7 +388,7 @@ Limit to Hostname You can restrict groups of routes to function only in certain domain or sub-domains of your application by passing the "hostname" option along with the desired domain to allow it on as part of the options array: -.. literalinclude:: routing/035.php +.. literalinclude:: routing/039.php This example would only allow the specified hosts to work if the domain exactly matched **accounts.example.com**. It would not work under the main site at **example.com**. @@ -399,12 +399,12 @@ Limit to Subdomains When the ``subdomain`` option is present, the system will restrict the routes to only be available on that sub-domain. The route will only be matched if the subdomain is the one the application is being viewed through: -.. literalinclude:: routing/036.php +.. literalinclude:: routing/040.php You can restrict it to any subdomain by setting the value to an asterisk, (``*``). If you are viewing from a URL that does not have any subdomain present, this will not be matched: -.. literalinclude:: routing/037.php +.. literalinclude:: routing/041.php .. important:: The system is not perfect and should be tested for your specific domain before being used in production. Most domains should work fine but some edge case ones, especially with a period in the domain itself (not used @@ -419,7 +419,7 @@ value being the number of segments to offset. This can be beneficial when developing API's with the first URI segment being the version number. It can also be used when the first parameter is a language string: -.. literalinclude:: routing/038.php +.. literalinclude:: routing/042.php .. _routing-priority: @@ -432,11 +432,11 @@ You can solve this problem by lowering the priority of route processing using th accepts positive integers and zero. The higher the number specified in the ``priority``, the lower route priority in the processing queue: -.. literalinclude:: routing/039.php +.. literalinclude:: routing/043.php To disable this functionality, you must call the method with the parameter ``false``: -.. literalinclude:: routing/040.php +.. literalinclude:: routing/044.php .. note:: By default, all routes have a priority of 0. Negative integers will be cast to the absolute value. @@ -458,12 +458,12 @@ specified by the route. By default, this value is ``App\Controllers``. If you set the value empty string (``''``), it leaves each route to specify the fully namespaced controller: -.. literalinclude:: routing/041.php +.. literalinclude:: routing/045.php If your controllers are not explicitly namespaced, there is no need to change this. If you namespace your controllers, then you can change this value to save typing: -.. literalinclude:: routing/042.php +.. literalinclude:: routing/046.php Default Controller ================== @@ -472,7 +472,7 @@ When a user visits the root of your site (i.e., example.com) the controller to u the ``setDefaultController()`` method, unless a route exists for it explicitly. The default value for this is ``Home`` which matches the controller at **app/Controllers/Home.php**: -.. literalinclude:: routing/043.php +.. literalinclude:: routing/047.php The default controller is also used when no matching route has been found, and the URI would point to a directory in the controllers directory. For example, if the user visits **example.com/admin**, if a controller was found at @@ -488,7 +488,7 @@ when a controller is found that matches the URI, but no segment exists for the m In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the ``Products::listAll()`` method would be executed: -.. literalinclude:: routing/044.php +.. literalinclude:: routing/048.php Translate URI Dashes ==================== @@ -497,7 +497,7 @@ This option enables you to automatically replace dashes (``-``) with underscores URI segments, thus saving you additional route entries if you need to do that. This is required because the dash isn't a valid class or method name character and would cause a fatal error if you try to use it: -.. literalinclude:: routing/045.php +.. literalinclude:: routing/049.php .. _use-defined-routes-only: @@ -508,7 +508,7 @@ When no defined route is found that matches the URI, the system will attempt to controllers and methods as described in :ref:`auto-routing`. You can disable this automatic matching, and restrict routes to only those defined by you, by setting the ``setAutoRoute()`` option to false: -.. literalinclude:: routing/046.php +.. literalinclude:: routing/050.php .. warning:: If you use the :doc:`CSRF protection `, it does not protect **GET** requests. If the URI is accessible by the GET method, the CSRF protection will not work. @@ -520,7 +520,7 @@ When a page is not found that matches the current URI, the system will show a ge what happens by specifying an action to happen with the ``set404Override()`` method. The value can be either a valid class/method pair, just like you would show in any route, or a Closure: -.. literalinclude:: routing/047.php +.. literalinclude:: routing/051.php Route processing by priority ============================ @@ -529,7 +529,7 @@ Enables or disables processing of the routes queue by priority. Lowering the pri Disabled by default. This functionality affects all routes. For an example use of lowering the priority see :ref:`routing-priority`: -.. literalinclude:: routing/048.php +.. literalinclude:: routing/052.php .. _auto-routing: diff --git a/user_guide_src/source/incoming/routing/004_1.php b/user_guide_src/source/incoming/routing/004_1.php deleted file mode 100644 index b562d01ba3b2..000000000000 --- a/user_guide_src/source/incoming/routing/004_1.php +++ /dev/null @@ -1,3 +0,0 @@ -get('/', [\App\Controllers\Home::class, 'index']); diff --git a/user_guide_src/source/incoming/routing/004_2.php b/user_guide_src/source/incoming/routing/004_2.php deleted file mode 100644 index 6105564b13f3..000000000000 --- a/user_guide_src/source/incoming/routing/004_2.php +++ /dev/null @@ -1,5 +0,0 @@ -get('/', [Home::class, 'index']); diff --git a/user_guide_src/source/incoming/routing/004_3.php b/user_guide_src/source/incoming/routing/004_3.php deleted file mode 100644 index cd98314d8fe8..000000000000 --- a/user_guide_src/source/incoming/routing/004_3.php +++ /dev/null @@ -1,8 +0,0 @@ -get('product/(:num)/(:num)', [Product::class, 'index']); - -// The above code is the same as the following: -$routes->get('product/(:num)/(:num)', 'Product::index/$1/$2'); diff --git a/user_guide_src/source/incoming/routing/004_4.php b/user_guide_src/source/incoming/routing/004_4.php deleted file mode 100644 index aed6cc5176df..000000000000 --- a/user_guide_src/source/incoming/routing/004_4.php +++ /dev/null @@ -1,8 +0,0 @@ -get('product/(:num)/(:num)', [[Product::class, 'index'], '$2/$1']); - -// The above code is the same as the following: -$routes->get('product/(:num)/(:num)', 'Product::index/$2/$1'); diff --git a/user_guide_src/source/incoming/routing/013.php b/user_guide_src/source/incoming/routing/013.php index cb1cdda7c78c..b562d01ba3b2 100644 --- a/user_guide_src/source/incoming/routing/013.php +++ b/user_guide_src/source/incoming/routing/013.php @@ -1,4 +1,3 @@ addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); -$routes->get('users/(:uuid)', 'Users::show/$1'); +$routes->get('/', [\App\Controllers\Home::class, 'index']); diff --git a/user_guide_src/source/incoming/routing/014.php b/user_guide_src/source/incoming/routing/014.php index a1619a4bf080..6105564b13f3 100644 --- a/user_guide_src/source/incoming/routing/014.php +++ b/user_guide_src/source/incoming/routing/014.php @@ -1,3 +1,5 @@ get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); +use App\Controllers\Home; + +$routes->get('/', [Home::class, 'index']); diff --git a/user_guide_src/source/incoming/routing/015.php b/user_guide_src/source/incoming/routing/015.php index c9ddfae73610..cd98314d8fe8 100644 --- a/user_guide_src/source/incoming/routing/015.php +++ b/user_guide_src/source/incoming/routing/015.php @@ -1,3 +1,8 @@ get('login/(.+)', 'Auth::login/$1'); +use App\Controllers\Product; + +$routes->get('product/(:num)/(:num)', [Product::class, 'index']); + +// The above code is the same as the following: +$routes->get('product/(:num)/(:num)', 'Product::index/$1/$2'); diff --git a/user_guide_src/source/incoming/routing/016.php b/user_guide_src/source/incoming/routing/016.php index e4fc5bde4a68..aed6cc5176df 100644 --- a/user_guide_src/source/incoming/routing/016.php +++ b/user_guide_src/source/incoming/routing/016.php @@ -1,7 +1,8 @@ get('feed', static function () { - $rss = new RSSFeeder(); +use App\Controllers\Product; - return $rss->feed('general'); -}); +$routes->get('product/(:num)/(:num)', [[Product::class, 'index'], '$2/$1']); + +// The above code is the same as the following: +$routes->get('product/(:num)/(:num)', 'Product::index/$2/$1'); diff --git a/user_guide_src/source/incoming/routing/017.php b/user_guide_src/source/incoming/routing/017.php index 8ebc27e3f9f5..cb1cdda7c78c 100644 --- a/user_guide_src/source/incoming/routing/017.php +++ b/user_guide_src/source/incoming/routing/017.php @@ -1,8 +1,4 @@ 'Catalog::productLookupById', - 'product/(:alphanum)' => 'Catalog::productLookupByName', -]; - -$routes->map($multipleRoutes); +$routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}'); +$routes->get('users/(:uuid)', 'Users::show/$1'); diff --git a/user_guide_src/source/incoming/routing/018.php b/user_guide_src/source/incoming/routing/018.php index d92d9934db5a..a1619a4bf080 100644 --- a/user_guide_src/source/incoming/routing/018.php +++ b/user_guide_src/source/incoming/routing/018.php @@ -1,8 +1,3 @@ get('users/profile', 'Users::profile', ['as' => 'profile']); - -// Redirect to a named route -$routes->addRedirect('users/about', 'profile'); -// Redirect to a URI -$routes->addRedirect('users/about', 'users/profile'); +$routes->get('products/([a-z]+)/(\d+)', 'Products::show/$1/id_$2'); diff --git a/user_guide_src/source/incoming/routing/019.php b/user_guide_src/source/incoming/routing/019.php index 6f08c319c551..c9ddfae73610 100644 --- a/user_guide_src/source/incoming/routing/019.php +++ b/user_guide_src/source/incoming/routing/019.php @@ -1,6 +1,3 @@ group('admin', static function ($routes) { - $routes->get('users', 'Admin\Users::index'); - $routes->get('blog', 'Admin\Blog::index'); -}); +$routes->get('login/(.+)', 'Auth::login/$1'); diff --git a/user_guide_src/source/incoming/routing/020.php b/user_guide_src/source/incoming/routing/020.php index 7c66c3b693dd..e4fc5bde4a68 100644 --- a/user_guide_src/source/incoming/routing/020.php +++ b/user_guide_src/source/incoming/routing/020.php @@ -1,5 +1,7 @@ group('api', ['namespace' => 'App\API\v1'], static function ($routes) { - $routes->resource('users'); +$routes->get('feed', static function () { + $rss = new RSSFeeder(); + + return $rss->feed('general'); }); diff --git a/user_guide_src/source/incoming/routing/021.php b/user_guide_src/source/incoming/routing/021.php index 75cec09100cb..8ebc27e3f9f5 100644 --- a/user_guide_src/source/incoming/routing/021.php +++ b/user_guide_src/source/incoming/routing/021.php @@ -1,5 +1,8 @@ group('api', ['filter' => 'api-auth'], static function ($routes) { - $routes->resource('users'); -}); +$multipleRoutes = [ + 'product/(:num)' => 'Catalog::productLookupById', + 'product/(:alphanum)' => 'Catalog::productLookupByName', +]; + +$routes->map($multipleRoutes); diff --git a/user_guide_src/source/incoming/routing/022.php b/user_guide_src/source/incoming/routing/022.php index 1ed2a8a96ee6..d92d9934db5a 100644 --- a/user_guide_src/source/incoming/routing/022.php +++ b/user_guide_src/source/incoming/routing/022.php @@ -1,7 +1,8 @@ group('admin', static function ($routes) { - $routes->group('users', static function ($routes) { - $routes->get('list', 'Admin\Users::list'); - }); -}); +$routes->get('users/profile', 'Users::profile', ['as' => 'profile']); + +// Redirect to a named route +$routes->addRedirect('users/about', 'profile'); +// Redirect to a URI +$routes->addRedirect('users/about', 'users/profile'); diff --git a/user_guide_src/source/incoming/routing/023.php b/user_guide_src/source/incoming/routing/023.php index d7624ddc6d5c..6f08c319c551 100644 --- a/user_guide_src/source/incoming/routing/023.php +++ b/user_guide_src/source/incoming/routing/023.php @@ -1,7 +1,6 @@ group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { - $routes->get('login', 'AuthController::login', ['as' => 'login']); - $routes->post('login', 'AuthController::attemptLogin'); - $routes->get('logout', 'AuthController::logout'); +$routes->group('admin', static function ($routes) { + $routes->get('users', 'Admin\Users::index'); + $routes->get('blog', 'Admin\Blog::index'); }); diff --git a/user_guide_src/source/incoming/routing/024.php b/user_guide_src/source/incoming/routing/024.php index 53921b33f5eb..7c66c3b693dd 100644 --- a/user_guide_src/source/incoming/routing/024.php +++ b/user_guide_src/source/incoming/routing/024.php @@ -1,5 +1,5 @@ environment('development', static function ($routes) { - $routes->get('builder', 'Tools\Builder::index'); +$routes->group('api', ['namespace' => 'App\API\v1'], static function ($routes) { + $routes->resource('users'); }); diff --git a/user_guide_src/source/incoming/routing/025.php b/user_guide_src/source/incoming/routing/025.php index e6bc6bdfb65f..75cec09100cb 100644 --- a/user_guide_src/source/incoming/routing/025.php +++ b/user_guide_src/source/incoming/routing/025.php @@ -1,10 +1,5 @@ get('users/(:num)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2'); - -?> - - -View Gallery - +$routes->group('api', ['filter' => 'api-auth'], static function ($routes) { + $routes->resource('users'); +}); diff --git a/user_guide_src/source/incoming/routing/026.php b/user_guide_src/source/incoming/routing/026.php index 1c1c629893e3..1ed2a8a96ee6 100644 --- a/user_guide_src/source/incoming/routing/026.php +++ b/user_guide_src/source/incoming/routing/026.php @@ -1,10 +1,7 @@ get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); - -?> - - -View Gallery - +$routes->group('admin', static function ($routes) { + $routes->group('users', static function ($routes) { + $routes->get('list', 'Admin\Users::list'); + }); +}); diff --git a/user_guide_src/source/incoming/routing/027.php b/user_guide_src/source/incoming/routing/027.php index e2a3784f335f..d7624ddc6d5c 100644 --- a/user_guide_src/source/incoming/routing/027.php +++ b/user_guide_src/source/incoming/routing/027.php @@ -1,3 +1,7 @@ add('products', 'Product::feature'); +$routes->group('', ['namespace' => 'Myth\Auth\Controllers'], static function ($routes) { + $routes->get('login', 'AuthController::login', ['as' => 'login']); + $routes->post('login', 'AuthController::attemptLogin'); + $routes->get('logout', 'AuthController::logout'); +}); diff --git a/user_guide_src/source/incoming/routing/028.php b/user_guide_src/source/incoming/routing/028.php index a82d57ebc5c7..53921b33f5eb 100644 --- a/user_guide_src/source/incoming/routing/028.php +++ b/user_guide_src/source/incoming/routing/028.php @@ -1,3 +1,5 @@ cli('migrate', 'App\Database::migrate'); +$routes->environment('development', static function ($routes) { + $routes->get('builder', 'Tools\Builder::index'); +}); diff --git a/user_guide_src/source/incoming/routing/029.php b/user_guide_src/source/incoming/routing/029.php index ff7e995a1526..e6bc6bdfb65f 100644 --- a/user_guide_src/source/incoming/routing/029.php +++ b/user_guide_src/source/incoming/routing/029.php @@ -1,14 +1,10 @@ add('from', 'to', $options); -$routes->get('from', 'to', $options); -$routes->post('from', 'to', $options); -$routes->put('from', 'to', $options); -$routes->head('from', 'to', $options); -$routes->options('from', 'to', $options); -$routes->delete('from', 'to', $options); -$routes->patch('from', 'to', $options); -$routes->match(['get', 'put'], 'from', 'to', $options); -$routes->resource('photos', $options); -$routes->map($array, $options); -$routes->group('name', $options, static function () {}); +// The route is defined as: +$routes->get('users/(:num)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2'); + +?> + + +View Gallery + diff --git a/user_guide_src/source/incoming/routing/030.php b/user_guide_src/source/incoming/routing/030.php index 2515937bb02a..1c1c629893e3 100644 --- a/user_guide_src/source/incoming/routing/030.php +++ b/user_guide_src/source/incoming/routing/030.php @@ -1,3 +1,10 @@ get('admin', ' AdminController::index', ['filter' => 'admin-auth']); +// The route is defined as: +$routes->get('users/(:num)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery']); + +?> + + +View Gallery + diff --git a/user_guide_src/source/incoming/routing/031.php b/user_guide_src/source/incoming/routing/031.php index b50db49bd962..e2a3784f335f 100644 --- a/user_guide_src/source/incoming/routing/031.php +++ b/user_guide_src/source/incoming/routing/031.php @@ -1,3 +1,3 @@ post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); +$routes->add('products', 'Product::feature'); diff --git a/user_guide_src/source/incoming/routing/032.php b/user_guide_src/source/incoming/routing/032.php index dd6cd63ba61d..a82d57ebc5c7 100644 --- a/user_guide_src/source/incoming/routing/032.php +++ b/user_guide_src/source/incoming/routing/032.php @@ -1,3 +1,3 @@ get('admin', ' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); +$routes->cli('migrate', 'App\Database::migrate'); diff --git a/user_guide_src/source/incoming/routing/033.php b/user_guide_src/source/incoming/routing/033.php index 94ae43246897..ff7e995a1526 100644 --- a/user_guide_src/source/incoming/routing/033.php +++ b/user_guide_src/source/incoming/routing/033.php @@ -1,3 +1,14 @@ get('admin', ' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); +$routes->add('from', 'to', $options); +$routes->get('from', 'to', $options); +$routes->post('from', 'to', $options); +$routes->put('from', 'to', $options); +$routes->head('from', 'to', $options); +$routes->options('from', 'to', $options); +$routes->delete('from', 'to', $options); +$routes->patch('from', 'to', $options); +$routes->match(['get', 'put'], 'from', 'to', $options); +$routes->resource('photos', $options); +$routes->map($array, $options); +$routes->group('name', $options, static function () {}); diff --git a/user_guide_src/source/incoming/routing/034.php b/user_guide_src/source/incoming/routing/034.php index b992deb96ecf..2515937bb02a 100644 --- a/user_guide_src/source/incoming/routing/034.php +++ b/user_guide_src/source/incoming/routing/034.php @@ -1,4 +1,3 @@ get('admin/users', 'Users::index', ['namespace' => 'Admin']); +$routes->get('admin', ' AdminController::index', ['filter' => 'admin-auth']); diff --git a/user_guide_src/source/incoming/routing/035.php b/user_guide_src/source/incoming/routing/035.php index 5b415a50138b..b50db49bd962 100644 --- a/user_guide_src/source/incoming/routing/035.php +++ b/user_guide_src/source/incoming/routing/035.php @@ -1,3 +1,3 @@ get('from', 'to', ['hostname' => 'accounts.example.com']); +$routes->post('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']); diff --git a/user_guide_src/source/incoming/routing/036.php b/user_guide_src/source/incoming/routing/036.php index 32a74934eb3a..dd6cd63ba61d 100644 --- a/user_guide_src/source/incoming/routing/036.php +++ b/user_guide_src/source/incoming/routing/036.php @@ -1,4 +1,3 @@ get('from', 'to', ['subdomain' => 'media']); +$routes->get('admin', ' AdminController::index', ['filter' => \App\Filters\SomeFilter::class]); diff --git a/user_guide_src/source/incoming/routing/037.php b/user_guide_src/source/incoming/routing/037.php index 0d0fd0e67fb4..94ae43246897 100644 --- a/user_guide_src/source/incoming/routing/037.php +++ b/user_guide_src/source/incoming/routing/037.php @@ -1,4 +1,3 @@ get('from', 'to', ['subdomain' => '*']); +$routes->get('admin', ' AdminController::index', ['filter' => ['admin-auth', \App\Filters\SomeFilter::class]]); diff --git a/user_guide_src/source/incoming/routing/038.php b/user_guide_src/source/incoming/routing/038.php index ec7fa680f65e..b992deb96ecf 100644 --- a/user_guide_src/source/incoming/routing/038.php +++ b/user_guide_src/source/incoming/routing/038.php @@ -1,6 +1,4 @@ get('users/(:num)', 'users/show/$1', ['offset' => 1]); - -// Creates: -$routes['users/(:num)'] = 'users/show/$2'; +// Routes to \Admin\Users::index() +$routes->get('admin/users', 'Users::index', ['namespace' => 'Admin']); diff --git a/user_guide_src/source/incoming/routing/039.php b/user_guide_src/source/incoming/routing/039.php index 29fc83e59f17..5b415a50138b 100644 --- a/user_guide_src/source/incoming/routing/039.php +++ b/user_guide_src/source/incoming/routing/039.php @@ -1,12 +1,3 @@ setPrioritize(); - -// App\Config\Routes -$routes->get('(.*)', 'Posts::index', ['priority' => 1]); - -// Modules\Acme\Config\Routes -$routes->get('admin', 'Admin::index'); - -// The "admin" route will now be processed before the wildcard router. +$routes->get('from', 'to', ['hostname' => 'accounts.example.com']); diff --git a/user_guide_src/source/incoming/routing/040.php b/user_guide_src/source/incoming/routing/040.php index 9465f4147e2c..32a74934eb3a 100644 --- a/user_guide_src/source/incoming/routing/040.php +++ b/user_guide_src/source/incoming/routing/040.php @@ -1,3 +1,4 @@ setPrioritize(false); +// Limit to media.example.com +$routes->get('from', 'to', ['subdomain' => 'media']); diff --git a/user_guide_src/source/incoming/routing/041.php b/user_guide_src/source/incoming/routing/041.php index 98aef9276f9d..0d0fd0e67fb4 100644 --- a/user_guide_src/source/incoming/routing/041.php +++ b/user_guide_src/source/incoming/routing/041.php @@ -1,9 +1,4 @@ setDefaultNamespace(''); - -// Controller is \Users -$routes->get('users', 'Users::index'); - -// Controller is \Admin\Users -$routes->get('users', 'Admin\Users::index'); +// Limit to any sub-domain +$routes->get('from', 'to', ['subdomain' => '*']); diff --git a/user_guide_src/source/incoming/routing/042.php b/user_guide_src/source/incoming/routing/042.php index fbbbee2300df..ec7fa680f65e 100644 --- a/user_guide_src/source/incoming/routing/042.php +++ b/user_guide_src/source/incoming/routing/042.php @@ -1,9 +1,6 @@ setDefaultNamespace('App'); +$routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]); -// Controller is \App\Users -$routes->get('users', 'Users::index'); - -// Controller is \App\Admin\Users -$routes->get('users', 'Admin\Users::index'); +// Creates: +$routes['users/(:num)'] = 'users/show/$2'; diff --git a/user_guide_src/source/incoming/routing/043.php b/user_guide_src/source/incoming/routing/043.php index 5d17df8130d4..29fc83e59f17 100644 --- a/user_guide_src/source/incoming/routing/043.php +++ b/user_guide_src/source/incoming/routing/043.php @@ -1,4 +1,12 @@ setDefaultController('Welcome'); +// First you need to enable sorting. +$routes->setPrioritize(); + +// App\Config\Routes +$routes->get('(.*)', 'Posts::index', ['priority' => 1]); + +// Modules\Acme\Config\Routes +$routes->get('admin', 'Admin::index'); + +// The "admin" route will now be processed before the wildcard router. diff --git a/user_guide_src/source/incoming/routing/044.php b/user_guide_src/source/incoming/routing/044.php index e926e651287d..9465f4147e2c 100644 --- a/user_guide_src/source/incoming/routing/044.php +++ b/user_guide_src/source/incoming/routing/044.php @@ -1,3 +1,3 @@ setDefaultMethod('listAll'); +$routes->setPrioritize(false); diff --git a/user_guide_src/source/incoming/routing/045.php b/user_guide_src/source/incoming/routing/045.php index 31d49508ab86..98aef9276f9d 100644 --- a/user_guide_src/source/incoming/routing/045.php +++ b/user_guide_src/source/incoming/routing/045.php @@ -1,3 +1,9 @@ setTranslateURIDashes(true); +$routes->setDefaultNamespace(''); + +// Controller is \Users +$routes->get('users', 'Users::index'); + +// Controller is \Admin\Users +$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/046.php b/user_guide_src/source/incoming/routing/046.php index c331102cd9f4..fbbbee2300df 100644 --- a/user_guide_src/source/incoming/routing/046.php +++ b/user_guide_src/source/incoming/routing/046.php @@ -1,3 +1,9 @@ setAutoRoute(false); +$routes->setDefaultNamespace('App'); + +// Controller is \App\Users +$routes->get('users', 'Users::index'); + +// Controller is \App\Admin\Users +$routes->get('users', 'Admin\Users::index'); diff --git a/user_guide_src/source/incoming/routing/047.php b/user_guide_src/source/incoming/routing/047.php index dddd067f0f26..5d17df8130d4 100644 --- a/user_guide_src/source/incoming/routing/047.php +++ b/user_guide_src/source/incoming/routing/047.php @@ -1,9 +1,4 @@ set404Override('App\Errors::show404'); - -// Will display a custom view -$routes->set404Override(static function () { - echo view('my_errors/not_found.html'); -}); +// example.com routes to app/Controllers/Welcome.php +$routes->setDefaultController('Welcome'); diff --git a/user_guide_src/source/incoming/routing/048.php b/user_guide_src/source/incoming/routing/048.php index e3dd9f60c989..e926e651287d 100644 --- a/user_guide_src/source/incoming/routing/048.php +++ b/user_guide_src/source/incoming/routing/048.php @@ -1,7 +1,3 @@ setPrioritize(); - -// to disable -$routes->setPrioritize(false); +$routes->setDefaultMethod('listAll'); diff --git a/user_guide_src/source/incoming/routing/049.php b/user_guide_src/source/incoming/routing/049.php new file mode 100644 index 000000000000..31d49508ab86 --- /dev/null +++ b/user_guide_src/source/incoming/routing/049.php @@ -0,0 +1,3 @@ +setTranslateURIDashes(true); diff --git a/user_guide_src/source/incoming/routing/050.php b/user_guide_src/source/incoming/routing/050.php new file mode 100644 index 000000000000..c331102cd9f4 --- /dev/null +++ b/user_guide_src/source/incoming/routing/050.php @@ -0,0 +1,3 @@ +setAutoRoute(false); diff --git a/user_guide_src/source/incoming/routing/051.php b/user_guide_src/source/incoming/routing/051.php new file mode 100644 index 000000000000..dddd067f0f26 --- /dev/null +++ b/user_guide_src/source/incoming/routing/051.php @@ -0,0 +1,9 @@ +set404Override('App\Errors::show404'); + +// Will display a custom view +$routes->set404Override(static function () { + echo view('my_errors/not_found.html'); +}); diff --git a/user_guide_src/source/incoming/routing/052.php b/user_guide_src/source/incoming/routing/052.php new file mode 100644 index 000000000000..e3dd9f60c989 --- /dev/null +++ b/user_guide_src/source/incoming/routing/052.php @@ -0,0 +1,7 @@ +setPrioritize(); + +// to disable +$routes->setPrioritize(false); diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 8dea63ab953f..59557db92cf8 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -37,7 +37,7 @@ Alternatively, you can use the helper function that will use the default configuration options. This version is a little friendlier to read, but does not take any configuration options. -.. literalinclude:: sessions/003.php +.. literalinclude:: sessions/002.php How do Sessions work? ===================== @@ -89,7 +89,7 @@ have the session open, while you've already processed it and therefore no longer need it. So, what you need is to close the session for the current request after you no longer need it. -.. literalinclude:: sessions/004.php +.. literalinclude:: sessions/003.php What is Session Data? ===================== @@ -115,25 +115,25 @@ Retrieving Session Data Any piece of information from the session array is available through the ``$_SESSION`` superglobal: -.. literalinclude:: sessions/005.php +.. literalinclude:: sessions/004.php Or through the conventional accessor method: -.. literalinclude:: sessions/006.php +.. literalinclude:: sessions/005.php Or through the magic getter: -.. literalinclude:: sessions/007.php +.. literalinclude:: sessions/006.php Or even through the session helper method: -.. literalinclude:: sessions/008.php +.. literalinclude:: sessions/007.php Where ``item`` is the array key corresponding to the item you wish to fetch. For example, to assign a previously stored 'name' item to the ``$name`` variable, you will do this: -.. literalinclude:: sessions/009.php +.. literalinclude:: sessions/008.php .. note:: The ``get()`` method returns null if the item you are trying to access does not exist. @@ -141,7 +141,7 @@ variable, you will do this: If you want to retrieve all of the existing userdata, you can simply omit the item key (magic getter only works for single property values): -.. literalinclude:: sessions/010.php +.. literalinclude:: sessions/009.php Adding Session Data =================== @@ -158,26 +158,26 @@ The former userdata method is deprecated, but you can pass an array containing your new session data to the ``set()`` method: -.. literalinclude:: sessions/011.php +.. literalinclude:: sessions/010.php Where ``$array`` is an associative array containing your new data. Here's an example: -.. literalinclude:: sessions/012.php +.. literalinclude:: sessions/011.php If you want to add session data one value at a time, ``set()`` also supports this syntax: -.. literalinclude:: sessions/013.php +.. literalinclude:: sessions/012.php If you want to verify that a session value exists, simply check with ``isset()``: -.. literalinclude:: sessions/014.php +.. literalinclude:: sessions/013.php Or you can call ``has()``: -.. literalinclude:: sessions/015.php +.. literalinclude:: sessions/014.php Pushing new value to session data ================================= @@ -185,7 +185,7 @@ Pushing new value to session data The push method is used to push a new value onto a session value that is an array. For instance, if the 'hobbies' key contains an array of hobbies, you can add a new value onto the array like so: -.. literalinclude:: sessions/016.php +.. literalinclude:: sessions/015.php Removing Session Data ===================== @@ -193,18 +193,18 @@ Removing Session Data Just as with any other variable, unsetting a value in ``$_SESSION`` can be done through ``unset()``: -.. literalinclude:: sessions/017.php +.. literalinclude:: sessions/016.php Also, just as ``set()`` can be used to add information to a session, ``remove()`` can be used to remove it, by passing the session key. For example, if you wanted to remove 'some_name' from your session data array: -.. literalinclude:: sessions/018.php +.. literalinclude:: sessions/017.php This method also accepts an array of item keys to unset: -.. literalinclude:: sessions/019.php +.. literalinclude:: sessions/018.php Flashdata ========= @@ -220,20 +220,20 @@ managed inside the CodeIgniter session handler. To mark an existing item as "flashdata": -.. literalinclude:: sessions/020.php +.. literalinclude:: sessions/019.php If you want to mark multiple items as flashdata, simply pass the keys as an array: -.. literalinclude:: sessions/021.php +.. literalinclude:: sessions/020.php To add flashdata: -.. literalinclude:: sessions/022.php +.. literalinclude:: sessions/021.php Or alternatively, using the ``setFlashdata()`` method: -.. literalinclude:: sessions/023.php +.. literalinclude:: sessions/022.php You can also pass an array to ``setFlashdata()``, in the same manner as ``set()``. @@ -241,7 +241,7 @@ You can also pass an array to ``setFlashdata()``, in the same manner as Reading flashdata variables is the same as reading regular session data through ``$_SESSION``: -.. literalinclude:: sessions/024.php +.. literalinclude:: sessions/023.php .. important:: The ``get()`` method WILL return flashdata items when retrieving a single item by key. It will not return flashdata when @@ -250,11 +250,11 @@ through ``$_SESSION``: However, if you want to be sure that you're reading "flashdata" (and not any other kind), you can also use the ``getFlashdata()`` method: -.. literalinclude:: sessions/025.php +.. literalinclude:: sessions/024.php Or to get an array with all flashdata, simply omit the key parameter: -.. literalinclude:: sessions/026.php +.. literalinclude:: sessions/025.php .. note:: The ``getFlashdata()`` method returns null if the item cannot be found. @@ -263,7 +263,7 @@ If you find that you need to preserve a flashdata variable through an additional request, you can do so using the ``keepFlashdata()`` method. You can either pass a single item or an array of flashdata items to keep. -.. literalinclude:: sessions/027.php +.. literalinclude:: sessions/026.php Tempdata ======== @@ -278,24 +278,24 @@ CodeIgniter session handler. To mark an existing item as "tempdata", simply pass its key and expiry time (in seconds!) to the ``markAsTempdata()`` method: -.. literalinclude:: sessions/028.php +.. literalinclude:: sessions/027.php You can mark multiple items as tempdata in two ways, depending on whether you want them all to have the same expiry time or not: -.. literalinclude:: sessions/029.php +.. literalinclude:: sessions/028.php To add tempdata: -.. literalinclude:: sessions/030.php +.. literalinclude:: sessions/029.php Or alternatively, using the ``setTempdata()`` method: -.. literalinclude:: sessions/031.php +.. literalinclude:: sessions/030.php You can also pass an array to ``setTempdata()``: -.. literalinclude:: sessions/032.php +.. literalinclude:: sessions/031.php .. note:: If the expiration is omitted or set to 0, the default time-to-live value of 300 seconds (or 5 minutes) will be used. @@ -303,7 +303,7 @@ You can also pass an array to ``setTempdata()``: To read a tempdata variable, again you can just access it through the ``$_SESSION`` superglobal array: -.. literalinclude:: sessions/033.php +.. literalinclude:: sessions/032.php .. important:: The ``get()`` method WILL return tempdata items when retrieving a single item by key. It will not return tempdata when @@ -312,11 +312,11 @@ To read a tempdata variable, again you can just access it through the Or if you want to be sure that you're reading "tempdata" (and not any other kind), you can also use the ``getTempdata()`` method: -.. literalinclude:: sessions/034.php +.. literalinclude:: sessions/033.php And of course, if you want to retrieve all existing tempdata: -.. literalinclude:: sessions/035.php +.. literalinclude:: sessions/034.php .. note:: The ``getTempdata()`` method returns null if the item cannot be found. @@ -324,14 +324,14 @@ And of course, if you want to retrieve all existing tempdata: If you need to remove a tempdata value before it expires, you can directly unset it from the ``$_SESSION`` array: -.. literalinclude:: sessions/036.php +.. literalinclude:: sessions/035.php However, this won't remove the marker that makes this specific item to be tempdata (it will be invalidated on the next HTTP request), so if you intend to reuse that same key in the same request, you'd want to use ``removeTempdata()``: -.. literalinclude:: sessions/037.php +.. literalinclude:: sessions/036.php Destroying a Session ==================== @@ -341,7 +341,7 @@ simply use either PHP's `session_destroy() function, or the library's ``destroy()`` method. Both will work in exactly the same way: -.. literalinclude:: sessions/038.php +.. literalinclude:: sessions/037.php .. note:: This must be the last session-related operation that you do during the same request. All session data (including flashdata and @@ -352,7 +352,7 @@ You may also use the ``stop()`` method to completely kill the session by removing the old session_id, destroying all data, and destroying the cookie that contained the session id: -.. literalinclude:: sessions/039.php +.. literalinclude:: sessions/038.php Accessing session metadata ========================== @@ -527,7 +527,7 @@ table that we already mentioned and then set it as your For example, if you would like to use 'ci_sessions' as your table name, you would do this: -.. literalinclude:: sessions/040.php +.. literalinclude:: sessions/039.php And then of course, create the database table ... @@ -567,7 +567,7 @@ setting**. The examples below work both on MySQL and PostgreSQL:: You can choose the Database group to use by adding a new line to the **app/Config/App.php** file with the name of the group to use: -.. literalinclude:: sessions/041.php +.. literalinclude:: sessions/040.php If you'd rather not do all of this by hand, you can use the ``session:migration`` command from the cli to generate a migration file for you:: @@ -620,7 +620,7 @@ link you to it: For the most common case however, a simple ``host:port`` pair should be sufficient: -.. literalinclude:: sessions/042.php +.. literalinclude:: sessions/041.php MemcachedHandler Driver ======================= @@ -647,7 +647,7 @@ considered as it may result in loss of sessions. The ``$sessionSavePath`` format is fairly straightforward here, being just a ``host:port`` pair: -.. literalinclude:: sessions/043.php +.. literalinclude:: sessions/042.php Bonus Tip --------- @@ -659,4 +659,4 @@ to note that we haven't tested if that is reliable. If you want to experiment with this feature (on your own risk), simply separate the multiple server paths with commas: -.. literalinclude:: sessions/044.php +.. literalinclude:: sessions/043.php diff --git a/user_guide_src/source/libraries/sessions/002.php b/user_guide_src/source/libraries/sessions/002.php new file mode 100644 index 000000000000..ba2650b4808a --- /dev/null +++ b/user_guide_src/source/libraries/sessions/002.php @@ -0,0 +1,3 @@ +get('item'); diff --git a/user_guide_src/source/libraries/sessions/006.php b/user_guide_src/source/libraries/sessions/006.php index 3248324f7ee6..180d52833615 100644 --- a/user_guide_src/source/libraries/sessions/006.php +++ b/user_guide_src/source/libraries/sessions/006.php @@ -1,3 +1,3 @@ get('item'); +$item = $session->item; diff --git a/user_guide_src/source/libraries/sessions/007.php b/user_guide_src/source/libraries/sessions/007.php index 180d52833615..2825b97d5c4b 100644 --- a/user_guide_src/source/libraries/sessions/007.php +++ b/user_guide_src/source/libraries/sessions/007.php @@ -1,3 +1,3 @@ item; +$item = session('item'); diff --git a/user_guide_src/source/libraries/sessions/008.php b/user_guide_src/source/libraries/sessions/008.php index 2825b97d5c4b..12632835f531 100644 --- a/user_guide_src/source/libraries/sessions/008.php +++ b/user_guide_src/source/libraries/sessions/008.php @@ -1,3 +1,11 @@ name; + +// or: + +$name = $session->get('name'); diff --git a/user_guide_src/source/libraries/sessions/009.php b/user_guide_src/source/libraries/sessions/009.php index 12632835f531..4bbbfb2646db 100644 --- a/user_guide_src/source/libraries/sessions/009.php +++ b/user_guide_src/source/libraries/sessions/009.php @@ -1,11 +1,5 @@ name; - -// or: - -$name = $session->get('name'); +$userData = $session->get(); diff --git a/user_guide_src/source/libraries/sessions/010.php b/user_guide_src/source/libraries/sessions/010.php index 4bbbfb2646db..b8b949797d22 100644 --- a/user_guide_src/source/libraries/sessions/010.php +++ b/user_guide_src/source/libraries/sessions/010.php @@ -1,5 +1,3 @@ get(); +$session->set($array); diff --git a/user_guide_src/source/libraries/sessions/011.php b/user_guide_src/source/libraries/sessions/011.php index b8b949797d22..01bbbe1670b0 100644 --- a/user_guide_src/source/libraries/sessions/011.php +++ b/user_guide_src/source/libraries/sessions/011.php @@ -1,3 +1,9 @@ set($array); +$newdata = [ + 'username' => 'johndoe', + 'email' => 'johndoe@some-site.com', + 'logged_in' => true, +]; + +$session->set($newdata); diff --git a/user_guide_src/source/libraries/sessions/012.php b/user_guide_src/source/libraries/sessions/012.php index 01bbbe1670b0..0d9c4699281a 100644 --- a/user_guide_src/source/libraries/sessions/012.php +++ b/user_guide_src/source/libraries/sessions/012.php @@ -1,9 +1,3 @@ 'johndoe', - 'email' => 'johndoe@some-site.com', - 'logged_in' => true, -]; - -$session->set($newdata); +$session->set('some_name', 'some_value'); diff --git a/user_guide_src/source/libraries/sessions/013.php b/user_guide_src/source/libraries/sessions/013.php index 0d9c4699281a..45bce58b5e06 100644 --- a/user_guide_src/source/libraries/sessions/013.php +++ b/user_guide_src/source/libraries/sessions/013.php @@ -1,3 +1,7 @@ set('some_name', 'some_value'); +// returns false if the 'some_name' item doesn't exist or is null, +// true otherwise: +if (isset($_SESSION['some_name'])) { + // ... +} diff --git a/user_guide_src/source/libraries/sessions/014.php b/user_guide_src/source/libraries/sessions/014.php index 45bce58b5e06..5b00a839dcb8 100644 --- a/user_guide_src/source/libraries/sessions/014.php +++ b/user_guide_src/source/libraries/sessions/014.php @@ -1,7 +1,3 @@ has('some_name'); diff --git a/user_guide_src/source/libraries/sessions/015.php b/user_guide_src/source/libraries/sessions/015.php index 5b00a839dcb8..e80a0177905a 100644 --- a/user_guide_src/source/libraries/sessions/015.php +++ b/user_guide_src/source/libraries/sessions/015.php @@ -1,3 +1,3 @@ has('some_name'); +$session->push('hobbies', ['sport' => 'tennis']); diff --git a/user_guide_src/source/libraries/sessions/016.php b/user_guide_src/source/libraries/sessions/016.php index e80a0177905a..2b00df65a034 100644 --- a/user_guide_src/source/libraries/sessions/016.php +++ b/user_guide_src/source/libraries/sessions/016.php @@ -1,3 +1,8 @@ push('hobbies', ['sport' => 'tennis']); +unset($_SESSION['some_name']); +// or multiple values: +unset( + $_SESSION['some_name'], + $_SESSION['another_name'] +); diff --git a/user_guide_src/source/libraries/sessions/017.php b/user_guide_src/source/libraries/sessions/017.php index 2b00df65a034..7c7dbf3ca32a 100644 --- a/user_guide_src/source/libraries/sessions/017.php +++ b/user_guide_src/source/libraries/sessions/017.php @@ -1,8 +1,3 @@ remove('some_name'); diff --git a/user_guide_src/source/libraries/sessions/018.php b/user_guide_src/source/libraries/sessions/018.php index 7c7dbf3ca32a..2ebd4f8a4e5f 100644 --- a/user_guide_src/source/libraries/sessions/018.php +++ b/user_guide_src/source/libraries/sessions/018.php @@ -1,3 +1,4 @@ remove('some_name'); +$array_items = ['username', 'email']; +$session->remove($array_items); diff --git a/user_guide_src/source/libraries/sessions/019.php b/user_guide_src/source/libraries/sessions/019.php index 2ebd4f8a4e5f..471c5c5fef96 100644 --- a/user_guide_src/source/libraries/sessions/019.php +++ b/user_guide_src/source/libraries/sessions/019.php @@ -1,4 +1,3 @@ remove($array_items); +$session->markAsFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/020.php b/user_guide_src/source/libraries/sessions/020.php index 471c5c5fef96..4be42e7f3a62 100644 --- a/user_guide_src/source/libraries/sessions/020.php +++ b/user_guide_src/source/libraries/sessions/020.php @@ -1,3 +1,3 @@ markAsFlashdata('item'); +$session->markAsFlashdata(['item', 'item2']); diff --git a/user_guide_src/source/libraries/sessions/021.php b/user_guide_src/source/libraries/sessions/021.php index 4be42e7f3a62..d87dd8763d34 100644 --- a/user_guide_src/source/libraries/sessions/021.php +++ b/user_guide_src/source/libraries/sessions/021.php @@ -1,3 +1,4 @@ markAsFlashdata(['item', 'item2']); +$_SESSION['item'] = 'value'; +$session->markAsFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/022.php b/user_guide_src/source/libraries/sessions/022.php index d87dd8763d34..f22af522ab61 100644 --- a/user_guide_src/source/libraries/sessions/022.php +++ b/user_guide_src/source/libraries/sessions/022.php @@ -1,4 +1,3 @@ markAsFlashdata('item'); +$session->setFlashdata('item', 'value'); diff --git a/user_guide_src/source/libraries/sessions/023.php b/user_guide_src/source/libraries/sessions/023.php index f22af522ab61..ec1e40879798 100644 --- a/user_guide_src/source/libraries/sessions/023.php +++ b/user_guide_src/source/libraries/sessions/023.php @@ -1,3 +1,3 @@ setFlashdata('item', 'value'); +$item = $_SESSION['item']; diff --git a/user_guide_src/source/libraries/sessions/024.php b/user_guide_src/source/libraries/sessions/024.php index ec1e40879798..407208d20b4a 100644 --- a/user_guide_src/source/libraries/sessions/024.php +++ b/user_guide_src/source/libraries/sessions/024.php @@ -1,3 +1,3 @@ getFlashdata('item'); diff --git a/user_guide_src/source/libraries/sessions/025.php b/user_guide_src/source/libraries/sessions/025.php index 407208d20b4a..7c387b5a4fa2 100644 --- a/user_guide_src/source/libraries/sessions/025.php +++ b/user_guide_src/source/libraries/sessions/025.php @@ -1,3 +1,3 @@ getFlashdata('item'); +$session->getFlashdata(); diff --git a/user_guide_src/source/libraries/sessions/026.php b/user_guide_src/source/libraries/sessions/026.php index 7c387b5a4fa2..94a299006a5d 100644 --- a/user_guide_src/source/libraries/sessions/026.php +++ b/user_guide_src/source/libraries/sessions/026.php @@ -1,3 +1,4 @@ getFlashdata(); +$session->keepFlashdata('item'); +$session->keepFlashdata(['item1', 'item2', 'item3']); diff --git a/user_guide_src/source/libraries/sessions/027.php b/user_guide_src/source/libraries/sessions/027.php index 94a299006a5d..d2ed461826c0 100644 --- a/user_guide_src/source/libraries/sessions/027.php +++ b/user_guide_src/source/libraries/sessions/027.php @@ -1,4 +1,4 @@ keepFlashdata('item'); -$session->keepFlashdata(['item1', 'item2', 'item3']); +// 'item' will be erased after 300 seconds +$session->markAsTempdata('item', 300); diff --git a/user_guide_src/source/libraries/sessions/028.php b/user_guide_src/source/libraries/sessions/028.php index d2ed461826c0..fd8d241ad069 100644 --- a/user_guide_src/source/libraries/sessions/028.php +++ b/user_guide_src/source/libraries/sessions/028.php @@ -1,4 +1,11 @@ markAsTempdata('item', 300); +// Both 'item' and 'item2' will expire after 300 seconds +$session->markAsTempdata(['item', 'item2'], 300); + +// 'item' will be erased after 300 seconds, while 'item2' +// will do so after only 240 seconds +$session->markAsTempdata([ + 'item' => 300, + 'item2' => 240, +]); diff --git a/user_guide_src/source/libraries/sessions/029.php b/user_guide_src/source/libraries/sessions/029.php index fd8d241ad069..d4e8941b5d34 100644 --- a/user_guide_src/source/libraries/sessions/029.php +++ b/user_guide_src/source/libraries/sessions/029.php @@ -1,11 +1,4 @@ markAsTempdata(['item', 'item2'], 300); - -// 'item' will be erased after 300 seconds, while 'item2' -// will do so after only 240 seconds -$session->markAsTempdata([ - 'item' => 300, - 'item2' => 240, -]); +$_SESSION['item'] = 'value'; +$session->markAsTempdata('item', 300); // Expire in 5 minutes diff --git a/user_guide_src/source/libraries/sessions/030.php b/user_guide_src/source/libraries/sessions/030.php index d4e8941b5d34..444c045adae9 100644 --- a/user_guide_src/source/libraries/sessions/030.php +++ b/user_guide_src/source/libraries/sessions/030.php @@ -1,4 +1,3 @@ markAsTempdata('item', 300); // Expire in 5 minutes +$session->setTempdata('item', 'value', 300); diff --git a/user_guide_src/source/libraries/sessions/031.php b/user_guide_src/source/libraries/sessions/031.php index 444c045adae9..f7099d76289a 100644 --- a/user_guide_src/source/libraries/sessions/031.php +++ b/user_guide_src/source/libraries/sessions/031.php @@ -1,3 +1,4 @@ setTempdata('item', 'value', 300); +$tempdata = ['newuser' => true, 'message' => 'Thanks for joining!']; +$session->setTempdata($tempdata, null, $expire); diff --git a/user_guide_src/source/libraries/sessions/032.php b/user_guide_src/source/libraries/sessions/032.php index f7099d76289a..ec1e40879798 100644 --- a/user_guide_src/source/libraries/sessions/032.php +++ b/user_guide_src/source/libraries/sessions/032.php @@ -1,4 +1,3 @@ true, 'message' => 'Thanks for joining!']; -$session->setTempdata($tempdata, null, $expire); +$item = $_SESSION['item']; diff --git a/user_guide_src/source/libraries/sessions/033.php b/user_guide_src/source/libraries/sessions/033.php index ec1e40879798..e940ed0e6a02 100644 --- a/user_guide_src/source/libraries/sessions/033.php +++ b/user_guide_src/source/libraries/sessions/033.php @@ -1,3 +1,3 @@ getTempdata('item'); diff --git a/user_guide_src/source/libraries/sessions/034.php b/user_guide_src/source/libraries/sessions/034.php index e940ed0e6a02..f44b959eee81 100644 --- a/user_guide_src/source/libraries/sessions/034.php +++ b/user_guide_src/source/libraries/sessions/034.php @@ -1,3 +1,3 @@ getTempdata('item'); +$session->getTempdata(); diff --git a/user_guide_src/source/libraries/sessions/035.php b/user_guide_src/source/libraries/sessions/035.php index f44b959eee81..f063fa2907f4 100644 --- a/user_guide_src/source/libraries/sessions/035.php +++ b/user_guide_src/source/libraries/sessions/035.php @@ -1,3 +1,3 @@ getTempdata(); +unset($_SESSION['item']); diff --git a/user_guide_src/source/libraries/sessions/036.php b/user_guide_src/source/libraries/sessions/036.php index f063fa2907f4..0c3302fb6db3 100644 --- a/user_guide_src/source/libraries/sessions/036.php +++ b/user_guide_src/source/libraries/sessions/036.php @@ -1,3 +1,3 @@ removeTempdata('item'); diff --git a/user_guide_src/source/libraries/sessions/037.php b/user_guide_src/source/libraries/sessions/037.php index 0c3302fb6db3..1e7931f34f33 100644 --- a/user_guide_src/source/libraries/sessions/037.php +++ b/user_guide_src/source/libraries/sessions/037.php @@ -1,3 +1,5 @@ removeTempdata('item'); +session_destroy(); +// or +$session->destroy(); diff --git a/user_guide_src/source/libraries/sessions/038.php b/user_guide_src/source/libraries/sessions/038.php index 1e7931f34f33..7b43795e71e4 100644 --- a/user_guide_src/source/libraries/sessions/038.php +++ b/user_guide_src/source/libraries/sessions/038.php @@ -1,5 +1,3 @@ destroy(); +$session->stop(); diff --git a/user_guide_src/source/libraries/sessions/039.php b/user_guide_src/source/libraries/sessions/039.php index 7b43795e71e4..3aedc2f047af 100644 --- a/user_guide_src/source/libraries/sessions/039.php +++ b/user_guide_src/source/libraries/sessions/039.php @@ -1,3 +1,12 @@ stop(); +namespace Config; + +use CodeIgniter\Config\BaseConfig; + +class App extends BaseConfig +{ + public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; + public $sessionSavePath = 'ci_sessions'; + // ... +} diff --git a/user_guide_src/source/libraries/sessions/040.php b/user_guide_src/source/libraries/sessions/040.php index 3aedc2f047af..f645887ec2be 100644 --- a/user_guide_src/source/libraries/sessions/040.php +++ b/user_guide_src/source/libraries/sessions/040.php @@ -6,7 +6,6 @@ class App extends BaseConfig { - public $sessionDriver = 'CodeIgniter\Session\Handlers\DatabaseHandler'; - public $sessionSavePath = 'ci_sessions'; + public $sessionDBGroup = 'groupName'; // ... } diff --git a/user_guide_src/source/libraries/sessions/041.php b/user_guide_src/source/libraries/sessions/041.php index f645887ec2be..f0aed919a816 100644 --- a/user_guide_src/source/libraries/sessions/041.php +++ b/user_guide_src/source/libraries/sessions/041.php @@ -6,6 +6,7 @@ class App extends BaseConfig { - public $sessionDBGroup = 'groupName'; + public $sessionDiver = 'CodeIgniter\Session\Handlers\RedisHandler'; + public $sessionSavePath = 'tcp://localhost:6379'; // ... } diff --git a/user_guide_src/source/libraries/sessions/042.php b/user_guide_src/source/libraries/sessions/042.php index f0aed919a816..cad56413151c 100644 --- a/user_guide_src/source/libraries/sessions/042.php +++ b/user_guide_src/source/libraries/sessions/042.php @@ -6,7 +6,7 @@ class App extends BaseConfig { - public $sessionDiver = 'CodeIgniter\Session\Handlers\RedisHandler'; - public $sessionSavePath = 'tcp://localhost:6379'; + public $sessionDriver = 'CodeIgniter\Session\Handlers\MemcachedHandler'; + public $sessionSavePath = 'localhost:11211'; // ... } diff --git a/user_guide_src/source/libraries/sessions/043.php b/user_guide_src/source/libraries/sessions/043.php index cad56413151c..e5fab8602236 100644 --- a/user_guide_src/source/libraries/sessions/043.php +++ b/user_guide_src/source/libraries/sessions/043.php @@ -6,7 +6,9 @@ class App extends BaseConfig { - public $sessionDriver = 'CodeIgniter\Session\Handlers\MemcachedHandler'; - public $sessionSavePath = 'localhost:11211'; + // localhost will be given higher priority (5) here, + // compared to 192.0.2.1 with a weight of 1. + public $sessionSavePath = 'localhost:11211:5,192.0.2.1:11211:1'; + // ... } diff --git a/user_guide_src/source/libraries/sessions/044.php b/user_guide_src/source/libraries/sessions/044.php deleted file mode 100644 index e5fab8602236..000000000000 --- a/user_guide_src/source/libraries/sessions/044.php +++ /dev/null @@ -1,14 +0,0 @@ -request->getFile('userfile'); diff --git a/user_guide_src/source/libraries/uploaded_files/005.php b/user_guide_src/source/libraries/uploaded_files/005.php new file mode 100644 index 000000000000..ad71bd5575fb --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/005.php @@ -0,0 +1,3 @@ +request->getFile('my-form.details.avatar'); diff --git a/user_guide_src/source/libraries/uploaded_files/006.php b/user_guide_src/source/libraries/uploaded_files/006.php new file mode 100644 index 000000000000..f0be5ba1aafb --- /dev/null +++ b/user_guide_src/source/libraries/uploaded_files/006.php @@ -0,0 +1,10 @@ +request->getFiles()) { + foreach ($imagefile['images'] as $img) { + if ($img->isValid() && ! $img->hasMoved()) { + $newName = $img->getRandomName(); + $img->move(WRITEPATH . 'uploads', $newName); + } + } +} diff --git a/user_guide_src/source/libraries/uploaded_files/007.php b/user_guide_src/source/libraries/uploaded_files/007.php index e5f6440d96fb..da51d17dbd15 100644 --- a/user_guide_src/source/libraries/uploaded_files/007.php +++ b/user_guide_src/source/libraries/uploaded_files/007.php @@ -1,3 +1,4 @@ request->getFile('userfile'); +$file1 = $this->request->getFile('images.0'); +$file2 = $this->request->getFile('images.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/008.php b/user_guide_src/source/libraries/uploaded_files/008.php index ad71bd5575fb..646e6bb0b8b9 100644 --- a/user_guide_src/source/libraries/uploaded_files/008.php +++ b/user_guide_src/source/libraries/uploaded_files/008.php @@ -1,3 +1,3 @@ request->getFile('my-form.details.avatar'); +$files = $this->request->getFileMultiple('images'); diff --git a/user_guide_src/source/libraries/uploaded_files/009.php b/user_guide_src/source/libraries/uploaded_files/009.php index f0be5ba1aafb..d18a755ba234 100644 --- a/user_guide_src/source/libraries/uploaded_files/009.php +++ b/user_guide_src/source/libraries/uploaded_files/009.php @@ -1,10 +1,4 @@ request->getFiles()) { - foreach ($imagefile['images'] as $img) { - if ($img->isValid() && ! $img->hasMoved()) { - $newName = $img->getRandomName(); - $img->move(WRITEPATH . 'uploads', $newName); - } - } -} +$file1 = $this->request->getFile('my-form.details.avatars.0'); +$file2 = $this->request->getFile('my-form.details.avatars.1'); diff --git a/user_guide_src/source/libraries/uploaded_files/010.php b/user_guide_src/source/libraries/uploaded_files/010.php index da51d17dbd15..094ea73c1064 100644 --- a/user_guide_src/source/libraries/uploaded_files/010.php +++ b/user_guide_src/source/libraries/uploaded_files/010.php @@ -1,4 +1,5 @@ request->getFile('images.0'); -$file2 = $this->request->getFile('images.1'); +if (! $file->isValid()) { + throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); +} diff --git a/user_guide_src/source/libraries/uploaded_files/011.php b/user_guide_src/source/libraries/uploaded_files/011.php index 646e6bb0b8b9..057a56b3e9a0 100644 --- a/user_guide_src/source/libraries/uploaded_files/011.php +++ b/user_guide_src/source/libraries/uploaded_files/011.php @@ -1,3 +1,3 @@ request->getFileMultiple('images'); +$name = $file->getName(); diff --git a/user_guide_src/source/libraries/uploaded_files/012.php b/user_guide_src/source/libraries/uploaded_files/012.php index d18a755ba234..4fb0cae0ad12 100644 --- a/user_guide_src/source/libraries/uploaded_files/012.php +++ b/user_guide_src/source/libraries/uploaded_files/012.php @@ -1,4 +1,3 @@ request->getFile('my-form.details.avatars.0'); -$file2 = $this->request->getFile('my-form.details.avatars.1'); +$originalName = $file->getClientName(); diff --git a/user_guide_src/source/libraries/uploaded_files/013.php b/user_guide_src/source/libraries/uploaded_files/013.php index 094ea73c1064..c9e4774a4bbf 100644 --- a/user_guide_src/source/libraries/uploaded_files/013.php +++ b/user_guide_src/source/libraries/uploaded_files/013.php @@ -1,5 +1,3 @@ isValid()) { - throw new \RuntimeException($file->getErrorString() . '(' . $file->getError() . ')'); -} +$tempfile = $file->getTempName(); diff --git a/user_guide_src/source/libraries/uploaded_files/014.php b/user_guide_src/source/libraries/uploaded_files/014.php index 057a56b3e9a0..867877238c76 100644 --- a/user_guide_src/source/libraries/uploaded_files/014.php +++ b/user_guide_src/source/libraries/uploaded_files/014.php @@ -1,3 +1,3 @@ getName(); +$ext = $file->getClientExtension(); diff --git a/user_guide_src/source/libraries/uploaded_files/015.php b/user_guide_src/source/libraries/uploaded_files/015.php index 4fb0cae0ad12..dd1288e441c3 100644 --- a/user_guide_src/source/libraries/uploaded_files/015.php +++ b/user_guide_src/source/libraries/uploaded_files/015.php @@ -1,3 +1,5 @@ getClientName(); +$type = $file->getClientMimeType(); + +echo $type; // image/png diff --git a/user_guide_src/source/libraries/uploaded_files/016.php b/user_guide_src/source/libraries/uploaded_files/016.php index c9e4774a4bbf..12499a3ca1ba 100644 --- a/user_guide_src/source/libraries/uploaded_files/016.php +++ b/user_guide_src/source/libraries/uploaded_files/016.php @@ -1,3 +1,3 @@ getTempName(); +$file->move(WRITEPATH . 'uploads'); diff --git a/user_guide_src/source/libraries/uploaded_files/017.php b/user_guide_src/source/libraries/uploaded_files/017.php index 867877238c76..2e6b39645a4b 100644 --- a/user_guide_src/source/libraries/uploaded_files/017.php +++ b/user_guide_src/source/libraries/uploaded_files/017.php @@ -1,3 +1,4 @@ getClientExtension(); +$newName = $file->getRandomName(); +$file->move(WRITEPATH . 'uploads', $newName); diff --git a/user_guide_src/source/libraries/uploaded_files/018.php b/user_guide_src/source/libraries/uploaded_files/018.php index dd1288e441c3..7f49d1f5232e 100644 --- a/user_guide_src/source/libraries/uploaded_files/018.php +++ b/user_guide_src/source/libraries/uploaded_files/018.php @@ -1,5 +1,5 @@ getClientMimeType(); - -echo $type; // image/png +if ($file->isValid() && ! $file->hasMoved()) { + $file->move($path); +} diff --git a/user_guide_src/source/libraries/uploaded_files/019.php b/user_guide_src/source/libraries/uploaded_files/019.php index 12499a3ca1ba..90f9495eaf7b 100644 --- a/user_guide_src/source/libraries/uploaded_files/019.php +++ b/user_guide_src/source/libraries/uploaded_files/019.php @@ -1,3 +1,3 @@ move(WRITEPATH . 'uploads'); +$path = $this->request->getFile('userfile')->store(); diff --git a/user_guide_src/source/libraries/uploaded_files/020.php b/user_guide_src/source/libraries/uploaded_files/020.php index 2e6b39645a4b..0e552f417d52 100644 --- a/user_guide_src/source/libraries/uploaded_files/020.php +++ b/user_guide_src/source/libraries/uploaded_files/020.php @@ -1,4 +1,3 @@ getRandomName(); -$file->move(WRITEPATH . 'uploads', $newName); +$path = $this->request->getFile('userfile')->store('head_img/', 'user_name.jpg'); diff --git a/user_guide_src/source/libraries/uploaded_files/021.php b/user_guide_src/source/libraries/uploaded_files/021.php deleted file mode 100644 index 7f49d1f5232e..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/021.php +++ /dev/null @@ -1,5 +0,0 @@ -isValid() && ! $file->hasMoved()) { - $file->move($path); -} diff --git a/user_guide_src/source/libraries/uploaded_files/022.php b/user_guide_src/source/libraries/uploaded_files/022.php deleted file mode 100644 index 90f9495eaf7b..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/022.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFile('userfile')->store(); diff --git a/user_guide_src/source/libraries/uploaded_files/023.php b/user_guide_src/source/libraries/uploaded_files/023.php deleted file mode 100644 index 0e552f417d52..000000000000 --- a/user_guide_src/source/libraries/uploaded_files/023.php +++ /dev/null @@ -1,3 +0,0 @@ -request->getFile('userfile')->store('head_img/', 'user_name.jpg'); diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 1d2c8490d339..8d3204804e92 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -484,7 +484,7 @@ You can check to see if an error exists with the ``hasError()`` method. The only When specifying a field with a wildcard, all errors matching the mask will be checked: -.. literalinclude:: validation/028.2.php +.. literalinclude:: validation/029.php Customizing Error Display ************************* @@ -500,12 +500,12 @@ The first step is to create custom views. These can be placed anywhere that the which means the standard View directory, or any namespaced View folder will work. For example, you could create a new view at **/app/Views/_errors_list.php**: -.. literalinclude:: validation/029.php +.. literalinclude:: validation/030.php An array named ``$errors`` is available within the view that contains a list of the errors, where the key is the name of the field that had the error, and the value is the error message, like this: -.. literalinclude:: validation/030.php +.. literalinclude:: validation/031.php There are actually two types of views that you can create. The first has an array of all of the errors, and is what we just looked at. The other type is simpler, and only contains a single variable, ``$error`` that contains the @@ -520,7 +520,7 @@ Once you have your views created, you need to let the Validation library know ab Inside, you'll find the ``$templates`` property where you can list as many custom views as you want, and provide an short alias they can be referenced by. If we were to add our example file from above, it would look something like: -.. literalinclude:: validation/031.php +.. literalinclude:: validation/032.php Specifying the Template ======================= @@ -541,7 +541,7 @@ Rules are stored within simple, namespaced classes. They can be stored any locat autoloader can find it. These files are called RuleSets. To add a new RuleSet, edit **Config/Validation.php** and add the new file to the ``$ruleSets`` array: -.. literalinclude:: validation/032.php +.. literalinclude:: validation/033.php You can add it as either a simple string with the fully qualified class name, or using the ``::class`` suffix as shown above. The primary benefit here is that it provides some extra navigation capabilities in more advanced IDEs. @@ -549,17 +549,17 @@ shown above. The primary benefit here is that it provides some extra navigation Within the file itself, each method is a rule and must accept a string as the first parameter, and must return a boolean true or false value signifying true if it passed the test or false if it did not: -.. literalinclude:: validation/033.php +.. literalinclude:: validation/034.php By default, the system will look within ``CodeIgniter\Language\en\Validation.php`` for the language strings used within errors. In custom rules, you may provide error messages by accepting a ``$error`` variable by reference in the second parameter: -.. literalinclude:: validation/034.php +.. literalinclude:: validation/035.php Your new custom rule could now be used just like any other rule: -.. literalinclude:: validation/035.php +.. literalinclude:: validation/036.php Allowing Parameters =================== @@ -568,7 +568,7 @@ If your method needs to work with parameters, the function will need a minimum o the parameter string, and an array with all of the data that was submitted the form. The ``$data`` array is especially handy for rules like ``require_with`` that needs to check the value of another submitted field to base its result on: -.. literalinclude:: validation/036.php +.. literalinclude:: validation/037.php Custom errors can be returned as the fourth parameter, just as described above. @@ -580,7 +580,7 @@ The following is a list of all the native rules that are available to use: .. note:: Rule is a string; there must be **no spaces** between the parameters, especially the ``is_unique`` rule. There can be no spaces before and after ``ignore_value``. -.. literalinclude:: validation/037.php +.. literalinclude:: validation/038.php ======================= ========== ============================================= =================================================== Rule Parameter Description Example diff --git a/user_guide_src/source/libraries/validation/028.2.php b/user_guide_src/source/libraries/validation/028.2.php deleted file mode 100644 index 5470a1eecea6..000000000000 --- a/user_guide_src/source/libraries/validation/028.2.php +++ /dev/null @@ -1,12 +0,0 @@ - 'Error', - * 'foo.baz.bar' => 'Error', - * ] - */ - -// returns true -$validation->hasError('foo.*.bar'); diff --git a/user_guide_src/source/libraries/validation/029.php b/user_guide_src/source/libraries/validation/029.php index f7c69eb42e99..5470a1eecea6 100644 --- a/user_guide_src/source/libraries/validation/029.php +++ b/user_guide_src/source/libraries/validation/029.php @@ -1,7 +1,12 @@ - + 'Error', + * 'foo.baz.bar' => 'Error', + * ] + */ + +// returns true +$validation->hasError('foo.*.bar'); diff --git a/user_guide_src/source/libraries/validation/030.php b/user_guide_src/source/libraries/validation/030.php index abac67b15dec..f7c69eb42e99 100644 --- a/user_guide_src/source/libraries/validation/030.php +++ b/user_guide_src/source/libraries/validation/030.php @@ -1,6 +1,7 @@ - 'The username field must be unique.', - 'email' => 'You must provide a valid email address.', -]; + diff --git a/user_guide_src/source/libraries/validation/031.php b/user_guide_src/source/libraries/validation/031.php index acec3cfc6ba2..abac67b15dec 100644 --- a/user_guide_src/source/libraries/validation/031.php +++ b/user_guide_src/source/libraries/validation/031.php @@ -1,14 +1,6 @@ 'CodeIgniter\Validation\Views\list', - 'single' => 'CodeIgniter\Validation\Views\single', - 'my_list' => '_errors_list', - ]; - - // ... -} +$errors = [ + 'username' => 'The username field must be unique.', + 'email' => 'You must provide a valid email address.', +]; diff --git a/user_guide_src/source/libraries/validation/032.php b/user_guide_src/source/libraries/validation/032.php index 890b4c453fc0..acec3cfc6ba2 100644 --- a/user_guide_src/source/libraries/validation/032.php +++ b/user_guide_src/source/libraries/validation/032.php @@ -2,18 +2,12 @@ namespace Config; -use CodeIgniter\Validation\CreditCardRules; -use CodeIgniter\Validation\FileRules; -use CodeIgniter\Validation\FormatRules; -use CodeIgniter\Validation\Rules; - class Validation { - public $ruleSets = [ - Rules::class, - FormatRules::class, - FileRules::class, - CreditCardRules::class, + public $templates = [ + 'list' => 'CodeIgniter\Validation\Views\list', + 'single' => 'CodeIgniter\Validation\Views\single', + 'my_list' => '_errors_list', ]; // ... diff --git a/user_guide_src/source/libraries/validation/033.php b/user_guide_src/source/libraries/validation/033.php index 282bef9aabbc..890b4c453fc0 100644 --- a/user_guide_src/source/libraries/validation/033.php +++ b/user_guide_src/source/libraries/validation/033.php @@ -1,9 +1,20 @@ validate($request, [ - 'foo' => 'required|even', -]); +class MyRules +{ + public function even(string $str, ?string &$error = null): bool + { + if ((int) $str % 2 !== 0) { + $error = lang('myerrors.evenError'); + + return false; + } + + return true; + } +} diff --git a/user_guide_src/source/libraries/validation/036.php b/user_guide_src/source/libraries/validation/036.php index 9e13c663b0d7..99db5f30eae4 100644 --- a/user_guide_src/source/libraries/validation/036.php +++ b/user_guide_src/source/libraries/validation/036.php @@ -1,35 +1,5 @@ required($str ?? ''); - - if ($present) { - return true; - } - - // Still here? Then we fail this test if - // any of the fields are present in $data - // as $fields is the lis - $requiredFields = []; - - foreach ($fields as $field) { - if (array_key_exists($field, $data)) { - $requiredFields[] = $field; - } - } - - // Remove any keys with empty values since, that means they - // weren't truly there, as far as this is concerned. - $requiredFields = array_filter($requiredFields, static fn ($item) => ! empty($data[$item])); - - return empty($requiredFields); - } -} +$this->validate($request, [ + 'foo' => 'required|even', +]); diff --git a/user_guide_src/source/libraries/validation/037.php b/user_guide_src/source/libraries/validation/037.php index f37307b0ae07..9e13c663b0d7 100644 --- a/user_guide_src/source/libraries/validation/037.php +++ b/user_guide_src/source/libraries/validation/037.php @@ -1,10 +1,35 @@ setRules([ - 'name' => "is_unique[supplier.name,uuid, {$uuid}]", // is not ok - 'name' => "is_unique[supplier.name,uuid,{$uuid} ]", // is not ok - 'name' => "is_unique[supplier.name,uuid,{$uuid}]", // is ok - 'name' => 'is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" -]); +class MyRules +{ + public function required_with($str, string $fields, array $data): bool + { + $fields = explode(',', $fields); + + // If the field is present we can safely assume that + // the field is here, no matter whether the corresponding + // search field is present or not. + $present = $this->required($str ?? ''); + + if ($present) { + return true; + } + + // Still here? Then we fail this test if + // any of the fields are present in $data + // as $fields is the lis + $requiredFields = []; + + foreach ($fields as $field) { + if (array_key_exists($field, $data)) { + $requiredFields[] = $field; + } + } + + // Remove any keys with empty values since, that means they + // weren't truly there, as far as this is concerned. + $requiredFields = array_filter($requiredFields, static fn ($item) => ! empty($data[$item])); + + return empty($requiredFields); + } +} diff --git a/user_guide_src/source/libraries/validation/038.php b/user_guide_src/source/libraries/validation/038.php new file mode 100644 index 000000000000..f37307b0ae07 --- /dev/null +++ b/user_guide_src/source/libraries/validation/038.php @@ -0,0 +1,10 @@ +setRules([ + 'name' => "is_unique[supplier.name,uuid, {$uuid}]", // is not ok + 'name' => "is_unique[supplier.name,uuid,{$uuid} ]", // is not ok + 'name' => "is_unique[supplier.name,uuid,{$uuid}]", // is ok + 'name' => 'is_unique[supplier.name,uuid,{uuid}]', // is ok - see "Validation Placeholders" +]); diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 2cfae8328caa..2ff02af66ac3 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -95,17 +95,17 @@ The static methods run before and after the entire test case, whereas the local 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/004.php +.. 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: -.. literalinclude:: overview/005.php +.. 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/006.php +.. literalinclude:: overview/005.php Traits ------ @@ -116,7 +116,7 @@ to run named for the trait itself. For example, if you needed to add authenticat of your test cases you could create an authentication trait with a set up method to fake a logged in user: -.. literalinclude:: overview/007.php +.. literalinclude:: overview/006.php Additional Assertions --------------------- @@ -127,19 +127,19 @@ Additional Assertions Ensure that something you expected to be logged actually was: -.. literalinclude:: overview/008.php +.. literalinclude:: overview/007.php **assertEventTriggered($eventName)** Ensure that an event you expected to be triggered actually was: -.. literalinclude:: overview/009.php +.. literalinclude:: overview/008.php **assertHeaderEmitted($header, $ignoreCase = false)** Ensure that a header or cookie was actually emitted: -.. literalinclude:: overview/010.php +.. literalinclude:: overview/009.php Note: the test case with this should be `run as a separate process in PHPunit `_. @@ -148,7 +148,7 @@ in PHPunit `_. @@ -158,7 +158,7 @@ in PHPunit model->purgeDeleted(); + } } diff --git a/user_guide_src/source/testing/overview/006.php b/user_guide_src/source/testing/overview/006.php index 86dc1c44b40f..6193eb88bf50 100644 --- a/user_guide_src/source/testing/overview/006.php +++ b/user_guide_src/source/testing/overview/006.php @@ -1,17 +1,21 @@ createFakeUser(); + $this->logInUser($user); + } + + // ... +} use CodeIgniter\Test\CIUnitTestCase; -final class OneOfMyModelsTest extends CIUnitTestCase +final class AuthenticationFeatureTest extends CIUnitTestCase { - protected $tearDownMethods = [ - 'purgeRows', - ]; + use AuthTrait; - protected function purgeRows() - { - $this->model->purgeDeleted(); - } + // ... } diff --git a/user_guide_src/source/testing/overview/007.php b/user_guide_src/source/testing/overview/007.php index 6193eb88bf50..55077ed36818 100644 --- a/user_guide_src/source/testing/overview/007.php +++ b/user_guide_src/source/testing/overview/007.php @@ -1,21 +1,9 @@ createFakeUser(); - $this->logInUser($user); - } +$config = new LoggerConfig(); +$logger = new Logger($config); - // ... -} +// ... do something that you expect a log entry from +$logger->log('error', "That's no moon"); -use CodeIgniter\Test\CIUnitTestCase; - -final class AuthenticationFeatureTest extends CIUnitTestCase -{ - use AuthTrait; - - // ... -} +$this->assertLogged('error', "That's no moon"); diff --git a/user_guide_src/source/testing/overview/008.php b/user_guide_src/source/testing/overview/008.php index 55077ed36818..5d69c01c16d5 100644 --- a/user_guide_src/source/testing/overview/008.php +++ b/user_guide_src/source/testing/overview/008.php @@ -1,9 +1,9 @@ log('error', "That's no moon"); +Events::trigger('foo', 'bar'); -$this->assertLogged('error', "That's no moon"); +$this->assertEventTriggered('foo'); diff --git a/user_guide_src/source/testing/overview/009.php b/user_guide_src/source/testing/overview/009.php index 5d69c01c16d5..506d75a8d433 100644 --- a/user_guide_src/source/testing/overview/009.php +++ b/user_guide_src/source/testing/overview/009.php @@ -1,9 +1,9 @@ setCookie('foo', 'bar'); -Events::trigger('foo', 'bar'); +ob_start(); +$this->response->send(); +$output = ob_get_clean(); // in case you want to check the actual body -$this->assertEventTriggered('foo'); +$this->assertHeaderEmitted('Set-Cookie: foo=bar'); diff --git a/user_guide_src/source/testing/overview/010.php b/user_guide_src/source/testing/overview/010.php index 506d75a8d433..10e9d4a0d31b 100644 --- a/user_guide_src/source/testing/overview/010.php +++ b/user_guide_src/source/testing/overview/010.php @@ -6,4 +6,4 @@ $this->response->send(); $output = ob_get_clean(); // in case you want to check the actual body -$this->assertHeaderEmitted('Set-Cookie: foo=bar'); +$this->assertHeaderNotEmitted('Set-Cookie: banana'); diff --git a/user_guide_src/source/testing/overview/011.php b/user_guide_src/source/testing/overview/011.php index 10e9d4a0d31b..c9b85aef7f87 100644 --- a/user_guide_src/source/testing/overview/011.php +++ b/user_guide_src/source/testing/overview/011.php @@ -1,9 +1,5 @@ setCookie('foo', 'bar'); - -ob_start(); -$this->response->send(); -$output = ob_get_clean(); // in case you want to check the actual body - -$this->assertHeaderNotEmitted('Set-Cookie: banana'); +$timer = new Timer(); +$timer->start('longjohn', strtotime('-11 minutes')); +$this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn')); diff --git a/user_guide_src/source/testing/overview/012.php b/user_guide_src/source/testing/overview/012.php index c9b85aef7f87..1c03733868e4 100644 --- a/user_guide_src/source/testing/overview/012.php +++ b/user_guide_src/source/testing/overview/012.php @@ -2,4 +2,4 @@ $timer = new Timer(); $timer->start('longjohn', strtotime('-11 minutes')); -$this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn')); +$this->assertCloseEnoughString(11 * 60, $timer->getElapsedTime('longjohn')); diff --git a/user_guide_src/source/testing/overview/013.php b/user_guide_src/source/testing/overview/013.php index 1c03733868e4..f228dcf28963 100644 --- a/user_guide_src/source/testing/overview/013.php +++ b/user_guide_src/source/testing/overview/013.php @@ -1,5 +1,10 @@ start('longjohn', strtotime('-11 minutes')); -$this->assertCloseEnoughString(11 * 60, $timer->getElapsedTime('longjohn')); +// Create an instance of the class to test +$obj = new Foo(); + +// Get the invoker for the 'privateMethod' method. +$method = $this->getPrivateMethodInvoker($obj, 'privateMethod'); + +// Test the results +$this->assertEquals('bar', $method('param1', 'param2')); diff --git a/user_guide_src/source/testing/overview/014.php b/user_guide_src/source/testing/overview/014.php index f228dcf28963..1befb710253e 100644 --- a/user_guide_src/source/testing/overview/014.php +++ b/user_guide_src/source/testing/overview/014.php @@ -3,8 +3,5 @@ // Create an instance of the class to test $obj = new Foo(); -// Get the invoker for the 'privateMethod' method. -$method = $this->getPrivateMethodInvoker($obj, 'privateMethod'); - -// Test the results -$this->assertEquals('bar', $method('param1', 'param2')); +// Test the value +$this->assertEquals('bar', $this->getPrivateProperty($obj, 'baz')); diff --git a/user_guide_src/source/testing/overview/015.php b/user_guide_src/source/testing/overview/015.php index 1befb710253e..c2e815953dd9 100644 --- a/user_guide_src/source/testing/overview/015.php +++ b/user_guide_src/source/testing/overview/015.php @@ -3,5 +3,7 @@ // Create an instance of the class to test $obj = new Foo(); -// Test the value -$this->assertEquals('bar', $this->getPrivateProperty($obj, 'baz')); +// Set the value +$this->setPrivateProperty($obj, 'baz', 'oops!'); + +// Do normal testing... diff --git a/user_guide_src/source/testing/overview/016.php b/user_guide_src/source/testing/overview/016.php index c2e815953dd9..cf0c211496b6 100644 --- a/user_guide_src/source/testing/overview/016.php +++ b/user_guide_src/source/testing/overview/016.php @@ -1,9 +1,16 @@ setPrivateProperty($obj, 'baz', 'oops!'); +final class SomeTest extends CIUnitTestCase +{ + public function testSomething() + { + $curlrequest = $this->getMockBuilder('CodeIgniter\HTTP\CURLRequest') + ->setMethods(['request']) + ->getMock(); + Services::injectMock('curlrequest', $curlrequest); -// Do normal testing... + // Do normal testing here.... + } +} diff --git a/user_guide_src/source/testing/overview/017.php b/user_guide_src/source/testing/overview/017.php index cf0c211496b6..67ccc4a634dc 100644 --- a/user_guide_src/source/testing/overview/017.php +++ b/user_guide_src/source/testing/overview/017.php @@ -4,13 +4,11 @@ final class SomeTest extends CIUnitTestCase { - public function testSomething() + protected function setUp(): void { - $curlrequest = $this->getMockBuilder('CodeIgniter\HTTP\CURLRequest') - ->setMethods(['request']) - ->getMock(); - Services::injectMock('curlrequest', $curlrequest); + parent::setUp(); - // Do normal testing here.... + $model = new MockUserModel(); + Factories::injectMock('models', 'App\Models\UserModel', $model); } } diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index 67ccc4a634dc..e0e55131f5b3 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -6,9 +6,19 @@ final class SomeTest extends CIUnitTestCase { protected function setUp(): void { - parent::setUp(); + CITestStreamFilter::$buffer = ''; + $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + } - $model = new MockUserModel(); - Factories::injectMock('models', 'App\Models\UserModel', $model); + protected function tearDown(): void + { + stream_filter_remove($this->stream_filter); + } + + public function testSomeOutput(): void + { + CLI::write('first.'); + $expected = "first.\n"; + $this->assertSame($expected, CITestStreamFilter::$buffer); } } diff --git a/user_guide_src/source/testing/overview/019.php b/user_guide_src/source/testing/overview/019.php deleted file mode 100644 index e0e55131f5b3..000000000000 --- a/user_guide_src/source/testing/overview/019.php +++ /dev/null @@ -1,24 +0,0 @@ -stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - } - - protected function tearDown(): void - { - stream_filter_remove($this->stream_filter); - } - - public function testSomeOutput(): void - { - CLI::write('first.'); - $expected = "first.\n"; - $this->assertSame($expected, CITestStreamFilter::$buffer); - } -} From 60c7083a741f20f4f32dd41a87e453c1ad801ffd Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Fri, 11 Mar 2022 17:41:49 +0100 Subject: [PATCH 1760/2325] Renumerate installation. --- .../source/installation/upgrade_configuration.rst | 2 +- .../upgrade_configuration/{002.php => 001.php} | 0 .../source/installation/upgrade_controllers.rst | 2 +- .../upgrade_controllers/{002.php => 001.php} | 0 .../source/installation/upgrade_database.rst | 2 +- .../installation/upgrade_database/{002.php => 001.php} | 0 user_guide_src/source/installation/upgrade_emails.rst | 2 +- .../installation/upgrade_emails/{002.php => 001.php} | 0 .../source/installation/upgrade_encryption.rst | 2 +- .../upgrade_encryption/{002.php => 001.php} | 0 .../source/installation/upgrade_file_upload.rst | 2 +- .../upgrade_file_upload/{002.php => 001.php} | 0 .../source/installation/upgrade_html_tables.rst | 2 +- .../upgrade_html_tables/{002.php => 001.php} | 0 .../source/installation/upgrade_localization.rst | 2 +- .../upgrade_localization/{003.php => 002.php} | 0 .../source/installation/upgrade_migrations.rst | 2 +- .../upgrade_migrations/{002.php => 001.php} | 0 user_guide_src/source/installation/upgrade_models.rst | 2 +- .../installation/upgrade_models/{002.php => 001.php} | 0 .../source/installation/upgrade_pagination.rst | 2 +- .../upgrade_pagination/{002.php => 001.php} | 0 .../source/installation/upgrade_responses.rst | 2 +- .../upgrade_responses/{002.php => 001.php} | 0 user_guide_src/source/installation/upgrade_routing.rst | 2 +- .../installation/upgrade_routing/{002.php => 001.php} | 0 .../source/installation/upgrade_security.rst | 10 +--------- .../source/installation/upgrade_security/002.php | 8 ++++++++ .../source/installation/upgrade_sessions.rst | 2 +- .../installation/upgrade_sessions/{002.php => 001.php} | 0 .../source/installation/upgrade_validations.rst | 2 +- .../upgrade_validations/{003.php => 002.php} | 0 .../source/installation/upgrade_view_parser.rst | 2 +- .../upgrade_view_parser/{002.php => 001.php} | 0 user_guide_src/source/installation/upgrade_views.rst | 2 +- .../installation/upgrade_views/{002.php => 001.php} | 0 36 files changed, 26 insertions(+), 26 deletions(-) rename user_guide_src/source/installation/upgrade_configuration/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_controllers/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_database/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_emails/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_encryption/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_file_upload/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_html_tables/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_localization/{003.php => 002.php} (100%) rename user_guide_src/source/installation/upgrade_migrations/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_models/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_pagination/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_responses/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_routing/{002.php => 001.php} (100%) create mode 100644 user_guide_src/source/installation/upgrade_security/002.php rename user_guide_src/source/installation/upgrade_sessions/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_validations/{003.php => 002.php} (100%) rename user_guide_src/source/installation/upgrade_view_parser/{002.php => 001.php} (100%) rename user_guide_src/source/installation/upgrade_views/{002.php => 001.php} (100%) diff --git a/user_guide_src/source/installation/upgrade_configuration.rst b/user_guide_src/source/installation/upgrade_configuration.rst index 6a9f38069478..aca4af05d4a7 100644 --- a/user_guide_src/source/installation/upgrade_configuration.rst +++ b/user_guide_src/source/installation/upgrade_configuration.rst @@ -47,4 +47,4 @@ CodeIgniter Version 4.x Path: **app/Config**: -.. literalinclude:: upgrade_configuration/002.php +.. literalinclude:: upgrade_configuration/001.php diff --git a/user_guide_src/source/installation/upgrade_configuration/002.php b/user_guide_src/source/installation/upgrade_configuration/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_configuration/002.php rename to user_guide_src/source/installation/upgrade_configuration/001.php diff --git a/user_guide_src/source/installation/upgrade_controllers.rst b/user_guide_src/source/installation/upgrade_controllers.rst index 3e7521445691..1810ea615506 100644 --- a/user_guide_src/source/installation/upgrade_controllers.rst +++ b/user_guide_src/source/installation/upgrade_controllers.rst @@ -50,4 +50,4 @@ CodeIgniter Version 4.x Path: **app/Controllers**: -.. literalinclude:: upgrade_controllers/002.php +.. literalinclude:: upgrade_controllers/001.php diff --git a/user_guide_src/source/installation/upgrade_controllers/002.php b/user_guide_src/source/installation/upgrade_controllers/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_controllers/002.php rename to user_guide_src/source/installation/upgrade_controllers/001.php diff --git a/user_guide_src/source/installation/upgrade_database.rst b/user_guide_src/source/installation/upgrade_database.rst index 10b1e6ac1c96..f62044d8a302 100644 --- a/user_guide_src/source/installation/upgrade_database.rst +++ b/user_guide_src/source/installation/upgrade_database.rst @@ -51,4 +51,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_database/002.php +.. literalinclude:: upgrade_database/001.php diff --git a/user_guide_src/source/installation/upgrade_database/002.php b/user_guide_src/source/installation/upgrade_database/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_database/002.php rename to user_guide_src/source/installation/upgrade_database/001.php diff --git a/user_guide_src/source/installation/upgrade_emails.rst b/user_guide_src/source/installation/upgrade_emails.rst index af322f2d7c7a..7eb40a050042 100644 --- a/user_guide_src/source/installation/upgrade_emails.rst +++ b/user_guide_src/source/installation/upgrade_emails.rst @@ -33,4 +33,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_emails/002.php +.. literalinclude:: upgrade_emails/001.php diff --git a/user_guide_src/source/installation/upgrade_emails/002.php b/user_guide_src/source/installation/upgrade_emails/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_emails/002.php rename to user_guide_src/source/installation/upgrade_emails/001.php diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index 9d626d341d5d..a4d8a74ce659 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -31,4 +31,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_encryption/002.php +.. literalinclude:: upgrade_encryption/001.php diff --git a/user_guide_src/source/installation/upgrade_encryption/002.php b/user_guide_src/source/installation/upgrade_encryption/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_encryption/002.php rename to user_guide_src/source/installation/upgrade_encryption/001.php diff --git a/user_guide_src/source/installation/upgrade_file_upload.rst b/user_guide_src/source/installation/upgrade_file_upload.rst index ed620bbaeb67..d7a38a1f97d8 100644 --- a/user_guide_src/source/installation/upgrade_file_upload.rst +++ b/user_guide_src/source/installation/upgrade_file_upload.rst @@ -32,4 +32,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_file_upload/002.php +.. literalinclude:: upgrade_file_upload/001.php diff --git a/user_guide_src/source/installation/upgrade_file_upload/002.php b/user_guide_src/source/installation/upgrade_file_upload/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_file_upload/002.php rename to user_guide_src/source/installation/upgrade_file_upload/001.php diff --git a/user_guide_src/source/installation/upgrade_html_tables.rst b/user_guide_src/source/installation/upgrade_html_tables.rst index ae97e8e3baf2..09059e547abe 100644 --- a/user_guide_src/source/installation/upgrade_html_tables.rst +++ b/user_guide_src/source/installation/upgrade_html_tables.rst @@ -32,4 +32,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_html_tables/002.php +.. literalinclude:: upgrade_html_tables/001.php diff --git a/user_guide_src/source/installation/upgrade_html_tables/002.php b/user_guide_src/source/installation/upgrade_html_tables/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_html_tables/002.php rename to user_guide_src/source/installation/upgrade_html_tables/001.php diff --git a/user_guide_src/source/installation/upgrade_localization.rst b/user_guide_src/source/installation/upgrade_localization.rst index 782336334974..d962eb462fd4 100644 --- a/user_guide_src/source/installation/upgrade_localization.rst +++ b/user_guide_src/source/installation/upgrade_localization.rst @@ -37,4 +37,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_localization/003.php +.. literalinclude:: upgrade_localization/002.php diff --git a/user_guide_src/source/installation/upgrade_localization/003.php b/user_guide_src/source/installation/upgrade_localization/002.php similarity index 100% rename from user_guide_src/source/installation/upgrade_localization/003.php rename to user_guide_src/source/installation/upgrade_localization/002.php diff --git a/user_guide_src/source/installation/upgrade_migrations.rst b/user_guide_src/source/installation/upgrade_migrations.rst index 60f6b8d7b090..31eabc0766e1 100644 --- a/user_guide_src/source/installation/upgrade_migrations.rst +++ b/user_guide_src/source/installation/upgrade_migrations.rst @@ -60,7 +60,7 @@ CodeIgniter Version 4.x Path: **app/Database/Migrations**: -.. literalinclude:: upgrade_migrations/002.php +.. literalinclude:: upgrade_migrations/001.php Search & Replace ================ diff --git a/user_guide_src/source/installation/upgrade_migrations/002.php b/user_guide_src/source/installation/upgrade_migrations/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_migrations/002.php rename to user_guide_src/source/installation/upgrade_migrations/001.php diff --git a/user_guide_src/source/installation/upgrade_models.rst b/user_guide_src/source/installation/upgrade_models.rst index 1ffce60151e0..6acf6aa76969 100644 --- a/user_guide_src/source/installation/upgrade_models.rst +++ b/user_guide_src/source/installation/upgrade_models.rst @@ -49,6 +49,6 @@ CodeIgniter Version 4.x Path: **app/Models**: -.. literalinclude:: upgrade_models/002.php +.. literalinclude:: upgrade_models/001.php To insert data you can just directly call the ``$model->insert()`` method because this method is built-in since CI4. diff --git a/user_guide_src/source/installation/upgrade_models/002.php b/user_guide_src/source/installation/upgrade_models/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_models/002.php rename to user_guide_src/source/installation/upgrade_models/001.php diff --git a/user_guide_src/source/installation/upgrade_pagination.rst b/user_guide_src/source/installation/upgrade_pagination.rst index 6658ae8e4bd7..69e19d57164c 100644 --- a/user_guide_src/source/installation/upgrade_pagination.rst +++ b/user_guide_src/source/installation/upgrade_pagination.rst @@ -39,4 +39,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_pagination/002.php +.. literalinclude:: upgrade_pagination/001.php diff --git a/user_guide_src/source/installation/upgrade_pagination/002.php b/user_guide_src/source/installation/upgrade_pagination/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_pagination/002.php rename to user_guide_src/source/installation/upgrade_pagination/001.php diff --git a/user_guide_src/source/installation/upgrade_responses.rst b/user_guide_src/source/installation/upgrade_responses.rst index c6b925d144f1..6788468c0b57 100644 --- a/user_guide_src/source/installation/upgrade_responses.rst +++ b/user_guide_src/source/installation/upgrade_responses.rst @@ -30,4 +30,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_responses/002.php +.. literalinclude:: upgrade_responses/001.php diff --git a/user_guide_src/source/installation/upgrade_responses/002.php b/user_guide_src/source/installation/upgrade_responses/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_responses/002.php rename to user_guide_src/source/installation/upgrade_responses/001.php diff --git a/user_guide_src/source/installation/upgrade_routing.rst b/user_guide_src/source/installation/upgrade_routing.rst index 9e6c512ff423..882ef380ca92 100644 --- a/user_guide_src/source/installation/upgrade_routing.rst +++ b/user_guide_src/source/installation/upgrade_routing.rst @@ -36,4 +36,4 @@ CodeIgniter Version 4.x ----------------------- Path: **app/Config/Routes.php**: -.. literalinclude:: upgrade_routing/002.php +.. literalinclude:: upgrade_routing/001.php diff --git a/user_guide_src/source/installation/upgrade_routing/002.php b/user_guide_src/source/installation/upgrade_routing/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_routing/002.php rename to user_guide_src/source/installation/upgrade_routing/001.php diff --git a/user_guide_src/source/installation/upgrade_security.rst b/user_guide_src/source/installation/upgrade_security.rst index 0a6d615e0841..c520b9c50350 100644 --- a/user_guide_src/source/installation/upgrade_security.rst +++ b/user_guide_src/source/installation/upgrade_security.rst @@ -37,13 +37,5 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -:: - - - - - - - - +.. literalinclude:: upgrade_security/002.php diff --git a/user_guide_src/source/installation/upgrade_security/002.php b/user_guide_src/source/installation/upgrade_security/002.php new file mode 100644 index 000000000000..89c3b3882c56 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_security/002.php @@ -0,0 +1,8 @@ +
    + + + + + + + diff --git a/user_guide_src/source/installation/upgrade_sessions.rst b/user_guide_src/source/installation/upgrade_sessions.rst index a309033bc816..177552282a9c 100644 --- a/user_guide_src/source/installation/upgrade_sessions.rst +++ b/user_guide_src/source/installation/upgrade_sessions.rst @@ -36,4 +36,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_sessions/002.php +.. literalinclude:: upgrade_sessions/001.php diff --git a/user_guide_src/source/installation/upgrade_sessions/002.php b/user_guide_src/source/installation/upgrade_sessions/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_sessions/002.php rename to user_guide_src/source/installation/upgrade_sessions/001.php diff --git a/user_guide_src/source/installation/upgrade_validations.rst b/user_guide_src/source/installation/upgrade_validations.rst index 3612784ade28..5bd6a2a1d514 100644 --- a/user_guide_src/source/installation/upgrade_validations.rst +++ b/user_guide_src/source/installation/upgrade_validations.rst @@ -110,4 +110,4 @@ Path: **app/Views**:: Path: **app/Controllers**: -.. literalinclude:: upgrade_validations/003.php +.. literalinclude:: upgrade_validations/002.php diff --git a/user_guide_src/source/installation/upgrade_validations/003.php b/user_guide_src/source/installation/upgrade_validations/002.php similarity index 100% rename from user_guide_src/source/installation/upgrade_validations/003.php rename to user_guide_src/source/installation/upgrade_validations/002.php diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index 5def5e912d5f..55e86fb357a4 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -32,4 +32,4 @@ CodeIgniter Version 3.x CodeIgniter Version 4.x ----------------------- -.. literalinclude:: upgrade_view_parser/002.php +.. literalinclude:: upgrade_view_parser/001.php diff --git a/user_guide_src/source/installation/upgrade_view_parser/002.php b/user_guide_src/source/installation/upgrade_view_parser/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_view_parser/002.php rename to user_guide_src/source/installation/upgrade_view_parser/001.php diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index 574de607b42b..8509705c76dc 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -43,4 +43,4 @@ CodeIgniter Version 4.x Path: **app/Views**: -.. literalinclude:: upgrade_views/002.php +.. literalinclude:: upgrade_views/001.php diff --git a/user_guide_src/source/installation/upgrade_views/002.php b/user_guide_src/source/installation/upgrade_views/001.php similarity index 100% rename from user_guide_src/source/installation/upgrade_views/002.php rename to user_guide_src/source/installation/upgrade_views/001.php From 2ccc2cdb9ea562c0e23dc953bcd1f328903099a3 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Fri, 11 Mar 2022 17:53:48 +0100 Subject: [PATCH 1761/2325] Delete renumerate script. --- user_guide_src/renumerate.php | 98 ----------------------------------- 1 file changed, 98 deletions(-) delete mode 100644 user_guide_src/renumerate.php diff --git a/user_guide_src/renumerate.php b/user_guide_src/renumerate.php deleted file mode 100644 index 7ecf1a631e4b..000000000000 --- a/user_guide_src/renumerate.php +++ /dev/null @@ -1,98 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -$srcFolder = __DIR__ . '/source'; - -// Exclude static folders -$excludes = ['_static', 'images']; - -// Safety prefix -$prefix = 'old_'; - -// Begin user info -echo 'The following sections were renumerated:', PHP_EOL; - -// Loop source directory -$srcIterator = new DirectoryIterator($srcFolder); - -foreach ($srcIterator as $chapterInfo) { - if (! $chapterInfo->isDot() && $chapterInfo->isDir() && ! in_array($chapterInfo->getFilename(), $excludes, true)) { - $chapterName = $chapterInfo->getFilename(); - - // Iterate the working directory - $chapterIterator = new DirectoryIterator($chapterInfo->getPathname()); - - foreach ($chapterIterator as $sectionInfo) { - if (! $sectionInfo->isDot() && $sectionInfo->isFile() && $sectionInfo->getExtension() === 'rst') { - $sectionName = $sectionInfo->getBasename('.rst'); - $sectionFolder = $sectionInfo->getPath() . '/' . $sectionName; - - // Read the section file - $sectionContent = file_get_contents($sectionInfo->getPathname()); - - // Match all includes - preg_match_all("~\\.\\. literalinclude:: {$sectionName}\\/(.+)\\.php~", $sectionContent, $matches); - $includeStrings = $matches[0]; - $exampleNames = $matches[1]; - - // Exit early if no matches - if (count($exampleNames) === 0) { - continue; - } - - // Check if examples are consecutive - $consecutive = true; - - foreach ($exampleNames as $exampleIndex => $exampleName) { - if (str_pad($exampleIndex + 1, 3, '0', STR_PAD_LEFT) !== $exampleName) { - $consecutive = false; - break; - } - } - - // Exit if examples are already consecutive - if ($consecutive) { - continue; - } - - // Rename all example files to avoid conflicts - $exampleIterator = new DirectoryIterator($sectionFolder); - - foreach ($exampleIterator as $exampleInfo) { - if (! $exampleInfo->isDot() && $exampleInfo->isFile() && $exampleInfo->getExtension() === 'php') { - rename($exampleInfo->getPathname(), $exampleInfo->getPath() . '/' . $prefix . $exampleInfo->getFilename()); - } - } - $sectionContent = preg_replace("~\\.\\. literalinclude:: {$sectionName}\\/(.+)\\.php~", ".. literalinclude:: {$sectionName}/{$prefix}$1.php", $sectionContent); - - // Renumerate examples - foreach ($exampleNames as $exampleIndex => $exampleName) { - $newName = str_pad($exampleIndex + 1, 3, '0', STR_PAD_LEFT); - - // Rename example file - rename($sectionFolder . '/' . $prefix . $exampleName . '.php', $sectionFolder . '/' . $newName . '.php'); - - // Fix include link - $sectionContent = preg_replace('~' . preg_quote(str_replace($exampleName, $prefix . $exampleName, $includeStrings[$exampleIndex]), '~') . '~', str_replace($exampleName, $newName, $includeStrings[$exampleIndex]), $sectionContent, 1, $count); - } - - // Write new content to rst - file_put_contents($sectionInfo->getPathname(), $sectionContent); - - // User info - echo $chapterName, '/', $sectionName, PHP_EOL; - } - } - } -} - -// End user info -echo 'Renumerating finished.', PHP_EOL; From 27a2132c598de9a9990207aa8ecfb5a156fba9d9 Mon Sep 17 00:00:00 2001 From: Alex Schmitz Date: Fri, 11 Mar 2022 18:00:21 +0100 Subject: [PATCH 1762/2325] Update cs-fixer excludes. --- .user-guide.php-cs-fixer.dist.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.user-guide.php-cs-fixer.dist.php b/.user-guide.php-cs-fixer.dist.php index 7a48f922f1d7..900c26ec81e1 100644 --- a/.user-guide.php-cs-fixer.dist.php +++ b/.user-guide.php-cs-fixer.dist.php @@ -25,8 +25,8 @@ ]) ->notPath([ 'ci3sample/', - 'libraries/sessions/017.php', - 'database/query_builder/074.php', + 'libraries/sessions/016.php', + 'database/query_builder/075.php', ]); $overrides = [ From 929cf6158fbb22657fb71b982e3780d6a546c37a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 12 Mar 2022 09:22:42 +0900 Subject: [PATCH 1763/2325] docs: fix `@return` description --- system/Debug/Timer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php index 5783c77aae72..9be1dd121f1a 100644 --- a/system/Debug/Timer.php +++ b/system/Debug/Timer.php @@ -78,7 +78,7 @@ public function stop(string $name) * @param string $name The name of the timer. * @param int $decimals Number of decimal places. * - * @return float|null Returns null if timer exists by that name. + * @return float|null Returns null if timer does not exist by that name. * Returns a float representing the number of * seconds elapsed while that timer was running. */ From 3c706a52b112aa7ea309a4d7c56dadfad6d956f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 12 Mar 2022 09:23:28 +0900 Subject: [PATCH 1764/2325] fix: Timer::getElapsedTime() returns incorrect value --- system/Debug/Timer.php | 2 +- tests/system/Debug/TimerTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php index 9be1dd121f1a..9ca51d1c9b08 100644 --- a/system/Debug/Timer.php +++ b/system/Debug/Timer.php @@ -96,7 +96,7 @@ public function getElapsedTime(string $name, int $decimals = 4) $timer['end'] = microtime(true); } - return (float) number_format($timer['end'] - $timer['start'], $decimals); + return (float) number_format($timer['end'] - $timer['start'], $decimals, '.', ''); } /** diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index 7b7b75199ea9..fdd09829d9ff 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -92,8 +92,8 @@ public function testThrowsExceptionStoppingNonTimer() public function testLongExecutionTime() { $timer = new Timer(); - $timer->start('longjohn', strtotime('-11 minutes')); - $this->assertCloseEnough(11 * 60, $timer->getElapsedTime('longjohn')); + $timer->start('longjohn', strtotime('-110 minutes')); + $this->assertCloseEnough(110 * 60, $timer->getElapsedTime('longjohn')); } public function testLongExecutionTimeThroughCommonFunc() From 81f062f84fe7d3e6cb19203596ad7d2ae516de02 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 12 Mar 2022 10:40:57 +0900 Subject: [PATCH 1765/2325] config: add .woff2 --- app/Config/Publisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php index 4f7cf11037f5..7088703fc0d5 100644 --- a/app/Config/Publisher.php +++ b/app/Config/Publisher.php @@ -23,6 +23,6 @@ class Publisher extends BasePublisher */ public $restrictions = [ ROOTPATH => '*', - FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|tff|eot|woff|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|tff|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', ]; } From 5d4753c824fcdfbdd6bc36888780debc62633116 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 12 Mar 2022 10:42:30 +0900 Subject: [PATCH 1766/2325] docs: add .woff2 --- user_guide_src/source/libraries/publisher.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 69de79bd7464..947a102019e1 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -83,7 +83,7 @@ receive files with the following extensions: * Web assets: css, scss, js, map * Non-executable web files: htm, html, xml, json, webmanifest -* Fonts: tff, eot, woff +* Fonts: tff, eot, woff, woff2 * Images: gif, jpg, jpeg, tif, tiff, png, webp, bmp, ico, svg If you need to add or adjust the security for your project then alter the ``$restrictions`` property of ``Config\Publisher`` in **app/Config/Publisher.php**. From 7b0520e495c7fbe3ee2c2c184cb41f7b897e80b2 Mon Sep 17 00:00:00 2001 From: MGatner Date: Tue, 15 Mar 2022 00:30:45 +0000 Subject: [PATCH 1767/2325] Fix extension typo --- app/Config/Publisher.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Publisher.php b/app/Config/Publisher.php index 7088703fc0d5..47475112c080 100644 --- a/app/Config/Publisher.php +++ b/app/Config/Publisher.php @@ -23,6 +23,6 @@ class Publisher extends BasePublisher */ public $restrictions = [ ROOTPATH => '*', - FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|tff|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', + FCPATH => '#\.(s?css|js|map|html?|xml|json|webmanifest|ttf|eot|woff2?|gif|jpe?g|tiff?|png|webp|bmp|ico|svg)$#i', ]; } From 75184b97b686f5283a5e5cfb57d12d8af9d9ded2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 15 Mar 2022 09:58:46 +0900 Subject: [PATCH 1768/2325] docs: fix extension typo See #5800 --- user_guide_src/source/libraries/publisher.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 947a102019e1..5b37369445f1 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -83,7 +83,7 @@ receive files with the following extensions: * Web assets: css, scss, js, map * Non-executable web files: htm, html, xml, json, webmanifest -* Fonts: tff, eot, woff, woff2 +* Fonts: ttf, eot, woff, woff2 * Images: gif, jpg, jpeg, tif, tiff, png, webp, bmp, ico, svg If you need to add or adjust the security for your project then alter the ``$restrictions`` property of ``Config\Publisher`` in **app/Config/Publisher.php**. From 74daf1aa53f10166671cd295b8e68e336c77c68e Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 08:50:11 +0900 Subject: [PATCH 1769/2325] test: remove helper('url') URL Helper is automatically loaded. --- tests/system/HTTP/UserAgentTest.php | 2 -- tests/system/Helpers/HTMLHelperTest.php | 2 -- tests/system/Helpers/URLHelper/CurrentUrlTest.php | 7 ------- tests/system/Helpers/URLHelper/MiscUrlTest.php | 7 ------- tests/system/Helpers/URLHelper/SiteUrlTest.php | 7 ------- tests/system/Pager/PagerTest.php | 1 - tests/system/View/ParserPluginTest.php | 5 ----- 7 files changed, 31 deletions(-) diff --git a/tests/system/HTTP/UserAgentTest.php b/tests/system/HTTP/UserAgentTest.php index 6b80d8f25b30..e4f2d1e7f025 100644 --- a/tests/system/HTTP/UserAgentTest.php +++ b/tests/system/HTTP/UserAgentTest.php @@ -34,8 +34,6 @@ protected function setUp(): void $_SERVER['HTTP_USER_AGENT'] = $this->_user_agent; $this->agent = new UserAgent(); - - helper('url'); } public function testMobile() diff --git a/tests/system/Helpers/HTMLHelperTest.php b/tests/system/Helpers/HTMLHelperTest.php index 79cb5da92334..b3ed47d0c3e6 100755 --- a/tests/system/Helpers/HTMLHelperTest.php +++ b/tests/system/Helpers/HTMLHelperTest.php @@ -35,8 +35,6 @@ protected function setUp(): void { parent::setUp(); - // URL is needed by the HTML Helper. - helper('url'); helper('html'); $this->tracks = [ diff --git a/tests/system/Helpers/URLHelper/CurrentUrlTest.php b/tests/system/Helpers/URLHelper/CurrentUrlTest.php index b4f522f16071..0f316a305988 100644 --- a/tests/system/Helpers/URLHelper/CurrentUrlTest.php +++ b/tests/system/Helpers/URLHelper/CurrentUrlTest.php @@ -30,13 +30,6 @@ final class CurrentUrlTest extends CIUnitTestCase { private App $config; - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper('url'); - } - protected function setUp(): void { parent::setUp(); diff --git a/tests/system/Helpers/URLHelper/MiscUrlTest.php b/tests/system/Helpers/URLHelper/MiscUrlTest.php index a5a78c5cc687..709d1b815207 100644 --- a/tests/system/Helpers/URLHelper/MiscUrlTest.php +++ b/tests/system/Helpers/URLHelper/MiscUrlTest.php @@ -27,13 +27,6 @@ final class MiscUrlTest extends CIUnitTestCase { private App $config; - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper('url'); - } - protected function setUp(): void { parent::setUp(); diff --git a/tests/system/Helpers/URLHelper/SiteUrlTest.php b/tests/system/Helpers/URLHelper/SiteUrlTest.php index e9b5ec9c25dd..f942ce453af8 100644 --- a/tests/system/Helpers/URLHelper/SiteUrlTest.php +++ b/tests/system/Helpers/URLHelper/SiteUrlTest.php @@ -30,13 +30,6 @@ final class SiteUrlTest extends CIUnitTestCase { private App $config; - public static function setUpBeforeClass(): void - { - parent::setUpBeforeClass(); - - helper('url'); - } - protected function setUp(): void { parent::setUp(); diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 05b069d83c21..745a8464111b 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -35,7 +35,6 @@ final class PagerTest extends CIUnitTestCase protected function setUp(): void { parent::setUp(); - helper('url'); $_SERVER['HTTP_HOST'] = 'example.com'; $_SERVER['REQUEST_URI'] = '/'; diff --git a/tests/system/View/ParserPluginTest.php b/tests/system/View/ParserPluginTest.php index 55e5e4ce9c75..7a4a94a87cc2 100644 --- a/tests/system/View/ParserPluginTest.php +++ b/tests/system/View/ParserPluginTest.php @@ -42,7 +42,6 @@ protected function setUp(): void public function testCurrentURL() { - helper('url'); $template = '{+ current_url +}'; $this->assertSame(current_url(), $this->parser->renderString($template)); @@ -50,7 +49,6 @@ public function testCurrentURL() public function testPreviousURL() { - helper('url'); $template = '{+ previous_url +}'; // Ensure a previous URL exists to work with. @@ -61,7 +59,6 @@ public function testPreviousURL() public function testMailto() { - helper('url'); $template = '{+ mailto email=foo@example.com title=Silly +}'; $this->assertSame(mailto('foo@example.com', 'Silly'), $this->parser->renderString($template)); @@ -72,7 +69,6 @@ public function testMailto() */ public function testMailtoWithDashAndParenthesis() { - helper('url'); $template = '{+ mailto email=foo-bar@example.com title="Scilly (the Great)" +}'; $this->assertSame(mailto('foo-bar@example.com', 'Scilly (the Great)'), $this->parser->renderString($template)); @@ -80,7 +76,6 @@ public function testMailtoWithDashAndParenthesis() public function testSafeMailto() { - helper('url'); $template = '{+ safe_mailto email=foo@example.com title=Silly +}'; $this->assertSame(safe_mailto('foo@example.com', 'Silly'), $this->parser->renderString($template)); From f83160b2be6393938a46bf04e378c05b21ed7e2f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 11:34:22 +0900 Subject: [PATCH 1770/2325] test: refactor setUp() $_SERVER['HTTP_HOST'] is not used in Pager or Request. --- tests/system/Pager/PagerTest.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 745a8464111b..1259e0065b50 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -36,18 +36,16 @@ protected function setUp(): void { parent::setUp(); - $_SERVER['HTTP_HOST'] = 'example.com'; $_SERVER['REQUEST_URI'] = '/'; $_GET = []; $config = new App(); $config->baseURL = 'http://example.com/'; $request = Services::request($config); - $request->uri = new URI('http://example.com'); + $request->uri = new URI($config->baseURL); Services::injectMock('request', $request); - $_GET = []; $this->config = new Pager(); $this->pager = new \CodeIgniter\Pager\Pager($this->config, Services::renderer()); } From d071fc4bb97e7d83b9724e9f98c1874e5cb37140 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 11:37:07 +0900 Subject: [PATCH 1771/2325] test: extract createPager() method --- tests/system/Pager/PagerTest.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 1259e0065b50..4a317fcdef42 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -36,13 +36,18 @@ protected function setUp(): void { parent::setUp(); - $_SERVER['REQUEST_URI'] = '/'; + $this->createPager('/'); + } + + private function createPager(string $path): void + { + $_SERVER['REQUEST_URI'] = $path; $_GET = []; $config = new App(); $config->baseURL = 'http://example.com/'; $request = Services::request($config); - $request->uri = new URI($config->baseURL); + $request->uri = new URI($config->baseURL . ltrim($path, '/')); Services::injectMock('request', $request); From 82a5a98e6ff887323c008a01f73e5fecfe7d0c1a Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 11:45:00 +0900 Subject: [PATCH 1772/2325] test: fix Request and Config state Setting $request->uri later does not make correct state of Request. At least Request::$path is incorrect. --- tests/system/Pager/PagerTest.php | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 4a317fcdef42..c4b180a00f05 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -11,7 +11,10 @@ namespace CodeIgniter\Pager; +use CodeIgniter\Config\Factories; +use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\URI; +use CodeIgniter\HTTP\UserAgent; use CodeIgniter\Pager\Exceptions\PagerException; use CodeIgniter\Test\CIUnitTestCase; use Config\App; @@ -46,8 +49,16 @@ private function createPager(string $path): void $config = new App(); $config->baseURL = 'http://example.com/'; - $request = Services::request($config); - $request->uri = new URI($config->baseURL . ltrim($path, '/')); + Factories::injectMock('config', 'App', $config); + + $request = new IncomingRequest( + $config, + new URI($config->baseURL . ltrim($path, '/')), + 'php://input', + new UserAgent() + ); + $request = $request->withMethod('GET'); + Services::injectMock('request', $request); Services::injectMock('request', $request); @@ -148,11 +159,11 @@ public function testStoreWithQueries() $this->pager->store('default', 3, 25, 100); - $this->assertSame('http://example.com/index.php?page=2&foo=bar', $this->pager->getPreviousPageURI()); - $this->assertSame('http://example.com/index.php?page=4&foo=bar', $this->pager->getNextPageURI()); - $this->assertSame('http://example.com/index.php?page=5&foo=bar', $this->pager->getPageURI(5)); + $this->assertSame('http://example.com/index.php/?page=2&foo=bar', $this->pager->getPreviousPageURI()); + $this->assertSame('http://example.com/index.php/?page=4&foo=bar', $this->pager->getNextPageURI()); + $this->assertSame('http://example.com/index.php/?page=5&foo=bar', $this->pager->getPageURI(5)); $this->assertSame( - 'http://example.com/index.php?foo=bar&page=5', + 'http://example.com/index.php/?foo=bar&page=5', $this->pager->only(['foo'])->getPageURI(5) ); } From 1094c371bc32e253bf4abea9c211fafcf86a69aa Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 12:55:16 +0900 Subject: [PATCH 1773/2325] test: remove `index.php` from URI --- tests/system/Pager/PagerTest.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index c4b180a00f05..e3f61694d76b 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -45,10 +45,12 @@ protected function setUp(): void private function createPager(string $path): void { $_SERVER['REQUEST_URI'] = $path; + $_SERVER['SCRIPT_NAME'] = '/index.php'; $_GET = []; - $config = new App(); - $config->baseURL = 'http://example.com/'; + $config = new App(); + $config->baseURL = 'http://example.com/'; + $config->indexPage = ''; Factories::injectMock('config', 'App', $config); $request = new IncomingRequest( @@ -159,11 +161,11 @@ public function testStoreWithQueries() $this->pager->store('default', 3, 25, 100); - $this->assertSame('http://example.com/index.php/?page=2&foo=bar', $this->pager->getPreviousPageURI()); - $this->assertSame('http://example.com/index.php/?page=4&foo=bar', $this->pager->getNextPageURI()); - $this->assertSame('http://example.com/index.php/?page=5&foo=bar', $this->pager->getPageURI(5)); + $this->assertSame('http://example.com/?page=2&foo=bar', $this->pager->getPreviousPageURI()); + $this->assertSame('http://example.com/?page=4&foo=bar', $this->pager->getNextPageURI()); + $this->assertSame('http://example.com/?page=5&foo=bar', $this->pager->getPageURI(5)); $this->assertSame( - 'http://example.com/index.php/?foo=bar&page=5', + 'http://example.com/?foo=bar&page=5', $this->pager->only(['foo'])->getPageURI(5) ); } From 41845d4ebe878caa519bdf8a355cb64765951afc Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 13:05:49 +0900 Subject: [PATCH 1774/2325] fix: can't get current page from segment --- system/Pager/Pager.php | 7 ++++++- tests/system/Pager/PagerTest.php | 10 ++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index f3d6d4bec39d..76eed216f5d5 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -163,6 +163,10 @@ public function setSegment(int $number, string $group = 'default') { $this->segment[$group] = $number; + // Recalculate current page + $this->ensureGroup($group); + $this->calculateCurrentPage($group); + return $this; } @@ -383,6 +387,7 @@ protected function ensureGroup(string $group, ?int $perPage = null) } $this->groups[$group] = [ + 'currentUri' => clone current_url(true), 'uri' => clone current_url(true), 'hasMore' => false, 'total' => null, @@ -405,7 +410,7 @@ protected function calculateCurrentPage(string $group) { if (array_key_exists($group, $this->segment)) { try { - $this->groups[$group]['currentPage'] = (int) $this->groups[$group]['uri']->setSilent(false)->getSegment($this->segment[$group]); + $this->groups[$group]['currentPage'] = (int) $this->groups[$group]['currentUri']->setSilent(false)->getSegment($this->segment[$group]); } catch (HTTPException $e) { $this->groups[$group]['currentPage'] = 1; } diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index e3f61694d76b..085c569864fa 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -229,6 +229,16 @@ public function testGetCurrentPageDetectsGroupedURI() $this->assertSame(2, $this->pager->getCurrentPage('foo')); } + public function testGetCurrentPageFromSegment() + { + $this->createPager('/page/2'); + + $this->pager->setPath('foo'); + $this->pager->setSegment(2); + + $this->assertSame(2, $this->pager->getCurrentPage()); + } + public function testGetTotalPagesDefaultsToOne() { $this->assertSame(1, $this->pager->getPageCount()); From e07611de529ca9c580b18a38788186c0812111a7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 13:28:39 +0900 Subject: [PATCH 1775/2325] test: rename variable name --- tests/system/Pager/PagerTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/system/Pager/PagerTest.php b/tests/system/Pager/PagerTest.php index 085c569864fa..6c6b14fdca7b 100644 --- a/tests/system/Pager/PagerTest.php +++ b/tests/system/Pager/PagerTest.php @@ -42,9 +42,9 @@ protected function setUp(): void $this->createPager('/'); } - private function createPager(string $path): void + private function createPager(string $requestUri): void { - $_SERVER['REQUEST_URI'] = $path; + $_SERVER['REQUEST_URI'] = $requestUri; $_SERVER['SCRIPT_NAME'] = '/index.php'; $_GET = []; @@ -55,7 +55,7 @@ private function createPager(string $path): void $request = new IncomingRequest( $config, - new URI($config->baseURL . ltrim($path, '/')), + new URI($config->baseURL . ltrim($requestUri, '/')), 'php://input', new UserAgent() ); From 65f5f6f6032f64a9ffd3349f7784118d7001d772 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 13:39:25 +0900 Subject: [PATCH 1776/2325] refactor: break long lines --- system/Pager/Pager.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/system/Pager/Pager.php b/system/Pager/Pager.php index 76eed216f5d5..32843ba9e98d 100644 --- a/system/Pager/Pager.php +++ b/system/Pager/Pager.php @@ -283,7 +283,15 @@ public function getPageURI(?int $page = null, string $group = 'default', bool $r $uri->setQueryArray($query); } - return $returnObject === true ? $uri : URI::createURIString($uri->getScheme(), $uri->getAuthority(), $uri->getPath(), $uri->getQuery(), $uri->getFragment()); + return ($returnObject === true) + ? $uri + : URI::createURIString( + $uri->getScheme(), + $uri->getAuthority(), + $uri->getPath(), + $uri->getQuery(), + $uri->getFragment() + ); } /** @@ -410,7 +418,8 @@ protected function calculateCurrentPage(string $group) { if (array_key_exists($group, $this->segment)) { try { - $this->groups[$group]['currentPage'] = (int) $this->groups[$group]['currentUri']->setSilent(false)->getSegment($this->segment[$group]); + $this->groups[$group]['currentPage'] = (int) $this->groups[$group]['currentUri'] + ->setSilent(false)->getSegment($this->segment[$group]); } catch (HTTPException $e) { $this->groups[$group]['currentPage'] = 1; } From e954172459431185ad8233c446507a8bb4453f53 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 14:16:20 +0900 Subject: [PATCH 1777/2325] fix: ErrorException when the field is not sent ErrorException DateTime::createFromFormat(): Passing null to parameter #2 ($datetime) of type string is deprecated --- system/Validation/FormatRules.php | 4 ++++ tests/system/Validation/FormatRulesTest.php | 5 +++++ 2 files changed, 9 insertions(+) diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index 990ea8128809..676ae8485ba2 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -333,6 +333,10 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu */ public function valid_date(?string $str = null, ?string $format = null): bool { + if (($str === null)) { + return false; + } + if (empty($format)) { return strtotime($str) !== false; } diff --git a/tests/system/Validation/FormatRulesTest.php b/tests/system/Validation/FormatRulesTest.php index f4a22b2af973..bf9bf92eb6dc 100644 --- a/tests/system/Validation/FormatRulesTest.php +++ b/tests/system/Validation/FormatRulesTest.php @@ -1206,6 +1206,11 @@ public function testValidDate(?string $str, ?string $format, bool $expected): vo public function validDateProvider(): Generator { yield from [ + [ + null, + 'Y-m-d', + false, + ], [ 'Sun', 'D', From 6bd3ee9ae10c21330f1bcbddcb3b3e7c39442dd7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 16 Mar 2022 21:13:35 +0900 Subject: [PATCH 1778/2325] refactor: remove uneeded parentheses --- system/Validation/FormatRules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Validation/FormatRules.php b/system/Validation/FormatRules.php index 676ae8485ba2..21353d1a3385 100644 --- a/system/Validation/FormatRules.php +++ b/system/Validation/FormatRules.php @@ -333,7 +333,7 @@ public function valid_url_strict(?string $str = null, ?string $validSchemes = nu */ public function valid_date(?string $str = null, ?string $format = null): bool { - if (($str === null)) { + if ($str === null) { return false; } From 2a2e9dae03905d7438dacbebce448383233167d7 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Thu, 17 Mar 2022 13:10:11 +0800 Subject: [PATCH 1779/2325] Update Laminas Escaper to v2.10 --- system/ThirdParty/Escaper/Escaper.php | 30 +++++++++------------------ 1 file changed, 10 insertions(+), 20 deletions(-) diff --git a/system/ThirdParty/Escaper/Escaper.php b/system/ThirdParty/Escaper/Escaper.php index ca0f1a9dd21c..d6a02e14c9be 100644 --- a/system/ThirdParty/Escaper/Escaper.php +++ b/system/ThirdParty/Escaper/Escaper.php @@ -6,10 +6,8 @@ use function bin2hex; use function ctype_digit; -use function function_exists; use function hexdec; use function htmlspecialchars; -use function iconv; use function in_array; use function mb_convert_encoding; use function ord; @@ -38,7 +36,7 @@ class Escaper * entities that XML supports. Using HTML entities would result in this error: * XML Parsing Error: undefined entity * - * @var array + * @var array */ protected static $htmlNamedEntityMap = [ 34 => 'quot', // quotation mark @@ -67,6 +65,7 @@ class Escaper * Static Matcher which escapes characters for HTML Attribute contexts * * @var callable + * @psalm-var callable(array):string */ protected $htmlAttrMatcher; @@ -74,6 +73,7 @@ class Escaper * Static Matcher which escapes characters for Javascript contexts * * @var callable + * @psalm-var callable(array):string */ protected $jsMatcher; @@ -81,6 +81,7 @@ class Escaper * Static Matcher which escapes characters for CSS Attribute contexts * * @var callable + * @psalm-var callable(array):string */ protected $cssMatcher; @@ -255,7 +256,7 @@ public function escapeCss(string $string) * Callback function for preg_replace_callback that applies HTML Attribute * escaping to all matches. * - * @param array $matches + * @param array $matches * @return string */ protected function htmlAttrMatcher($matches) @@ -302,7 +303,7 @@ protected function htmlAttrMatcher($matches) * Callback function for preg_replace_callback that applies Javascript * escaping to all matches. * - * @param array $matches + * @param array $matches * @return string */ protected function jsMatcher($matches) @@ -325,7 +326,7 @@ protected function jsMatcher($matches) * Callback function for preg_replace_callback that applies CSS * escaping to all matches. * - * @param array $matches + * @param array $matches * @return string */ protected function cssMatcher($matches) @@ -391,32 +392,21 @@ protected function isUtf8($string) } /** - * Encoding conversion helper which wraps iconv and mbstring where they exist or throws - * and exception where neither is available. + * Encoding conversion helper which wraps mb_convert_encoding * * @param string $string * @param string $to * @param array|string $from - * @throws Exception\RuntimeException * @return string */ protected function convertEncoding($string, $to, $from) { - if (function_exists('iconv')) { - $result = iconv($from, $to, $string); - } elseif (function_exists('mb_convert_encoding')) { - $result = mb_convert_encoding($string, $to, $from); - } else { - throw new Exception\RuntimeException( - static::class - . ' requires either the iconv or mbstring extension to be installed' - . ' when escaping for non UTF-8 strings.' - ); - } + $result = mb_convert_encoding($string, $to, $from); if ($result === false) { return ''; // return non-fatal blank string on encoding errors from users } + return $result; } } From b3589085dd1643e0c953d396d7515514651c1356 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 18 Mar 2022 11:59:00 +0900 Subject: [PATCH 1780/2325] docs: clarify that current_url() returns URL based on Config\App --- system/Helpers/url_helper.php | 2 +- user_guide_src/source/helpers/url_helper.rst | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php index 98dd596c1a4d..e1e8b8a30e32 100644 --- a/system/Helpers/url_helper.php +++ b/system/Helpers/url_helper.php @@ -109,7 +109,7 @@ function base_url($relativePath = '', ?string $scheme = null): string if (! function_exists('current_url')) { /** - * Returns the current full URL based on the IncomingRequest. + * Returns the current full URL based on the Config\App settings and IncomingRequest. * String returns ignore query and fragment parts. * * @param bool $returnObject True to return an object instead of a string diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst index 37374890548e..8f0252c27cff 100644 --- a/user_guide_src/source/helpers/url_helper.rst +++ b/user_guide_src/source/helpers/url_helper.rst @@ -88,8 +88,9 @@ The following functions are available: :returns: The current URL :rtype: string|\\CodeIgniter\\HTTP\\URI - Returns the full URL (including segments) of the page being currently - viewed. + Returns the full URL (including segments) of the page being currently viewed. + However for security reasons, it is created based on the ``Config\App`` settings, + and not intended to match the browser URL. .. note:: Calling this function is the same as doing this: From 5b528af01f1a2b478454ff10c528c1aaecd54252 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 6 Mar 2022 14:38:42 +0900 Subject: [PATCH 1781/2325] fix: now initEnvValue() converts type when the default property value is int and float --- system/Config/BaseConfig.php | 22 ++++++++++++++----- tests/system/Config/BaseConfigTest.php | 19 ++++++++++++++++ tests/system/Config/fixtures/.env | 5 +++++ tests/system/Config/fixtures/SimpleConfig.php | 3 +++ 4 files changed, 44 insertions(+), 5 deletions(-) diff --git a/system/Config/BaseConfig.php b/system/Config/BaseConfig.php index 9b71a4963bab..359fcc1488ba 100644 --- a/system/Config/BaseConfig.php +++ b/system/Config/BaseConfig.php @@ -88,7 +88,7 @@ public function __construct() * * @param mixed $property * - * @return mixed + * @return void */ protected function initEnvValue(&$property, string $name, string $prefix, string $shortPrefix) { @@ -102,16 +102,28 @@ protected function initEnvValue(&$property, string $name, string $prefix, string } elseif ($value === 'true') { $value = true; } - $property = is_bool($value) ? $value : trim($value, '\'"'); - } + if (is_bool($value)) { + $property = $value; + + return; + } + + $value = trim($value, '\'"'); - return $property; + if (is_int($property)) { + $value = (int) $value; + } elseif (is_float($property)) { + $value = (float) $value; + } + + $property = $value; + } } /** * Retrieve an environment-specific configuration setting * - * @return mixed + * @return string|null */ protected function getEnvValue(string $property, string $prefix, string $shortPrefix) { diff --git a/tests/system/Config/BaseConfigTest.php b/tests/system/Config/BaseConfigTest.php index 4c2d4ba20ccb..667a877287fb 100644 --- a/tests/system/Config/BaseConfigTest.php +++ b/tests/system/Config/BaseConfigTest.php @@ -55,6 +55,25 @@ public function testBasicValues() $this->assertSame(18, $config->golf); } + public function testUseDefaultValueTypeIntAndFloatValues() + { + $dotenv = new DotEnv($this->fixturesFolder, '.env'); + $dotenv->load(); + $config = new SimpleConfig(); + + $this->assertSame(0.0, $config->float); + $this->assertSame(999, $config->int); + } + + public function testUseDefaultValueTypeStringValue() + { + $dotenv = new DotEnv($this->fixturesFolder, '.env'); + $dotenv->load(); + $config = new SimpleConfig(); + + $this->assertSame('123456', $config->password); + } + /** * @runInSeparateProcess * @preserveGlobalState disabled diff --git a/tests/system/Config/fixtures/.env b/tests/system/Config/fixtures/.env index 2f859cc9faca..38ca0bed6f0b 100644 --- a/tests/system/Config/fixtures/.env +++ b/tests/system/Config/fixtures/.env @@ -32,3 +32,8 @@ SimpleConfig.crew.captain = Malcolm SimpleConfig.crew.pilot = Wash SimpleConfig.crew.comms = true SimpleConfig.crew.doctor = false + +SimpleConfig.float = '0.0' +SimpleConfig.int = '999' + +SimpleConfig.password = 123456 diff --git a/tests/system/Config/fixtures/SimpleConfig.php b/tests/system/Config/fixtures/SimpleConfig.php index 69f5590e90f1..d64aa1a0d741 100644 --- a/tests/system/Config/fixtures/SimpleConfig.php +++ b/tests/system/Config/fixtures/SimpleConfig.php @@ -48,4 +48,7 @@ class SimpleConfig extends \CodeIgniter\Config\BaseConfig public $one_deep = [ 'under_deep' => null, ]; + public $float = 12.34; + public $int = 1234; + public $password = 'secret'; } From 8524bb963bd79bd3be676fa21ab82b8c98b6a412 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 18 Mar 2022 16:08:22 +0900 Subject: [PATCH 1782/2325] test: add test for nullable int property --- tests/system/Config/BaseConfigTest.php | 3 +++ tests/system/Config/fixtures/.env | 2 ++ tests/system/Config/fixtures/SimpleConfig.php | 7 ++++--- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/tests/system/Config/BaseConfigTest.php b/tests/system/Config/BaseConfigTest.php index 667a877287fb..20d2f77c8421 100644 --- a/tests/system/Config/BaseConfigTest.php +++ b/tests/system/Config/BaseConfigTest.php @@ -117,6 +117,9 @@ public function testEnvironmentOverrides() $this->assertSame('bar', $config->onedeep_value); // array property name with underscore and key with underscore $this->assertSame('foo', $config->one_deep['under_deep']); + + // The default property value is null but has type + $this->assertSame(20, $config->size); } public function testPrefixedValues() diff --git a/tests/system/Config/fixtures/.env b/tests/system/Config/fixtures/.env index 38ca0bed6f0b..36f5651cf532 100644 --- a/tests/system/Config/fixtures/.env +++ b/tests/system/Config/fixtures/.env @@ -37,3 +37,5 @@ SimpleConfig.float = '0.0' SimpleConfig.int = '999' SimpleConfig.password = 123456 + +SimpleConfig.size=20 diff --git a/tests/system/Config/fixtures/SimpleConfig.php b/tests/system/Config/fixtures/SimpleConfig.php index d64aa1a0d741..9870c72b0ac2 100644 --- a/tests/system/Config/fixtures/SimpleConfig.php +++ b/tests/system/Config/fixtures/SimpleConfig.php @@ -48,7 +48,8 @@ class SimpleConfig extends \CodeIgniter\Config\BaseConfig public $one_deep = [ 'under_deep' => null, ]; - public $float = 12.34; - public $int = 1234; - public $password = 'secret'; + public $float = 12.34; + public $int = 1234; + public $password = 'secret'; + public ?int $size = null; } From 2609cc949c1fdb05f585f2211c12e8b9ca8c3887 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 18 Mar 2022 17:30:31 +0900 Subject: [PATCH 1783/2325] docs: add note about `attributes` --- user_guide_src/source/models/entities.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/models/entities.rst b/user_guide_src/source/models/entities.rst index a1941fb31d97..d2c99c8623b6 100644 --- a/user_guide_src/source/models/entities.rst +++ b/user_guide_src/source/models/entities.rst @@ -31,6 +31,8 @@ Assume you have a database table named ``users`` that has the following schema:: password - string created_at - datetime +.. important:: ``attributes`` is a reserved word for internal use. If you use it as a column name, the Entity does not work correctly. + Create the Entity Class ----------------------- From d61b3c7487f2168f38b6f01ea2398b409d7c2523 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 19 Mar 2022 10:11:18 +0900 Subject: [PATCH 1784/2325] test: change .env entry Do not recommend to use `'` for int/float value. --- tests/system/Config/fixtures/.env | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/system/Config/fixtures/.env b/tests/system/Config/fixtures/.env index 36f5651cf532..17d9e8e9116e 100644 --- a/tests/system/Config/fixtures/.env +++ b/tests/system/Config/fixtures/.env @@ -33,9 +33,12 @@ SimpleConfig.crew.pilot = Wash SimpleConfig.crew.comms = true SimpleConfig.crew.doctor = false -SimpleConfig.float = '0.0' -SimpleConfig.int = '999' +# The default value's type in the Config class is float, so it will be converted to float +SimpleConfig.float = 0.0 +# The default value's type in the Config class is int, so it will be converted to int +SimpleConfig.int = 999 SimpleConfig.password = 123456 +# The property type in the Config class is ?int, so it will be converted to int by PHP SimpleConfig.size=20 From 4f97aac34420631753a936c2b7decd7f17cb68c0 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sat, 19 Mar 2022 22:52:14 +0700 Subject: [PATCH 1785/2325] [Rector] Clean up skip config and re-run Rector --- app/Config/App.php | 3 +- app/Config/Database.php | 3 +- app/Config/Format.php | 8 +++-- app/Config/Logger.php | 3 +- rector.php | 16 +++++++--- system/Cache/Handlers/PredisHandler.php | 2 +- system/CodeIgniter.php | 2 +- system/Commands/Database/CreateDatabase.php | 3 +- .../Generators/ControllerGenerator.php | 9 ++++-- system/Config/AutoloadConfig.php | 28 +++++++++++------ system/Config/BaseService.php | 4 +-- system/Database/BaseConnection.php | 2 +- system/Database/BasePreparedQuery.php | 2 +- system/Database/BaseResult.php | 3 +- system/Database/MySQLi/Result.php | 2 +- system/Database/OCI8/Result.php | 2 +- system/Database/Postgre/Result.php | 2 +- system/Database/SQLSRV/Result.php | 2 +- system/Database/SQLite3/Connection.php | 2 +- system/Database/SQLite3/Result.php | 4 +-- system/Images/Handlers/ImageMagickHandler.php | 2 +- system/Language/Language.php | 2 +- system/Test/Fabricator.php | 3 +- system/Test/Mock/MockResult.php | 3 +- system/View/View.php | 3 +- tests/system/API/ResponseTraitTest.php | 8 ++--- tests/system/Autoloader/AutoloaderTest.php | 11 +++---- tests/system/Autoloader/FileLocatorTest.php | 5 +-- tests/system/CLI/CLITest.php | 5 +-- tests/system/Cache/CacheFactoryTest.php | 9 +++--- .../system/Cache/Handlers/BaseHandlerTest.php | 5 +-- .../system/Cache/Handlers/FileHandlerTest.php | 3 +- tests/system/CodeIgniterTest.php | 9 ++---- tests/system/CommonFunctionsTest.php | 2 +- tests/system/Config/DotEnvTest.php | 5 +-- tests/system/Config/ServicesTest.php | 3 +- tests/system/Database/Builder/InsertTest.php | 7 +++-- tests/system/Database/Builder/ReplaceTest.php | 3 +- tests/system/Database/Builder/UpdateTest.php | 9 +++--- tests/system/Database/ConfigTest.php | 13 ++++---- tests/system/Database/DatabaseSeederTest.php | 7 +++-- tests/system/Database/Live/DbUtilsTest.php | 5 +-- tests/system/Database/Live/DeleteTest.php | 2 +- tests/system/Database/Live/ForgeTest.php | 31 ++++++++++--------- tests/system/Database/Live/GetTest.php | 5 +-- .../Database/Live/SQLite/AlterTableTest.php | 16 ++++------ .../Migrations/MigrationRunnerTest.php | 5 +-- tests/system/Encryption/EncryptionTest.php | 14 ++++----- .../Handlers/OpenSSLHandlerTest.php | 12 +++---- .../Encryption/Handlers/SodiumHandlerTest.php | 24 ++++++-------- tests/system/Entity/EntityTest.php | 2 +- tests/system/Files/FileTest.php | 3 +- tests/system/Format/FormatTest.php | 8 ++--- tests/system/Format/JSONFormatterTest.php | 3 +- .../HTTP/CURLRequestDoNotShareOptionsTest.php | 7 ++--- tests/system/HTTP/CURLRequestTest.php | 7 ++--- tests/system/Helpers/ArrayHelperTest.php | 6 ++-- tests/system/HomeTest.php | 3 +- tests/system/Honeypot/HoneypotTest.php | 4 +-- tests/system/I18n/TimeTest.php | 22 ++++++------- tests/system/Language/LanguageTest.php | 5 +-- tests/system/Models/FindModelTest.php | 3 +- .../system/RESTful/ResourceControllerTest.php | 10 +++--- .../system/RESTful/ResourcePresenterTest.php | 18 +++++------ .../Session/Handlers/DatabaseHandlerTest.php | 2 +- tests/system/Session/SessionTest.php | 2 +- tests/system/Test/FabricatorTest.php | 8 ++--- tests/system/Test/FilterTestTraitTest.php | 6 ++-- tests/system/View/CellTest.php | 9 ++---- 69 files changed, 235 insertions(+), 226 deletions(-) diff --git a/app/Config/App.php b/app/Config/App.php index 7ab0c7d7cfcb..c6c716822756 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -3,6 +3,7 @@ namespace Config; use CodeIgniter\Config\BaseConfig; +use CodeIgniter\Session\Handlers\FileHandler; class App extends BaseConfig { @@ -151,7 +152,7 @@ class App extends BaseConfig * * @var string */ - public $sessionDriver = 'CodeIgniter\Session\Handlers\FileHandler'; + public $sessionDriver = FileHandler::class; /** * -------------------------------------------------------------------------- diff --git a/app/Config/Database.php b/app/Config/Database.php index 1e6340899bf4..376de53a821d 100644 --- a/app/Config/Database.php +++ b/app/Config/Database.php @@ -3,6 +3,7 @@ namespace Config; use CodeIgniter\Database\Config; +use SQLite3; /** * Database Configuration @@ -62,7 +63,7 @@ class Database extends Config 'username' => '', 'password' => '', 'database' => ':memory:', - 'DBDriver' => 'SQLite3', + 'DBDriver' => SQLite3::class, 'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), diff --git a/app/Config/Format.php b/app/Config/Format.php index 533540e27918..d89e40842c22 100644 --- a/app/Config/Format.php +++ b/app/Config/Format.php @@ -4,6 +4,8 @@ use CodeIgniter\Config\BaseConfig; use CodeIgniter\Format\FormatterInterface; +use CodeIgniter\Format\JSONFormatter; +use CodeIgniter\Format\XMLFormatter; class Format extends BaseConfig { @@ -40,9 +42,9 @@ class Format extends BaseConfig * @var array */ public $formatters = [ - 'application/json' => 'CodeIgniter\Format\JSONFormatter', - 'application/xml' => 'CodeIgniter\Format\XMLFormatter', - 'text/xml' => 'CodeIgniter\Format\XMLFormatter', + 'application/json' => JSONFormatter::class, + 'application/xml' => XMLFormatter::class, + 'text/xml' => XMLFormatter::class, ]; /** diff --git a/app/Config/Logger.php b/app/Config/Logger.php index a4eaeb648955..406d9aaccc85 100644 --- a/app/Config/Logger.php +++ b/app/Config/Logger.php @@ -2,6 +2,7 @@ namespace Config; +use CodeIgniter\Log\Handlers\FileHandler; use CodeIgniter\Config\BaseConfig; class Logger extends BaseConfig @@ -83,7 +84,7 @@ class Logger extends BaseConfig * File Handler * -------------------------------------------------------------------- */ - 'CodeIgniter\Log\Handlers\FileHandler' => [ + FileHandler::class => [ // The log levels that this handler will handle. 'handles' => [ diff --git a/rector.php b/rector.php index b90225d80fcf..6c2bc99bcf8d 100644 --- a/rector.php +++ b/rector.php @@ -84,8 +84,6 @@ RemoveUnusedPrivateMethodRector::class => [ // private method called via getPrivateMethodInvoker __DIR__ . '/tests/system/Test/ReflectionHelperTest.php', - // Rector bug? - __DIR__ . '/system/CodeIgniter.php', ], // call on purpose for nothing happen check @@ -103,9 +101,17 @@ __DIR__ . '/system/Session/Handlers', ], - // may cause load view files directly when detecting class that - // make warning - StringClassNameToClassConstantRector::class, + StringClassNameToClassConstantRector::class => [ + // may cause load view files directly when detecting namespaced string + // due to internal PHPStan issue + __DIR__ . '/app/Config/Pager.php', + __DIR__ . '/app/Config/Validation.php', + __DIR__ . '/tests/system/Validation/StrictRules/ValidationTest.php', + __DIR__ . '/tests/system/Validation/ValidationTest.php', + + // expected Qualified name + __DIR__ . '/tests/system/Autoloader/FileLocatorTest.php', + ], // sometime too detail CountOnNullRector::class, diff --git a/system/Cache/Handlers/PredisHandler.php b/system/Cache/Handlers/PredisHandler.php index 5d1f37cdfc24..87ab4e333dca 100644 --- a/system/Cache/Handlers/PredisHandler.php +++ b/system/Cache/Handlers/PredisHandler.php @@ -222,6 +222,6 @@ public function getMetaData(string $key) */ public function isSupported(): bool { - return class_exists('Predis\Client'); + return class_exists(Client::class); } } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 86e70546dd41..127e087458a0 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -830,7 +830,7 @@ protected function startController() $this->benchmark->start('controller_constructor'); // Is it routed to a Closure? - if (is_object($this->controller) && (get_class($this->controller) === 'Closure')) { + if (is_object($this->controller) && (get_class($this->controller) === Closure::class)) { $controller = $this->controller; return $controller(...$this->router->params()); diff --git a/system/Commands/Database/CreateDatabase.php b/system/Commands/Database/CreateDatabase.php index 17e1e51bb68b..0682f945b9bf 100644 --- a/system/Commands/Database/CreateDatabase.php +++ b/system/Commands/Database/CreateDatabase.php @@ -16,6 +16,7 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Database\SQLite3\Connection; use Config\Database; +use SQLite3; use Throwable; /** @@ -106,7 +107,7 @@ public function run(array $params) $name = str_replace(['.db', '.sqlite'], '', $name) . ".{$ext}"; } - $config->{$group}['DBDriver'] = 'SQLite3'; + $config->{$group}['DBDriver'] = SQLite3::class; $config->{$group}['database'] = $name; if ($name !== ':memory:') { diff --git a/system/Commands/Generators/ControllerGenerator.php b/system/Commands/Generators/ControllerGenerator.php index 36a951cf0df0..f27c77ee0fe5 100644 --- a/system/Commands/Generators/ControllerGenerator.php +++ b/system/Commands/Generators/ControllerGenerator.php @@ -14,6 +14,9 @@ use CodeIgniter\CLI\BaseCommand; use CodeIgniter\CLI\CLI; use CodeIgniter\CLI\GeneratorTrait; +use CodeIgniter\Controller; +use CodeIgniter\RESTful\ResourceController; +use CodeIgniter\RESTful\ResourcePresenter; /** * Generates a skeleton controller file. @@ -99,7 +102,7 @@ protected function prepare(string $class): string // Gets the appropriate parent class to extend. if ($bare || $rest) { if ($bare) { - $useStatement = 'CodeIgniter\Controller'; + $useStatement = Controller::class; $extends = 'Controller'; } elseif ($rest) { $rest = is_string($rest) ? $rest : 'controller'; @@ -112,10 +115,10 @@ protected function prepare(string $class): string } if ($rest === 'controller') { - $useStatement = 'CodeIgniter\RESTful\ResourceController'; + $useStatement = ResourceController::class; $extends = 'ResourceController'; } elseif ($rest === 'presenter') { - $useStatement = 'CodeIgniter\RESTful\ResourcePresenter'; + $useStatement = ResourcePresenter::class; $extends = 'ResourcePresenter'; } } diff --git a/system/Config/AutoloadConfig.php b/system/Config/AutoloadConfig.php index d3dbefcd7c3c..13a6721fd2e6 100644 --- a/system/Config/AutoloadConfig.php +++ b/system/Config/AutoloadConfig.php @@ -11,6 +11,16 @@ namespace CodeIgniter\Config; +use Laminas\Escaper\Escaper; +use Psr\Log\AbstractLogger; +use Psr\Log\InvalidArgumentException; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; +use Psr\Log\LoggerInterface; +use Psr\Log\LoggerTrait; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; + /** * AUTOLOADER CONFIGURATION * @@ -93,15 +103,15 @@ class AutoloadConfig * @var array */ protected $coreClassmap = [ - 'Psr\Log\AbstractLogger' => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php', - 'Psr\Log\InvalidArgumentException' => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php', - 'Psr\Log\LoggerAwareInterface' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php', - 'Psr\Log\LoggerAwareTrait' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php', - 'Psr\Log\LoggerInterface' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php', - 'Psr\Log\LoggerTrait' => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php', - 'Psr\Log\LogLevel' => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php', - 'Psr\Log\NullLogger' => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php', - 'Laminas\Escaper\Escaper' => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php', + AbstractLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php', + InvalidArgumentException::class => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php', + LoggerAwareInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php', + LoggerAwareTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php', + LoggerInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php', + LoggerTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php', + LogLevel::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php', + NullLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php', + Escaper::class => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php', ]; /** diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 572b6cf576bd..4244b7a7097d 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -332,7 +332,7 @@ protected static function discoverServices(string $name, array $arguments) foreach ($files as $file) { $classname = $locator->getClassname($file); - if (! in_array($classname, ['CodeIgniter\\Config\\Services'], true)) { + if (! in_array($classname, [\CodeIgniter\Config\Services::class], true)) { static::$services[] = new $classname(); } } @@ -369,7 +369,7 @@ protected static function buildServicesCache(): void foreach ($files as $file) { $classname = $locator->getClassname($file); - if ($classname !== 'CodeIgniter\\Config\\Services') { + if ($classname !== \CodeIgniter\Config\Services::class) { self::$serviceNames[] = $classname; static::$services[] = new $classname(); } diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 4f54c1980830..d2ce3fdd390a 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -326,7 +326,7 @@ abstract class BaseConnection implements ConnectionInterface * * @var string */ - protected $queryClass = 'CodeIgniter\\Database\\Query'; + protected $queryClass = Query::class; /** * Saves our connection settings. diff --git a/system/Database/BasePreparedQuery.php b/system/Database/BasePreparedQuery.php index b6e2db706d2a..ce5a208a1ef3 100644 --- a/system/Database/BasePreparedQuery.php +++ b/system/Database/BasePreparedQuery.php @@ -69,7 +69,7 @@ public function __construct(BaseConnection $db) * * @return mixed */ - public function prepare(string $sql, array $options = [], string $queryClass = 'CodeIgniter\\Database\\Query') + public function prepare(string $sql, array $options = [], string $queryClass = Query::class) { // We only supports positional placeholders (?) // in order to work with the execute method below, so we diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index 5d223c7fc08b..b5818525dc30 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Database; use CodeIgniter\Entity\Entity; +use stdClass; /** * Class BaseResult @@ -508,5 +509,5 @@ abstract protected function fetchAssoc(); * * @return object */ - abstract protected function fetchObject(string $className = 'stdClass'); + abstract protected function fetchObject(string $className = stdClass::class); } diff --git a/system/Database/MySQLi/Result.php b/system/Database/MySQLi/Result.php index 7eab7d86c685..35f480776c85 100644 --- a/system/Database/MySQLi/Result.php +++ b/system/Database/MySQLi/Result.php @@ -139,7 +139,7 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = 'stdClass') + protected function fetchObject(string $className = stdClass::class) { if (is_subclass_of($className, Entity::class)) { return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data); diff --git a/system/Database/OCI8/Result.php b/system/Database/OCI8/Result.php index ce3a73def1c4..6ad26b649480 100644 --- a/system/Database/OCI8/Result.php +++ b/system/Database/OCI8/Result.php @@ -98,7 +98,7 @@ protected function fetchObject(string $className = stdClass::class) { $row = oci_fetch_object($this->resultID); - if ($className === 'stdClass' || ! $row) { + if ($className === stdClass::class || ! $row) { return $row; } if (is_subclass_of($className, Entity::class)) { diff --git a/system/Database/Postgre/Result.php b/system/Database/Postgre/Result.php index 76a0dd956515..581d79b1d421 100644 --- a/system/Database/Postgre/Result.php +++ b/system/Database/Postgre/Result.php @@ -105,7 +105,7 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = 'stdClass') + protected function fetchObject(string $className = stdClass::class) { if (is_subclass_of($className, Entity::class)) { return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data); diff --git a/system/Database/SQLSRV/Result.php b/system/Database/SQLSRV/Result.php index 2a55e452ac09..045a5eebd81a 100755 --- a/system/Database/SQLSRV/Result.php +++ b/system/Database/SQLSRV/Result.php @@ -147,7 +147,7 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = 'stdClass') + protected function fetchObject(string $className = stdClass::class) { if (is_subclass_of($className, Entity::class)) { return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data); diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 39fbca8bcfea..e335e7985ba7 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -28,7 +28,7 @@ class Connection extends BaseConnection * * @var string */ - public $DBDriver = 'SQLite3'; + public $DBDriver = SQLite3::class; /** * Identifier escape character diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 6afc04c51578..39b9897af1e4 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -122,14 +122,14 @@ protected function fetchAssoc() * * @return bool|object */ - protected function fetchObject(string $className = 'stdClass') + protected function fetchObject(string $className = stdClass::class) { // No native support for fetching rows as objects if (($row = $this->fetchAssoc()) === false) { return false; } - if ($className === 'stdClass') { + if ($className === stdClass::class) { return (object) $row; } diff --git a/system/Images/Handlers/ImageMagickHandler.php b/system/Images/Handlers/ImageMagickHandler.php index 37bd168ead02..5e0bafe00841 100644 --- a/system/Images/Handlers/ImageMagickHandler.php +++ b/system/Images/Handlers/ImageMagickHandler.php @@ -49,7 +49,7 @@ public function __construct($config = null) // We should never see this, so can't test it // @codeCoverageIgnoreStart - if (! (extension_loaded('imagick') || class_exists('Imagick'))) { + if (! (extension_loaded('imagick') || class_exists(Imagick::class))) { throw ImageException::forMissingExtension('IMAGICK'); } // @codeCoverageIgnoreEnd diff --git a/system/Language/Language.php b/system/Language/Language.php index 299618657aa2..640dcfaa552d 100644 --- a/system/Language/Language.php +++ b/system/Language/Language.php @@ -57,7 +57,7 @@ public function __construct(string $locale) { $this->locale = $locale; - if (class_exists('MessageFormatter')) { + if (class_exists(MessageFormatter::class)) { $this->intlSupport = true; } } diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index d4369765f0ee..d474e796df78 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -17,6 +17,7 @@ use Faker\Generator; use InvalidArgumentException; use RuntimeException; +use stdClass; /** * Fabricator @@ -409,7 +410,7 @@ public function makeObject(?string $className = null): object { if ($className === null) { if ($this->model->returnType === 'object' || $this->model->returnType === 'array') { - $className = 'stdClass'; + $className = stdClass::class; } else { $className = $this->model->returnType; } diff --git a/system/Test/Mock/MockResult.php b/system/Test/Mock/MockResult.php index 0aaa340a95de..f3807d9170c9 100644 --- a/system/Test/Mock/MockResult.php +++ b/system/Test/Mock/MockResult.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Test\Mock; use CodeIgniter\Database\BaseResult; +use stdClass; class MockResult extends BaseResult { @@ -81,7 +82,7 @@ protected function fetchAssoc() * * @return object */ - protected function fetchObject($className = 'stdClass') + protected function fetchObject($className = stdClass::class) { return new $className(); } diff --git a/system/View/View.php b/system/View/View.php index f557b6629b0a..b0206d67caba 100644 --- a/system/View/View.php +++ b/system/View/View.php @@ -13,6 +13,7 @@ use CodeIgniter\Autoloader\FileLocator; use CodeIgniter\Debug\Toolbar\Collectors\Views; +use CodeIgniter\Filters\DebugToolbar; use CodeIgniter\View\Exceptions\ViewException; use Config\Services; use Config\Toolbar; @@ -235,7 +236,7 @@ public function render(string $view, ?array $options = null, ?bool $saveData = n $this->logPerformance($this->renderVars['start'], microtime(true), $this->renderVars['view']); if (($this->debug && (! isset($options['debug']) || $options['debug'] === true)) - && in_array('CodeIgniter\Filters\DebugToolbar', service('filters')->getFiltersClass()['after'], true) + && in_array(DebugToolbar::class, service('filters')->getFiltersClass()['after'], true) ) { $toolbarCollectors = config(Toolbar::class)->collectors; diff --git a/tests/system/API/ResponseTraitTest.php b/tests/system/API/ResponseTraitTest.php index 8cf06372dcdd..821e217a35b8 100644 --- a/tests/system/API/ResponseTraitTest.php +++ b/tests/system/API/ResponseTraitTest.php @@ -29,11 +29,7 @@ final class ResponseTraitTest extends CIUnitTestCase { protected $request; protected $response; - - /** - * @var FormatterInterface|null - */ - protected $formatter; + protected ?FormatterInterface $formatter = null; protected function setUp(): void { @@ -505,7 +501,7 @@ public function testXMLFormatter() $this->formatter = new XMLFormatter(); $controller = $this->makeController(); - $this->assertInstanceOf('CodeIgniter\Format\XMLFormatter', $this->formatter); + $this->assertInstanceOf(XMLFormatter::class, $this->formatter); $this->invoke($controller, 'respondCreated', [['id' => 3], 'A Custom Reason']); diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 3c7156abdde2..95d74c6c1b7e 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -15,6 +15,7 @@ use Config\Autoload; use Config\Modules; use Config\Services; +use InvalidArgumentException; use UnnamespacedClass; /** @@ -22,12 +23,8 @@ */ final class AutoloaderTest extends CIUnitTestCase { - /** - * @var Autoloader - */ - protected $loader; - - protected $filesPath = SUPPORTPATH . 'Autoloader/'; + protected Autoloader $loader; + protected string $filesPath = SUPPORTPATH . 'Autoloader/'; protected function setUp(): void { @@ -58,7 +55,7 @@ public function testLoadStoredClass() public function testInitializeWithInvalidArguments() { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage("Config array must contain either the 'psr4' key or the 'classmap' key."); $config = new Autoload(); diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 3a40ed24345b..54a471d74453 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -20,10 +20,7 @@ */ final class FileLocatorTest extends CIUnitTestCase { - /** - * @var FileLocator - */ - protected $locator; + protected FileLocator $locator; protected function setUp(): void { diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 68008ccc1e4d..107ac1463e67 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -14,6 +14,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Filters\CITestStreamFilter; use ReflectionProperty; +use RuntimeException; /** * @internal @@ -100,7 +101,7 @@ public function testNewLine() public function testColorExceptionForeground() { - $this->expectException('RuntimeException'); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Invalid foreground color: Foreground'); CLI::color('test', 'Foreground'); @@ -108,7 +109,7 @@ public function testColorExceptionForeground() public function testColorExceptionBackground() { - $this->expectException('RuntimeException'); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Invalid background color: Background'); CLI::color('test', 'white', 'Background'); diff --git a/tests/system/Cache/CacheFactoryTest.php b/tests/system/Cache/CacheFactoryTest.php index c67d1c805ad0..45bc16df58e8 100644 --- a/tests/system/Cache/CacheFactoryTest.php +++ b/tests/system/Cache/CacheFactoryTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Cache; +use CodeIgniter\Cache\Exceptions\CacheException; use CodeIgniter\Cache\Handlers\DummyHandler; use CodeIgniter\Test\CIUnitTestCase; use Config\Cache; @@ -50,7 +51,7 @@ public function testNew() public function testGetHandlerExceptionCacheInvalidHandlers() { - $this->expectException('CodeIgniter\Cache\Exceptions\CacheException'); + $this->expectException(CacheException::class); $this->expectExceptionMessage('Cache config must have an array of $validHandlers.'); $this->config->validHandlers = null; @@ -60,7 +61,7 @@ public function testGetHandlerExceptionCacheInvalidHandlers() public function testGetHandlerExceptionCacheNoBackup() { - $this->expectException('CodeIgniter\Cache\Exceptions\CacheException'); + $this->expectException(CacheException::class); $this->expectExceptionMessage('Cache config must have a handler and backupHandler set.'); $this->config->backupHandler = null; @@ -70,7 +71,7 @@ public function testGetHandlerExceptionCacheNoBackup() public function testGetHandlerExceptionCacheNoHandler() { - $this->expectException('CodeIgniter\Cache\Exceptions\CacheException'); + $this->expectException(CacheException::class); $this->expectExceptionMessage('Cache config must have a handler and backupHandler set.'); $this->config->handler = null; @@ -80,7 +81,7 @@ public function testGetHandlerExceptionCacheNoHandler() public function testGetHandlerExceptionCacheHandlerNotFound() { - $this->expectException('CodeIgniter\Cache\Exceptions\CacheException'); + $this->expectException(CacheException::class); $this->expectExceptionMessage('Cache config has an invalid handler or backup handler specified.'); unset($this->config->validHandlers[$this->config->handler]); diff --git a/tests/system/Cache/Handlers/BaseHandlerTest.php b/tests/system/Cache/Handlers/BaseHandlerTest.php index b2ebb61e01ef..18bfcff0d113 100644 --- a/tests/system/Cache/Handlers/BaseHandlerTest.php +++ b/tests/system/Cache/Handlers/BaseHandlerTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Cache\Handlers; use CodeIgniter\Test\CIUnitTestCase; +use InvalidArgumentException; use stdClass; use Tests\Support\Cache\RestrictiveHandler; @@ -27,7 +28,7 @@ final class BaseHandlerTest extends CIUnitTestCase */ public function testValidateKeyInvalidType($input) { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Cache key must be a string'); BaseHandler::validateKey($input); @@ -48,7 +49,7 @@ public function testValidateKeyUsesConfig() { config('Cache')->reservedCharacters = 'b'; - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Cache key contains reserved characters b'); BaseHandler::validateKey('banana'); diff --git a/tests/system/Cache/Handlers/FileHandlerTest.php b/tests/system/Cache/Handlers/FileHandlerTest.php index 032243d890f1..23573dee3314 100644 --- a/tests/system/Cache/Handlers/FileHandlerTest.php +++ b/tests/system/Cache/Handlers/FileHandlerTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Cache\Handlers; +use CodeIgniter\Cache\Exceptions\CacheException; use CodeIgniter\CLI\CLI; use Config\Cache; @@ -76,7 +77,7 @@ public function testNew() public function testNewWithNonWritablePath() { - $this->expectException('CodeIgniter\Cache\Exceptions\CacheException'); + $this->expectException(CacheException::class); chmod($this->config->file['storePath'], 0444); new FileHandler($this->config); diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index 418bde4530f6..42706e39d110 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter; use CodeIgniter\Config\Services; +use CodeIgniter\HTTP\Response; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCodeIgniter; @@ -26,11 +27,7 @@ */ final class CodeIgniterTest extends CIUnitTestCase { - /** - * @var CodeIgniter - */ - protected $codeigniter; - + protected CodeIgniter $codeigniter; protected $routes; protected function setUp(): void @@ -218,7 +215,7 @@ public function testResponseConfigEmpty() $response = Services::response(null, false); - $this->assertInstanceOf('\CodeIgniter\HTTP\Response', $response); + $this->assertInstanceOf(Response::class, $response); } public function testRoutesIsEmpty() diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 1c8088fdf227..758e1727eca1 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -399,7 +399,7 @@ public function testSlashItem() protected function injectSessionMock() { $defaults = [ - 'sessionDriver' => 'CodeIgniter\Session\Handlers\FileHandler', + 'sessionDriver' => FileHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, 'sessionSavePath' => null, diff --git a/tests/system/Config/DotEnvTest.php b/tests/system/Config/DotEnvTest.php index 2aff090b9576..077bd8f23ea4 100644 --- a/tests/system/Config/DotEnvTest.php +++ b/tests/system/Config/DotEnvTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Config; use CodeIgniter\Test\CIUnitTestCase; +use InvalidArgumentException; use org\bovigo\vfs\vfsStream; /** @@ -115,7 +116,7 @@ public function testLoadsUnreadableFile() $file = 'unreadable.env'; $path = rtrim($this->fixturesFolder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $file; chmod($path, 0000); - $this->expectException('\InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage("The .env file is not readable: {$path}"); $dotenv = new DotEnv($this->fixturesFolder, $file); $dotenv->load(); @@ -135,7 +136,7 @@ public function testQuotedDotenvLoadsEnvironmentVars() public function testSpacedValuesWithoutQuotesThrowsException() { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('.env values containing spaces must be surrounded by quotes.'); $dotenv = new DotEnv($this->fixturesFolder, 'spaced-wrong.env'); diff --git a/tests/system/Config/ServicesTest.php b/tests/system/Config/ServicesTest.php index b33ff13f9387..14fbd27a2910 100644 --- a/tests/system/Config/ServicesTest.php +++ b/tests/system/Config/ServicesTest.php @@ -43,6 +43,7 @@ use CodeIgniter\View\Parser; use Config\App; use Config\Exceptions; +use RuntimeException; use Tests\Support\Config\Services; /** @@ -69,7 +70,7 @@ protected function tearDown(): void public function testCanReplaceFrameworkServices() { - $this->expectException('RuntimeException'); + $this->expectException(RuntimeException::class); $this->expectExceptionMessage('Service originated from Tests\Support\Config\Services'); Services::uri('testCanReplaceFrameworkServices'); diff --git a/tests/system/Database/Builder/InsertTest.php b/tests/system/Database/Builder/InsertTest.php index 1844434d3a1c..713e77bd15a7 100644 --- a/tests/system/Database/Builder/InsertTest.php +++ b/tests/system/Database/Builder/InsertTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Database\Builder; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Query; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockConnection; @@ -62,7 +63,7 @@ public function testThrowsExceptionOnNoValuesSet() { $builder = $this->db->table('jobs'); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('You must use the "set" method to update an entry.'); $builder->testMode()->insert(null, true); @@ -192,7 +193,7 @@ public function testInsertBatchThrowsExceptionOnNoData() { $builder = $this->db->table('jobs'); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('You must use the "set" method to update an entry.'); $builder->insertBatch(); } @@ -201,7 +202,7 @@ public function testInsertBatchThrowsExceptionOnEmptyData() { $builder = $this->db->table('jobs'); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('insertBatch() called with no data'); $builder->insertBatch([]); } diff --git a/tests/system/Database/Builder/ReplaceTest.php b/tests/system/Database/Builder/ReplaceTest.php index 4197ed05449d..e7a1262cb107 100644 --- a/tests/system/Database/Builder/ReplaceTest.php +++ b/tests/system/Database/Builder/ReplaceTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Database\Builder; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockConnection; @@ -47,7 +48,7 @@ public function testReplaceThrowsExceptionWithNoData() { $builder = $this->db->table('jobs'); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('You must use the "set" method to update an entry.'); $builder->replace(); diff --git a/tests/system/Database/Builder/UpdateTest.php b/tests/system/Database/Builder/UpdateTest.php index bda9ae49915d..5af1490f6f66 100644 --- a/tests/system/Database/Builder/UpdateTest.php +++ b/tests/system/Database/Builder/UpdateTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Database\Builder; use CodeIgniter\Database\BaseBuilder; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockConnection; use CodeIgniter\Test\Mock\MockQuery; @@ -177,7 +178,7 @@ public function testUpdateThrowsExceptionWithNoData() { $builder = new BaseBuilder('jobs', $this->db); - $this->expectException('CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('You must use the "set" method to update an entry.'); $builder->update(null, null, null); @@ -266,7 +267,7 @@ public function testUpdateBatchThrowsExceptionWithNoData() { $builder = new BaseBuilder('jobs', $this->db); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('You must use the "set" method to update an entry.'); $builder->updateBatch(null, 'id'); @@ -276,7 +277,7 @@ public function testUpdateBatchThrowsExceptionWithNoID() { $builder = new BaseBuilder('jobs', $this->db); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('You must specify an index to match on for batch updates.'); $builder->updateBatch([]); @@ -286,7 +287,7 @@ public function testUpdateBatchThrowsExceptionWithEmptySetArray() { $builder = new BaseBuilder('jobs', $this->db); - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->expectExceptionMessage('updateBatch() called with no data'); $builder->updateBatch([], 'id'); diff --git a/tests/system/Database/ConfigTest.php b/tests/system/Database/ConfigTest.php index 0dc9a1619485..301a95158bf1 100644 --- a/tests/system/Database/ConfigTest.php +++ b/tests/system/Database/ConfigTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\ReflectionHelper; +use SQLite3; /** * @internal @@ -21,7 +22,7 @@ final class ConfigTest extends CIUnitTestCase { use ReflectionHelper; - protected $group = [ + protected array $group = [ 'DSN' => '', 'hostname' => 'localhost', 'username' => 'first', @@ -40,13 +41,13 @@ final class ConfigTest extends CIUnitTestCase 'failover' => [], 'port' => 3306, ]; - protected $dsnGroup = [ + protected array $dsnGroup = [ 'DSN' => 'MySQLi://user:pass@localhost:3306/dbname?DBPrefix=test_&pConnect=true&charset=latin1&DBCollat=latin1_swedish_ci', 'hostname' => '', 'username' => '', 'password' => '', 'database' => '', - 'DBDriver' => 'SQLite3', + 'DBDriver' => SQLite3::class, 'DBPrefix' => 't_', 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), @@ -59,13 +60,13 @@ final class ConfigTest extends CIUnitTestCase 'failover' => [], 'port' => 3306, ]; - protected $dsnGroupPostgre = [ + protected array $dsnGroupPostgre = [ 'DSN' => 'Postgre://user:pass@localhost:5432/dbname?DBPrefix=test_&connect_timeout=5&sslmode=1', 'hostname' => '', 'username' => '', 'password' => '', 'database' => '', - 'DBDriver' => 'SQLite3', + 'DBDriver' => SQLite3::class, 'DBPrefix' => 't_', 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), @@ -78,7 +79,7 @@ final class ConfigTest extends CIUnitTestCase 'failover' => [], 'port' => 5432, ]; - protected $dsnGroupPostgreNative = [ + protected array $dsnGroupPostgreNative = [ 'DSN' => 'pgsql:host=localhost;port=5432;dbname=database_name', 'hostname' => '', 'username' => '', diff --git a/tests/system/Database/DatabaseSeederTest.php b/tests/system/Database/DatabaseSeederTest.php index 7e08d6648508..70721718ea8a 100644 --- a/tests/system/Database/DatabaseSeederTest.php +++ b/tests/system/Database/DatabaseSeederTest.php @@ -14,6 +14,7 @@ use CodeIgniter\Test\CIUnitTestCase; use Config\Database; use Faker\Generator; +use InvalidArgumentException; /** * @internal @@ -22,7 +23,7 @@ final class DatabaseSeederTest extends CIUnitTestCase { public function testInstantiateNoSeedPath() { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $config = new Database(); $config->filesPath = ''; @@ -31,7 +32,7 @@ public function testInstantiateNoSeedPath() public function testInstantiateNotDirSeedPath() { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $config = new Database(); $config->filesPath = APPPATH . 'Foo'; @@ -48,7 +49,7 @@ public function testFakerGet() public function testCallOnEmptySeeder() { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $seeder = new Seeder(new Database()); $seeder->call(''); diff --git a/tests/system/Database/Live/DbUtilsTest.php b/tests/system/Database/Live/DbUtilsTest.php index e767d0b6991d..414412a72ded 100644 --- a/tests/system/Database/Live/DbUtilsTest.php +++ b/tests/system/Database/Live/DbUtilsTest.php @@ -15,6 +15,7 @@ use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; +use SQLite3; /** * @group DatabaseLive @@ -80,7 +81,7 @@ public function testUtilsListDatabases() $databases = $util->listDatabases(); $this->assertContains($this->db->getDatabase(), $databases); - } elseif ($this->db->DBDriver === 'SQLite3') { + } elseif ($this->db->DBDriver === SQLite3::class) { $this->expectException(DatabaseException::class); $this->expectExceptionMessage('Unsupported feature of the database platform you are using.'); @@ -96,7 +97,7 @@ public function testUtilsDatabaseExist() $exist = $util->databaseExists($this->db->getDatabase()); $this->assertTrue($exist); - } elseif ($this->db->DBDriver === 'SQLite3') { + } elseif ($this->db->DBDriver === SQLite3::class) { $this->expectException(DatabaseException::class); $this->expectExceptionMessage('Unsupported feature of the database platform you are using.'); diff --git a/tests/system/Database/Live/DeleteTest.php b/tests/system/Database/Live/DeleteTest.php index 31b89412e78a..f8311e9d042a 100644 --- a/tests/system/Database/Live/DeleteTest.php +++ b/tests/system/Database/Live/DeleteTest.php @@ -29,7 +29,7 @@ final class DeleteTest extends CIUnitTestCase public function testDeleteThrowExceptionWithNoCriteria() { - $this->expectException('\CodeIgniter\Database\Exceptions\DatabaseException'); + $this->expectException(DatabaseException::class); $this->db->table('job')->delete(); } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 113f2c0a211e..f83593ed320e 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -18,6 +18,7 @@ use Config\Database; use InvalidArgumentException; use RuntimeException; +use SQLite3; /** * @group DatabaseLive @@ -56,7 +57,7 @@ public function testCreateDatabaseIfNotExists() $dbName = 'test_forge_database_exist'; $databaseCreateIfNotExists = $this->forge->createDatabase($dbName, true); - if ($this->db->DBDriver !== 'SQLite3') { + if ($this->db->DBDriver !== SQLite3::class) { $this->forge->dropDatabase($dbName); } @@ -72,7 +73,7 @@ public function testCreateDatabaseIfNotExistsWithDb() $this->forge->createDatabase($dbName); $databaseExists = $this->forge->createDatabase($dbName, true); - if ($this->db->DBDriver !== 'SQLite3') { + if ($this->db->DBDriver !== SQLite3::class) { $this->forge->dropDatabase($dbName); } @@ -84,7 +85,7 @@ public function testDropDatabase() if ($this->db->DBDriver === 'OCI8') { $this->markTestSkipped('OCI8 does not support drop database.'); } - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->markTestSkipped('SQLite3 requires file path to drop database'); } @@ -97,7 +98,7 @@ public function testCreateDatabaseExceptionNoCreateStatement() { $this->setPrivateProperty($this->forge, 'createDatabaseStr', false); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $databaseCreated = $this->forge->createDatabase('test_forge_database'); $this->assertTrue($databaseCreated); } else { @@ -112,7 +113,7 @@ public function testDropDatabaseExceptionNoDropStatement() { $this->setPrivateProperty($this->forge, 'dropDatabaseStr', false); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->markTestSkipped('SQLite3 requires file path to drop database'); } else { $this->expectException(DatabaseException::class); @@ -175,7 +176,7 @@ public function testCreateTableApplyBigInt() $this->assertSame(strtolower($fieldsData[0]->type), 'bigint'); } elseif ($this->db->DBDriver === 'Postgre') { $this->assertSame(strtolower($fieldsData[0]->type), 'bigint'); - } elseif ($this->db->DBDriver === 'SQLite3') { + } elseif ($this->db->DBDriver === SQLite3::class) { $this->assertSame(strtolower($fieldsData[0]->type), 'integer'); } elseif ($this->db->DBDriver === 'OCI8') { $this->assertSame(strtolower($fieldsData[0]->type), 'number'); @@ -191,7 +192,7 @@ public function testCreateTableWithAttributes() if ($this->db->DBDriver === 'OCI8') { $this->markTestSkipped('OCI8 does not support comments on tables or columns.'); } - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->markTestSkipped('SQLite3 does not support comments on tables or columns.'); } @@ -213,7 +214,7 @@ public function testCreateTableWithAttributes() public function testCreateTableWithArrayFieldConstraints() { - if (in_array($this->db->DBDriver, ['MySQLi', 'SQLite3'], true)) { + if (in_array($this->db->DBDriver, ['MySQLi', SQLite3::class], true)) { $this->forge->dropTable('forge_array_constraint', true); $this->forge->addField([ 'status' => [ @@ -231,7 +232,7 @@ public function testCreateTableWithArrayFieldConstraints() $this->assertSame('status', $fields[0]->name); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { // SQLite3 converts array constraints to TEXT CHECK(...) $this->assertSame('TEXT', $fields[0]->type); } else { @@ -431,7 +432,7 @@ public function testForeignKey() $foreignKeyData = $this->db->getForeignKeyData($tableName); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->assertSame($foreignKeyData[0]->constraint_name, 'users_id to db_forge_test_users.id'); $this->assertSame($foreignKeyData[0]->sequence, 0); } elseif ($this->db->DBDriver === 'OCI8') { @@ -553,7 +554,7 @@ public function testCompositeForeignKey() $foreignKeyData = $this->db->getForeignKeyData($forgeTestInvoicesTableName); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->assertSame('users_id to db_forge_test_users.id', $foreignKeyData[0]->constraint_name); $this->assertSame(0, $foreignKeyData[0]->sequence); $this->assertSame('users_second_id to db_forge_test_users.second_id', $foreignKeyData[1]->constraint_name); @@ -843,7 +844,7 @@ public function testAddFields() $this->assertSame(32, (int) $fieldsData[0]->max_length); $this->assertNull($fieldsData[1]->default); $this->assertSame(255, (int) $fieldsData[1]->max_length); - } elseif ($this->db->DBDriver === 'SQLite3') { + } elseif ($this->db->DBDriver === SQLite3::class) { $this->assertSame('integer', strtolower($fieldsData[0]->type)); $this->assertSame('varchar', strtolower($fieldsData[1]->type)); $this->assertNull($fieldsData[1]->default); @@ -868,7 +869,7 @@ public function testAddFields() public function testCompositeKey() { // SQLite3 uses auto increment different - $uniqueOrAuto = $this->db->DBDriver === 'SQLite3' ? 'unique' : 'auto_increment'; + $uniqueOrAuto = $this->db->DBDriver === SQLite3::class ? 'unique' : 'auto_increment'; $this->forge->addField([ 'id' => [ @@ -916,7 +917,7 @@ public function testCompositeKey() $this->assertSame($keys['db_forge_test_1_code_active']->name, 'db_forge_test_1_code_active'); $this->assertSame($keys['db_forge_test_1_code_active']->fields, ['code', 'active']); $this->assertSame($keys['db_forge_test_1_code_active']->type, 'UNIQUE'); - } elseif ($this->db->DBDriver === 'SQLite3') { + } elseif ($this->db->DBDriver === SQLite3::class) { $this->assertSame($keys['sqlite_autoindex_db_forge_test_1_1']->name, 'sqlite_autoindex_db_forge_test_1_1'); $this->assertSame($keys['sqlite_autoindex_db_forge_test_1_1']->fields, ['id']); $this->assertSame($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); @@ -1054,7 +1055,7 @@ public function testDropTableSuccess() $this->assertFalse($this->db->tableExists('dropTest')); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->assertCount(0, $this->db->getIndexData('droptest')); } } diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index 20ae2e099d0d..768f24d72de3 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -14,6 +14,7 @@ use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; +use SQLite3; /** * @group DatabaseLive @@ -91,7 +92,7 @@ public function testGetFieldData() $typeTest = $this->db->table('type_test')->get()->getFieldData(); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->assertSame('integer', $typeTest[0]->type_name); // INTEGER AUTO INC $this->assertSame('text', $typeTest[1]->type_name); // VARCHAR $this->assertSame('text', $typeTest[2]->type_name); // CHAR @@ -172,7 +173,7 @@ public function testGetDataSeek() { $data = $this->db->table('job')->get(); - if ($this->db->DBDriver === 'SQLite3') { + if ($this->db->DBDriver === SQLite3::class) { $this->expectException(DatabaseException::class); $this->expectExceptionMessage('SQLite3 doesn\'t support seeking to other offset.'); } elseif ($this->db->DBDriver === 'OCI8') { diff --git a/tests/system/Database/Live/SQLite/AlterTableTest.php b/tests/system/Database/Live/SQLite/AlterTableTest.php index 2816008a2a54..8889c9d8f639 100644 --- a/tests/system/Database/Live/SQLite/AlterTableTest.php +++ b/tests/system/Database/Live/SQLite/AlterTableTest.php @@ -11,12 +11,14 @@ namespace CodeIgniter\Database\Live\SQLite; +use CodeIgniter\Database\Exceptions\DataException; use CodeIgniter\Database\SQLite3\Connection; use CodeIgniter\Database\SQLite3\Forge; use CodeIgniter\Database\SQLite3\Table; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; use Config\Database; +use SQLite3; /** * @group DatabaseLive @@ -34,27 +36,21 @@ final class AlterTableTest extends CIUnitTestCase */ protected $migrate = false; - /** - * @var Table - */ - protected $table; + protected Table $table; /** * @var Connection */ protected $db; - /** - * @var Forge - */ - protected $forge; + protected Forge $forge; protected function setUp(): void { parent::setUp(); $config = [ - 'DBDriver' => 'SQLite3', + 'DBDriver' => SQLite3::class, 'database' => 'database.db', ]; @@ -77,7 +73,7 @@ private function dropTables() public function testFromTableThrowsOnNoTable() { - $this->expectException('CodeIgniter\Database\Exceptions\DataException'); + $this->expectException(DataException::class); $this->expectExceptionMessage('Table `foo` was not found in the current database.'); $this->table->fromTable('foo'); diff --git a/tests/system/Database/Migrations/MigrationRunnerTest.php b/tests/system/Database/Migrations/MigrationRunnerTest.php index 2c9fa09e1d73..9a5f467ed9c2 100644 --- a/tests/system/Database/Migrations/MigrationRunnerTest.php +++ b/tests/system/Database/Migrations/MigrationRunnerTest.php @@ -22,6 +22,7 @@ use Config\Migrations; use Config\Services; use org\bovigo\vfs\vfsStream; +use SQLite3; /** * @group DatabaseLive @@ -74,7 +75,7 @@ public function testLoadsDefaultDatabaseWhenNoneSpecified() $this->assertInstanceOf(BaseConnection::class, $db); $this->assertSame( - ($dbConfig->tests['DBDriver'] === 'SQLite3' ? WRITEPATH : '') . $dbConfig->tests['database'], + ($dbConfig->tests['DBDriver'] === SQLite3::class ? WRITEPATH : '') . $dbConfig->tests['database'], $this->getPrivateProperty($db, 'database') ); $this->assertSame($dbConfig->tests['DBDriver'], $this->getPrivateProperty($db, 'DBDriver')); @@ -254,7 +255,7 @@ public function testFindMigrationsSuccessTimestamp() public function testMigrationThrowsDisabledException() { - $this->expectException('CodeIgniter\Exceptions\ConfigException'); + $this->expectException(ConfigException::class); $this->expectExceptionMessage('Migrations have been loaded but are disabled or setup incorrectly.'); $config = $this->config; diff --git a/tests/system/Encryption/EncryptionTest.php b/tests/system/Encryption/EncryptionTest.php index a1f6085a33a6..cb4eb4cad7da 100644 --- a/tests/system/Encryption/EncryptionTest.php +++ b/tests/system/Encryption/EncryptionTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Encryption; +use CodeIgniter\Encryption\Exceptions\EncryptionException; use CodeIgniter\Test\CIUnitTestCase; use Config\Encryption as EncryptionConfig; use Config\Services; @@ -20,10 +21,7 @@ */ final class EncryptionTest extends CIUnitTestCase { - /** - * @var \CodeIgniter\Encryption\Encryption - */ - protected $encryption; + protected \CodeIgniter\Encryption\Encryption $encryption; protected function setUp(): void { @@ -57,7 +55,7 @@ public function testConstructor() */ public function testBadDriver() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); // ask for a bad driver $config = new EncryptionConfig(); @@ -72,7 +70,7 @@ public function testBadDriver() */ public function testMissingDriver() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); // ask for a bad driver $config = new EncryptionConfig(); @@ -101,7 +99,7 @@ public function testServiceSuccess() public function testServiceFailure() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); // ask for a bad driver $config = new EncryptionConfig(); @@ -113,7 +111,7 @@ public function testServiceFailure() public function testServiceWithoutKey() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); Services::encrypter(); } diff --git a/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php b/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php index 89886b6f8901..5427c99a5edb 100644 --- a/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php +++ b/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Encryption\Handlers; use CodeIgniter\Encryption\Encryption; +use CodeIgniter\Encryption\Exceptions\EncryptionException; use CodeIgniter\Test\CIUnitTestCase; use Config\Encryption as EncryptionConfig; @@ -20,10 +21,7 @@ */ final class OpenSSLHandlerTest extends CIUnitTestCase { - /** - * @var \CodeIgniter\Encryption\Encryption - */ - protected $encryption; + protected \CodeIgniter\Encryption\Encryption $encryption; protected function setUp(): void { @@ -79,7 +77,7 @@ public function testSimple() */ public function testWithoutKey() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $encrypter = new OpenSSLHandler(); $message1 = 'This is a plain-text message.'; @@ -100,7 +98,7 @@ public function testWithKeyString() */ public function testWithWrongKeyString() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $key1 = 'abracadabra'; $encrypter = new OpenSSLHandler(); @@ -125,7 +123,7 @@ public function testWithKeyArray() */ public function testWithWrongKeyArray() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $key1 = 'abracadabra'; $encrypter = new OpenSSLHandler(); diff --git a/tests/system/Encryption/Handlers/SodiumHandlerTest.php b/tests/system/Encryption/Handlers/SodiumHandlerTest.php index fc5f353d2ffb..421af43e1330 100644 --- a/tests/system/Encryption/Handlers/SodiumHandlerTest.php +++ b/tests/system/Encryption/Handlers/SodiumHandlerTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Encryption\Handlers; use CodeIgniter\Encryption\Encryption; +use CodeIgniter\Encryption\Exceptions\EncryptionException; use CodeIgniter\Test\CIUnitTestCase; use Config\Encryption as EncryptionConfig; @@ -20,15 +21,8 @@ */ final class SodiumHandlerTest extends CIUnitTestCase { - /** - * @var \CodeIgniter\Encryption\Encryption - */ - protected $encryption; - - /** - * @var \Config\Encryption - */ - protected $config; + protected \CodeIgniter\Encryption\Encryption $encryption; + protected \Config\Encryption $config; protected function setUp(): void { @@ -57,7 +51,7 @@ public function testPropertiesGetter() public function testEmptyKeyThrowsErrorOnInitialize() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $this->config->key = ''; $this->encryption->initialize($this->config); @@ -65,7 +59,7 @@ public function testEmptyKeyThrowsErrorOnInitialize() public function testEmptyKeyThrowsErrorOnEncrypt() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $encrypter = $this->encryption->initialize($this->config); $encrypter->encrypt('Some message to encrypt', ''); @@ -73,7 +67,7 @@ public function testEmptyKeyThrowsErrorOnEncrypt() public function testInvalidBlockSizeThrowsErrorOnEncrypt() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $this->config->blockSize = -1; $encrypter = $this->encryption->initialize($this->config); @@ -82,7 +76,7 @@ public function testInvalidBlockSizeThrowsErrorOnEncrypt() public function testEmptyKeyThrowsErrorOnDecrypt() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $encrypter = $this->encryption->initialize($this->config); $ciphertext = $encrypter->encrypt('Some message to encrypt'); @@ -92,7 +86,7 @@ public function testEmptyKeyThrowsErrorOnDecrypt() public function testInvalidBlockSizeThrowsErrorOnDecrypt() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $key = $this->config->key; $encrypter = $this->encryption->initialize($this->config); @@ -103,7 +97,7 @@ public function testInvalidBlockSizeThrowsErrorOnDecrypt() public function testTruncatedMessageThrowsErrorOnDecrypt() { - $this->expectException('CodeIgniter\Encryption\Exceptions\EncryptionException'); + $this->expectException(EncryptionException::class); $encrypter = $this->encryption->initialize($this->config); $ciphertext = $encrypter->encrypt('Some message to encrypt'); diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index a9a59502575f..82c758f92f5e 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -382,7 +382,7 @@ public function testCastDateTime() $entity->eighth = 'March 12, 2017'; - $this->assertInstanceOf('DateTime', $entity->eighth); + $this->assertInstanceOf(DateTime::class, $entity->eighth); $this->assertSame('2017-03-12', $entity->eighth->format('Y-m-d')); } diff --git a/tests/system/Files/FileTest.php b/tests/system/Files/FileTest.php index 6ff5b77fd3bc..573c8cdb3499 100644 --- a/tests/system/Files/FileTest.php +++ b/tests/system/Files/FileTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Files; +use CodeIgniter\Files\Exceptions\FileNotFoundException; use CodeIgniter\Test\CIUnitTestCase; /** @@ -85,7 +86,7 @@ public function testGetSizeReturnsBytes() public function testThrowsExceptionIfNotAFile() { - $this->expectException('CodeIgniter\Files\Exceptions\FileNotFoundException'); + $this->expectException(FileNotFoundException::class); new File(SYSTEMPATH . 'Commoner.php', true); } diff --git a/tests/system/Format/FormatTest.php b/tests/system/Format/FormatTest.php index 0cd53e62a22c..3bc6854fa3ae 100644 --- a/tests/system/Format/FormatTest.php +++ b/tests/system/Format/FormatTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Format; use CodeIgniter\Format\Exceptions\FormatException; +use CodeIgniter\HTTP\URI; use CodeIgniter\Test\CIUnitTestCase; /** @@ -19,10 +20,7 @@ */ final class FormatTest extends CIUnitTestCase { - /** - * @var Format - */ - protected $format; + protected Format $format; protected function setUp(): void { @@ -66,7 +64,7 @@ public function testGetFormatterExpectsExceptionOnClassNotImplementingFormatterI { $this->format->getConfig()->formatters = array_merge( $this->format->getConfig()->formatters, - ['text/xml' => 'CodeIgniter\HTTP\URI'] + ['text/xml' => URI::class] ); $this->expectException(FormatException::class); diff --git a/tests/system/Format/JSONFormatterTest.php b/tests/system/Format/JSONFormatterTest.php index b2eb5f2e0d5e..19dacb02e86c 100644 --- a/tests/system/Format/JSONFormatterTest.php +++ b/tests/system/Format/JSONFormatterTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Format; use CodeIgniter\Test\CIUnitTestCase; +use RuntimeException; /** * @internal @@ -67,7 +68,7 @@ public function testKeepsURLs() public function testJSONError() { - $this->expectException('RuntimeException'); + $this->expectException(RuntimeException::class); $data = ["\xB1\x31"]; $expected = 'Boom'; diff --git a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php index 21070736d741..bcf9d1c51124 100644 --- a/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php +++ b/tests/system/HTTP/CURLRequestDoNotShareOptionsTest.php @@ -25,10 +25,7 @@ */ final class CURLRequestDoNotShareOptionsTest extends CIUnitTestCase { - /** - * @var MockCURLRequest - */ - protected $request; + protected MockCURLRequest $request; protected function setUp(): void { @@ -96,7 +93,7 @@ public function testSendReturnsResponse() $response = $this->request->setOutput($output)->send('get', 'http://example.com'); - $this->assertInstanceOf('CodeIgniter\\HTTP\\Response', $response); + $this->assertInstanceOf(Response::class, $response); $this->assertSame($output, $response->getBody()); } diff --git a/tests/system/HTTP/CURLRequestTest.php b/tests/system/HTTP/CURLRequestTest.php index 64b824cbad56..31808a739e29 100644 --- a/tests/system/HTTP/CURLRequestTest.php +++ b/tests/system/HTTP/CURLRequestTest.php @@ -25,10 +25,7 @@ */ final class CURLRequestTest extends CIUnitTestCase { - /** - * @var MockCURLRequest - */ - protected $request; + protected MockCURLRequest $request; protected function setUp(): void { @@ -96,7 +93,7 @@ public function testSendReturnsResponse() $response = $this->request->setOutput($output)->send('get', 'http://example.com'); - $this->assertInstanceOf('CodeIgniter\\HTTP\\Response', $response); + $this->assertInstanceOf(Response::class, $response); $this->assertSame($output, $response->getBody()); } diff --git a/tests/system/Helpers/ArrayHelperTest.php b/tests/system/Helpers/ArrayHelperTest.php index 90413c570a00..59257fbab7d6 100644 --- a/tests/system/Helpers/ArrayHelperTest.php +++ b/tests/system/Helpers/ArrayHelperTest.php @@ -12,6 +12,8 @@ namespace CodeIgniter\Helpers; use CodeIgniter\Test\CIUnitTestCase; +use ErrorException; +use ValueError; /** * @internal @@ -295,9 +297,9 @@ public function testArraySortByMultipleKeysFailsInconsistentArraySizes($data) { // PHP 8 changes this error type if (version_compare(PHP_VERSION, '8.0', '<')) { - $this->expectException('ErrorException'); + $this->expectException(ErrorException::class); } else { - $this->expectException('ValueError'); + $this->expectException(ValueError::class); } $this->expectExceptionMessage('Array sizes are inconsistent'); diff --git a/tests/system/HomeTest.php b/tests/system/HomeTest.php index fca482d3dec8..382e6c4ee522 100644 --- a/tests/system/HomeTest.php +++ b/tests/system/HomeTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\FeatureTestTrait; +use CodeIgniter\Test\TestResponse; /** * @internal @@ -32,7 +33,7 @@ public function testPageLoadsSuccessfully() ]); $response = $this->get('home'); - $this->assertInstanceOf('CodeIgniter\Test\TestResponse', $response); + $this->assertInstanceOf(TestResponse::class, $response); $this->assertTrue($response->isOK()); } } diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 860d552d4e86..b732b27fca7b 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -103,7 +103,7 @@ public function testConfigName() public function testHoneypotFilterBefore() { $config = [ - 'aliases' => ['trap' => '\CodeIgniter\Filters\Honeypot'], + 'aliases' => ['trap' => \CodeIgniter\Filters\Honeypot::class], 'globals' => [ 'before' => ['trap'], 'after' => [], @@ -120,7 +120,7 @@ public function testHoneypotFilterBefore() public function testHoneypotFilterAfter() { $config = [ - 'aliases' => ['trap' => '\CodeIgniter\Filters\Honeypot'], + 'aliases' => ['trap' => \CodeIgniter\Filters\Honeypot::class], 'globals' => [ 'before' => [], 'after' => ['trap'], diff --git a/tests/system/I18n/TimeTest.php b/tests/system/I18n/TimeTest.php index ed1b747699a4..03f142479478 100644 --- a/tests/system/I18n/TimeTest.php +++ b/tests/system/I18n/TimeTest.php @@ -497,7 +497,7 @@ public function testSetDay() public function testSetDayOverMaxInCurrentMonth() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('Feb 02, 2009'); $time->setDay(29); @@ -545,7 +545,7 @@ public function testSetSecond() public function testSetMonthTooSmall() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setMonth(-5); @@ -553,7 +553,7 @@ public function testSetMonthTooSmall() public function testSetMonthTooBig() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setMonth(30); @@ -561,7 +561,7 @@ public function testSetMonthTooBig() public function testSetDayTooSmall() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setDay(-5); @@ -569,7 +569,7 @@ public function testSetDayTooSmall() public function testSetDayTooBig() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setDay(80); @@ -577,7 +577,7 @@ public function testSetDayTooBig() public function testSetHourTooSmall() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setHour(-5); @@ -585,7 +585,7 @@ public function testSetHourTooSmall() public function testSetHourTooBig() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setHour(80); @@ -593,7 +593,7 @@ public function testSetHourTooBig() public function testSetMinuteTooSmall() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setMinute(-5); @@ -601,7 +601,7 @@ public function testSetMinuteTooSmall() public function testSetMinuteTooBig() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setMinute(80); @@ -609,7 +609,7 @@ public function testSetMinuteTooBig() public function testSetSecondTooSmall() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setSecond(-5); @@ -617,7 +617,7 @@ public function testSetSecondTooSmall() public function testSetSecondTooBig() { - $this->expectException('CodeIgniter\I18n\Exceptions\I18nException'); + $this->expectException(I18nException::class); $time = Time::parse('May 10, 2017'); $time->setSecond(80); diff --git a/tests/system/Language/LanguageTest.php b/tests/system/Language/LanguageTest.php index f89e6dd18125..58994434b3ec 100644 --- a/tests/system/Language/LanguageTest.php +++ b/tests/system/Language/LanguageTest.php @@ -14,6 +14,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockLanguage; use Config\Services; +use MessageFormatter; use Tests\Support\Language\SecondMockLanguage; /** @@ -96,7 +97,7 @@ public function testGetLineArrayReturnsLineArray() public function testGetLineFormatsMessage() { // No intl extension? then we can't test this - go away.... - if (! class_exists('MessageFormatter')) { + if (! class_exists(MessageFormatter::class)) { $this->markTestSkipped('No intl support.'); } @@ -110,7 +111,7 @@ public function testGetLineFormatsMessage() public function testGetLineArrayFormatsMessages() { // No intl extension? Then we can't test this - go away... - if (! class_exists('MessageFormatter')) { + if (! class_exists(MessageFormatter::class)) { $this->markTestSkipped('No intl support.'); } diff --git a/tests/system/Models/FindModelTest.php b/tests/system/Models/FindModelTest.php index e564f570ec8c..e0fdad5024a1 100644 --- a/tests/system/Models/FindModelTest.php +++ b/tests/system/Models/FindModelTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Database\Exceptions\DataException; use CodeIgniter\Exceptions\ModelException; +use stdClass; use Tests\Support\Models\JobModel; use Tests\Support\Models\SecondaryModel; use Tests\Support\Models\UserModel; @@ -295,7 +296,7 @@ public function testFirstWithNoPrimaryKey(): void ]); $record = $this->model->first(); - $this->assertInstanceOf('stdClass', $record); + $this->assertInstanceOf(stdClass::class, $record); $this->assertSame('foo', $record->key); } diff --git a/tests/system/RESTful/ResourceControllerTest.php b/tests/system/RESTful/ResourceControllerTest.php index e6098527d09c..06719fdbfd85 100644 --- a/tests/system/RESTful/ResourceControllerTest.php +++ b/tests/system/RESTful/ResourceControllerTest.php @@ -19,6 +19,7 @@ use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\URI; use CodeIgniter\HTTP\UserAgent; +use CodeIgniter\Model; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCodeIgniter; @@ -40,10 +41,7 @@ */ final class ResourceControllerTest extends CIUnitTestCase { - /** - * @var CodeIgniter - */ - protected $codeigniter; + protected CodeIgniter $codeigniter; /** * @var RouteCollection @@ -247,7 +245,7 @@ public function testModelByName() { $resource = new MockResourceController(); $resource->setModel('\Tests\Support\Models\UserModel'); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); } @@ -256,7 +254,7 @@ public function testModelByObject() $resource = new MockResourceController(); $model = new UserModel(); $resource->setModel($model); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); // Note that the leading backslash is missing if we build it this way $this->assertSame('Tests\Support\Models\UserModel', $resource->getModelName()); diff --git a/tests/system/RESTful/ResourcePresenterTest.php b/tests/system/RESTful/ResourcePresenterTest.php index 26ea1084b196..568b395a778c 100644 --- a/tests/system/RESTful/ResourcePresenterTest.php +++ b/tests/system/RESTful/ResourcePresenterTest.php @@ -13,6 +13,7 @@ use CodeIgniter\CodeIgniter; use CodeIgniter\Config\Services; +use CodeIgniter\Model; use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCodeIgniter; @@ -34,10 +35,7 @@ */ final class ResourcePresenterTest extends CIUnitTestCase { - /** - * @var CodeIgniter - */ - protected $codeigniter; + protected CodeIgniter $codeigniter; /** * @var RouteCollection @@ -247,7 +245,7 @@ public function testModelByName() { $resource = new MockResourcePresenter(); $resource->setModel('\Tests\Support\Models\UserModel'); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); } @@ -256,7 +254,7 @@ public function testModelByObject() $resource = new MockResourcePresenter(); $model = new UserModel(); $resource->setModel($model); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); // Note that the leading backslash is missing if we build it this way $this->assertSame('Tests\Support\Models\UserModel', $resource->getModelName()); @@ -266,12 +264,12 @@ public function testChangeSetModelByObject() { $resource = new MockResourcePresenter(); $resource->setModel('\Tests\Support\Models\UserModel'); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); $model = new EntityModel(); $resource->setModel($model); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); $this->assertSame('Tests\Support\Models\EntityModel', $resource->getModelName()); } @@ -279,11 +277,11 @@ public function testChangeSetModelByName() { $resource = new MockResourcePresenter(); $resource->setModel('\Tests\Support\Models\UserModel'); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); $this->assertSame('\Tests\Support\Models\UserModel', $resource->getModelName()); $resource->setModel('\Tests\Support\Models\EntityModel'); - $this->assertInstanceOf('CodeIgniter\Model', $resource->getModel()); + $this->assertInstanceOf(Model::class, $resource->getModel()); $this->assertSame('\Tests\Support\Models\EntityModel', $resource->getModelName()); } } diff --git a/tests/system/Session/Handlers/DatabaseHandlerTest.php b/tests/system/Session/Handlers/DatabaseHandlerTest.php index 2349bc292bd8..7af077606cba 100644 --- a/tests/system/Session/Handlers/DatabaseHandlerTest.php +++ b/tests/system/Session/Handlers/DatabaseHandlerTest.php @@ -40,7 +40,7 @@ protected function setUp(): void protected function getInstance($options = []) { $defaults = [ - 'sessionDriver' => 'CodeIgniter\Session\Handlers\DatabaseHandler', + 'sessionDriver' => DatabaseHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, 'sessionSavePath' => 'ci_sessions', diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index c295e26ba7d3..574ffaf99ce9 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -41,7 +41,7 @@ protected function setUp(): void protected function getInstance($options = []) { $defaults = [ - 'sessionDriver' => 'CodeIgniter\Session\Handlers\FileHandler', + 'sessionDriver' => FileHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, 'sessionSavePath' => null, diff --git a/tests/system/Test/FabricatorTest.php b/tests/system/Test/FabricatorTest.php index f7ba5781979a..13de446cbcb9 100644 --- a/tests/system/Test/FabricatorTest.php +++ b/tests/system/Test/FabricatorTest.php @@ -26,10 +26,8 @@ final class FabricatorTest extends CIUnitTestCase { /** * Default formatters to use for UserModel. Should match detected version. - * - * @var array */ - protected $formatters = [ + protected array $formatters = [ 'name' => 'name', 'email' => 'email', 'country' => 'country', @@ -363,7 +361,7 @@ public function testMakeReturnsSingleton() $result = $fabricator->make(); - $this->assertInstanceOf('stdClass', $result); + $this->assertInstanceOf(stdClass::class, $result); } public function testMakeReturnsExpectedCount() @@ -383,7 +381,7 @@ public function testCreateMockReturnsSingleton() $result = $fabricator->create(null, true); - $this->assertInstanceOf('stdClass', $result); + $this->assertInstanceOf(stdClass::class, $result); } public function testCreateMockReturnsExpectedCount() diff --git a/tests/system/Test/FilterTestTraitTest.php b/tests/system/Test/FilterTestTraitTest.php index 15b98379fbcf..f3cb0a4a6165 100644 --- a/tests/system/Test/FilterTestTraitTest.php +++ b/tests/system/Test/FilterTestTraitTest.php @@ -11,8 +11,10 @@ namespace CodeIgniter\Test; +use Closure; use CodeIgniter\Filters\Filters; use CodeIgniter\HTTP\RequestInterface; +use InvalidArgumentException; use Tests\Support\Filters\Customfilter; /** @@ -50,12 +52,12 @@ public function testGetCallerReturnsClosure() $caller = $this->getFilterCaller('test-customfilter', 'before'); $this->assertIsCallable($caller); - $this->assertInstanceOf('Closure', $caller); + $this->assertInstanceOf(Closure::class, $caller); } public function testGetCallerInvalidPosition() { - $this->expectException('InvalidArgumentException'); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid filter position passed: banana'); $this->getFilterCaller('test-customfilter', 'banana'); diff --git a/tests/system/View/CellTest.php b/tests/system/View/CellTest.php index 2d05fad5fbf2..f15e7ce16abb 100644 --- a/tests/system/View/CellTest.php +++ b/tests/system/View/CellTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\View; +use CodeIgniter\HTTP\Response; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCache; use CodeIgniter\View\Exceptions\ViewException; @@ -21,11 +22,7 @@ final class CellTest extends CIUnitTestCase { protected $cache; - - /** - * @var Cell - */ - protected $cell; + protected Cell $cell; protected function setUp(): void { @@ -252,6 +249,6 @@ public function testParametersDontMatch() public function testCallInitControllerIfMethodExists() { - $this->assertSame('CodeIgniter\HTTP\Response', $this->cell->render('\Tests\Support\View\SampleClassWithInitController::index')); + $this->assertSame(Response::class, $this->cell->render('\Tests\Support\View\SampleClassWithInitController::index')); } } From f33b0feb28c724df00273846512b1c0ef9f56412 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 20 Mar 2022 01:25:13 +0700 Subject: [PATCH 1786/2325] Update system/Config/BaseService.php Co-authored-by: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> --- system/Config/BaseService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 4244b7a7097d..0e36c6254e9f 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -332,7 +332,7 @@ protected static function discoverServices(string $name, array $arguments) foreach ($files as $file) { $classname = $locator->getClassname($file); - if (! in_array($classname, [\CodeIgniter\Config\Services::class], true)) { + if (! in_array($classname, [Services::class], true)) { static::$services[] = new $classname(); } } From 74cb75c1b02a0fcc9812d7e8995805c2c28a7c69 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 20 Mar 2022 01:25:18 +0700 Subject: [PATCH 1787/2325] Update system/Config/BaseService.php Co-authored-by: Mostafa Khudair <59371810+mostafakhudair@users.noreply.github.com> --- system/Config/BaseService.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 0e36c6254e9f..ba2779d4f580 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -369,7 +369,7 @@ protected static function buildServicesCache(): void foreach ($files as $file) { $classname = $locator->getClassname($file); - if ($classname !== \CodeIgniter\Config\Services::class) { + if ($classname !== Services::class) { self::$serviceNames[] = $classname; static::$services[] = new $classname(); } From 8aa0a1eae255f5e0e81f7d098a4a1d39d2763669 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 09:30:15 +0900 Subject: [PATCH 1788/2325] refactor: rename variable names --- system/Router/Router.php | 52 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/system/Router/Router.php b/system/Router/Router.php index da00d054e4af..f930a3ba3f9b 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -362,31 +362,31 @@ protected function checkRoutes(string $uri): bool : trim($uri, '/ '); // Loop through the route array looking for wildcards - foreach ($routes as $key => $val) { + foreach ($routes as $routeKey => $handler) { // Reset localeSegment $localeSegment = null; - $key = $key === '/' - ? $key - : ltrim($key, '/ '); + $routeKey = $routeKey === '/' + ? $routeKey + : ltrim($routeKey, '/ '); - $matchedKey = $key; + $matchedKey = $routeKey; // Are we dealing with a locale? - if (strpos($key, '{locale}') !== false) { - $localeSegment = array_search('{locale}', preg_split('/[\/]*((^[a-zA-Z0-9])|\(([^()]*)\))*[\/]+/m', $key), true); + if (strpos($routeKey, '{locale}') !== false) { + $localeSegment = array_search('{locale}', preg_split('/[\/]*((^[a-zA-Z0-9])|\(([^()]*)\))*[\/]+/m', $routeKey), true); // Replace it with a regex so it // will actually match. - $key = str_replace('/', '\/', $key); - $key = str_replace('{locale}', '[^\/]+', $key); + $routeKey = str_replace('/', '\/', $routeKey); + $routeKey = str_replace('{locale}', '[^\/]+', $routeKey); } // Does the RegEx match? - if (preg_match('#^' . $key . '$#u', $uri, $matches)) { + if (preg_match('#^' . $routeKey . '$#u', $uri, $matches)) { // Is this route supposed to redirect to another? - if ($this->collection->isRedirect($key)) { - throw new RedirectException(is_array($val) ? key($val) : $val, $this->collection->getRedirectCode($key)); + if ($this->collection->isRedirect($routeKey)) { + throw new RedirectException(is_array($handler) ? key($handler) : $handler, $this->collection->getRedirectCode($routeKey)); } // Store our locale so CodeIgniter object can // assign it to the Request. @@ -399,8 +399,8 @@ protected function checkRoutes(string $uri): bool // Are we using Closures? If so, then we need // to collect the params into an array // so it can be passed to the controller method later. - if (! is_string($val) && is_callable($val)) { - $this->controller = $val; + if (! is_string($handler) && is_callable($handler)) { + $this->controller = $handler; // Remove the original string from the matches array array_shift($matches); @@ -409,7 +409,7 @@ protected function checkRoutes(string $uri): bool $this->matchedRoute = [ $matchedKey, - $val, + $handler, ]; $this->matchedRouteOptions = $this->collection->getRoutesOptions($matchedKey); @@ -420,26 +420,26 @@ protected function checkRoutes(string $uri): bool // Support resource route when function with subdirectory // ex: $routes->resource('Admin/Admins'); - if (strpos($val, '$') !== false && strpos($key, '(') !== false && strpos($key, '/') !== false) { - $replacekey = str_replace('/(.*)', '', $key); - $val = preg_replace('#^' . $key . '$#u', $val, $uri); - $val = str_replace($replacekey, str_replace('/', '\\', $replacekey), $val); - } elseif (strpos($val, '$') !== false && strpos($key, '(') !== false) { - $val = preg_replace('#^' . $key . '$#u', $val, $uri); - } elseif (strpos($val, '/') !== false) { - [$controller, $method] = explode('::', $val); + if (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false && strpos($routeKey, '/') !== false) { + $replacekey = str_replace('/(.*)', '', $routeKey); + $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); + $handler = str_replace($replacekey, str_replace('/', '\\', $replacekey), $handler); + } elseif (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false) { + $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); + } elseif (strpos($handler, '/') !== false) { + [$controller, $method] = explode('::', $handler); // Only replace slashes in the controller, not in the method. $controller = str_replace('/', '\\', $controller); - $val = $controller . '::' . $method; + $handler = $controller . '::' . $method; } - $this->setRequest(explode('/', $val)); + $this->setRequest(explode('/', $handler)); $this->matchedRoute = [ $matchedKey, - $val, + $handler, ]; $this->matchedRouteOptions = $this->collection->getRoutesOptions($matchedKey); From bb6f480e3039939241257b29d7be30bb8f5ef9e0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 09:40:58 +0900 Subject: [PATCH 1789/2325] docs: remove comments I don't understand what's saying. --- system/Router/Router.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/system/Router/Router.php b/system/Router/Router.php index f930a3ba3f9b..1f8d2ea2f7db 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -416,10 +416,7 @@ protected function checkRoutes(string $uri): bool return true; } - // Are we using the default method for back-references? - // Support resource route when function with subdirectory - // ex: $routes->resource('Admin/Admins'); if (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false && strpos($routeKey, '/') !== false) { $replacekey = str_replace('/(.*)', '', $routeKey); $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); From 44d68fa6908f554708b795e098ab1f0b4161f63e Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 09:46:49 +0900 Subject: [PATCH 1790/2325] test: fix route key All lowercase is better. --- tests/system/Router/RouterTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index 4ba9972b1288..c3fed4d15660 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -59,7 +59,7 @@ protected function setUp(): void 'books/(:num)/(:alpha)/(:num)' => 'Blog::show/$3/$1', 'closure/(:num)/(:alpha)' => static fn ($num, $str) => $num . '-' . $str, '{locale}/pages' => 'App\Pages::list_all', - 'Admin/Admins' => 'App\Admin\Admins::list_all', + 'admin/admins' => 'App\Admin\Admins::list_all', '/some/slash' => 'App\Slash::index', 'objects/(:segment)/sort/(:segment)/([A-Z]{3,7})' => 'AdminList::objectsSortCreate/$1/$2/$3', ]; @@ -398,7 +398,7 @@ public function testRouteResource() { $router = new Router($this->collection, $this->request); - $router->handle('Admin/Admins'); + $router->handle('admin/admins'); $this->assertSame('\App\Admin\Admins', $router->controllerName()); $this->assertSame('list_all', $router->methodName()); From 53ac90afe0e73b19ec3aca8399c52a1a7665b50f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 10:00:22 +0900 Subject: [PATCH 1791/2325] test: remove empty tearDown() --- tests/system/Router/RouterTest.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index c3fed4d15660..06e6b2033daa 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -69,10 +69,6 @@ protected function setUp(): void $this->request->setMethod('get'); } - protected function tearDown(): void - { - } - public function testEmptyURIMatchesDefaults() { $router = new Router($this->collection, $this->request); From 98fdcb909e0d37ed14244d5d436ce9d7c6864ffe Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 10:00:45 +0900 Subject: [PATCH 1792/2325] refactor: make if conditions a bit easier to read --- system/Router/Router.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/system/Router/Router.php b/system/Router/Router.php index 1f8d2ea2f7db..ccf83f143740 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -417,12 +417,16 @@ protected function checkRoutes(string $uri): bool return true; } - if (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false && strpos($routeKey, '/') !== false) { - $replacekey = str_replace('/(.*)', '', $routeKey); - $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); - $handler = str_replace($replacekey, str_replace('/', '\\', $replacekey), $handler); - } elseif (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false) { - $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); + if (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false) { + // Using back-references + + if (strpos($routeKey, '/') !== false) { + $replacekey = str_replace('/(.*)', '', $routeKey); + $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); + $handler = str_replace($replacekey, str_replace('/', '\\', $replacekey), $handler); + } else { + $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); + } } elseif (strpos($handler, '/') !== false) { [$controller, $method] = explode('::', $handler); From 46401c205dcf7c63fab4d31a70fcb87ae052b49a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 10:21:04 +0900 Subject: [PATCH 1793/2325] fix: add check for dynamic controller Dynamic controller should not be used, but if you set a route like this, it worked. $routes->get('(:segment)/(:segment)/(:segment)', '\App\Controllers\\\\$2::$3'); --- system/Language/en/Router.php | 5 +++-- system/Router/Exceptions/RouterException.php | 10 ++++++++++ system/Router/Router.php | 6 ++++++ tests/system/Router/RouterTest.php | 12 ++++++++++++ 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/system/Language/en/Router.php b/system/Language/en/Router.php index 9f6cdb700f04..90aaa132b489 100644 --- a/system/Language/en/Router.php +++ b/system/Language/en/Router.php @@ -11,6 +11,7 @@ // Router language settings return [ - 'invalidParameter' => 'A parameter does not match the expected type.', - 'missingDefaultRoute' => 'Unable to determine what should be displayed. A default route has not been specified in the routing file.', + 'invalidParameter' => 'A parameter does not match the expected type.', + 'missingDefaultRoute' => 'Unable to determine what should be displayed. A default route has not been specified in the routing file.', + 'invalidDynamicController' => 'A dynamic controller is not allowed for security reasons. Route handler: {0}', ]; diff --git a/system/Router/Exceptions/RouterException.php b/system/Router/Exceptions/RouterException.php index 8c469d967b78..b50042b3421b 100644 --- a/system/Router/Exceptions/RouterException.php +++ b/system/Router/Exceptions/RouterException.php @@ -58,4 +58,14 @@ public static function forInvalidRoute(string $route) { return new static(lang('HTTP.invalidRoute', [$route])); } + + /** + * Throw when dynamic controller. + * + * @return RouterException + */ + public static function forDynamicController(string $handler) + { + return new static(lang('Router.invalidDynamicController', [$handler])); + } } diff --git a/system/Router/Router.php b/system/Router/Router.php index ccf83f143740..42f2eb0c7a42 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -420,6 +420,12 @@ protected function checkRoutes(string $uri): bool if (strpos($handler, '$') !== false && strpos($routeKey, '(') !== false) { // Using back-references + // Checks dynamic controller + [$controller, ] = explode('::', $handler); + if (strpos($controller, '$') !== false) { + throw RouterException::forDynamicController($handler); + } + if (strpos($routeKey, '/') !== false) { $replacekey = str_replace('/(.*)', '', $routeKey); $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index 06e6b2033daa..b2c476f5add6 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -14,6 +14,7 @@ use CodeIgniter\Config\Services; use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\Router\Exceptions\RouterException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; use Tests\Support\Filters\Customfilter; @@ -62,6 +63,7 @@ protected function setUp(): void 'admin/admins' => 'App\Admin\Admins::list_all', '/some/slash' => 'App\Slash::index', 'objects/(:segment)/sort/(:segment)/([A-Z]{3,7})' => 'AdminList::objectsSortCreate/$1/$2/$3', + '(:segment)/(:segment)/(:segment)' => '$2::$3/$1', ]; $this->collection->map($routes); @@ -410,6 +412,16 @@ public function testRouteWithLeadingSlash() $this->assertSame('index', $router->methodName()); } + public function testRouteWithDynamicController() + { + $this->expectException(RouterException::class); + $this->expectExceptionMessage('A dynamic controller is not allowed for security reasons. Route handler: \$2::$3/$1'); + + $router = new Router($this->collection, $this->request); + + $router->handle('en/zoo/bar'); + } + // options need to be declared separately, to not confuse PHPCBF public function testMatchedRouteOptions() { From 579d0d5119423a8c7d4bc350c1bcf622a623c422 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 11:13:40 +0900 Subject: [PATCH 1794/2325] docs: change the description to note to make it stand out --- user_guide_src/source/helpers/url_helper.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/helpers/url_helper.rst b/user_guide_src/source/helpers/url_helper.rst index 8f0252c27cff..9f673b88e8bb 100644 --- a/user_guide_src/source/helpers/url_helper.rst +++ b/user_guide_src/source/helpers/url_helper.rst @@ -106,10 +106,10 @@ The following functions are available: Returns the full URL (including segments) of the page the user was previously on. - Due to security issues of blindly trusting the HTTP_REFERER system variable, CodeIgniter will - store previously visited pages in the session if it's available. This ensures that we always - use a known and trusted source. If the session hasn't been loaded, or is otherwise unavailable, - then a sanitized version of HTTP_REFERER will be used. + .. note:: Due to security issues of blindly trusting the HTTP_REFERER system variable, CodeIgniter will + store previously visited pages in the session if it's available. This ensures that we always + use a known and trusted source. If the session hasn't been loaded, or is otherwise unavailable, + then a sanitized version of HTTP_REFERER will be used. .. php:function:: uri_string([$relative = false]) From fedf4f18ec2752b4f3651ead5dfe0430ba19a736 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 11:14:36 +0900 Subject: [PATCH 1795/2325] docs: add explanation about redirect()->back() --- user_guide_src/source/general/common_functions.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/general/common_functions.rst b/user_guide_src/source/general/common_functions.rst index 920e2496b43b..f8cbcf69bc53 100755 --- a/user_guide_src/source/general/common_functions.rst +++ b/user_guide_src/source/general/common_functions.rst @@ -303,6 +303,10 @@ Miscellaneous Functions .. literalinclude:: common_functions/005.php + .. note:: ``redirect()->back()`` is not the same as browser "back" button. + It takes a visitor to "the last page viewed during the Session" when the Session is available. + If the Session hasn’t been loaded, or is otherwise unavailable, then a sanitized version of HTTP_REFERER will be used. + When passing an argument into the function, it is treated as a named/reverse-routed route, not a relative/full URI, treating it the same as using ``redirect()->route()``: From e4fcba2749b3e7e5dd3af55b5cdd057820343fe0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 16:14:40 +0900 Subject: [PATCH 1796/2325] fix: failover's DBPrefix not working Fixes #5812 --- system/Database/BaseConnection.php | 7 +++++++ tests/system/Database/Live/ConnectTest.php | 12 ++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 4f54c1980830..9c803d0c1372 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -342,6 +342,13 @@ public function __construct(array $params) if (class_exists($queryClass)) { $this->queryClass = $queryClass; } + + if ($this->failover !== []) { + // If there is a failover database, connect now to do failover. + // Otherwise, Query Builder creates SQL statement with the main database config + // (DBPrefix) even when the main database is down. + $this->initialize(); + } } /** diff --git a/tests/system/Database/Live/ConnectTest.php b/tests/system/Database/Live/ConnectTest.php index 743b5450cca3..1757f91cb676 100644 --- a/tests/system/Database/Live/ConnectTest.php +++ b/tests/system/Database/Live/ConnectTest.php @@ -95,14 +95,22 @@ public function testConnectWorksWithGroupName() public function testConnectWithFailover() { $this->tests['failover'][] = $this->tests; - unset($this->tests['failover'][0]['failover']); + // Change main's DBPrefix + $this->tests['DBPrefix'] = 'main_'; + + if ($this->tests['DBDriver'] === 'SQLite3') { + // Change main's database path to fail to connect + $this->tests['database'] = '/does/not/exists/test.db'; + } + $this->tests['username'] = 'wrong'; $db1 = Database::connect($this->tests); - $this->assertSame($this->tests['failover'][0]['DBDriver'], $this->getPrivateProperty($db1, 'DBDriver')); + $this->assertSame($this->tests['failover'][0]['DBPrefix'], $this->getPrivateProperty($db1, 'DBPrefix')); + $this->assertGreaterThanOrEqual(0, count($db1->listTables())); } } From 5a456125d8a8503945568564b91a2ad256d2d184 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 20 Mar 2022 16:40:08 +0900 Subject: [PATCH 1797/2325] test: fix failed test --- tests/system/Database/BaseConnectionTest.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/system/Database/BaseConnectionTest.php b/tests/system/Database/BaseConnectionTest.php index 9bb8ddee1499..781588dd78e8 100644 --- a/tests/system/Database/BaseConnectionTest.php +++ b/tests/system/Database/BaseConnectionTest.php @@ -105,8 +105,11 @@ public function testCanConnectToFailoverWhenNoConnectionAvailable() $options = $this->options; $options['failover'] = [$this->failoverOptions]; - $db = new MockConnection($options); - $db->shouldReturn('connect', [false, 345])->initialize(); + $db = new class ($options) extends MockConnection { + protected $returnValues = [ + 'connect' => [false, 345], + ]; + }; $this->assertSame(345, $db->getConnection()); $this->assertSame('failover', $db->username); From 6a0ed54b9922c7c88dce16033615750d7fe67d36 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 20 Mar 2022 15:45:17 +0700 Subject: [PATCH 1798/2325] revert SQLite3 as string --- app/Config/Database.php | 3 +- rector.php | 11 +++++++ system/Commands/Database/CreateDatabase.php | 3 +- system/Database/SQLite3/Connection.php | 2 +- tests/system/Database/ConfigTest.php | 5 ++- tests/system/Database/Live/DbUtilsTest.php | 5 ++- tests/system/Database/Live/ForgeTest.php | 31 +++++++++---------- tests/system/Database/Live/GetTest.php | 5 ++- .../Database/Live/SQLite/AlterTableTest.php | 3 +- .../Migrations/MigrationRunnerTest.php | 3 +- 10 files changed, 37 insertions(+), 34 deletions(-) diff --git a/app/Config/Database.php b/app/Config/Database.php index 376de53a821d..1e6340899bf4 100644 --- a/app/Config/Database.php +++ b/app/Config/Database.php @@ -3,7 +3,6 @@ namespace Config; use CodeIgniter\Database\Config; -use SQLite3; /** * Database Configuration @@ -63,7 +62,7 @@ class Database extends Config 'username' => '', 'password' => '', 'database' => ':memory:', - 'DBDriver' => SQLite3::class, + 'DBDriver' => 'SQLite3', 'DBPrefix' => 'db_', // Needed to ensure we're working correctly with prefixes live. DO NOT REMOVE FOR CI DEVS 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), diff --git a/rector.php b/rector.php index 6c2bc99bcf8d..c43f25f3a274 100644 --- a/rector.php +++ b/rector.php @@ -111,6 +111,17 @@ // expected Qualified name __DIR__ . '/tests/system/Autoloader/FileLocatorTest.php', + + // SQLite3 as string + __DIR__ . '/app/Config/Database.php', + __DIR__ . '/system/Commands/Database/CreateDatabase.php', + __DIR__ . '/system/Database/SQLite3/Connection.php', + __DIR__ . '/tests/system/Database/ConfigTest.php', + __DIR__ . '/tests/system/Database/Live/DbUtilsTest.php', + __DIR__ . '/tests/system/Database/Live/ForgeTest.php', + __DIR__ . '/tests/system/Database/Live/GetTest.php', + __DIR__ . '/tests/system/Database/Live/SQLite/AlterTableTest.php', + __DIR__ . '/tests/system/Database/Migrations/MigrationRunnerTest.php', ], // sometime too detail diff --git a/system/Commands/Database/CreateDatabase.php b/system/Commands/Database/CreateDatabase.php index 0682f945b9bf..17e1e51bb68b 100644 --- a/system/Commands/Database/CreateDatabase.php +++ b/system/Commands/Database/CreateDatabase.php @@ -16,7 +16,6 @@ use CodeIgniter\Config\Factories; use CodeIgniter\Database\SQLite3\Connection; use Config\Database; -use SQLite3; use Throwable; /** @@ -107,7 +106,7 @@ public function run(array $params) $name = str_replace(['.db', '.sqlite'], '', $name) . ".{$ext}"; } - $config->{$group}['DBDriver'] = SQLite3::class; + $config->{$group}['DBDriver'] = 'SQLite3'; $config->{$group}['database'] = $name; if ($name !== ':memory:') { diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index e335e7985ba7..39fbca8bcfea 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -28,7 +28,7 @@ class Connection extends BaseConnection * * @var string */ - public $DBDriver = SQLite3::class; + public $DBDriver = 'SQLite3'; /** * Identifier escape character diff --git a/tests/system/Database/ConfigTest.php b/tests/system/Database/ConfigTest.php index 301a95158bf1..fdbc42749d1d 100644 --- a/tests/system/Database/ConfigTest.php +++ b/tests/system/Database/ConfigTest.php @@ -13,7 +13,6 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\ReflectionHelper; -use SQLite3; /** * @internal @@ -47,7 +46,7 @@ final class ConfigTest extends CIUnitTestCase 'username' => '', 'password' => '', 'database' => '', - 'DBDriver' => SQLite3::class, + 'DBDriver' => 'SQLite3', 'DBPrefix' => 't_', 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), @@ -66,7 +65,7 @@ final class ConfigTest extends CIUnitTestCase 'username' => '', 'password' => '', 'database' => '', - 'DBDriver' => SQLite3::class, + 'DBDriver' => 'SQLite3', 'DBPrefix' => 't_', 'pConnect' => false, 'DBDebug' => (ENVIRONMENT !== 'production'), diff --git a/tests/system/Database/Live/DbUtilsTest.php b/tests/system/Database/Live/DbUtilsTest.php index 414412a72ded..e767d0b6991d 100644 --- a/tests/system/Database/Live/DbUtilsTest.php +++ b/tests/system/Database/Live/DbUtilsTest.php @@ -15,7 +15,6 @@ use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; -use SQLite3; /** * @group DatabaseLive @@ -81,7 +80,7 @@ public function testUtilsListDatabases() $databases = $util->listDatabases(); $this->assertContains($this->db->getDatabase(), $databases); - } elseif ($this->db->DBDriver === SQLite3::class) { + } elseif ($this->db->DBDriver === 'SQLite3') { $this->expectException(DatabaseException::class); $this->expectExceptionMessage('Unsupported feature of the database platform you are using.'); @@ -97,7 +96,7 @@ public function testUtilsDatabaseExist() $exist = $util->databaseExists($this->db->getDatabase()); $this->assertTrue($exist); - } elseif ($this->db->DBDriver === SQLite3::class) { + } elseif ($this->db->DBDriver === 'SQLite3') { $this->expectException(DatabaseException::class); $this->expectExceptionMessage('Unsupported feature of the database platform you are using.'); diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index f83593ed320e..113f2c0a211e 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -18,7 +18,6 @@ use Config\Database; use InvalidArgumentException; use RuntimeException; -use SQLite3; /** * @group DatabaseLive @@ -57,7 +56,7 @@ public function testCreateDatabaseIfNotExists() $dbName = 'test_forge_database_exist'; $databaseCreateIfNotExists = $this->forge->createDatabase($dbName, true); - if ($this->db->DBDriver !== SQLite3::class) { + if ($this->db->DBDriver !== 'SQLite3') { $this->forge->dropDatabase($dbName); } @@ -73,7 +72,7 @@ public function testCreateDatabaseIfNotExistsWithDb() $this->forge->createDatabase($dbName); $databaseExists = $this->forge->createDatabase($dbName, true); - if ($this->db->DBDriver !== SQLite3::class) { + if ($this->db->DBDriver !== 'SQLite3') { $this->forge->dropDatabase($dbName); } @@ -85,7 +84,7 @@ public function testDropDatabase() if ($this->db->DBDriver === 'OCI8') { $this->markTestSkipped('OCI8 does not support drop database.'); } - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->markTestSkipped('SQLite3 requires file path to drop database'); } @@ -98,7 +97,7 @@ public function testCreateDatabaseExceptionNoCreateStatement() { $this->setPrivateProperty($this->forge, 'createDatabaseStr', false); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $databaseCreated = $this->forge->createDatabase('test_forge_database'); $this->assertTrue($databaseCreated); } else { @@ -113,7 +112,7 @@ public function testDropDatabaseExceptionNoDropStatement() { $this->setPrivateProperty($this->forge, 'dropDatabaseStr', false); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->markTestSkipped('SQLite3 requires file path to drop database'); } else { $this->expectException(DatabaseException::class); @@ -176,7 +175,7 @@ public function testCreateTableApplyBigInt() $this->assertSame(strtolower($fieldsData[0]->type), 'bigint'); } elseif ($this->db->DBDriver === 'Postgre') { $this->assertSame(strtolower($fieldsData[0]->type), 'bigint'); - } elseif ($this->db->DBDriver === SQLite3::class) { + } elseif ($this->db->DBDriver === 'SQLite3') { $this->assertSame(strtolower($fieldsData[0]->type), 'integer'); } elseif ($this->db->DBDriver === 'OCI8') { $this->assertSame(strtolower($fieldsData[0]->type), 'number'); @@ -192,7 +191,7 @@ public function testCreateTableWithAttributes() if ($this->db->DBDriver === 'OCI8') { $this->markTestSkipped('OCI8 does not support comments on tables or columns.'); } - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->markTestSkipped('SQLite3 does not support comments on tables or columns.'); } @@ -214,7 +213,7 @@ public function testCreateTableWithAttributes() public function testCreateTableWithArrayFieldConstraints() { - if (in_array($this->db->DBDriver, ['MySQLi', SQLite3::class], true)) { + if (in_array($this->db->DBDriver, ['MySQLi', 'SQLite3'], true)) { $this->forge->dropTable('forge_array_constraint', true); $this->forge->addField([ 'status' => [ @@ -232,7 +231,7 @@ public function testCreateTableWithArrayFieldConstraints() $this->assertSame('status', $fields[0]->name); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { // SQLite3 converts array constraints to TEXT CHECK(...) $this->assertSame('TEXT', $fields[0]->type); } else { @@ -432,7 +431,7 @@ public function testForeignKey() $foreignKeyData = $this->db->getForeignKeyData($tableName); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->assertSame($foreignKeyData[0]->constraint_name, 'users_id to db_forge_test_users.id'); $this->assertSame($foreignKeyData[0]->sequence, 0); } elseif ($this->db->DBDriver === 'OCI8') { @@ -554,7 +553,7 @@ public function testCompositeForeignKey() $foreignKeyData = $this->db->getForeignKeyData($forgeTestInvoicesTableName); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->assertSame('users_id to db_forge_test_users.id', $foreignKeyData[0]->constraint_name); $this->assertSame(0, $foreignKeyData[0]->sequence); $this->assertSame('users_second_id to db_forge_test_users.second_id', $foreignKeyData[1]->constraint_name); @@ -844,7 +843,7 @@ public function testAddFields() $this->assertSame(32, (int) $fieldsData[0]->max_length); $this->assertNull($fieldsData[1]->default); $this->assertSame(255, (int) $fieldsData[1]->max_length); - } elseif ($this->db->DBDriver === SQLite3::class) { + } elseif ($this->db->DBDriver === 'SQLite3') { $this->assertSame('integer', strtolower($fieldsData[0]->type)); $this->assertSame('varchar', strtolower($fieldsData[1]->type)); $this->assertNull($fieldsData[1]->default); @@ -869,7 +868,7 @@ public function testAddFields() public function testCompositeKey() { // SQLite3 uses auto increment different - $uniqueOrAuto = $this->db->DBDriver === SQLite3::class ? 'unique' : 'auto_increment'; + $uniqueOrAuto = $this->db->DBDriver === 'SQLite3' ? 'unique' : 'auto_increment'; $this->forge->addField([ 'id' => [ @@ -917,7 +916,7 @@ public function testCompositeKey() $this->assertSame($keys['db_forge_test_1_code_active']->name, 'db_forge_test_1_code_active'); $this->assertSame($keys['db_forge_test_1_code_active']->fields, ['code', 'active']); $this->assertSame($keys['db_forge_test_1_code_active']->type, 'UNIQUE'); - } elseif ($this->db->DBDriver === SQLite3::class) { + } elseif ($this->db->DBDriver === 'SQLite3') { $this->assertSame($keys['sqlite_autoindex_db_forge_test_1_1']->name, 'sqlite_autoindex_db_forge_test_1_1'); $this->assertSame($keys['sqlite_autoindex_db_forge_test_1_1']->fields, ['id']); $this->assertSame($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); @@ -1055,7 +1054,7 @@ public function testDropTableSuccess() $this->assertFalse($this->db->tableExists('dropTest')); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->assertCount(0, $this->db->getIndexData('droptest')); } } diff --git a/tests/system/Database/Live/GetTest.php b/tests/system/Database/Live/GetTest.php index 768f24d72de3..20ae2e099d0d 100644 --- a/tests/system/Database/Live/GetTest.php +++ b/tests/system/Database/Live/GetTest.php @@ -14,7 +14,6 @@ use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; -use SQLite3; /** * @group DatabaseLive @@ -92,7 +91,7 @@ public function testGetFieldData() $typeTest = $this->db->table('type_test')->get()->getFieldData(); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->assertSame('integer', $typeTest[0]->type_name); // INTEGER AUTO INC $this->assertSame('text', $typeTest[1]->type_name); // VARCHAR $this->assertSame('text', $typeTest[2]->type_name); // CHAR @@ -173,7 +172,7 @@ public function testGetDataSeek() { $data = $this->db->table('job')->get(); - if ($this->db->DBDriver === SQLite3::class) { + if ($this->db->DBDriver === 'SQLite3') { $this->expectException(DatabaseException::class); $this->expectExceptionMessage('SQLite3 doesn\'t support seeking to other offset.'); } elseif ($this->db->DBDriver === 'OCI8') { diff --git a/tests/system/Database/Live/SQLite/AlterTableTest.php b/tests/system/Database/Live/SQLite/AlterTableTest.php index 8889c9d8f639..ff103d699510 100644 --- a/tests/system/Database/Live/SQLite/AlterTableTest.php +++ b/tests/system/Database/Live/SQLite/AlterTableTest.php @@ -18,7 +18,6 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; use Config\Database; -use SQLite3; /** * @group DatabaseLive @@ -50,7 +49,7 @@ protected function setUp(): void parent::setUp(); $config = [ - 'DBDriver' => SQLite3::class, + 'DBDriver' => 'SQLite3', 'database' => 'database.db', ]; diff --git a/tests/system/Database/Migrations/MigrationRunnerTest.php b/tests/system/Database/Migrations/MigrationRunnerTest.php index 9a5f467ed9c2..e97e4e38e56c 100644 --- a/tests/system/Database/Migrations/MigrationRunnerTest.php +++ b/tests/system/Database/Migrations/MigrationRunnerTest.php @@ -22,7 +22,6 @@ use Config\Migrations; use Config\Services; use org\bovigo\vfs\vfsStream; -use SQLite3; /** * @group DatabaseLive @@ -75,7 +74,7 @@ public function testLoadsDefaultDatabaseWhenNoneSpecified() $this->assertInstanceOf(BaseConnection::class, $db); $this->assertSame( - ($dbConfig->tests['DBDriver'] === SQLite3::class ? WRITEPATH : '') . $dbConfig->tests['database'], + ($dbConfig->tests['DBDriver'] === 'SQLite3' ? WRITEPATH : '') . $dbConfig->tests['database'], $this->getPrivateProperty($db, 'database') ); $this->assertSame($dbConfig->tests['DBDriver'], $this->getPrivateProperty($db, 'DBDriver')); From 4ccda780e5f8300cc210a6834851f8f99f94d4c9 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 20 Mar 2022 17:58:20 +0700 Subject: [PATCH 1799/2325] Update tests/system/Encryption/Handlers/SodiumHandlerTest.php Co-authored-by: kenjis --- tests/system/Encryption/Handlers/SodiumHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Encryption/Handlers/SodiumHandlerTest.php b/tests/system/Encryption/Handlers/SodiumHandlerTest.php index 421af43e1330..e7cf3a54eef5 100644 --- a/tests/system/Encryption/Handlers/SodiumHandlerTest.php +++ b/tests/system/Encryption/Handlers/SodiumHandlerTest.php @@ -21,7 +21,7 @@ */ final class SodiumHandlerTest extends CIUnitTestCase { - protected \CodeIgniter\Encryption\Encryption $encryption; + protected Encryption $encryption; protected \Config\Encryption $config; protected function setUp(): void From de9adf5d2e2061abfc156f4450aa7e2d175c8f26 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 20 Mar 2022 17:58:55 +0700 Subject: [PATCH 1800/2325] Update tests/system/Encryption/Handlers/SodiumHandlerTest.php Co-authored-by: kenjis --- tests/system/Encryption/Handlers/SodiumHandlerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/system/Encryption/Handlers/SodiumHandlerTest.php b/tests/system/Encryption/Handlers/SodiumHandlerTest.php index e7cf3a54eef5..28319b477ea6 100644 --- a/tests/system/Encryption/Handlers/SodiumHandlerTest.php +++ b/tests/system/Encryption/Handlers/SodiumHandlerTest.php @@ -22,7 +22,7 @@ final class SodiumHandlerTest extends CIUnitTestCase { protected Encryption $encryption; - protected \Config\Encryption $config; + protected EncryptionConfig $config; protected function setUp(): void { From 977defed45be74def619915bb5390fee789056e2 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Sun, 20 Mar 2022 18:00:43 +0700 Subject: [PATCH 1801/2325] use Encryption class --- tests/system/Encryption/EncryptionTest.php | 2 +- tests/system/Encryption/Handlers/OpenSSLHandlerTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Encryption/EncryptionTest.php b/tests/system/Encryption/EncryptionTest.php index cb4eb4cad7da..c5681e10e66a 100644 --- a/tests/system/Encryption/EncryptionTest.php +++ b/tests/system/Encryption/EncryptionTest.php @@ -21,7 +21,7 @@ */ final class EncryptionTest extends CIUnitTestCase { - protected \CodeIgniter\Encryption\Encryption $encryption; + protected Encryption $encryption; protected function setUp(): void { diff --git a/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php b/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php index 5427c99a5edb..81f3959710bc 100644 --- a/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php +++ b/tests/system/Encryption/Handlers/OpenSSLHandlerTest.php @@ -21,7 +21,7 @@ */ final class OpenSSLHandlerTest extends CIUnitTestCase { - protected \CodeIgniter\Encryption\Encryption $encryption; + protected Encryption $encryption; protected function setUp(): void { From 0176bb4224c3fcdf86b5c526808a1d754035154b Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 21 Mar 2022 01:39:09 +0700 Subject: [PATCH 1802/2325] exclude native classes --- rector.php | 20 +++++++++---------- system/CodeIgniter.php | 2 +- system/Database/BaseResult.php | 3 +-- system/Database/MySQLi/Result.php | 2 +- system/Database/OCI8/Result.php | 5 ++--- system/Database/Postgre/Result.php | 2 +- system/Database/SQLSRV/Result.php | 2 +- system/Database/SQLite3/Result.php | 4 ++-- system/Test/Fabricator.php | 3 +-- system/Test/Mock/MockResult.php | 3 +-- tests/system/Autoloader/AutoloaderTest.php | 3 +-- .../system/Cache/Handlers/BaseHandlerTest.php | 5 ++--- tests/system/CommonFunctionsTest.php | 3 +-- tests/system/Config/DotEnvTest.php | 5 ++--- tests/system/Config/FactoriesTest.php | 8 ++++---- tests/system/Cookie/CookieTest.php | 3 +-- tests/system/Database/Builder/WhereTest.php | 5 ++--- tests/system/Database/DatabaseSeederTest.php | 7 +++---- tests/system/Database/Live/ForgeTest.php | 7 +++---- tests/system/Entity/EntityTest.php | 5 ++--- tests/system/Helpers/FilesystemHelperTest.php | 5 ++--- tests/system/Models/FindModelTest.php | 3 +-- .../system/Models/MiscellaneousModelTest.php | 3 +-- tests/system/Test/ControllerTestTraitTest.php | 5 ++--- tests/system/Test/DOMParserTest.php | 4 +--- tests/system/Test/FabricatorTest.php | 12 +++++------ tests/system/Test/FilterTestTraitTest.php | 6 ++---- 27 files changed, 55 insertions(+), 80 deletions(-) diff --git a/rector.php b/rector.php index c43f25f3a274..9ee8a4217d21 100644 --- a/rector.php +++ b/rector.php @@ -111,17 +111,6 @@ // expected Qualified name __DIR__ . '/tests/system/Autoloader/FileLocatorTest.php', - - // SQLite3 as string - __DIR__ . '/app/Config/Database.php', - __DIR__ . '/system/Commands/Database/CreateDatabase.php', - __DIR__ . '/system/Database/SQLite3/Connection.php', - __DIR__ . '/tests/system/Database/ConfigTest.php', - __DIR__ . '/tests/system/Database/Live/DbUtilsTest.php', - __DIR__ . '/tests/system/Database/Live/ForgeTest.php', - __DIR__ . '/tests/system/Database/Live/GetTest.php', - __DIR__ . '/tests/system/Database/Live/SQLite/AlterTableTest.php', - __DIR__ . '/tests/system/Database/Migrations/MigrationRunnerTest.php', ], // sometime too detail @@ -164,4 +153,13 @@ $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); $services->set(SimplifyEmptyArrayCheckRector::class); $services->set(NormalizeNamespaceByPSR4ComposerAutoloadRector::class); + $services->set(StringClassNameToClassConstantRector::class) + ->configure([ + 'Error', + 'Exception', + 'InvalidArgumentException', + 'Closure', + 'stdClass', + 'SQLite3', + ]); }; diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 127e087458a0..86e70546dd41 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -830,7 +830,7 @@ protected function startController() $this->benchmark->start('controller_constructor'); // Is it routed to a Closure? - if (is_object($this->controller) && (get_class($this->controller) === Closure::class)) { + if (is_object($this->controller) && (get_class($this->controller) === 'Closure')) { $controller = $this->controller; return $controller(...$this->router->params()); diff --git a/system/Database/BaseResult.php b/system/Database/BaseResult.php index b5818525dc30..5d223c7fc08b 100644 --- a/system/Database/BaseResult.php +++ b/system/Database/BaseResult.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Database; use CodeIgniter\Entity\Entity; -use stdClass; /** * Class BaseResult @@ -509,5 +508,5 @@ abstract protected function fetchAssoc(); * * @return object */ - abstract protected function fetchObject(string $className = stdClass::class); + abstract protected function fetchObject(string $className = 'stdClass'); } diff --git a/system/Database/MySQLi/Result.php b/system/Database/MySQLi/Result.php index 35f480776c85..7eab7d86c685 100644 --- a/system/Database/MySQLi/Result.php +++ b/system/Database/MySQLi/Result.php @@ -139,7 +139,7 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = stdClass::class) + protected function fetchObject(string $className = 'stdClass') { if (is_subclass_of($className, Entity::class)) { return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data); diff --git a/system/Database/OCI8/Result.php b/system/Database/OCI8/Result.php index 6ad26b649480..72a1b0980a28 100644 --- a/system/Database/OCI8/Result.php +++ b/system/Database/OCI8/Result.php @@ -14,7 +14,6 @@ use CodeIgniter\Database\BaseResult; use CodeIgniter\Database\ResultInterface; use CodeIgniter\Entity; -use stdClass; /** * Result for OCI8 @@ -94,11 +93,11 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = stdClass::class) + protected function fetchObject(string $className = 'stdClass') { $row = oci_fetch_object($this->resultID); - if ($className === stdClass::class || ! $row) { + if ($className === 'stdClass' || ! $row) { return $row; } if (is_subclass_of($className, Entity::class)) { diff --git a/system/Database/Postgre/Result.php b/system/Database/Postgre/Result.php index 581d79b1d421..76a0dd956515 100644 --- a/system/Database/Postgre/Result.php +++ b/system/Database/Postgre/Result.php @@ -105,7 +105,7 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = stdClass::class) + protected function fetchObject(string $className = 'stdClass') { if (is_subclass_of($className, Entity::class)) { return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data); diff --git a/system/Database/SQLSRV/Result.php b/system/Database/SQLSRV/Result.php index 045a5eebd81a..2a55e452ac09 100755 --- a/system/Database/SQLSRV/Result.php +++ b/system/Database/SQLSRV/Result.php @@ -147,7 +147,7 @@ protected function fetchAssoc() * * @return bool|Entity|object */ - protected function fetchObject(string $className = stdClass::class) + protected function fetchObject(string $className = 'stdClass') { if (is_subclass_of($className, Entity::class)) { return empty($data = $this->fetchAssoc()) ? false : (new $className())->setAttributes($data); diff --git a/system/Database/SQLite3/Result.php b/system/Database/SQLite3/Result.php index 39b9897af1e4..6afc04c51578 100644 --- a/system/Database/SQLite3/Result.php +++ b/system/Database/SQLite3/Result.php @@ -122,14 +122,14 @@ protected function fetchAssoc() * * @return bool|object */ - protected function fetchObject(string $className = stdClass::class) + protected function fetchObject(string $className = 'stdClass') { // No native support for fetching rows as objects if (($row = $this->fetchAssoc()) === false) { return false; } - if ($className === stdClass::class) { + if ($className === 'stdClass') { return (object) $row; } diff --git a/system/Test/Fabricator.php b/system/Test/Fabricator.php index d474e796df78..d4369765f0ee 100644 --- a/system/Test/Fabricator.php +++ b/system/Test/Fabricator.php @@ -17,7 +17,6 @@ use Faker\Generator; use InvalidArgumentException; use RuntimeException; -use stdClass; /** * Fabricator @@ -410,7 +409,7 @@ public function makeObject(?string $className = null): object { if ($className === null) { if ($this->model->returnType === 'object' || $this->model->returnType === 'array') { - $className = stdClass::class; + $className = 'stdClass'; } else { $className = $this->model->returnType; } diff --git a/system/Test/Mock/MockResult.php b/system/Test/Mock/MockResult.php index f3807d9170c9..0aaa340a95de 100644 --- a/system/Test/Mock/MockResult.php +++ b/system/Test/Mock/MockResult.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Test\Mock; use CodeIgniter\Database\BaseResult; -use stdClass; class MockResult extends BaseResult { @@ -82,7 +81,7 @@ protected function fetchAssoc() * * @return object */ - protected function fetchObject($className = stdClass::class) + protected function fetchObject($className = 'stdClass') { return new $className(); } diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 95d74c6c1b7e..f9a56cae82db 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -15,7 +15,6 @@ use Config\Autoload; use Config\Modules; use Config\Services; -use InvalidArgumentException; use UnnamespacedClass; /** @@ -55,7 +54,7 @@ public function testLoadStoredClass() public function testInitializeWithInvalidArguments() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("Config array must contain either the 'psr4' key or the 'classmap' key."); $config = new Autoload(); diff --git a/tests/system/Cache/Handlers/BaseHandlerTest.php b/tests/system/Cache/Handlers/BaseHandlerTest.php index 18bfcff0d113..b2ebb61e01ef 100644 --- a/tests/system/Cache/Handlers/BaseHandlerTest.php +++ b/tests/system/Cache/Handlers/BaseHandlerTest.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Cache\Handlers; use CodeIgniter\Test\CIUnitTestCase; -use InvalidArgumentException; use stdClass; use Tests\Support\Cache\RestrictiveHandler; @@ -28,7 +27,7 @@ final class BaseHandlerTest extends CIUnitTestCase */ public function testValidateKeyInvalidType($input) { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Cache key must be a string'); BaseHandler::validateKey($input); @@ -49,7 +48,7 @@ public function testValidateKeyUsesConfig() { config('Cache')->reservedCharacters = 'b'; - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Cache key contains reserved characters b'); BaseHandler::validateKey('banana'); diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 758e1727eca1..b69f6120656a 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -29,7 +29,6 @@ use Config\App; use Config\Logger; use Config\Modules; -use InvalidArgumentException; use Kint; use stdClass; use Tests\Support\Models\JobModel; @@ -167,7 +166,7 @@ public function testEscapeWithDifferentEncodings() public function testEscapeBadContext() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); esc(['width' => '800', 'height' => '600'], 'bogus'); } diff --git a/tests/system/Config/DotEnvTest.php b/tests/system/Config/DotEnvTest.php index 077bd8f23ea4..71fb1b560f77 100644 --- a/tests/system/Config/DotEnvTest.php +++ b/tests/system/Config/DotEnvTest.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Config; use CodeIgniter\Test\CIUnitTestCase; -use InvalidArgumentException; use org\bovigo\vfs\vfsStream; /** @@ -116,7 +115,7 @@ public function testLoadsUnreadableFile() $file = 'unreadable.env'; $path = rtrim($this->fixturesFolder, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $file; chmod($path, 0000); - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage("The .env file is not readable: {$path}"); $dotenv = new DotEnv($this->fixturesFolder, $file); $dotenv->load(); @@ -136,7 +135,7 @@ public function testQuotedDotenvLoadsEnvironmentVars() public function testSpacedValuesWithoutQuotesThrowsException() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('.env values containing spaces must be surrounded by quotes.'); $dotenv = new DotEnv($this->fixturesFolder, 'spaced-wrong.env'); diff --git a/tests/system/Config/FactoriesTest.php b/tests/system/Config/FactoriesTest.php index 3a8cb7584f7d..92356d638106 100644 --- a/tests/system/Config/FactoriesTest.php +++ b/tests/system/Config/FactoriesTest.php @@ -189,7 +189,7 @@ public function testInjection() $result = Factories::widgets('Banana'); - $this->assertInstanceOf(stdClass::class, $result); + $this->assertInstanceOf('stdClass', $result); } public function testRespectsComponentAlias() @@ -210,7 +210,7 @@ public function testRespectsPath() public function testRespectsInstanceOf() { - Factories::setOptions('widgets', ['instanceOf' => stdClass::class]); + Factories::setOptions('widgets', ['instanceOf' => 'stdClass']); $result = Factories::widgets('SomeWidget'); $this->assertInstanceOf(SomeWidget::class, $result); @@ -223,13 +223,13 @@ public function testSharedRespectsInstanceOf() { Factories::injectMock('widgets', 'SomeWidget', new OtherWidget()); - $result = Factories::widgets('SomeWidget', ['instanceOf' => stdClass::class]); + $result = Factories::widgets('SomeWidget', ['instanceOf' => 'stdClass']); $this->assertInstanceOf(SomeWidget::class, $result); } public function testPrioritizesParameterOptions() { - Factories::setOptions('widgets', ['instanceOf' => stdClass::class]); + Factories::setOptions('widgets', ['instanceOf' => 'stdClass']); $result = Factories::widgets('OtherWidget', ['instanceOf' => null]); $this->assertInstanceOf(OtherWidget::class, $result); diff --git a/tests/system/Cookie/CookieTest.php b/tests/system/Cookie/CookieTest.php index 34d9d59955e6..341280024ae4 100644 --- a/tests/system/Cookie/CookieTest.php +++ b/tests/system/Cookie/CookieTest.php @@ -16,7 +16,6 @@ use Config\Cookie as CookieConfig; use DateTimeImmutable; use DateTimeZone; -use InvalidArgumentException; use LogicException; /** @@ -274,7 +273,7 @@ public function testArrayAccessOfCookie(): void $this->assertArrayHasKey('path', $cookie); $this->assertSame($cookie['path'], $cookie->getPath()); - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $cookie['expiry']; } diff --git a/tests/system/Database/Builder/WhereTest.php b/tests/system/Database/Builder/WhereTest.php index 60d328483972..ace628f6bc38 100644 --- a/tests/system/Database/Builder/WhereTest.php +++ b/tests/system/Database/Builder/WhereTest.php @@ -14,7 +14,6 @@ use CodeIgniter\Database\BaseBuilder; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockConnection; -use InvalidArgumentException; use stdClass; /** @@ -267,7 +266,7 @@ public function provideInvalidKeys() */ public function testWhereInvalidKeyThrowInvalidArgumentException($key) { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $builder = $this->db->table('jobs'); $builder->whereIn($key, ['Politician', 'Accountant']); @@ -289,7 +288,7 @@ public function provideInvalidValues() */ public function testWhereInEmptyValuesThrowInvalidArgumentException($values) { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $builder = $this->db->table('jobs'); $builder->whereIn('name', $values); diff --git a/tests/system/Database/DatabaseSeederTest.php b/tests/system/Database/DatabaseSeederTest.php index 70721718ea8a..7e08d6648508 100644 --- a/tests/system/Database/DatabaseSeederTest.php +++ b/tests/system/Database/DatabaseSeederTest.php @@ -14,7 +14,6 @@ use CodeIgniter\Test\CIUnitTestCase; use Config\Database; use Faker\Generator; -use InvalidArgumentException; /** * @internal @@ -23,7 +22,7 @@ final class DatabaseSeederTest extends CIUnitTestCase { public function testInstantiateNoSeedPath() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $config = new Database(); $config->filesPath = ''; @@ -32,7 +31,7 @@ public function testInstantiateNoSeedPath() public function testInstantiateNotDirSeedPath() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $config = new Database(); $config->filesPath = APPPATH . 'Foo'; @@ -49,7 +48,7 @@ public function testFakerGet() public function testCallOnEmptySeeder() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $seeder = new Seeder(new Database()); $seeder->call(''); diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 113f2c0a211e..47eadc34d0b2 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -16,7 +16,6 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; use Config\Database; -use InvalidArgumentException; use RuntimeException; /** @@ -297,7 +296,7 @@ public function testCreateTableWithEmptyName() $this->forge->addField('id'); $this->forge->addField('name varchar(100) NULL'); - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('A table name is required for that operation.'); $this->forge->createTable(''); @@ -315,7 +314,7 @@ public function testCreateTableWithNoFields() public function testCreateTableWithStringFieldException() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Field information is required for that operation.'); $this->forge->dropTable('forge_test_table', true); @@ -351,7 +350,7 @@ public function testRenameTableEmptyNameException() $this->forge->createTable('forge_test_table'); - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('A table name is required for that operation.'); $this->forge->renameTable('forge_test_table', ''); diff --git a/tests/system/Entity/EntityTest.php b/tests/system/Entity/EntityTest.php index 82c758f92f5e..d88f509694f7 100644 --- a/tests/system/Entity/EntityTest.php +++ b/tests/system/Entity/EntityTest.php @@ -19,7 +19,6 @@ use CodeIgniter\Test\ReflectionHelper; use DateTime; use ReflectionException; -use stdClass; use Tests\Support\Entity\Cast\CastBase64; use Tests\Support\Entity\Cast\CastPassParameters; use Tests\Support\Entity\Cast\NotExtendsBaseCast; @@ -372,7 +371,7 @@ public function testCastObject() $entity->sixth = $data; $this->assertIsObject($entity->sixth); - $this->assertInstanceOf(stdClass::class, $entity->sixth); + $this->assertInstanceOf('stdClass', $entity->sixth); $this->assertSame($data, (array) $entity->sixth); } @@ -516,7 +515,7 @@ public function testCastAsJSON() $check = $this->getPrivateProperty($entity, 'attributes')['tenth']; $this->assertSame('{"foo":"bar"}', $check); - $this->assertInstanceOf(stdClass::class, $entity->tenth); + $this->assertInstanceOf('stdClass', $entity->tenth); $this->assertSame(['foo' => 'bar'], (array) $entity->tenth); } diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index 7b837064a410..d20d93481e39 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Helpers; use CodeIgniter\Test\CIUnitTestCase; -use InvalidArgumentException; use org\bovigo\vfs\vfsStream; use org\bovigo\vfs\visitor\vfsStreamStructureVisitor; @@ -525,13 +524,13 @@ public function testSymbolicPermissions() public function testRealPathURL() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); set_realpath('http://somewhere.com/overtherainbow'); } public function testRealPathInvalid() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); set_realpath(SUPPORTPATH . 'root/../', true); } diff --git a/tests/system/Models/FindModelTest.php b/tests/system/Models/FindModelTest.php index e0fdad5024a1..e564f570ec8c 100644 --- a/tests/system/Models/FindModelTest.php +++ b/tests/system/Models/FindModelTest.php @@ -13,7 +13,6 @@ use CodeIgniter\Database\Exceptions\DataException; use CodeIgniter\Exceptions\ModelException; -use stdClass; use Tests\Support\Models\JobModel; use Tests\Support\Models\SecondaryModel; use Tests\Support\Models\UserModel; @@ -296,7 +295,7 @@ public function testFirstWithNoPrimaryKey(): void ]); $record = $this->model->first(); - $this->assertInstanceOf(stdClass::class, $record); + $this->assertInstanceOf('stdClass', $record); $this->assertSame('foo', $record->key); } diff --git a/tests/system/Models/MiscellaneousModelTest.php b/tests/system/Models/MiscellaneousModelTest.php index 1c4af20a87f0..80a9639cd2f1 100644 --- a/tests/system/Models/MiscellaneousModelTest.php +++ b/tests/system/Models/MiscellaneousModelTest.php @@ -13,7 +13,6 @@ use CodeIgniter\Database\Exceptions\DataException; use CodeIgniter\I18n\Time; -use InvalidArgumentException; use Tests\Support\Models\EntityModel; use Tests\Support\Models\JobModel; use Tests\Support\Models\SimpleEntity; @@ -102,7 +101,7 @@ public function testGetValidationMessagesForReplace(): void public function testUndefinedTypeInTransformDataToArray(): void { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Invalid type "whatever" used upon transforming data to array.'); $this->createModel(JobModel::class); diff --git a/tests/system/Test/ControllerTestTraitTest.php b/tests/system/Test/ControllerTestTraitTest.php index 65a671bf4df9..a5e10323a4ee 100644 --- a/tests/system/Test/ControllerTestTraitTest.php +++ b/tests/system/Test/ControllerTestTraitTest.php @@ -17,7 +17,6 @@ use CodeIgniter\Test\Mock\MockLogger as LoggerConfig; use Config\App; use Config\Services; -use InvalidArgumentException; use Tests\Support\Controllers\Popcorn; /** @@ -34,7 +33,7 @@ final class ControllerTestTraitTest extends CIUnitTestCase public function testBadController() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $logger = new Logger(new LoggerConfig()); $this->withURI('http://example.com') ->withLogger($logger) @@ -44,7 +43,7 @@ public function testBadController() public function testBadControllerMethod() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $logger = new Logger(new LoggerConfig()); $this->withURI('http://example.com') ->withLogger($logger) diff --git a/tests/system/Test/DOMParserTest.php b/tests/system/Test/DOMParserTest.php index 7eeee05e4385..e700a3daa163 100644 --- a/tests/system/Test/DOMParserTest.php +++ b/tests/system/Test/DOMParserTest.php @@ -11,8 +11,6 @@ namespace CodeIgniter\Test; -use InvalidArgumentException; - /** * @internal */ @@ -396,7 +394,7 @@ public function testWithNotFile() $filename = APPPATH . 'bogus.html'; - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $dom->withFile($filename); } diff --git a/tests/system/Test/FabricatorTest.php b/tests/system/Test/FabricatorTest.php index 13de446cbcb9..701eecb02c30 100644 --- a/tests/system/Test/FabricatorTest.php +++ b/tests/system/Test/FabricatorTest.php @@ -12,8 +12,6 @@ namespace CodeIgniter\Test; use CodeIgniter\Database\ModelFactory; -use InvalidArgumentException; -use stdClass; use Tests\Support\Models\EntityModel; use Tests\Support\Models\EventModel; use Tests\Support\Models\FabricatorModel; @@ -59,7 +57,7 @@ public function testConstructorWithInstance() public function testConstructorWithInvalid() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage(lang('Fabricator.invalidModel')); new Fabricator('SillyRabbit\Models\AreForKids'); @@ -313,7 +311,7 @@ public function testMakeObjectReturnsStdClassForArrayReturnType() $result = $fabricator->makeObject(); - $this->assertInstanceOf(stdClass::class, $result); + $this->assertInstanceOf('stdClass', $result); } public function testMakeObjectReturnsStdClassForObjectReturnType() @@ -322,7 +320,7 @@ public function testMakeObjectReturnsStdClassForObjectReturnType() $result = $fabricator->makeObject(); - $this->assertInstanceOf(stdClass::class, $result); + $this->assertInstanceOf('stdClass', $result); } public function testMakeObjectUsesOverrides() @@ -361,7 +359,7 @@ public function testMakeReturnsSingleton() $result = $fabricator->make(); - $this->assertInstanceOf(stdClass::class, $result); + $this->assertInstanceOf('stdClass', $result); } public function testMakeReturnsExpectedCount() @@ -381,7 +379,7 @@ public function testCreateMockReturnsSingleton() $result = $fabricator->create(null, true); - $this->assertInstanceOf(stdClass::class, $result); + $this->assertInstanceOf('stdClass', $result); } public function testCreateMockReturnsExpectedCount() diff --git a/tests/system/Test/FilterTestTraitTest.php b/tests/system/Test/FilterTestTraitTest.php index f3cb0a4a6165..15b98379fbcf 100644 --- a/tests/system/Test/FilterTestTraitTest.php +++ b/tests/system/Test/FilterTestTraitTest.php @@ -11,10 +11,8 @@ namespace CodeIgniter\Test; -use Closure; use CodeIgniter\Filters\Filters; use CodeIgniter\HTTP\RequestInterface; -use InvalidArgumentException; use Tests\Support\Filters\Customfilter; /** @@ -52,12 +50,12 @@ public function testGetCallerReturnsClosure() $caller = $this->getFilterCaller('test-customfilter', 'before'); $this->assertIsCallable($caller); - $this->assertInstanceOf(Closure::class, $caller); + $this->assertInstanceOf('Closure', $caller); } public function testGetCallerInvalidPosition() { - $this->expectException(InvalidArgumentException::class); + $this->expectException('InvalidArgumentException'); $this->expectExceptionMessage('Invalid filter position passed: banana'); $this->getFilterCaller('test-customfilter', 'banana'); From 42d50cc9353aaf8f761cdf4a40b75cc2fea95177 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Mar 2022 15:03:28 +0000 Subject: [PATCH 1803/2325] chore(deps): bump actions/cache from 2 to 3 Bumps [actions/cache](https://github.com/actions/cache) from 2 to 3. - [Release notes](https://github.com/actions/cache/releases) - [Commits](https://github.com/actions/cache/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test-autoreview.yml | 2 +- .github/workflows/test-coding-standards.yml | 2 +- .github/workflows/test-deptrac.yml | 4 ++-- .github/workflows/test-phpstan.yml | 4 ++-- .github/workflows/test-phpunit.yml | 2 +- .github/workflows/test-rector.yml | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test-autoreview.yml b/.github/workflows/test-autoreview.yml index ccc97dcf137e..7e6ff05c2734 100644 --- a/.github/workflows/test-autoreview.yml +++ b/.github/workflows/test-autoreview.yml @@ -34,7 +34,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composercache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} diff --git a/.github/workflows/test-coding-standards.yml b/.github/workflows/test-coding-standards.yml index c966d9e1e603..e5b4a2043342 100644 --- a/.github/workflows/test-coding-standards.yml +++ b/.github/workflows/test-coding-standards.yml @@ -40,7 +40,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-${{ matrix.php-version }}-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/test-deptrac.yml b/.github/workflows/test-deptrac.yml index ac280f964d0a..42b77998325c 100644 --- a/.github/workflows/test-deptrac.yml +++ b/.github/workflows/test-deptrac.yml @@ -50,7 +50,7 @@ jobs: run: mkdir -p ${{ steps.composer-cache.outputs.dir }} - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} @@ -60,7 +60,7 @@ jobs: run: mkdir -p build/ - name: Cache Deptrac results - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: build key: ${{ runner.os }}-deptrac-${{ github.sha }} diff --git a/.github/workflows/test-phpstan.yml b/.github/workflows/test-phpstan.yml index f7c09d1aa89e..805e34edcdde 100644 --- a/.github/workflows/test-phpstan.yml +++ b/.github/workflows/test-phpstan.yml @@ -59,7 +59,7 @@ jobs: run: mkdir -p ${{ steps.composer-cache.outputs.dir }} - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} @@ -69,7 +69,7 @@ jobs: run: mkdir -p build/phpstan - name: Cache PHPStan result cache directory - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: build/phpstan key: ${{ runner.os }}-phpstan-${{ github.sha }} diff --git a/.github/workflows/test-phpunit.yml b/.github/workflows/test-phpunit.yml index 623d13f59475..9b7850ea03d5 100644 --- a/.github/workflows/test-phpunit.yml +++ b/.github/workflows/test-phpunit.yml @@ -144,7 +144,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composercache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/.github/workflows/test-rector.yml b/.github/workflows/test-rector.yml index a96821da3191..372b10289291 100644 --- a/.github/workflows/test-rector.yml +++ b/.github/workflows/test-rector.yml @@ -59,7 +59,7 @@ jobs: run: mkdir -p ${{ steps.composer-cache.outputs.dir }} - name: Cache composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.json') }} From 50c0bb1bb96214f2ea9c2500f82ce06ae7b5f1f2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 21 Mar 2022 15:03:33 +0000 Subject: [PATCH 1804/2325] chore(deps-dev): update rector/rector requirement Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.12.17...0.12.18) --- 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 ed6ff59ccad4..bee1f4e924d1 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.17" + "rector/rector": "0.12.18" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From 7784157f4482a90c5d02c363f14054d1c2c6759f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 15 Feb 2022 12:01:35 +0900 Subject: [PATCH 1805/2325] refactor: Database Session Handler --- system/Config/Services.php | 20 +- .../Handlers/Database/MySQLiHandler.php | 53 ++++++ .../Handlers/Database/PostgreHandler.php | 175 ++++++++++++++++++ system/Session/Handlers/DatabaseHandler.php | 79 +------- .../AbstactHandlerTestCase.php} | 33 +--- .../Handlers/Database/MySQLiHandlerTest.php | 57 ++++++ .../Handlers/Database/PostgreHandlerTest.php | 57 ++++++ 7 files changed, 374 insertions(+), 100 deletions(-) create mode 100644 system/Session/Handlers/Database/MySQLiHandler.php create mode 100644 system/Session/Handlers/Database/PostgreHandler.php rename tests/system/Session/Handlers/{DatabaseHandlerTest.php => Database/AbstactHandlerTestCase.php} (77%) create mode 100644 tests/system/Session/Handlers/Database/MySQLiHandlerTest.php create mode 100644 tests/system/Session/Handlers/Database/PostgreHandlerTest.php diff --git a/system/Config/Services.php b/system/Config/Services.php index 2d44e3ccfd78..9dca50115f51 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -47,6 +47,9 @@ use CodeIgniter\Router\RouteCollectionInterface; use CodeIgniter\Router\Router; use CodeIgniter\Security\Security; +use CodeIgniter\Session\Handlers\Database\MySQLiHandler; +use CodeIgniter\Session\Handlers\Database\PostgreHandler; +use CodeIgniter\Session\Handlers\DatabaseHandler; use CodeIgniter\Session\Session; use CodeIgniter\Throttle\Throttler; use CodeIgniter\Typography\Typography; @@ -58,6 +61,7 @@ use Config\App; use Config\Cache; use Config\ContentSecurityPolicy as CSPConfig; +use Config\Database; use Config\Email as EmailConfig; use Config\Encryption as EncryptionConfig; use Config\Exceptions as ExceptionsConfig; @@ -585,7 +589,21 @@ public static function session(?App $config = null, bool $getShared = true) $logger = AppServices::logger(); $driverName = $config->sessionDriver; - $driver = new $driverName($config, AppServices::request()->getIPAddress()); + + if ($driverName === DatabaseHandler::class) { + $DBGroup = $config->sessionDBGroup ?? config(Database::class)->defaultGroup; + $db = Database::connect($DBGroup); + + $driver = $db->getPlatform(); + + if ($driver === 'MySQLi') { + $driverName = MySQLiHandler::class; + } elseif ($driver === 'Postgre') { + $driverName = PostgreHandler::class; + } + } + + $driver = new $driverName($config, AppServices::request()->getIPAddress()); $driver->setLogger($logger); $session = new Session($driver, $config); diff --git a/system/Session/Handlers/Database/MySQLiHandler.php b/system/Session/Handlers/Database/MySQLiHandler.php new file mode 100644 index 000000000000..fabaae451e6a --- /dev/null +++ b/system/Session/Handlers/Database/MySQLiHandler.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Session\Handlers\Database; + +use CodeIgniter\Session\Handlers\DatabaseHandler; + +/** + * Session handler for MySQLi + */ +class MySQLiHandler extends DatabaseHandler +{ + /** + * Lock the session. + */ + protected function lockSession(string $sessionID): bool + { + $arg = md5($sessionID . ($this->matchIP ? '_' . $this->ipAddress : '')); + if ($this->db->query("SELECT GET_LOCK('{$arg}', 300) AS ci_session_lock")->getRow()->ci_session_lock) { + $this->lock = $arg; + + return true; + } + + return $this->fail(); + } + + /** + * Releases the lock, if any. + */ + protected function releaseLock(): bool + { + if (! $this->lock) { + return true; + } + + if ($this->db->query("SELECT RELEASE_LOCK('{$this->lock}') AS ci_session_lock")->getRow()->ci_session_lock) { + $this->lock = false; + + return true; + } + + return $this->fail(); + } +} diff --git a/system/Session/Handlers/Database/PostgreHandler.php b/system/Session/Handlers/Database/PostgreHandler.php new file mode 100644 index 000000000000..a75d4ea4eaf0 --- /dev/null +++ b/system/Session/Handlers/Database/PostgreHandler.php @@ -0,0 +1,175 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Session\Handlers\Database; + +use CodeIgniter\Session\Handlers\DatabaseHandler; +use ReturnTypeWillChange; + +/** + * Session handler for Postgre + */ +class PostgreHandler extends DatabaseHandler +{ + /** + * Reads the session data from the session storage, and returns the results. + * + * @param string $id The session ID + * + * @return false|string Returns an encoded string of the read data. + * If nothing was read, it must return false. + */ + #[ReturnTypeWillChange] + public function read($id) + { + if ($this->lockSession($id) === false) { + $this->fingerprint = md5(''); + + return ''; + } + + if (! isset($this->sessionID)) { + $this->sessionID = $id; + } + + $builder = $this->db->table($this->table) + ->select("encode(data, 'base64') AS data") + ->where('id', $id); + + if ($this->matchIP) { + $builder = $builder->where('ip_address', $this->ipAddress); + } + + $result = $builder->get()->getRow(); + + if ($result === null) { + // PHP7 will reuse the same SessionHandler object after + // ID regeneration, so we need to explicitly set this to + // FALSE instead of relying on the default ... + $this->rowExists = false; + $this->fingerprint = md5(''); + + return ''; + } + + $result = is_bool($result) ? '' : base64_decode(rtrim($result->data), true); + + $this->fingerprint = md5($result); + $this->rowExists = true; + + return $result; + } + + /** + * Writes the session data to the session storage. + * + * @param string $id The session ID + * @param string $data The encoded session data + */ + public function write($id, $data): bool + { + if ($this->lock === false) { + return $this->fail(); + } + + if ($this->sessionID !== $id) { + $this->rowExists = false; + $this->sessionID = $id; + } + + if ($this->rowExists === false) { + $insertData = [ + 'id' => $id, + 'ip_address' => $this->ipAddress, + 'data' => '\x' . bin2hex($data), + ]; + + if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) { + return $this->fail(); + } + + $this->fingerprint = md5($data); + $this->rowExists = true; + + return true; + } + + $builder = $this->db->table($this->table)->where('id', $id); + + if ($this->matchIP) { + $builder = $builder->where('ip_address', $this->ipAddress); + } + + $updateData = []; + + if ($this->fingerprint !== md5($data)) { + $updateData['data'] = '\x' . bin2hex($data); + } + + if (! $builder->set('timestamp', 'now()', false)->update($updateData)) { + return $this->fail(); + } + + $this->fingerprint = md5($data); + + return true; + } + + /** + * Cleans up expired sessions. + * + * @param int $max_lifetime Sessions that have not updated + * for the last max_lifetime seconds will be removed. + * + * @return false|int Returns the number of deleted sessions on success, or false on failure. + */ + #[ReturnTypeWillChange] + public function gc($max_lifetime) + { + $separator = '\''; + $interval = implode($separator, ['', "{$max_lifetime} second", '']); + + return $this->db->table($this->table)->where('timestamp <', "now() - INTERVAL {$interval}", false)->delete() ? 1 : $this->fail(); + } + + /** + * Lock the session. + */ + protected function lockSession(string $sessionID): bool + { + $arg = "hashtext('{$sessionID}')" . ($this->matchIP ? ", hashtext('{$this->ipAddress}')" : ''); + if ($this->db->simpleQuery("SELECT pg_advisory_lock({$arg})")) { + $this->lock = $arg; + + return true; + } + + return $this->fail(); + } + + /** + * Releases the lock, if any. + */ + protected function releaseLock(): bool + { + if (! $this->lock) { + return true; + } + + if ($this->db->simpleQuery("SELECT pg_advisory_unlock({$this->lock})")) { + $this->lock = false; + + return true; + } + + return $this->fail(); + } +} diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index dfaa472029fd..64c6a1c511d1 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -18,7 +18,9 @@ use ReturnTypeWillChange; /** - * Session handler using current Database for storage + * Base database session handler + * + * Do not use this class. Use database specific handler class. */ class DatabaseHandler extends BaseHandler { @@ -44,7 +46,7 @@ class DatabaseHandler extends BaseHandler protected $db; /** - * The database type, for locking purposes. + * The database type * * @var string */ @@ -73,13 +75,7 @@ public function __construct(AppConfig $config, string $ipAddress) $this->db = Database::connect($this->DBGroup); - $driver = strtolower(get_class($this->db)); - - if (strpos($driver, 'mysql') !== false) { - $this->platform = 'mysql'; - } elseif (strpos($driver, 'postgre') !== false) { - $this->platform = 'postgre'; - } + $this->platform = $this->db->getPlatform(); } /** @@ -119,7 +115,7 @@ public function read($id) } $builder = $this->db->table($this->table) - ->select($this->platform === 'postgre' ? "encode(data, 'base64') AS data" : 'data') + ->select('data') ->where('id', $id); if ($this->matchIP) { @@ -138,11 +134,7 @@ public function read($id) return ''; } - if (is_bool($result)) { - $result = ''; - } else { - $result = ($this->platform === 'postgre') ? base64_decode(rtrim($result->data), true) : $result->data; - } + $result = is_bool($result) ? '' : $result->data; $this->fingerprint = md5($result); $this->rowExists = true; @@ -171,7 +163,7 @@ public function write($id, $data): bool $insertData = [ 'id' => $id, 'ip_address' => $this->ipAddress, - 'data' => $this->platform === 'postgre' ? '\x' . bin2hex($data) : $data, + 'data' => $data, ]; if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) { @@ -193,7 +185,7 @@ public function write($id, $data): bool $updateData = []; if ($this->fingerprint !== md5($data)) { - $updateData['data'] = ($this->platform === 'postgre') ? '\x' . bin2hex($data) : $data; + $updateData['data'] = $data; } if (! $builder->set('timestamp', 'now()', false)->update($updateData)) { @@ -252,43 +244,12 @@ public function destroy($id): bool #[ReturnTypeWillChange] public function gc($max_lifetime) { - $separator = $this->platform === 'postgre' ? '\'' : ' '; + $separator = ' '; $interval = implode($separator, ['', "{$max_lifetime} second", '']); return $this->db->table($this->table)->where('timestamp <', "now() - INTERVAL {$interval}", false)->delete() ? 1 : $this->fail(); } - /** - * Lock the session. - */ - protected function lockSession(string $sessionID): bool - { - if ($this->platform === 'mysql') { - $arg = md5($sessionID . ($this->matchIP ? '_' . $this->ipAddress : '')); - if ($this->db->query("SELECT GET_LOCK('{$arg}', 300) AS ci_session_lock")->getRow()->ci_session_lock) { - $this->lock = $arg; - - return true; - } - - return $this->fail(); - } - - if ($this->platform === 'postgre') { - $arg = "hashtext('{$sessionID}')" . ($this->matchIP ? ", hashtext('{$this->ipAddress}')" : ''); - if ($this->db->simpleQuery("SELECT pg_advisory_lock({$arg})")) { - $this->lock = $arg; - - return true; - } - - return $this->fail(); - } - - // Unsupported DB? Let the parent handle the simplified version. - return parent::lockSession($sessionID); - } - /** * Releases the lock, if any. */ @@ -298,26 +259,6 @@ protected function releaseLock(): bool return true; } - if ($this->platform === 'mysql') { - if ($this->db->query("SELECT RELEASE_LOCK('{$this->lock}') AS ci_session_lock")->getRow()->ci_session_lock) { - $this->lock = false; - - return true; - } - - return $this->fail(); - } - - if ($this->platform === 'postgre') { - if ($this->db->simpleQuery("SELECT pg_advisory_unlock({$this->lock})")) { - $this->lock = false; - - return true; - } - - return $this->fail(); - } - // Unsupported DB? Let the parent handle the simple version. return parent::releaseLock(); } diff --git a/tests/system/Session/Handlers/DatabaseHandlerTest.php b/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php similarity index 77% rename from tests/system/Session/Handlers/DatabaseHandlerTest.php rename to tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php index 7af077606cba..9d6a6781ce57 100644 --- a/tests/system/Session/Handlers/DatabaseHandlerTest.php +++ b/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php @@ -9,18 +9,16 @@ * the LICENSE file that was distributed with this source code. */ -namespace CodeIgniter\Session\Handlers; +namespace CodeIgniter\Session\Handlers\Database; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; use CodeIgniter\Test\ReflectionHelper; -use Config\App as AppConfig; -use Config\Database as DatabaseConfig; /** * @internal */ -final class DatabaseHandlerTest extends CIUnitTestCase +abstract class AbstactHandlerTestCase extends CIUnitTestCase { use DatabaseTestTrait; use ReflectionHelper; @@ -37,32 +35,7 @@ protected function setUp(): void } } - protected function getInstance($options = []) - { - $defaults = [ - 'sessionDriver' => DatabaseHandler::class, - 'sessionCookieName' => 'ci_session', - 'sessionExpiration' => 7200, - 'sessionSavePath' => 'ci_sessions', - 'sessionMatchIP' => false, - 'sessionTimeToUpdate' => 300, - 'sessionRegenerateDestroy' => false, - 'cookieDomain' => '', - 'cookiePrefix' => '', - 'cookiePath' => '/', - 'cookieSecure' => false, - 'cookieSameSite' => 'Lax', - ]; - - $config = array_merge($defaults, $options); - $appConfig = new AppConfig(); - - foreach ($config as $key => $c) { - $appConfig->{$key} = $c; - } - - return new DatabaseHandler($appConfig, '127.0.0.1'); - } + abstract protected function getInstance($options = []); public function testOpen() { diff --git a/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php b/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php new file mode 100644 index 000000000000..b1fcd51dd24c --- /dev/null +++ b/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Session\Handlers\Database; + +use Config\App as AppConfig; +use Config\Database as DatabaseConfig; + +/** + * @internal + */ +final class MySQLiHandlerTest extends AbstactHandlerTestCase +{ + protected function setUp(): void + { + parent::setUp(); + + if (config(DatabaseConfig::class)->tests['DBDriver'] !== 'MySQLi') { + $this->markTestSkipped('This test case needs MySQLi'); + } + } + + protected function getInstance($options = []) + { + $defaults = [ + 'sessionDriver' => 'CodeIgniter\Session\Handlers\DatabaseHandler', + 'sessionCookieName' => 'ci_session', + 'sessionExpiration' => 7200, + 'sessionSavePath' => 'ci_sessions', + 'sessionMatchIP' => false, + 'sessionTimeToUpdate' => 300, + 'sessionRegenerateDestroy' => false, + 'cookieDomain' => '', + 'cookiePrefix' => '', + 'cookiePath' => '/', + 'cookieSecure' => false, + 'cookieSameSite' => 'Lax', + ]; + + $config = array_merge($defaults, $options); + $appConfig = new AppConfig(); + + foreach ($config as $key => $c) { + $appConfig->{$key} = $c; + } + + return new MySQLiHandler($appConfig, '127.0.0.1'); + } +} diff --git a/tests/system/Session/Handlers/Database/PostgreHandlerTest.php b/tests/system/Session/Handlers/Database/PostgreHandlerTest.php new file mode 100644 index 000000000000..b84298f92868 --- /dev/null +++ b/tests/system/Session/Handlers/Database/PostgreHandlerTest.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Session\Handlers\Database; + +use Config\App as AppConfig; +use Config\Database as DatabaseConfig; + +/** + * @internal + */ +final class PostgreHandlerTest extends AbstactHandlerTestCase +{ + protected function setUp(): void + { + parent::setUp(); + + if (config(DatabaseConfig::class)->tests['DBDriver'] !== 'Postgre') { + $this->markTestSkipped('This test case needs Postgre'); + } + } + + protected function getInstance($options = []) + { + $defaults = [ + 'sessionDriver' => 'CodeIgniter\Session\Handlers\DatabaseHandler', + 'sessionCookieName' => 'ci_session', + 'sessionExpiration' => 7200, + 'sessionSavePath' => 'ci_sessions', + 'sessionMatchIP' => false, + 'sessionTimeToUpdate' => 300, + 'sessionRegenerateDestroy' => false, + 'cookieDomain' => '', + 'cookiePrefix' => '', + 'cookiePath' => '/', + 'cookieSecure' => false, + 'cookieSameSite' => 'Lax', + ]; + + $config = array_merge($defaults, $options); + $appConfig = new AppConfig(); + + foreach ($config as $key => $c) { + $appConfig->{$key} = $c; + } + + return new PostgreHandler($appConfig, '127.0.0.1'); + } +} From 43f2453472ef06d5806cd7174c0e4fe0e6c14bb4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 15 Feb 2022 12:02:40 +0900 Subject: [PATCH 1806/2325] docs: fix PHPDocs --- phpstan-baseline.neon.dist | 20 -------------------- system/Database/BaseConnection.php | 2 +- system/Session/Handlers/BaseHandler.php | 2 +- 3 files changed, 2 insertions(+), 22 deletions(-) diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 7c0704286696..1021eb445899 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -745,26 +745,6 @@ parameters: count: 1 path: system/Session/Handlers/DatabaseHandler.php - - - message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" - count: 1 - path: system/Session/Handlers/DatabaseHandler.php - - - - message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" - count: 1 - path: system/Session/Handlers/FileHandler.php - - - - message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" - count: 1 - path: system/Session/Handlers/MemcachedHandler.php - - - - message: "#^Property CodeIgniter\\\\Session\\\\Handlers\\\\BaseHandler\\:\\:\\$sessionID \\(string\\) in isset\\(\\) is not nullable\\.$#" - count: 1 - path: system/Session/Handlers/RedisHandler.php - - message: "#^Strict comparison using \\=\\=\\= between string and true will always evaluate to false\\.$#" count: 1 diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index d2ce3fdd390a..23a78d423c47 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -508,7 +508,7 @@ public function getPrefix(): string } /** - * The name of the platform in use (MySQLi, mssql, etc) + * The name of the platform in use (MySQLi, Postgre, SQLite3, OCI8, etc) */ public function getPlatform(): string { diff --git a/system/Session/Handlers/BaseHandler.php b/system/Session/Handlers/BaseHandler.php index f6fa57b23b68..008cae369e80 100644 --- a/system/Session/Handlers/BaseHandler.php +++ b/system/Session/Handlers/BaseHandler.php @@ -81,7 +81,7 @@ abstract class BaseHandler implements SessionHandlerInterface /** * Current session ID * - * @var string + * @var string|null */ protected $sessionID; From 9cf3b5e45279b812c5a985062574c693b20f6dee Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 15 Feb 2022 14:06:17 +0900 Subject: [PATCH 1807/2325] refactor: remove duplicate code in write() --- .../Handlers/Database/PostgreHandler.php | 53 ++----------------- system/Session/Handlers/DatabaseHandler.php | 12 ++++- 2 files changed, 13 insertions(+), 52 deletions(-) diff --git a/system/Session/Handlers/Database/PostgreHandler.php b/system/Session/Handlers/Database/PostgreHandler.php index a75d4ea4eaf0..3a708fefc746 100644 --- a/system/Session/Handlers/Database/PostgreHandler.php +++ b/system/Session/Handlers/Database/PostgreHandler.php @@ -69,58 +69,11 @@ public function read($id) } /** - * Writes the session data to the session storage. - * - * @param string $id The session ID - * @param string $data The encoded session data + * Prepare data to insert/update */ - public function write($id, $data): bool + protected function prepareData(string $data): string { - if ($this->lock === false) { - return $this->fail(); - } - - if ($this->sessionID !== $id) { - $this->rowExists = false; - $this->sessionID = $id; - } - - if ($this->rowExists === false) { - $insertData = [ - 'id' => $id, - 'ip_address' => $this->ipAddress, - 'data' => '\x' . bin2hex($data), - ]; - - if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) { - return $this->fail(); - } - - $this->fingerprint = md5($data); - $this->rowExists = true; - - return true; - } - - $builder = $this->db->table($this->table)->where('id', $id); - - if ($this->matchIP) { - $builder = $builder->where('ip_address', $this->ipAddress); - } - - $updateData = []; - - if ($this->fingerprint !== md5($data)) { - $updateData['data'] = '\x' . bin2hex($data); - } - - if (! $builder->set('timestamp', 'now()', false)->update($updateData)) { - return $this->fail(); - } - - $this->fingerprint = md5($data); - - return true; + return '\x' . bin2hex($data); } /** diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index 64c6a1c511d1..6f20c7688dd8 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -163,7 +163,7 @@ public function write($id, $data): bool $insertData = [ 'id' => $id, 'ip_address' => $this->ipAddress, - 'data' => $data, + 'data' => $this->prepareData($data), ]; if (! $this->db->table($this->table)->set('timestamp', 'now()', false)->insert($insertData)) { @@ -185,7 +185,7 @@ public function write($id, $data): bool $updateData = []; if ($this->fingerprint !== md5($data)) { - $updateData['data'] = $data; + $updateData['data'] = $this->prepareData($data); } if (! $builder->set('timestamp', 'now()', false)->update($updateData)) { @@ -197,6 +197,14 @@ public function write($id, $data): bool return true; } + /** + * Prepare data to insert/update + */ + protected function prepareData(string $data): string + { + return $data; + } + /** * Closes the current session. */ From 0b2f01c6befbde7d9604351b9825ade841e8f0e6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 15 Feb 2022 14:41:46 +0900 Subject: [PATCH 1808/2325] refactor: remove duplicate code in read() --- .../Handlers/Database/PostgreHandler.php | 56 +++++-------------- system/Session/Handlers/DatabaseHandler.php | 29 ++++++++-- 2 files changed, 39 insertions(+), 46 deletions(-) diff --git a/system/Session/Handlers/Database/PostgreHandler.php b/system/Session/Handlers/Database/PostgreHandler.php index 3a708fefc746..2b730d831c89 100644 --- a/system/Session/Handlers/Database/PostgreHandler.php +++ b/system/Session/Handlers/Database/PostgreHandler.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Session\Handlers\Database; +use CodeIgniter\Database\BaseBuilder; use CodeIgniter\Session\Handlers\DatabaseHandler; use ReturnTypeWillChange; @@ -20,52 +21,23 @@ class PostgreHandler extends DatabaseHandler { /** - * Reads the session data from the session storage, and returns the results. + * Sets SELECT clause + */ + protected function setSelect(BaseBuilder $builder) + { + $builder->select("encode(data, 'base64') AS data"); + } + + /** + * Decodes column data * - * @param string $id The session ID + * @param mixed $data * - * @return false|string Returns an encoded string of the read data. - * If nothing was read, it must return false. + * @return false|string */ - #[ReturnTypeWillChange] - public function read($id) + protected function decodeData($data) { - if ($this->lockSession($id) === false) { - $this->fingerprint = md5(''); - - return ''; - } - - if (! isset($this->sessionID)) { - $this->sessionID = $id; - } - - $builder = $this->db->table($this->table) - ->select("encode(data, 'base64') AS data") - ->where('id', $id); - - if ($this->matchIP) { - $builder = $builder->where('ip_address', $this->ipAddress); - } - - $result = $builder->get()->getRow(); - - if ($result === null) { - // PHP7 will reuse the same SessionHandler object after - // ID regeneration, so we need to explicitly set this to - // FALSE instead of relying on the default ... - $this->rowExists = false; - $this->fingerprint = md5(''); - - return ''; - } - - $result = is_bool($result) ? '' : base64_decode(rtrim($result->data), true); - - $this->fingerprint = md5($result); - $this->rowExists = true; - - return $result; + return base64_decode(rtrim($data), true); } /** diff --git a/system/Session/Handlers/DatabaseHandler.php b/system/Session/Handlers/DatabaseHandler.php index 6f20c7688dd8..8cbf43ca280a 100644 --- a/system/Session/Handlers/DatabaseHandler.php +++ b/system/Session/Handlers/DatabaseHandler.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Session\Handlers; +use CodeIgniter\Database\BaseBuilder; use CodeIgniter\Database\BaseConnection; use CodeIgniter\Session\Exceptions\SessionException; use Config\App as AppConfig; @@ -114,14 +115,14 @@ public function read($id) $this->sessionID = $id; } - $builder = $this->db->table($this->table) - ->select('data') - ->where('id', $id); + $builder = $this->db->table($this->table)->where('id', $id); if ($this->matchIP) { $builder = $builder->where('ip_address', $this->ipAddress); } + $this->setSelect($builder); + $result = $builder->get()->getRow(); if ($result === null) { @@ -134,7 +135,7 @@ public function read($id) return ''; } - $result = is_bool($result) ? '' : $result->data; + $result = is_bool($result) ? '' : $this->decodeData($result->data); $this->fingerprint = md5($result); $this->rowExists = true; @@ -142,6 +143,26 @@ public function read($id) return $result; } + /** + * Sets SELECT clause + */ + protected function setSelect(BaseBuilder $builder) + { + $builder->select('data'); + } + + /** + * Decodes column data + * + * @param mixed $data + * + * @return false|string + */ + protected function decodeData($data) + { + return $data; + } + /** * Writes the session data to the session storage. * From 685a11bdf6ed209641fd4602e938bd9ffa5a249e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Mar 2022 10:54:57 +0900 Subject: [PATCH 1809/2325] refactor: vendor/bin/rector --- tests/system/Session/Handlers/Database/MySQLiHandlerTest.php | 3 ++- tests/system/Session/Handlers/Database/PostgreHandlerTest.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php b/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php index b1fcd51dd24c..469b0c8e1f7e 100644 --- a/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php +++ b/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Session\Handlers\Database; +use CodeIgniter\Session\Handlers\DatabaseHandler; use Config\App as AppConfig; use Config\Database as DatabaseConfig; @@ -31,7 +32,7 @@ protected function setUp(): void protected function getInstance($options = []) { $defaults = [ - 'sessionDriver' => 'CodeIgniter\Session\Handlers\DatabaseHandler', + 'sessionDriver' => DatabaseHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, 'sessionSavePath' => 'ci_sessions', diff --git a/tests/system/Session/Handlers/Database/PostgreHandlerTest.php b/tests/system/Session/Handlers/Database/PostgreHandlerTest.php index b84298f92868..9575b68e499f 100644 --- a/tests/system/Session/Handlers/Database/PostgreHandlerTest.php +++ b/tests/system/Session/Handlers/Database/PostgreHandlerTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Session\Handlers\Database; +use CodeIgniter\Session\Handlers\DatabaseHandler; use Config\App as AppConfig; use Config\Database as DatabaseConfig; @@ -31,7 +32,7 @@ protected function setUp(): void protected function getInstance($options = []) { $defaults = [ - 'sessionDriver' => 'CodeIgniter\Session\Handlers\DatabaseHandler', + 'sessionDriver' => DatabaseHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, 'sessionSavePath' => 'ci_sessions', From 036d9b55993ac1edd6157daa7aec04b36e78ea84 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Mar 2022 11:08:03 +0900 Subject: [PATCH 1810/2325] test: fix mistake of rebase --- .../system/Session/Handlers/Database/AbstactHandlerTestCase.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php b/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php index 9d6a6781ce57..7434301f40cc 100644 --- a/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php +++ b/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php @@ -14,6 +14,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; use CodeIgniter\Test\ReflectionHelper; +use Config\Database as DatabaseConfig; /** * @internal From 51057f144c2b461f2ec89fdb46b2e0b89f079c79 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 22 Mar 2022 17:24:36 +0900 Subject: [PATCH 1811/2325] docs: add full support for PHP 8.1 --- user_guide_src/source/changelogs/v4.1.6.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.1.6.rst b/user_guide_src/source/changelogs/v4.1.6.rst index 2321f413e173..84e4f9f7d39e 100644 --- a/user_guide_src/source/changelogs/v4.1.6.rst +++ b/user_guide_src/source/changelogs/v4.1.6.rst @@ -37,6 +37,7 @@ Validation changes Enhancements ************ +- Full support for PHP 8.1. - Database pane on debug toolbar now displays location where Query was called from. Also displays full backtrace. - :ref:`Subqueries ` in QueryBuilder can now be an instance of the BaseBuilder class. - Kint was updated from ^3.3 to ^4.0. From 4ba72e6ab7df9a40e2d376cb5d2abe4e7fa572b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?= Date: Tue, 22 Mar 2022 16:33:11 +0100 Subject: [PATCH 1812/2325] Update incomingrequest.rst --- user_guide_src/source/incoming/incomingrequest.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/incomingrequest.rst b/user_guide_src/source/incoming/incomingrequest.rst index c20e897b92de..74f3cf5289b0 100644 --- a/user_guide_src/source/incoming/incomingrequest.rst +++ b/user_guide_src/source/incoming/incomingrequest.rst @@ -44,10 +44,10 @@ You can check the HTTP method that this request represents with the ``method()`` .. literalinclude:: incomingrequest/005.php By default, the method is returned as a lower-case string (i.e., 'get', 'post', etc). You can get an -uppercase version by wrapping the call in ``str_to_upper()``:: +uppercase version by wrapping the call in ``strtoupper()``:: // Returns 'GET' - $method = str_to_upper($request->getMethod()); + $method = strtoupper($request->getMethod()); You can also check if the request was made through and HTTPS connection with the ``isSecure()`` method: From 57e0594a8d2a12b32de852ecd52a1ab679fa4705 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 23 Mar 2022 09:13:11 +0900 Subject: [PATCH 1813/2325] chore: remove App\ and Config\ in autoload.psr-4 in app starter composer.json Revert #3423 Problems: - Cannot change `app` folder name. Because the composer's path overwrite the config in Config\Autoload. - Causes error when defining new namespace under app/. See #5818 --- admin/starter/composer.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/admin/starter/composer.json b/admin/starter/composer.json index f2959dd49b51..026329ca9a24 100644 --- a/admin/starter/composer.json +++ b/admin/starter/composer.json @@ -17,10 +17,6 @@ "ext-fileinfo": "Improves mime type detection for files" }, "autoload": { - "psr-4": { - "App\\": "app", - "Config\\": "app/Config" - }, "exclude-from-classmap": [ "**/Database/Migrations/**" ] From 135222d40724d3b6bc470fd88bf9c85b1fff9b95 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 23 Mar 2022 09:23:43 +0900 Subject: [PATCH 1814/2325] docs: add @TODO --- system/CLI/Commands.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/CLI/Commands.php b/system/CLI/Commands.php index 3f84f33d918f..d153b3aa857a 100644 --- a/system/CLI/Commands.php +++ b/system/CLI/Commands.php @@ -76,6 +76,10 @@ public function getCommands() /** * Discovers all commands in the framework and within user code, * and collects instances of them to work with. + * + * @TODO this approach (find qualified classname from path) causes error, + * when using Composer autoloader. + * See https://github.com/codeigniter4/CodeIgniter4/issues/5818 */ public function discoverCommands() { From 15931e9c4283f01474c56874ec7dec2c3c68c1b2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 23 Mar 2022 17:27:04 +0000 Subject: [PATCH 1815/2325] chore(deps-dev): update rector/rector requirement Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.12.18...0.12.19) --- 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 bee1f4e924d1..8d77bc48cde8 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.18" + "rector/rector": "0.12.19" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From c5eb48011648c5f9dfa0f2390f69297a13d7e651 Mon Sep 17 00:00:00 2001 From: "John Paul E. Balandan, CPA" Date: Sun, 27 Mar 2022 00:11:10 +0800 Subject: [PATCH 1816/2325] Rename `Abstact` to `Abstract` --- .../{AbstactHandlerTestCase.php => AbstractHandlerTestCase.php} | 2 +- tests/system/Session/Handlers/Database/MySQLiHandlerTest.php | 2 +- tests/system/Session/Handlers/Database/PostgreHandlerTest.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename tests/system/Session/Handlers/Database/{AbstactHandlerTestCase.php => AbstractHandlerTestCase.php} (98%) diff --git a/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php b/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php similarity index 98% rename from tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php rename to tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php index 7434301f40cc..f252fc24fb43 100644 --- a/tests/system/Session/Handlers/Database/AbstactHandlerTestCase.php +++ b/tests/system/Session/Handlers/Database/AbstractHandlerTestCase.php @@ -19,7 +19,7 @@ /** * @internal */ -abstract class AbstactHandlerTestCase extends CIUnitTestCase +abstract class AbstractHandlerTestCase extends CIUnitTestCase { use DatabaseTestTrait; use ReflectionHelper; diff --git a/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php b/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php index 469b0c8e1f7e..5fba8bb779d0 100644 --- a/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php +++ b/tests/system/Session/Handlers/Database/MySQLiHandlerTest.php @@ -18,7 +18,7 @@ /** * @internal */ -final class MySQLiHandlerTest extends AbstactHandlerTestCase +final class MySQLiHandlerTest extends AbstractHandlerTestCase { protected function setUp(): void { diff --git a/tests/system/Session/Handlers/Database/PostgreHandlerTest.php b/tests/system/Session/Handlers/Database/PostgreHandlerTest.php index 9575b68e499f..d28d1fab7134 100644 --- a/tests/system/Session/Handlers/Database/PostgreHandlerTest.php +++ b/tests/system/Session/Handlers/Database/PostgreHandlerTest.php @@ -18,7 +18,7 @@ /** * @internal */ -final class PostgreHandlerTest extends AbstactHandlerTestCase +final class PostgreHandlerTest extends AbstractHandlerTestCase { protected function setUp(): void { From 7612cdb09129ab2ce3e736fa3c131f834b52caa9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 28 Mar 2022 12:46:08 +0900 Subject: [PATCH 1817/2325] docs: add index.php/spark changes in changelog --- user_guide_src/source/changelogs/v4.2.0.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 9751dd06fee0..f12a13bcb416 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -13,6 +13,9 @@ BREAKING ******** - The method signature of ``Validation::setRule()`` has been changed. The ``string`` typehint on the ``$rules`` parameter was removed. Extending classes should likewise remove the parameter so as not to break LSP. +- The ``CodeIgniter\CodeIgniter`` class has a new property ``$context`` and it must have the correct context at runtime. So the following files have been changed: + - ``public/index.php`` + - ``spark`` Enhancements ************ From 2f8157dc34d328ba450788ab473fcc076f3a3772 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 28 Mar 2022 13:02:28 +0900 Subject: [PATCH 1818/2325] chore: fix ImportError ImportError: cannot import name 'environmentfilter' from 'jinja2' (/usr/local/lib/python3.10/site-packages/jinja2/__init__.py) See https://github.com/sphinx-doc/sphinx/issues/10291 --- user_guide_src/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/requirements.txt b/user_guide_src/requirements.txt index 19f5064b9815..5d11554964d1 100644 --- a/user_guide_src/requirements.txt +++ b/user_guide_src/requirements.txt @@ -2,3 +2,4 @@ sphinx>=2.4.4,<3 sphinxcontrib-phpdomain>=0.7.1 docutils>=0.16 sphinx-rtd-theme>=0.5.0 +jinja2<3.1 From 4138c04808f95699699a9140671a9fe605e5c2eb Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 29 Mar 2022 21:16:43 +0900 Subject: [PATCH 1819/2325] config: add mime type for webp --- app/Config/Mimes.php | 1 + user_guide_src/source/changelogs/v4.2.0.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index 786bc6a1e5c7..a1bb458a2804 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -260,6 +260,7 @@ class Mimes 'image/png', 'image/x-png', ], + 'webp' => 'image/webp', 'tif' => 'image/tiff', 'tiff' => 'image/tiff', 'css' => [ diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index f12a13bcb416..a0494ebd47c0 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -34,6 +34,7 @@ Enhancements - The ``spark routes`` command now shows closure routes, auto routes, and filters. See :ref:`URI Routing `. - Exception information logged through ``log_message()`` has now improved. It now includes the file and line where the exception originated. It also does not truncate the message anymore. - The log format has also changed. If users are depending on the log format in their apps, the new log format is "<1-based count> (): " +- Added support for webp files to **app/Config/Mimes.php**. Changes ******* From 250b0cadc1a453573a86d721ad9acbf31e8dfc0b Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 30 Mar 2022 11:27:59 +0900 Subject: [PATCH 1820/2325] docs: fix comment --- system/View/Parser.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/View/Parser.php b/system/View/Parser.php index 6834c003e500..dbb0395fbd0b 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -289,7 +289,7 @@ protected function parsePair(string $variable, array $data, string $template): a */ foreach ($matches as $match) { // Loop over each piece of $data, replacing - // it's contents so that we know what to replace in parse() + // its contents so that we know what to replace in parse() $str = ''; // holds the new contents for this tag pair. foreach ($data as $row) { From 9a85788f51b056c24c1d7c4477a4108e52bec9f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 30 Mar 2022 11:28:59 +0900 Subject: [PATCH 1821/2325] fix: view parser fails with ({variable}) in loop --- system/View/Parser.php | 11 +---------- tests/system/View/ParserTest.php | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/system/View/Parser.php b/system/View/Parser.php index dbb0395fbd0b..6f62ca4fb333 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -338,8 +338,7 @@ protected function parsePair(string $variable, array $data, string $template): a $str .= $out; } - // Escape | character from filters as it's handled as OR in regex - $escapedMatch = preg_replace('/(?assertSame("Super Heroes\nTom Dick Henry ", $this->parser->renderString($template)); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5825 + */ + public function testParseLoopVariableWithParentheses() + { + $data = [ + 'title' => 'Super Heroes', + 'powers' => [ + ['name' => 'Tom'], + ['name' => 'Dick'], + ['name' => 'Henry'], + ], + ]; + + $template = "{title}\n{powers}({name}) {/powers}"; + + $this->parser->setData($data); + $this->assertSame("Super Heroes\n(Tom) (Dick) (Henry) ", $this->parser->renderString($template)); + } + public function testParseLoopObjectProperties() { $obj1 = new stdClass(); From 78d42a58f57eb4cc6a8a6e9f74be876b93b4051c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 28 Mar 2022 11:40:45 +0900 Subject: [PATCH 1822/2325] fix: spark can't use options in PHP 7.4 Cannot unpack array with string keys at SYSTEMPATH/CodeIgniter.php:893 --- system/CLI/CommandRunner.php | 4 ++-- system/CodeIgniter.php | 10 +++++---- tests/system/CLI/CommandRunnerTest.php | 2 +- tests/system/SparkTest.php | 29 ++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 tests/system/SparkTest.php diff --git a/system/CLI/CommandRunner.php b/system/CLI/CommandRunner.php index a6985d0db931..06d06863de2f 100644 --- a/system/CLI/CommandRunner.php +++ b/system/CLI/CommandRunner.php @@ -40,13 +40,13 @@ public function __construct() * so we have the chance to look for a Command first. * * @param string $method - * @param array ...$params + * @param array $params * * @throws ReflectionException * * @return mixed */ - public function _remap($method, ...$params) + public function _remap($method, $params) { // The first param is usually empty, so scrap it. if (empty($params[0])) { diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 86e70546dd41..093687254c77 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -884,14 +884,16 @@ protected function runController($class) /** @var CLIRequest $request */ $request = $this->request; $params = $request->getArgs(); + + $output = $class->_remap($this->method, $params); } else { // This is a Web request or PHP CLI request $params = $this->router->params(); - } - $output = method_exists($class, '_remap') - ? $class->_remap($this->method, ...$params) - : $class->{$this->method}(...$params); + $output = method_exists($class, '_remap') + ? $class->_remap($this->method, ...$params) + : $class->{$this->method}(...$params); + } $this->benchmark->stop('controller'); diff --git a/tests/system/CLI/CommandRunnerTest.php b/tests/system/CLI/CommandRunnerTest.php index 32ca71357e75..c9e3245b932c 100644 --- a/tests/system/CLI/CommandRunnerTest.php +++ b/tests/system/CLI/CommandRunnerTest.php @@ -123,7 +123,7 @@ public function testBadCommand() */ public function testRemapEmptyFirstParams() { - self::$runner->_remap('anyvalue', null, 'list'); + self::$runner->_remap('anyvalue', [null, 'list']); $result = CITestStreamFilter::$buffer; // make sure the result looks like a command list diff --git a/tests/system/SparkTest.php b/tests/system/SparkTest.php new file mode 100644 index 000000000000..0cd76453c02a --- /dev/null +++ b/tests/system/SparkTest.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter; + +use CodeIgniter\Test\CIUnitTestCase; + +/** + * @internal + */ +final class SparkTest extends CIUnitTestCase +{ + public function testCanUseOption() + { + ob_start(); + passthru('php spark list --simple'); + $output = ob_get_clean(); + + $this->assertStringContainsString('cache:clear', $output); + } +} From 9cade91cf68f5121428c507135aba69a7dc182c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 28 Mar 2022 11:44:41 +0900 Subject: [PATCH 1823/2325] refactor: remove unneeded logic It seems out of dated logic. --- system/CLI/CommandRunner.php | 5 ----- tests/system/CLI/CommandRunnerTest.php | 12 ------------ 2 files changed, 17 deletions(-) diff --git a/system/CLI/CommandRunner.php b/system/CLI/CommandRunner.php index 06d06863de2f..ef4ed057b606 100644 --- a/system/CLI/CommandRunner.php +++ b/system/CLI/CommandRunner.php @@ -48,11 +48,6 @@ public function __construct() */ public function _remap($method, $params) { - // The first param is usually empty, so scrap it. - if (empty($params[0])) { - array_shift($params); - } - return $this->index($params); } diff --git a/tests/system/CLI/CommandRunnerTest.php b/tests/system/CLI/CommandRunnerTest.php index c9e3245b932c..892b7b5ff516 100644 --- a/tests/system/CLI/CommandRunnerTest.php +++ b/tests/system/CLI/CommandRunnerTest.php @@ -117,16 +117,4 @@ public function testBadCommand() // make sure the result looks like a command list $this->assertStringContainsString('Command "bogus" not found', CITestStreamFilter::$buffer); } - - /** - * @TODO When the first param is empty? Use case? - */ - public function testRemapEmptyFirstParams() - { - self::$runner->_remap('anyvalue', [null, 'list']); - $result = CITestStreamFilter::$buffer; - - // make sure the result looks like a command list - $this->assertStringContainsString('Lists the available commands.', $result); - } } From d0b323d9fbf7a7227551b7190f80ba0dbbf265ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 30 Mar 2022 19:16:35 +0900 Subject: [PATCH 1824/2325] docs: add CommandRunner::_remap() change in changelogs --- user_guide_src/source/changelogs/v4.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index f12a13bcb416..34daeff2f474 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -16,6 +16,7 @@ BREAKING - The ``CodeIgniter\CodeIgniter`` class has a new property ``$context`` and it must have the correct context at runtime. So the following files have been changed: - ``public/index.php`` - ``spark`` +- The method signature of ``CodeIgniter\CLI\CommandRunner::_remap()`` has been changed to fix a bug. Enhancements ************ From 60ee4f3b946b7984ce7465d4770b4cd97bd3d2fe Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 11:09:11 +0900 Subject: [PATCH 1825/2325] config: disable auto-routing by default --- app/Config/Routes.php | 2 +- system/Router/RouteCollection.php | 2 +- tests/system/CodeIgniterTest.php | 14 ++++++++++++++ tests/system/Commands/RoutesTest.php | 1 + .../Utilities/Routes/FilterCollectorTest.php | 2 ++ tests/system/Router/RouterTest.php | 4 ++++ user_guide_src/source/changelogs/v4.2.0.rst | 1 + 7 files changed, 24 insertions(+), 2 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 0060a6f67dff..2b35d0dda6f8 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -21,7 +21,7 @@ $routes->setDefaultMethod('index'); $routes->setTranslateURIDashes(false); $routes->set404Override(); -$routes->setAutoRoute(true); +$routes->setAutoRoute(false); /* * -------------------------------------------------------------------- diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 65bf4f4985af..a1dd7b1a8fe7 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -76,7 +76,7 @@ class RouteCollection implements RouteCollectionInterface * * @var bool */ - protected $autoRoute = true; + protected $autoRoute = false; /** * A callable that will be shown diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index 42706e39d110..a29879522e37 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -47,6 +47,8 @@ protected function tearDown(): void if (count(ob_list_handlers()) > 1) { ob_end_clean(); } + + $this->resetServices(); } public function testRunEmptyDefaultRoute() @@ -469,6 +471,12 @@ public function testSpoofRequestMethodCanUsePUT() $_POST['_method'] = 'PUT'; + $routes = \Config\Services::routes(); + $routes->setDefaultNamespace('App\Controllers'); + $routes->resetRoutes(); + $routes->post('/', 'Home::index'); + $routes->put('/', 'Home::index'); + ob_start(); $this->codeigniter->useSafeOutput(true)->run(); ob_get_clean(); @@ -487,6 +495,12 @@ public function testSpoofRequestMethodCannotUseGET() $_POST['_method'] = 'GET'; + $routes = \Config\Services::routes(); + $routes->setDefaultNamespace('App\Controllers'); + $routes->resetRoutes(); + $routes->post('/', 'Home::index'); + $routes->get('/', 'Home::index'); + ob_start(); $this->codeigniter->useSafeOutput(true)->run(); ob_get_clean(); diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index dd5e6b3280a8..1787e8bef3fa 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -67,6 +67,7 @@ public function testRoutesCommandRouteFilterAndAutoRoute() $routes->setDefaultNamespace('App\Controllers'); $routes->resetRoutes(); $routes->get('/', 'Home::index', ['filter' => 'csrf']); + $routes->setAutoRoute(true); command('routes'); diff --git a/tests/system/Commands/Utilities/Routes/FilterCollectorTest.php b/tests/system/Commands/Utilities/Routes/FilterCollectorTest.php index 6002323d3393..5037c148b704 100644 --- a/tests/system/Commands/Utilities/Routes/FilterCollectorTest.php +++ b/tests/system/Commands/Utilities/Routes/FilterCollectorTest.php @@ -23,6 +23,8 @@ public function testGet() { $routes = Services::routes(); $routes->resetRoutes(); + $routes->setDefaultNamespace('App\Controllers'); + $routes->get('/', 'Home::index'); $collector = new FilterCollector(); diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index b2c476f5add6..d3ca04422c41 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -728,7 +728,10 @@ public function testAutoRouteMatchesZeroParams() public function testAutoRouteMethodEmpty() { $router = new Router($this->collection, $this->request); + $this->collection->setAutoRoute(true); + $router->handle('Home/'); + $this->assertSame('Home', $router->controllerName()); $this->assertSame('index', $router->methodName()); } @@ -775,6 +778,7 @@ public function testRegularExpressionPlaceholderWithUnicode() public function testRouterPriorDirectory() { $router = new Router($this->collection, $this->request); + $this->collection->setAutoRoute(true); $router->setDirectory('foo/bar/baz', false, true); $router->handle('Some_controller/some_method/param1/param2/param3'); diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index f12a13bcb416..55f7986375aa 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -43,6 +43,7 @@ Changes - The process of sending cookies has been moved to the ``Response`` class. Now the ``Session`` class doesn't send cookies, set them to the Response. - Validation. Changed generation of errors when using fields with a wildcard (*). Now the error key contains the full path. See :ref:`validation-getting-all-errors`. - ``Validation::getError()`` when using a wildcard will return all found errors matching the mask as a string. +- To make the default configuration more secure, auto-routing has been changed to disabled by default. Deprecations ************ From d9a2389bf4437bf811368568cd536ba216bc5fc1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 11:33:42 +0900 Subject: [PATCH 1826/2325] docs: move "Default Controller" in the "Auto Routing" --- user_guide_src/source/incoming/routing.rst | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index eb7d57370015..3a761ed1d5a0 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -465,31 +465,6 @@ then you can change this value to save typing: .. literalinclude:: routing/046.php -Default Controller -================== - -When a user visits the root of your site (i.e., example.com) the controller to use is determined by the value set by -the ``setDefaultController()`` method, unless a route exists for it explicitly. The default value for this is ``Home`` -which matches the controller at **app/Controllers/Home.php**: - -.. literalinclude:: routing/047.php - -The default controller is also used when no matching route has been found, and the URI would point to a directory -in the controllers directory. For example, if the user visits **example.com/admin**, if a controller was found at -**app/Controllers/Admin/Home.php**, it would be used. - -Default Method -============== - -This works similar to the default controller setting, but is used to determine the default method that is used -when a controller is found that matches the URI, but no segment exists for the method. The default value is -``index``. - -In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the -``Products::listAll()`` method would be executed: - -.. literalinclude:: routing/048.php - Translate URI Dashes ==================== @@ -566,8 +541,33 @@ and executes the corresponding controller method. The auto-routing is enabled by .. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. +Default Controller +================== + +When a user visits the root of your site (i.e., example.com) the controller to use is determined by the value set by +the ``setDefaultController()`` method, unless a route exists for it explicitly. The default value for this is ``Home`` +which matches the controller at **app/Controllers/Home.php**: + +.. literalinclude:: routing/047.php + +The default controller is also used when no matching route has been found, and the URI would point to a directory +in the controllers directory. For example, if the user visits **example.com/admin**, if a controller was found at +**app/Controllers/Admin/Home.php**, it would be used. + See :ref:`Auto Routing in Controllers ` for more info. +Default Method +============== + +This works similar to the default controller setting, but is used to determine the default method that is used +when a controller is found that matches the URI, but no segment exists for the method. The default value is +``index``. + +In this example, if the user were to visit **example.com/products**, and a ``Products`` controller existed, the +``Products::listAll()`` method would be executed: + +.. literalinclude:: routing/048.php + Confirming Routes ***************** From aa69f381eae378e867d940c38363efc548ec047f Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 11:40:19 +0900 Subject: [PATCH 1827/2325] docs: move "Default Method" in "Auto Routing" --- user_guide_src/source/incoming/routing.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 3a761ed1d5a0..d4b4c2f34cf1 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -539,10 +539,13 @@ and executes the corresponding controller method. The auto-routing is enabled by .. note:: To prevent misconfiguration and miscoding, we recommend that you disable the auto-routing feature. See :ref:`use-defined-routes-only`. +Configuration Options +===================== + .. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. Default Controller -================== +------------------ When a user visits the root of your site (i.e., example.com) the controller to use is determined by the value set by the ``setDefaultController()`` method, unless a route exists for it explicitly. The default value for this is ``Home`` @@ -557,7 +560,7 @@ in the controllers directory. For example, if the user visits **example.com/admi See :ref:`Auto Routing in Controllers ` for more info. Default Method -============== +-------------- This works similar to the default controller setting, but is used to determine the default method that is used when a controller is found that matches the URI, but no segment exists for the method. The default value is From fabcf1c4ab76efdc41faf24553d094bde2cee385 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 11:53:07 +0900 Subject: [PATCH 1828/2325] docs: add "Enable Auto Routing" --- user_guide_src/source/incoming/routing.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index d4b4c2f34cf1..04beafd9f2dc 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -515,6 +515,15 @@ It is recommended that all routes are defined in the **app/Config/Routes.php** f However, CodeIgniter can also automatically route HTTP requests based on conventions and execute the corresponding controller methods. +Enable Auto Routing +=================== + +Since v4.2.0, the auto-routing is disabled by default. + +To use it, you need to change the setting ``setAutoRoute()`` option to true in **app/Config/Routes.php**:: + + $routes->setAutoRoute(true); + URI Segments ============ From a514043270fa56efe301f37e5a4955d140a72527 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 11:53:54 +0900 Subject: [PATCH 1829/2325] docs: update existing description for disabling auto-routing by default --- user_guide_src/source/incoming/controllers.rst | 6 +++--- user_guide_src/source/incoming/routing.rst | 14 +++++++++----- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 037710255100..287d6ae28153 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -114,10 +114,10 @@ Auto Routing This section describes the functionality of the auto-routing. It automatically routes an HTTP request, and executes the corresponding controller method -without route definitions. The auto-routing is enabled by default. +without route definitions. The auto-routing is disabled by default. .. note:: To prevent misconfiguration and miscoding, we recommend that you disable - the auto-routing feature. See :ref:`use-defined-routes-only`. + the auto-routing feature. .. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. @@ -220,7 +220,7 @@ Your method will be passed URI segments 3 and 4 (``'sandals'`` and ``'123'``): .. literalinclude:: controllers/014.php .. important:: If you are using the :doc:`URI Routing ` - feature, the segments passed to your method will be the re-routed + feature, the segments passed to your method will be the defined ones. Defining a Default Controller diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 04beafd9f2dc..77d68533fba2 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -312,7 +312,7 @@ available from the command line: .. literalinclude:: routing/032.php -.. warning:: If you don't disable auto-routing and place the command file in **app/Controllers**, +.. warning:: If you enable auto-routing and place the command file in **app/Controllers**, anyone could access the command with the help of auto-routing via HTTP. Global Options @@ -515,6 +515,11 @@ It is recommended that all routes are defined in the **app/Config/Routes.php** f However, CodeIgniter can also automatically route HTTP requests based on conventions and execute the corresponding controller methods. +.. warning:: To prevent misconfiguration and miscoding, we recommend that you disable + the auto-routing feature. + +.. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. + Enable Auto Routing =================== @@ -543,15 +548,14 @@ In the above example, CodeIgniter would attempt to find a controller named **Hel and executes ``index()`` method with passing ``'1'`` as the first argument. We call this "**Auto Routes**". CodeIgniter automatically routes an HTTP request, -and executes the corresponding controller method. The auto-routing is enabled by default. +and executes the corresponding controller method. The auto-routing is disabled by default. -.. note:: To prevent misconfiguration and miscoding, we recommend that you disable - the auto-routing feature. See :ref:`use-defined-routes-only`. +See :ref:`Auto Routing in Controllers ` for more info. Configuration Options ===================== -.. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. +These options are available at the top of **app/Config/Routes.php**. Default Controller ------------------ From 1e6a48625fd77546390107b71823a095f9b13428 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 12:51:06 +0900 Subject: [PATCH 1830/2325] docs: replace remap with map --- user_guide_src/source/incoming/controllers.rst | 2 +- user_guide_src/source/incoming/routing.rst | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 287d6ae28153..a4c635a6532c 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -279,7 +279,7 @@ called if the URL contains *only* the sub-directory. Simply put a controller in there that matches the name of your default controller as specified in your **app/Config/Routes.php** file. -CodeIgniter also permits you to remap your URIs using its :doc:`URI Routing ` feature. +CodeIgniter also permits you to map your URIs using its :doc:`URI Routing ` feature. Remapping Method Calls ********************** diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 77d68533fba2..41741fb93ebf 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -76,22 +76,22 @@ Examples Here are a few basic routing examples. -A URL containing the word **journals** in the first segment will be remapped to the ``\App\Controllers\Blogs`` class, +A URL containing the word **journals** in the first segment will be mapped to the ``\App\Controllers\Blogs`` class, and the default method, which is usually ``index()``: .. literalinclude:: routing/006.php -A URL containing the segments **blog/joe** will be remapped to the ``\App\Controllers\Blogs`` class and the ``users`` method. +A URL containing the segments **blog/joe** will be mapped to the ``\App\Controllers\Blogs`` class and the ``users`` method. The ID will be set to ``34``: .. literalinclude:: routing/007.php -A URL with **product** as the first segment, and anything in the second will be remapped to the ``\App\Controllers\Catalog`` class +A URL with **product** as the first segment, and anything in the second will be mapped to the ``\App\Controllers\Catalog`` class and the ``productLookup`` method: .. literalinclude:: routing/008.php -A URL with **product** as the first segment, and a number in the second will be remapped to the ``\App\Controllers\Catalog`` class +A URL with **product** as the first segment, and a number in the second will be mapped to the ``\App\Controllers\Catalog`` class and the ``productLookupByID`` method passing in the match as a variable to the method: .. literalinclude:: routing/009.php From 08ecf84170635df1235ae757c6d9ff4b4ee1fe92 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 1 Mar 2022 12:55:26 +0900 Subject: [PATCH 1831/2325] docs: add `()` at the end of method names --- user_guide_src/source/incoming/routing.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 41741fb93ebf..4103abb6e428 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -81,18 +81,18 @@ and the default method, which is usually ``index()``: .. literalinclude:: routing/006.php -A URL containing the segments **blog/joe** will be mapped to the ``\App\Controllers\Blogs`` class and the ``users`` method. +A URL containing the segments **blog/joe** will be mapped to the ``\App\Controllers\Blogs`` class and the ``users()`` method. The ID will be set to ``34``: .. literalinclude:: routing/007.php A URL with **product** as the first segment, and anything in the second will be mapped to the ``\App\Controllers\Catalog`` class -and the ``productLookup`` method: +and the ``productLookup()`` method: .. literalinclude:: routing/008.php A URL with **product** as the first segment, and a number in the second will be mapped to the ``\App\Controllers\Catalog`` class -and the ``productLookupByID`` method passing in the match as a variable to the method: +and the ``productLookupByID()`` method passing in the match as a variable to the method: .. literalinclude:: routing/009.php From ab1d3d862c2774b51e432279412124daa5344e04 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 2 Mar 2022 09:32:49 +0900 Subject: [PATCH 1832/2325] docs: update Tutorial --- .../source/tutorial/create_news_items.rst | 2 +- .../source/tutorial/create_news_items/004.php | 5 + .../source/tutorial/news_section.rst | 3 +- .../source/tutorial/news_section/008.php | 5 + .../source/tutorial/static_pages.rst | 120 +++++++----------- .../source/tutorial/static_pages/003.php | 6 + .../source/tutorial/static_pages/004.php | 1 + 7 files changed, 68 insertions(+), 74 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 32bc4b703e18..49ebc36c2bc3 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -119,7 +119,7 @@ Routing Before you can start adding news items into your CodeIgniter application you have to add an extra rule to **app/Config/Routes.php** file. Make sure your -file contains the following. This makes sure CodeIgniter sees ``create`` +file contains the following. This makes sure CodeIgniter sees ``create()`` as a method instead of a news item's slug. You can read more about different routing types :doc:`here `. diff --git a/user_guide_src/source/tutorial/create_news_items/004.php b/user_guide_src/source/tutorial/create_news_items/004.php index c8c66824fd82..8a0905770c82 100644 --- a/user_guide_src/source/tutorial/create_news_items/004.php +++ b/user_guide_src/source/tutorial/create_news_items/004.php @@ -1,6 +1,11 @@ match(['get', 'post'], 'news/create', 'News::create'); $routes->get('news/(:segment)', 'News::view/$1'); $routes->get('news', 'News::index'); +$routes->get('pages', 'Pages::index'); $routes->get('(:any)', 'Pages::view/$1'); + +// ... diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index 2797c8a5cfaa..a27902819265 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -171,8 +171,7 @@ The only thing left to do is create the corresponding view at Routing ******* -Because of the wildcard routing rule created earlier, you need an extra -route to view the controller that you just made. Modify your routing file +Modify your routing file (**app/Config/Routes.php**) so it looks as follows. This makes sure the requests reach the ``News`` controller instead of going directly to the ``Pages`` controller. The first line routes URI's diff --git a/user_guide_src/source/tutorial/news_section/008.php b/user_guide_src/source/tutorial/news_section/008.php index 8943925258bd..4ba41638ef7f 100644 --- a/user_guide_src/source/tutorial/news_section/008.php +++ b/user_guide_src/source/tutorial/news_section/008.php @@ -1,5 +1,10 @@ get('news/(:segment)', 'News::view/$1'); $routes->get('news', 'News::index'); +$routes->get('pages', 'Pages::index'); $routes->get('(:any)', 'Pages::view/$1'); + +// ... diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index 5128d6665e2c..6c39f82b5f80 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -9,20 +9,6 @@ The first thing you're going to do is set up a **controller** to handle static pages. A controller is simply a class that helps delegate work. It is the glue of your web application. -For example, when a call is made to:: - - http://example.com/news/latest/10 - -We might imagine that there is a controller named "news". The method -being called on news would be "latest". The news method's job could be to -grab 10 news items, and render them on the page. Very often in MVC, -you'll see URL patterns that match:: - - http://example.com/[controller-class]/[controller-method]/[arguments] - -As URL schemes become more complex, this may change. But for now, this -is all we will need to know. - Let's Make our First Controller ******************************* @@ -126,59 +112,11 @@ view. throw errors on case-sensitive platforms. You can read more about it :doc:`here `. -Running the App -*************** - -Ready to test? You cannot run the app using PHP's built-in server, -since it will not properly process the ``.htaccess`` rules that are provided in -``public``, and which eliminate the need to specify "index.php/" -as part of a URL. CodeIgniter has its own command that you can use though. - -From the command line, at the root of your project:: - - > php spark serve - -will start a web server, accessible on port 8080. If you set the location field -in your browser to ``localhost:8080``, you should see the CodeIgniter welcome page. - -You can now try several URLs in the browser location field, to see what the ``Pages`` -controller you made above produces... - -.. table:: - :widths: 20 80 - - +---------------------------------+-----------------------------------------------------------------+ - | URL | Will show | - +=================================+=================================================================+ - | localhost:8080/pages | the results from the `index` method inside our `Pages` | - | | controller, which is to display the CodeIgniter "welcome" page, | - | | because "index" is the default controller method | - +---------------------------------+-----------------------------------------------------------------+ - | localhost:8080/pages/index | the CodeIgniter "welcome" page, because we explicitly asked for | - | | the "index" method | - +---------------------------------+-----------------------------------------------------------------+ - | localhost:8080/pages/view | the "home" page that you made above, because it is the default | - | | "page" parameter to the ``view()`` method. | - +---------------------------------+-----------------------------------------------------------------+ - | localhost:8080/pages/view/home | show the "home" page that you made above, because we explicitly | - | | asked for it | - +---------------------------------+-----------------------------------------------------------------+ - | localhost:8080/pages/view/about | the "about" page that you made above, because we explicitly | - | | asked for it | - +---------------------------------+-----------------------------------------------------------------+ - | localhost:8080/pages/view/shop | a "404 - File Not Found" error page, because there is no | - | | `app/Views/pages/shop.php` | - +---------------------------------+-----------------------------------------------------------------+ - Routing ******* -The controller is now functioning! - -Using custom routing rules, you have the power to map any URI to any -controller and method, and break free from the normal convention:: - - http://example.com/[controller-class]/[controller-method]/[arguments] +We have made the controller. The next thing is to set routing rules. +Routing associates a URI with a controller's method. Let's do that. Open the routing file located at **app/Config/Routes.php** and look for the "Route Definitions" @@ -191,9 +129,10 @@ The only uncommented line there to start with should be: This directive says that any incoming request without any content specified should be handled by the ``index()`` method inside the ``Home`` controller. -Add the following line, **after** the route directive for '/'. +Add the following lines, **after** the route directive for '/'. .. literalinclude:: static_pages/004.php + :lines: 2- CodeIgniter reads its routing rules from top to bottom and routes the request to the first matching rule. Each rule is a regular expression @@ -205,18 +144,57 @@ arguments. More information about routing can be found in the URI Routing :doc:`documentation `. -Here, the second rule in the ``$routes`` object matches **any** request -using the wildcard string ``(:any)``. and passes the parameter to the +Here, the second rule in the ``$routes`` object matches GET request +to the URI path ``/pages`` maps the ``index()`` method of the ``Pages`` class. + +The third rule in the ``$routes`` object matches GET request to **any** URI path +using the wildcard string ``(:any)``, and passes the parameter to the ``view()`` method of the ``Pages`` class. +Running the App +*************** + +Ready to test? You cannot run the app using PHP's built-in server, +since it will not properly process the ``.htaccess`` rules that are provided in +``public``, and which eliminate the need to specify "index.php/" +as part of a URL. CodeIgniter has its own command that you can use though. + +From the command line, at the root of your project:: + + > php spark serve + +will start a web server, accessible on port 8080. If you set the location field +in your browser to ``localhost:8080``, you should see the CodeIgniter welcome page. + Now visit ``localhost:8080/home``. Did it get routed correctly to the ``view()`` -method in the pages controller? Awesome! +method in the ``Pages`` controller? Awesome! You should see something like the following: .. image:: ../images/tutorial1.png :align: center -.. note:: When manually specifying routes, it is recommended to disable - auto-routing by setting ``$routes->setAutoRoute(false);`` in the **Routes.php** file. - This ensures that only routes you define can be accessed. +You can now try several URLs in the browser location field, to see what the ``Pages`` +controller you made above produces... + +.. table:: + :widths: 20 80 + + +---------------------------------+-----------------------------------------------------------------+ + | URL | Will show | + +=================================+=================================================================+ + | localhost:8080/pages | the results from the ``index()`` method inside our ``Pages`` | + | | controller, which is to display the CodeIgniter "welcome" page. | + +---------------------------------+-----------------------------------------------------------------+ + | localhost:8080/pages/view | the "home" page that you made above, because it is the default | + | | "page" parameter to the ``view()`` method. | + +---------------------------------+-----------------------------------------------------------------+ + | localhost:8080/pages/view/home | show the "home" page that you made above, because we explicitly | + | | asked for it. | + +---------------------------------+-----------------------------------------------------------------+ + | localhost:8080/pages/view/about | the "about" page that you made above, because we explicitly | + | | asked for it. | + +---------------------------------+-----------------------------------------------------------------+ + | localhost:8080/pages/view/shop | a "404 - File Not Found" error page, because there is no | + | | **app/Views/pages/shop.php**. | + +---------------------------------+-----------------------------------------------------------------+ diff --git a/user_guide_src/source/tutorial/static_pages/003.php b/user_guide_src/source/tutorial/static_pages/003.php index d799d1cf0fb5..956c097d390f 100644 --- a/user_guide_src/source/tutorial/static_pages/003.php +++ b/user_guide_src/source/tutorial/static_pages/003.php @@ -1,3 +1,9 @@ get('/', 'Home::index'); + +// ... diff --git a/user_guide_src/source/tutorial/static_pages/004.php b/user_guide_src/source/tutorial/static_pages/004.php index f998b89762fd..a48a8caf18cb 100644 --- a/user_guide_src/source/tutorial/static_pages/004.php +++ b/user_guide_src/source/tutorial/static_pages/004.php @@ -1,3 +1,4 @@ get('pages', 'Pages::index'); $routes->get('(:any)', 'Pages::view/$1'); From 4027b1f9247ea3d6cf5b18c26a3d21179ccd7a67 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 2 Mar 2022 10:00:10 +0900 Subject: [PATCH 1833/2325] docs: change "note" to "warning" --- user_guide_src/source/incoming/controllers.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index a4c635a6532c..928a16fff9b3 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -116,7 +116,7 @@ This section describes the functionality of the auto-routing. It automatically routes an HTTP request, and executes the corresponding controller method without route definitions. The auto-routing is disabled by default. -.. note:: To prevent misconfiguration and miscoding, we recommend that you disable +.. warning:: To prevent misconfiguration and miscoding, we recommend that you disable the auto-routing feature. .. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. From c7edb7c4c26ce82044b29607177de761e84b5311 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 2 Mar 2022 12:26:02 +0900 Subject: [PATCH 1834/2325] docs: make warning more detailed --- user_guide_src/source/incoming/controllers.rst | 5 +++-- user_guide_src/source/incoming/routing.rst | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 928a16fff9b3..99c22b5a356d 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -116,8 +116,9 @@ This section describes the functionality of the auto-routing. It automatically routes an HTTP request, and executes the corresponding controller method without route definitions. The auto-routing is disabled by default. -.. warning:: To prevent misconfiguration and miscoding, we recommend that you disable - the auto-routing feature. +.. warning:: To prevent misconfiguration and miscoding, we recommend that you do not use + the auto-routing feature. It is easy to create vulnerable apps where controller filters + or CSRF protection are bypassed. .. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 4103abb6e428..504e555dd76c 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -515,8 +515,9 @@ It is recommended that all routes are defined in the **app/Config/Routes.php** f However, CodeIgniter can also automatically route HTTP requests based on conventions and execute the corresponding controller methods. -.. warning:: To prevent misconfiguration and miscoding, we recommend that you disable - the auto-routing feature. +.. warning:: To prevent misconfiguration and miscoding, we recommend that you do not use + the auto-routing feature. It is easy to create vulnerable apps where controller filters + or CSRF protection are bypassed. .. important:: The auto-routing routes a HTTP request with **any** HTTP method to a controller method. From d811d5b37ad4ede6d04afb4dd51ff510481e9205 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 2 Mar 2022 12:27:06 +0900 Subject: [PATCH 1835/2325] docs: update description --- user_guide_src/source/cli/cli.rst | 2 +- user_guide_src/source/incoming/routing.rst | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/cli/cli.rst b/user_guide_src/source/cli/cli.rst index f3ffcc9285f6..bd57d4f608fd 100644 --- a/user_guide_src/source/cli/cli.rst +++ b/user_guide_src/source/cli/cli.rst @@ -88,7 +88,7 @@ works exactly like a normal route definition: For more information, see the :ref:`Routes ` page. -.. warning:: If you don't disable auto-routing and place the command file in **app/Controllers**, +.. warning:: If you enable auto-routing and place the command file in **app/Controllers**, anyone could access the command with the help of auto-routing via HTTP. The CLI Library diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 504e555dd76c..4989f0891e0b 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -479,8 +479,12 @@ dash isn't a valid class or method name character and would cause a fatal error Use Defined Routes Only ======================= +Since v4.2.0, the auto-routing is disabled by default. + When no defined route is found that matches the URI, the system will attempt to match that URI against the -controllers and methods as described in :ref:`auto-routing`. You can disable this automatic matching, and restrict routes +controllers and methods when :ref:`auto-routing` is enabled. + +You can disable this automatic matching, and restrict routes to only those defined by you, by setting the ``setAutoRoute()`` option to false: .. literalinclude:: routing/050.php From 1fe49bafc27d3483f9d0c863c4dbc4c29fb853fb Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 2 Mar 2022 12:33:35 +0900 Subject: [PATCH 1836/2325] docs: add warning as a comment --- app/Config/Routes.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 2b35d0dda6f8..15371af7de5e 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -21,7 +21,10 @@ $routes->setDefaultMethod('index'); $routes->setTranslateURIDashes(false); $routes->set404Override(); -$routes->setAutoRoute(false); +// The auto-routing is very dangerous. It is easy to create vulnerable apps +// where controller filters or CSRF protection are bypassed. +// It is recommended that you do not set it to `true`. +//$routes->setAutoRoute(false); /* * -------------------------------------------------------------------- From a65bc3ab2f5302c11bff26e545b12ec7b75e4e8f Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 3 Mar 2022 09:21:21 +0900 Subject: [PATCH 1837/2325] docs: add about the config change of auto-routing in Upgrade Note --- user_guide_src/source/installation/upgrade_420.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/installation/upgrade_420.rst b/user_guide_src/source/installation/upgrade_420.rst index a302f113ae61..daf89b39290f 100644 --- a/user_guide_src/source/installation/upgrade_420.rst +++ b/user_guide_src/source/installation/upgrade_420.rst @@ -49,7 +49,8 @@ Content Changes The following files received significant changes (including deprecations or visual adjustments) and it is recommended that you merge the updated versions with your application: -* +* ``app/Config/Routes.php`` + * To make the default configuration more secure, auto-routing has been changed to disabled by default. All Changes =========== From dafce4979cba1aed3b8a39705b919014fa6cd340 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 31 Mar 2022 10:34:00 +0900 Subject: [PATCH 1838/2325] feat: add options to change delimitors for conditionals To avoid accidentally changing JavaScript code. --- system/View/Parser.php | 45 +++++++++++++++++++++++++++-- tests/system/View/ParserTest.php | 49 ++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 3 deletions(-) diff --git a/system/View/Parser.php b/system/View/Parser.php index 6834c003e500..665347d8f978 100644 --- a/system/View/Parser.php +++ b/system/View/Parser.php @@ -37,6 +37,16 @@ class Parser extends View */ public $rightDelimiter = '}'; + /** + * Left delimiter characters for conditionals + */ + protected string $leftConditionalDelimiter = '{'; + + /** + * Right delimiter characters for conditionals + */ + protected string $rightConditionalDelimiter = '}'; + /** * Stores extracted noparse blocks. * @@ -405,7 +415,14 @@ public function insertNoparse(string $template): string */ protected function parseConditionals(string $template): string { - $pattern = '/\{\s*(if|elseif)\s*((?:\()?(.*?)(?:\))?)\s*\}/ms'; + $leftDelimiter = preg_quote($this->leftConditionalDelimiter, '/'); + $rightDelimiter = preg_quote($this->rightConditionalDelimiter, '/'); + + $pattern = '/' + . $leftDelimiter + . '\s*(if|elseif)\s*((?:\()?(.*?)(?:\))?)\s*' + . $rightDelimiter + . '/ms'; /* * For each match: @@ -424,8 +441,16 @@ protected function parseConditionals(string $template): string $template = str_replace($match[0], $statement, $template); } - $template = preg_replace('/\{\s*else\s*\}/ms', '', $template); - $template = preg_replace('/\{\s*endif\s*\}/ms', '', $template); + $template = preg_replace( + '/' . $leftDelimiter . '\s*else\s*' . $rightDelimiter . '/ms', + '', + $template + ); + $template = preg_replace( + '/' . $leftDelimiter . '\s*endif\s*' . $rightDelimiter . '/ms', + '', + $template + ); // Parse the PHP itself, or insert an error so they can debug ob_start(); @@ -461,6 +486,20 @@ public function setDelimiters($leftDelimiter = '{', $rightDelimiter = '}'): Rend return $this; } + /** + * Over-ride the substitution conditional delimiters. + * + * @param string $leftDelimiter + * @param string $rightDelimiter + */ + public function setConditionalDelimiters($leftDelimiter = '{', $rightDelimiter = '}'): RendererInterface + { + $this->leftConditionalDelimiter = $leftDelimiter; + $this->rightConditionalDelimiter = $rightDelimiter; + + return $this; + } + /** * Handles replacing a pseudo-variable with the actual content. Will double-check * for escaping brackets. diff --git a/tests/system/View/ParserTest.php b/tests/system/View/ParserTest.php index 3462b0cc2a84..bf307a419f61 100644 --- a/tests/system/View/ParserTest.php +++ b/tests/system/View/ParserTest.php @@ -938,4 +938,53 @@ public function testRenderFindsOtherView() $expected = '

    Hello World

    '; $this->assertSame($expected, $this->parser->render('Simpler.html')); } + + public function testChangedConditionalDelimitersTrue() + { + $this->parser->setConditionalDelimiters('{%', '%}'); + + $data = [ + 'doit' => true, + 'dontdoit' => false, + ]; + $this->parser->setData($data); + + $template = '{% if $doit %}Howdy{% endif %}{% if $dontdoit === false %}Welcome{% endif %}'; + $output = $this->parser->renderString($template); + + $this->assertSame('HowdyWelcome', $output); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5831 + */ + public function testChangeConditionalDelimitersWorkWithJavaScriptCode() + { + $this->parser->setConditionalDelimiters('{%', '%}'); + + $data = [ + 'message' => 'Warning!', + ]; + $this->parser->setData($data); + + $template = <<<'EOL' + + EOL; + $expected = <<<'EOL' + + EOL; + $this->assertSame($expected, $this->parser->renderString($template)); + } } From 2d90f0cc6ca2bca0927bd73413d04f60d77fd9a2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 31 Mar 2022 10:55:53 +0900 Subject: [PATCH 1839/2325] docs: add setConditionalDelimiters() --- .../source/outgoing/view_parser.rst | 25 +++++++++++++++++++ .../source/outgoing/view_parser/027.php | 3 +++ 2 files changed, 28 insertions(+) create mode 100644 user_guide_src/source/outgoing/view_parser/027.php diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 2e615e52bdb9..752dcc489590 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -290,6 +290,31 @@ of the comparison operators you would normally, like ``==``, ``===``, ``!==``, ` .. warning:: In the background, conditionals are parsed using an ``eval()``, so you must ensure that you take care with the user data that is used within conditionals, or you could open your application up to security risks. +Changing the Conditional Delimiters +----------------------------------- + +If you have JavaScript code like the following in your templates, the Parser raises a syntax error because there are strings that can be interpreted as a conditional:: + + + +In that case, you can change the delimiters for conditionals with the ``setConditionalDelimiters()`` method to avoid misinterpretations: + +.. literalinclude:: view_parser/027.php + +In this case, you will write code in your template:: + + {% if $role=='admin' %} +

    Welcome, Admin

    + {% else %} +

    Welcome, User

    + {% endif %} + Escaping Data ============= diff --git a/user_guide_src/source/outgoing/view_parser/027.php b/user_guide_src/source/outgoing/view_parser/027.php new file mode 100644 index 000000000000..84730679ced5 --- /dev/null +++ b/user_guide_src/source/outgoing/view_parser/027.php @@ -0,0 +1,3 @@ +setConditionalDelimiters('{%', '%}'); From e521f66fdabee7d0d109761caf084809132ccebc Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 31 Mar 2022 11:40:15 +0900 Subject: [PATCH 1840/2325] docs: replace variables with properties They are different. --- user_guide_src/source/tutorial/static_pages.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index 6c39f82b5f80..668683995231 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -30,7 +30,7 @@ displays the CodeIgniter welcome page. The ``Pages`` class is extending the ``BaseController`` class that extends the ``CodeIgniter\Controller`` class. This means that the new Pages class can access the -methods and variables defined in the ``CodeIgniter\Controller`` class +methods and properties defined in the ``CodeIgniter\Controller`` class (**system/Controller.php**). The **controller is what will become the center of every request** to From 5dacb15c7ccd93ecb74b99d9788397941dd642cb Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 31 Mar 2022 11:59:08 +0900 Subject: [PATCH 1841/2325] fix: remove session _ci_validation_errors before running validation --- system/Validation/Validation.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/system/Validation/Validation.php b/system/Validation/Validation.php index 155efc223492..f330c91799f6 100644 --- a/system/Validation/Validation.php +++ b/system/Validation/Validation.php @@ -108,6 +108,12 @@ public function __construct($config, RendererInterface $view) */ public function run(?array $data = null, ?string $group = null, ?string $dbGroup = null): bool { + // If there are still validation errors for redirect_with_input request, remove them. + // See `getErrors()` method. + if (isset($_SESSION, $_SESSION['_ci_validation_errors'])) { + unset($_SESSION['_ci_validation_errors']); + } + $data ??= $this->data; // i.e. is_unique From 35c2947d1a1988f37a422275e5ba037f32f11aa3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 31 Mar 2022 11:40:53 +0900 Subject: [PATCH 1842/2325] docs: remove `echo` in the controller and use `return` echo() has side effects, so return is better. --- .../source/tutorial/create_news_items/002.php | 10 +++++----- user_guide_src/source/tutorial/news_section/004.php | 6 +++--- user_guide_src/source/tutorial/news_section/006.php | 6 +++--- user_guide_src/source/tutorial/static_pages/002.php | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/user_guide_src/source/tutorial/create_news_items/002.php b/user_guide_src/source/tutorial/create_news_items/002.php index cdebb0a71e6a..66ff5e26776b 100644 --- a/user_guide_src/source/tutorial/create_news_items/002.php +++ b/user_guide_src/source/tutorial/create_news_items/002.php @@ -18,11 +18,11 @@ public function create() 'body' => $this->request->getPost('body'), ]); - echo view('news/success'); - } else { - echo view('templates/header', ['title' => 'Create a news item']); - echo view('news/create'); - echo view('templates/footer'); + return view('news/success'); } + + return view('templates/header', ['title' => 'Create a news item']) + . view('news/create') + . view('templates/footer'); } } diff --git a/user_guide_src/source/tutorial/news_section/004.php b/user_guide_src/source/tutorial/news_section/004.php index 475b86fa2f45..b62562bfe351 100644 --- a/user_guide_src/source/tutorial/news_section/004.php +++ b/user_guide_src/source/tutorial/news_section/004.php @@ -15,8 +15,8 @@ public function index() 'title' => 'News archive', ]; - echo view('templates/header', $data); - echo view('news/overview', $data); - echo view('templates/footer', $data); + return view('templates/header', $data) + . view('news/overview', $data) + . view('templates/footer', $data); } } diff --git a/user_guide_src/source/tutorial/news_section/006.php b/user_guide_src/source/tutorial/news_section/006.php index 36faacb39a50..8bfc123e43f7 100644 --- a/user_guide_src/source/tutorial/news_section/006.php +++ b/user_guide_src/source/tutorial/news_section/006.php @@ -18,8 +18,8 @@ public function view($slug = null) $data['title'] = $data['news']['title']; - echo view('templates/header', $data); - echo view('news/view', $data); - echo view('templates/footer', $data); + return view('templates/header', $data) + . view('news/view', $data) + . view('templates/footer', $data); } } diff --git a/user_guide_src/source/tutorial/static_pages/002.php b/user_guide_src/source/tutorial/static_pages/002.php index 970e663558d5..9f80c4556a58 100644 --- a/user_guide_src/source/tutorial/static_pages/002.php +++ b/user_guide_src/source/tutorial/static_pages/002.php @@ -13,8 +13,8 @@ public function view($page = 'home') $data['title'] = ucfirst($page); // Capitalize the first letter - echo view('templates/header', $data); - echo view('pages/' . $page, $data); - echo view('templates/footer', $data); + return view('templates/header', $data) + . view('pages/' . $page, $data) + . view('templates/footer', $data); } } From 59260c1cceda48673214e82b4607ba8567f135c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Apr 2022 11:27:15 +0900 Subject: [PATCH 1843/2325] docs: remove unneeded & in sample code --- user_guide_src/source/models/model/055.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/models/model/055.php b/user_guide_src/source/models/model/055.php index 1d62c54ba058..537199753d49 100644 --- a/user_guide_src/source/models/model/055.php +++ b/user_guide_src/source/models/model/055.php @@ -8,8 +8,8 @@ class UserModel { protected $db; - public function __construct(ConnectionInterface &$db) + public function __construct(ConnectionInterface $db) { - $this->db = &$db; + $this->db = $db; } } From d84440415a86cfd5deb32a88d74bbf4236ef9e75 Mon Sep 17 00:00:00 2001 From: Toto Date: Fri, 1 Apr 2022 21:26:11 +0700 Subject: [PATCH 1844/2325] update link https://codeigniter.com/en/contribute not found --- app/Views/welcome_message.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php index 9ee2e427c308..b982f58aa158 100644 --- a/app/Views/welcome_message.php +++ b/app/Views/welcome_message.php @@ -279,7 +279,7 @@

    CodeIgniter is a community driven project and accepts contributions of code and documentation from the community. Why not - + join us ?

    From 88a7f8b88a9bbd29daaea1f94deeb95a618ccd76 Mon Sep 17 00:00:00 2001 From: Lonnie Ezell Date: Fri, 1 Apr 2022 12:28:28 -0500 Subject: [PATCH 1845/2325] Added contributors to readme --- README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a8a3566e395d..d8525f299037 100644 --- a/README.md +++ b/README.md @@ -69,10 +69,19 @@ to optional packages, with their own repository. ## Contributing -We **are** accepting contributions from the community! +We **are** accepting contributions from the community! It doesn't matter whether you can code, write documentation, or help find bugs, +all contributions are welcome. Please read the [*Contributing to CodeIgniter*](https://github.com/codeigniter4/CodeIgniter4/blob/develop/contributing/README.md). +CodeIgniter has had thousands on contributions from people since its creation. This project would not be what it is without them. + + + + + +Made with [contrib.rocks](https://contrib.rocks). + ## Server Requirements PHP version 7.4 or higher is required, with the following extensions installed: From 27a74023bb25aefd752beb8f473393e84ac4fbfd Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 12:50:56 +0900 Subject: [PATCH 1846/2325] fix: FileLocator::listFiles() returns directories We don't need directories. --- system/Autoloader/FileLocator.php | 3 +++ tests/system/Autoloader/FileLocatorTest.php | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index f9734828b692..0b7b5d1d4345 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -309,6 +309,9 @@ public function listFiles(string $path): array $tempFiles = get_filenames($fullPath, true); + // Remove directories + $tempFiles = array_filter($tempFiles, static fn ($path) => strtolower(substr($path, -4)) === '.php'); + if (! empty($tempFiles)) { $files = array_merge($files, $tempFiles); } diff --git a/tests/system/Autoloader/FileLocatorTest.php b/tests/system/Autoloader/FileLocatorTest.php index 54a471d74453..3b86cfb7e535 100644 --- a/tests/system/Autoloader/FileLocatorTest.php +++ b/tests/system/Autoloader/FileLocatorTest.php @@ -211,6 +211,18 @@ public function testListFilesSimple() $this->assertTrue(in_array($expectedWin, $files, true) || in_array($expectedLin, $files, true)); } + public function testListFilesDoesNotContainDirectories() + { + $files = $this->locator->listFiles('Config/'); + + $directory = str_replace( + '/', + DIRECTORY_SEPARATOR, + APPPATH . 'Config/Boot' + ); + $this->assertNotContains($directory, $files); + } + public function testListFilesWithFileAsInput() { $files = $this->locator->listFiles('Config/App.php'); From 37e99bf13f1db654c546c2187d30dc9ec3c8b6f1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 12:53:10 +0900 Subject: [PATCH 1847/2325] docs: add @return --- system/Autoloader/FileLocator.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/Autoloader/FileLocator.php b/system/Autoloader/FileLocator.php index 0b7b5d1d4345..cfe12b79c2fa 100644 --- a/system/Autoloader/FileLocator.php +++ b/system/Autoloader/FileLocator.php @@ -289,6 +289,8 @@ public function findQualifiedNameFromPath(string $path) /** * Scans the defined namespaces, returning a list of all files * that are contained within the subpath specified by $path. + * + * @return string[] List of file paths */ public function listFiles(string $path): array { @@ -323,6 +325,8 @@ public function listFiles(string $path): array /** * Scans the provided namespace, returning a list of all files * that are contained within the sub path specified by $path. + * + * @return string[] List of file paths */ public function listNamespaceFiles(string $prefix, string $path): array { From 7aba08ab2f93a2e42a452a6fd995ad9b5c308318 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 12:53:51 +0900 Subject: [PATCH 1848/2325] fix: discoverCommands() loads incorrect classname --- system/CLI/Commands.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/system/CLI/Commands.php b/system/CLI/Commands.php index d153b3aa857a..2714db30bcf9 100644 --- a/system/CLI/Commands.php +++ b/system/CLI/Commands.php @@ -76,10 +76,6 @@ public function getCommands() /** * Discovers all commands in the framework and within user code, * and collects instances of them to work with. - * - * @TODO this approach (find qualified classname from path) causes error, - * when using Composer autoloader. - * See https://github.com/codeigniter4/CodeIgniter4/issues/5818 */ public function discoverCommands() { @@ -100,9 +96,9 @@ public function discoverCommands() // Loop over each file checking to see if a command with that // alias exists in the class. foreach ($files as $file) { - $className = $locator->findQualifiedNameFromPath($file); + $className = $locator->getClassname($file); - if (empty($className) || ! class_exists($className)) { + if ($className === '' || ! class_exists($className)) { continue; } From 4c1dc38a75847a52e9efe2dab952cdcdbbc46ed1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tuna=20=C3=87a=C4=9Flar=20G=C3=BCm=C3=BC=C5=9F?= Date: Sat, 2 Apr 2022 13:58:12 +0300 Subject: [PATCH 1849/2325] wrong function name. Needs to be orWhere(). There is no or_where in CI 4. --- user_guide_src/source/database/query_builder.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/query_builder.rst b/user_guide_src/source/database/query_builder.rst index d6e5b27aac36..5e05f0ce6b0b 100755 --- a/user_guide_src/source/database/query_builder.rst +++ b/user_guide_src/source/database/query_builder.rst @@ -804,7 +804,7 @@ Generates a **DELETE** SQL string and runs the query. .. literalinclude:: query_builder/093.php The first parameter is the where clause. -You can also use the ``where()`` or ``or_where()`` methods instead of passing +You can also use the ``where()`` or ``orWhere()`` methods instead of passing the data to the first parameter of the method: .. literalinclude:: query_builder/094.php From de7c19c456bf944e61c9e32835097727cd5d79ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 14:02:14 +0900 Subject: [PATCH 1850/2325] test: fix assertions If we use Compoesr autoloader, the path would be like `/vendor/composer/../../app/Controllers/Home.php`. --- tests/system/Autoloader/AutoloaderTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index f9a56cae82db..82e0307affad 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -88,7 +88,7 @@ public function testServiceAutoLoaderFromShareInstances() // look for Home controller, as that should be in base repo $actual = $autoloader->loadClass('App\Controllers\Home'); $expected = APPPATH . 'Controllers' . DIRECTORY_SEPARATOR . 'Home.php'; - $this->assertSame($expected, $actual); + $this->assertSame($expected, realpath($actual) ?: $actual); } public function testServiceAutoLoader() @@ -99,7 +99,7 @@ public function testServiceAutoLoader() // look for Home controller, as that should be in base repo $actual = $autoloader->loadClass('App\Controllers\Home'); $expected = APPPATH . 'Controllers' . DIRECTORY_SEPARATOR . 'Home.php'; - $this->assertSame($expected, $actual); + $this->assertSame($expected, realpath($actual) ?: $actual); } public function testExistingFile() From 46b3de8aef4d74600235693a09a9052c476df731 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 14:07:33 +0900 Subject: [PATCH 1851/2325] refactor: extract method --- system/Autoloader/Autoloader.php | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index bfd535f856ca..7423fc235586 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -106,7 +106,8 @@ public function initialize(Autoload $config, Modules $modules) // Should we load through Composer's namespaces, also? if ($modules->discoverInComposer) { - $this->discoverComposerNamespaces(); + $this->loadComposerClassmap(); + $this->loadComposerNamespaces(); } return $this; @@ -296,10 +297,7 @@ public function sanitizeFilename(string $filename): string return trim($filename, '.-_'); } - /** - * Locates autoload information from Composer, if available. - */ - protected function discoverComposerNamespaces() + protected function loadComposerNamespaces() { if (! is_file(COMPOSER_PATH)) { return; @@ -310,7 +308,6 @@ protected function discoverComposerNamespaces() */ $composer = include COMPOSER_PATH; $paths = $composer->getPrefixesPsr4(); - $classes = $composer->getClassMap(); unset($composer); @@ -327,6 +324,23 @@ protected function discoverComposerNamespaces() } $this->prefixes = array_merge($this->prefixes, $newPaths); + } + + protected function loadComposerClassmap(): void + { + if (! is_file(COMPOSER_PATH)) { + return; + } + + /** + * @var ClassLoader $composer + */ + $composer = include COMPOSER_PATH; + + $classes = $composer->getClassMap(); + + unset($composer); + $this->classmap = array_merge($this->classmap, $classes); } } From ceb9418bd5ea051fd0a71fb916cb90a399bb0bda Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 14:17:41 +0900 Subject: [PATCH 1852/2325] refactor: move duplicated logic up --- system/Autoloader/Autoloader.php | 44 ++++++++++++-------------------- 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 7423fc235586..88f3dd743470 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -104,10 +104,19 @@ public function initialize(Autoload $config, Modules $modules) $this->files = $config->files; } - // Should we load through Composer's namespaces, also? - if ($modules->discoverInComposer) { - $this->loadComposerClassmap(); - $this->loadComposerNamespaces(); + if (is_file(COMPOSER_PATH)) { + /** + * @var ClassLoader $composer + */ + $composer = include COMPOSER_PATH; + + // Should we load through Composer's namespaces, also? + if ($modules->discoverInComposer) { + $this->loadComposerClassmap($composer); + $this->loadComposerNamespaces($composer); + } + + unset($composer); } return $this; @@ -297,19 +306,9 @@ public function sanitizeFilename(string $filename): string return trim($filename, '.-_'); } - protected function loadComposerNamespaces() + protected function loadComposerNamespaces(ClassLoader $composer): void { - if (! is_file(COMPOSER_PATH)) { - return; - } - - /** - * @var ClassLoader $composer - */ - $composer = include COMPOSER_PATH; - $paths = $composer->getPrefixesPsr4(); - - unset($composer); + $paths = $composer->getPrefixesPsr4(); // Get rid of CodeIgniter so we don't have duplicates if (isset($paths['CodeIgniter\\'])) { @@ -326,21 +325,10 @@ protected function loadComposerNamespaces() $this->prefixes = array_merge($this->prefixes, $newPaths); } - protected function loadComposerClassmap(): void + protected function loadComposerClassmap(ClassLoader $composer): void { - if (! is_file(COMPOSER_PATH)) { - return; - } - - /** - * @var ClassLoader $composer - */ - $composer = include COMPOSER_PATH; - $classes = $composer->getClassMap(); - unset($composer); - $this->classmap = array_merge($this->classmap, $classes); } } From 954b647ddd7ac3df8f455a44b4cbfa13f6f68194 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 14:18:22 +0900 Subject: [PATCH 1853/2325] fix: don't load Composer classmap if $discoverInComposer is false Now it always loads and uses Composer classmap if it is available. --- system/Autoloader/Autoloader.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 88f3dd743470..f4c37b4d250e 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -110,9 +110,10 @@ public function initialize(Autoload $config, Modules $modules) */ $composer = include COMPOSER_PATH; + $this->loadComposerClassmap($composer); + // Should we load through Composer's namespaces, also? if ($modules->discoverInComposer) { - $this->loadComposerClassmap($composer); $this->loadComposerNamespaces($composer); } From 783835efddd6c383de74c42402380c95903f88f5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Apr 2022 14:20:09 +0900 Subject: [PATCH 1854/2325] refactor: extract method --- system/Autoloader/Autoloader.php | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index f4c37b4d250e..cca4a7d28f1e 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -105,22 +105,27 @@ public function initialize(Autoload $config, Modules $modules) } if (is_file(COMPOSER_PATH)) { - /** - * @var ClassLoader $composer - */ - $composer = include COMPOSER_PATH; + $this->loadComposerInfo($modules); + } - $this->loadComposerClassmap($composer); + return $this; + } - // Should we load through Composer's namespaces, also? - if ($modules->discoverInComposer) { - $this->loadComposerNamespaces($composer); - } + protected function loadComposerInfo(Modules $modules): void + { + /** + * @var ClassLoader $composer + */ + $composer = include COMPOSER_PATH; + + $this->loadComposerClassmap($composer); - unset($composer); + // Should we load through Composer's namespaces, also? + if ($modules->discoverInComposer) { + $this->loadComposerNamespaces($composer); } - return $this; + unset($composer); } /** From c179ed044558faa93d7ad05869b1e4c9b22069ca Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 08:01:39 +0900 Subject: [PATCH 1855/2325] refactor: restore discoverComposerNamespaces() and deprecate --- system/Autoloader/Autoloader.php | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index cca4a7d28f1e..7152f160c652 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -337,4 +337,40 @@ protected function loadComposerClassmap(ClassLoader $composer): void $this->classmap = array_merge($this->classmap, $classes); } + + /** + * Locates autoload information from Composer, if available. + * + * @deprecated No longer used. + */ + protected function discoverComposerNamespaces() + { + if (! is_file(COMPOSER_PATH)) { + return; + } + + /** + * @var ClassLoader $composer + */ + $composer = include COMPOSER_PATH; + $paths = $composer->getPrefixesPsr4(); + $classes = $composer->getClassMap(); + + unset($composer); + + // Get rid of CodeIgniter so we don't have duplicates + if (isset($paths['CodeIgniter\\'])) { + unset($paths['CodeIgniter\\']); + } + + $newPaths = []; + + foreach ($paths as $key => $value) { + // Composer stores namespaces with trailing slash. We don't. + $newPaths[rtrim($key, '\\ ')] = $value; + } + + $this->prefixes = array_merge($this->prefixes, $newPaths); + $this->classmap = array_merge($this->classmap, $classes); + } } From 577eefe25c4061e0a286b51969fc96ad177282b3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 08:03:15 +0900 Subject: [PATCH 1856/2325] refactor: make new methods private --- system/Autoloader/Autoloader.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 7152f160c652..520e669be685 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -111,7 +111,7 @@ public function initialize(Autoload $config, Modules $modules) return $this; } - protected function loadComposerInfo(Modules $modules): void + private function loadComposerInfo(Modules $modules): void { /** * @var ClassLoader $composer @@ -312,7 +312,7 @@ public function sanitizeFilename(string $filename): string return trim($filename, '.-_'); } - protected function loadComposerNamespaces(ClassLoader $composer): void + private function loadComposerNamespaces(ClassLoader $composer): void { $paths = $composer->getPrefixesPsr4(); @@ -331,7 +331,7 @@ protected function loadComposerNamespaces(ClassLoader $composer): void $this->prefixes = array_merge($this->prefixes, $newPaths); } - protected function loadComposerClassmap(ClassLoader $composer): void + private function loadComposerClassmap(ClassLoader $composer): void { $classes = $composer->getClassMap(); From c7e659fc367eefd76cb0680214880fb14eaa4585 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 08:13:44 +0900 Subject: [PATCH 1857/2325] docs: add changelog --- user_guide_src/source/changelogs/v4.2.0.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 465054262b41..99f980d6b35e 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -17,6 +17,7 @@ BREAKING - ``public/index.php`` - ``spark`` - The method signature of ``CodeIgniter\CLI\CommandRunner::_remap()`` has been changed to fix a bug. +- The ``CodeIgniter\Autoloader\Autoloader::initialize()`` has changed the behavior to fix a bug. It used to use Composer classmap only when ``$modules->discoverInComposer`` is true. Now it always uses the Composer classmap if Composer is available. Enhancements ************ @@ -55,6 +56,7 @@ Deprecations - ``CodeIgniter\Log\Logger::cleanFilenames()`` and ``CodeIgniter\Test\TestLogger::cleanup()`` are both deprecated. Use the ``clean_path()`` function instead. - ``CodeIgniter\Router\Router::setDefaultController()`` is deprecated. - The constant ``SPARKED`` in **spark** is deprecated. Use the ``$context`` property in ``CodeIgniter\CodeIgniter`` instead. +- ``CodeIgniter\Autoloader\Autoloader::discoverComposerNamespaces()`` is deprecated, and no longer used. Bugs Fixed ********** From c03df2ea180af20c82ad94a8a96e55b2bab35b15 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:10:11 +0900 Subject: [PATCH 1858/2325] docs: add missing `+` --- user_guide_src/source/outgoing/view_parser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 752dcc489590..b431b9979602 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -458,7 +458,7 @@ While plugins will often consist of tag pairs, like shown above, they can also b Opening tags can also contain parameters that can customize how the plugin works. The parameters are represented as key/value pairs:: - {+ foo bar=2 baz="x y" } + {+ foo bar=2 baz="x y" +} Parameters can also be single values:: From 53fb7ac06fd959077323bec40d9c4d596d21d853 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:10:40 +0900 Subject: [PATCH 1859/2325] docs: remove unnecessary line breaks in sample code --- user_guide_src/source/installation/upgrade_view_parser/001.php | 3 +-- user_guide_src/source/outgoing/view_parser.rst | 3 +-- user_guide_src/source/outgoing/view_parser/003.php | 3 +-- user_guide_src/source/outgoing/view_parser/006.php | 3 +-- user_guide_src/source/outgoing/view_parser/007.php | 3 +-- user_guide_src/source/outgoing/view_parser/008.php | 3 +-- user_guide_src/source/outgoing/view_parser/018.php | 3 +-- user_guide_src/source/outgoing/view_parser/019.php | 3 +-- user_guide_src/source/outgoing/view_parser/020.php | 3 +-- user_guide_src/source/outgoing/view_parser/021.php | 3 +-- 10 files changed, 10 insertions(+), 20 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_view_parser/001.php b/user_guide_src/source/installation/upgrade_view_parser/001.php index 6bef47ef69ec..27dc410b1708 100644 --- a/user_guide_src/source/installation/upgrade_view_parser/001.php +++ b/user_guide_src/source/installation/upgrade_view_parser/001.php @@ -7,5 +7,4 @@ 'blog_heading' => 'My Blog Heading', ]; -echo $parser->setData($data) - ->render('blog_template'); +echo $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index b431b9979602..6c6c2601b451 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -550,8 +550,7 @@ An example with the iteration controlled in the view:: ['title' => 'Second Link', 'link' => '/second'], ] ]; - echo $parser->setData($data) - ->renderString($template); + echo $parser->setData($data)->renderString($template); Result:: diff --git a/user_guide_src/source/outgoing/view_parser/003.php b/user_guide_src/source/outgoing/view_parser/003.php index 1ee48b997ae6..da4ef088f6bd 100644 --- a/user_guide_src/source/outgoing/view_parser/003.php +++ b/user_guide_src/source/outgoing/view_parser/003.php @@ -5,5 +5,4 @@ 'blog_heading' => 'My Blog Heading', ]; -echo $parser->setData($data) - ->render('blog_template'); +echo $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/006.php b/user_guide_src/source/outgoing/view_parser/006.php index 6b1409c46c1d..dfde61eec728 100644 --- a/user_guide_src/source/outgoing/view_parser/006.php +++ b/user_guide_src/source/outgoing/view_parser/006.php @@ -12,5 +12,4 @@ ], ]; -echo $parser->setData($data) - ->render('blog_template'); +echo $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/007.php b/user_guide_src/source/outgoing/view_parser/007.php index 032f9d55f268..b3ca937f711f 100644 --- a/user_guide_src/source/outgoing/view_parser/007.php +++ b/user_guide_src/source/outgoing/view_parser/007.php @@ -8,5 +8,4 @@ 'blog_entries' => $query->getResultArray(), ]; -echo $parser->setData($data) - ->render('blog_template'); +echo $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/008.php b/user_guide_src/source/outgoing/view_parser/008.php index 62be126a407d..4b0a6215830e 100644 --- a/user_guide_src/source/outgoing/view_parser/008.php +++ b/user_guide_src/source/outgoing/view_parser/008.php @@ -9,5 +9,4 @@ ], ]; -echo $parser->setData($data) - ->render('blog_template'); +echo $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php index 4e039f02a08c..0bb60828d691 100644 --- a/user_guide_src/source/outgoing/view_parser/018.php +++ b/user_guide_src/source/outgoing/view_parser/018.php @@ -6,6 +6,5 @@ 'firstname' => 'John', 'lastname' => 'Doe', ]; -echo $parser->setData($data) - ->renderString($template); +echo $parser->setData($data)->renderString($template); // Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php index 16621ef2f190..a3cb80300299 100644 --- a/user_guide_src/source/outgoing/view_parser/019.php +++ b/user_guide_src/source/outgoing/view_parser/019.php @@ -6,6 +6,5 @@ 'firstname' => 'John', 'lastname' => 'Doe', ]; -echo $parser->setData($data) - ->renderString($template); +echo $parser->setData($data)->renderString($template); // Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php index 9226793f280d..62256192019d 100644 --- a/user_guide_src/source/outgoing/view_parser/020.php +++ b/user_guide_src/source/outgoing/view_parser/020.php @@ -10,6 +10,5 @@ ['degree' => 'PhD'], ], ]; -echo $parser->setData($data) - ->renderString($template); +echo $parser->setData($data)->renderString($template); // Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php index 3c9982437a19..977b8b958140 100644 --- a/user_guide_src/source/outgoing/view_parser/021.php +++ b/user_guide_src/source/outgoing/view_parser/021.php @@ -15,5 +15,4 @@ $data = [ 'menuitems' => $temp, ]; -echo $parser->setData($data) - ->renderString($template2); +echo $parser->setData($data)->renderString($template2); From 71a7682d1eba5bad20109362e292479cf952f5b4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:13:15 +0900 Subject: [PATCH 1860/2325] docs: fix text decoration for variable --- user_guide_src/source/outgoing/view_parser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 6c6c2601b451..e3908ec0a391 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -491,7 +491,7 @@ Registering a Plugin -------------------- At its simplest, all you need to do to register a new plugin and make it ready for use is to add it to the -**app/Config/View.php**, under the **$plugins** array. The key is the name of the plugin that is +**app/Config/View.php**, under the ``$plugins`` array. The key is the name of the plugin that is used within the template file. The value is any valid PHP callable, including static class methods: .. literalinclude:: view_parser/014.php From 931c6f43a7724446b9fcf8dbd13b782e0dd352c6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:20:31 +0900 Subject: [PATCH 1861/2325] docs: remove unsupported options `leftDelimiter` and `rightDelimiter` --- user_guide_src/source/outgoing/view_parser.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index e3908ec0a391..67ee0b7680eb 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -595,8 +595,6 @@ Class Reference - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath - ``cascadeData`` - true if the data pairs in effect when a nested or loop substitution occurs should be propagated - ``saveData`` - true if the view data parameter should be retained for subsequent calls - - ``leftDelimiter`` - the left delimiter to use in pseudo-variable syntax - - ``rightDelimiter`` - the right delimiter to use in pseudo-variable syntax Any conditional substitutions are performed first, then remaining substitutions are performed for each data pair. From 20194690313be9d7e7f60165808376baf49a12f9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:24:59 +0900 Subject: [PATCH 1862/2325] docs: rename variable name in sample code Make the same name as other sample code. --- user_guide_src/source/outgoing/view_parser/024.php | 2 +- user_guide_src/source/outgoing/view_parser/025.php | 2 +- user_guide_src/source/outgoing/view_parser/026.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser/024.php b/user_guide_src/source/outgoing/view_parser/024.php index 42ddfa949331..17a0a477e756 100644 --- a/user_guide_src/source/outgoing/view_parser/024.php +++ b/user_guide_src/source/outgoing/view_parser/024.php @@ -1,3 +1,3 @@ setData(['name' => 'George', 'position' => 'Boss']); +$parser->setData(['name' => 'George', 'position' => 'Boss']); diff --git a/user_guide_src/source/outgoing/view_parser/025.php b/user_guide_src/source/outgoing/view_parser/025.php index 8fa85f4faa98..fe67fe17aeb4 100644 --- a/user_guide_src/source/outgoing/view_parser/025.php +++ b/user_guide_src/source/outgoing/view_parser/025.php @@ -1,3 +1,3 @@ setVar('name', 'Joe', 'html'); +$parser->setVar('name', 'Joe', 'html'); diff --git a/user_guide_src/source/outgoing/view_parser/026.php b/user_guide_src/source/outgoing/view_parser/026.php index 46cfd9afd818..a7efd14837f2 100644 --- a/user_guide_src/source/outgoing/view_parser/026.php +++ b/user_guide_src/source/outgoing/view_parser/026.php @@ -1,3 +1,3 @@ setDelimiters('[', ']'); +$parser->setDelimiters('[', ']'); From 08d4dbecccf14847f098804edfa2987120668efe Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:29:10 +0900 Subject: [PATCH 1863/2325] docs: add setConditionalDelimiters() in Class Reference --- user_guide_src/source/outgoing/view_parser.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 67ee0b7680eb..c369e7a5a78b 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -652,3 +652,14 @@ Class Reference Override the substitution field delimiters: .. literalinclude:: view_parser/026.php + + .. php:method:: setConditionalDelimiters($leftDelimiter = '{', $rightDelimiter = '}') + + :param string $leftDelimiter: Left delimiter for conditionals + :param string $rightDelimiter: right delimiter for conditionals + :returns: The Renderer, for method chaining + :rtype: CodeIgniter\\View\\RendererInterface. + + Override the conditional delimiters: + + .. literalinclude:: view_parser/027.php From bbea1665c368b235086a7b3cbbc5f462431e26f3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:32:27 +0900 Subject: [PATCH 1864/2325] docs: remove parameters of methods in text No parameters make them easier to read. --- user_guide_src/source/outgoing/view_parser.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index c369e7a5a78b..f4239b320207 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -53,9 +53,9 @@ can instantiate it directly: .. literalinclude:: view_parser/002.php Then you can use any of the three standard rendering methods that it provides: -``render(viewpath, options, save)``, ``setVar(name, value, context)`` and -``setData(data, context)``. You will also be able to specify delimiters directly, -through the ``setDelimiters(left, right)`` method. +``render()``, ``setVar()`` and +``setData()``. You will also be able to specify delimiters directly, +through the ``setDelimiters()`` method. Using the ``Parser``, your view templates are processed only by the Parser itself, and not like a conventional view PHP script. PHP code in such a script From faf39c2003bbb17c04957facf03d9300b0969424 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:36:29 +0900 Subject: [PATCH 1865/2325] docs: make text as a important note --- user_guide_src/source/outgoing/view_parser.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index f4239b320207..b72388486eb6 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -57,11 +57,11 @@ Then you can use any of the three standard rendering methods that it provides: ``setData()``. You will also be able to specify delimiters directly, through the ``setDelimiters()`` method. -Using the ``Parser``, your view templates are processed only by the Parser -itself, and not like a conventional view PHP script. PHP code in such a script -is ignored by the parser, and only substitutions are performed. +.. important:: Using the ``Parser``, your view templates are processed only by the Parser + itself, and not like a conventional view PHP script. PHP code in such a script + is ignored by the parser, and only substitutions are performed. -This is purposeful: view files with no PHP. + This is purposeful: view files with no PHP. What It Does ============ From d368c511299d7ca063e9cfa70f56761924129b7c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:44:45 +0900 Subject: [PATCH 1866/2325] docs: fix text decoration for filter --- user_guide_src/source/outgoing/view_parser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index b72388486eb6..50b4b4376707 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -336,7 +336,7 @@ Filters Any single variable substitution can have one or more filters applied to it to modify the way it is presented. These are not intended to drastically change the output, but provide ways to reuse the same variable data but with different -presentations. The **esc** filter discussed above is one example. Dates are another common use case, where you might +presentations. The ``esc`` filter discussed above is one example. Dates are another common use case, where you might need to format the same data differently in several sections on the same page. Filters are commands that come after the pseudo-variable name, and are separated by the pipe symbol, ``|``:: From b5423cc15a7f8471cc14d32ea7da22bc3ca821d9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 09:45:05 +0900 Subject: [PATCH 1867/2325] docs: add space between tags --- user_guide_src/source/outgoing/view_parser.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 50b4b4376707..961d8ea96c31 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -250,7 +250,7 @@ This example gives different results, depending on cascading: Preventing Parsing ================== -You can specify portions of the page to not be parsed with the ``{noparse}{/noparse}`` tag pair. Anything in this +You can specify portions of the page to not be parsed with the ``{noparse}`` ``{/noparse}`` tag pair. Anything in this section will stay exactly as it is, with no variable substitution, looping, etc, happening to the markup between the brackets. :: From cf4d83d1e5d7e144a44d49e19892ac819d908c6c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 10:25:57 +0900 Subject: [PATCH 1868/2325] docs: add links to reference --- user_guide_src/source/tutorial/conclusion.rst | 5 +++-- user_guide_src/source/tutorial/news_section.rst | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/tutorial/conclusion.rst b/user_guide_src/source/tutorial/conclusion.rst index afb38465904b..2a4f66264784 100644 --- a/user_guide_src/source/tutorial/conclusion.rst +++ b/user_guide_src/source/tutorial/conclusion.rst @@ -10,8 +10,9 @@ design patterns, which you can expand upon. Now that you've completed this tutorial, we recommend you check out the rest of the documentation. CodeIgniter is often praised because of its comprehensive documentation. Use this to your advantage and read the -"Overview" and "General Topics" sections thoroughly. You should read -the class and helper references when needed. +:doc:`Overview ` and :doc:`/general/index` +sections thoroughly. You should read +the :doc:`Library ` and :doc:`/helpers/index` references when needed. Every intermediate PHP programmer should be able to get the hang of CodeIgniter within a few days. diff --git a/user_guide_src/source/tutorial/news_section.rst b/user_guide_src/source/tutorial/news_section.rst index a27902819265..aca19a25cad3 100644 --- a/user_guide_src/source/tutorial/news_section.rst +++ b/user_guide_src/source/tutorial/news_section.rst @@ -80,7 +80,7 @@ library. This will make the database class available through the Now that the database and a model have been set up, you'll need a method to get all of our posts from our database. To do this, the database abstraction layer that is included with CodeIgniter - -:doc:`Query Builder <../database/query_builder>` - is used. This makes it +:doc:`Query Builder <../database/query_builder>` - is used in the ``CodeIgnite\Model``. This makes it possible to write your 'queries' once and make them work on :doc:`all supported database systems <../intro/requirements>`. The Model class also allows you to easily work with the Query Builder and provides From 3f480d453479b17a6d75cc0abadf3ded39c65e34 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 10:26:28 +0900 Subject: [PATCH 1869/2325] docs: update forum url and add slack url --- user_guide_src/source/tutorial/conclusion.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/tutorial/conclusion.rst b/user_guide_src/source/tutorial/conclusion.rst index 2a4f66264784..94b8ba5e3f2d 100644 --- a/user_guide_src/source/tutorial/conclusion.rst +++ b/user_guide_src/source/tutorial/conclusion.rst @@ -20,4 +20,5 @@ CodeIgniter within a few days. If you still have questions about the framework or your own CodeIgniter code, you can: -- Check out our `forums `_ +- Check out our `Forum `_ +- Check out our `Slack `_ From f58bac1954d5c189bf635309eb2a1ec6e8d5ed84 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 10:26:58 +0900 Subject: [PATCH 1870/2325] docs: remove unneeded `` --- user_guide_src/source/tutorial/create_news_items.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index 49ebc36c2bc3..a59124515a59 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -50,7 +50,7 @@ the slug from our title in the model. Create a new view at There are probably only three things here that look unfamiliar. -The ``getFlashdata('error') ?>`` function is used to report +The ``session()->getFlashdata('error')`` function is used to report errors related to CSRF protection. The ``service('validation')->listErrors()`` function is used to report From 54d80bcd0727c9f10c5f7ebf2f98548131732402 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 10:27:26 +0900 Subject: [PATCH 1871/2325] docs: fix link to validation page --- user_guide_src/source/incoming/controllers.rst | 2 ++ user_guide_src/source/tutorial/create_news_items.rst | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index 99c22b5a356d..c5a963c81fdd 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -61,6 +61,8 @@ modify this by passing the duration (in seconds) as the first parameter: .. note:: A number of :doc:`time-based constants ` are always available for you to use, including ``YEAR``, ``MONTH``, and more. +.. _controller-validate: + Validating data *************** diff --git a/user_guide_src/source/tutorial/create_news_items.rst b/user_guide_src/source/tutorial/create_news_items.rst index a59124515a59..99d28abf3cdb 100644 --- a/user_guide_src/source/tutorial/create_news_items.rst +++ b/user_guide_src/source/tutorial/create_news_items.rst @@ -60,8 +60,8 @@ The ``csrf_field()`` function creates a hidden input with a CSRF token that help Go back to your ``News`` controller. You're going to do two things here, check whether the form was submitted and whether the submitted data -passed the validation rules. You'll use the :doc:`form -validation <../libraries/validation>` library to do this. +passed the validation rules. +You'll use the :ref:`validation method in Controller ` to do this. .. literalinclude:: create_news_items/002.php From 149555ebd23d404ecf8684e52cb363365a7470ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 13:47:18 +0900 Subject: [PATCH 1872/2325] docs: replace echo with return --- user_guide_src/source/tutorial/static_pages.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/tutorial/static_pages.rst b/user_guide_src/source/tutorial/static_pages.rst index 668683995231..6fde0a671da7 100644 --- a/user_guide_src/source/tutorial/static_pages.rst +++ b/user_guide_src/source/tutorial/static_pages.rst @@ -24,7 +24,7 @@ displays the CodeIgniter welcome page. .. note:: There are two ``view()`` functions referred to in this tutorial. One is the class method created with ``public function view($page = 'home')`` - and ``echo view('welcome_message')`` for displaying a view. + and ``return view('welcome_message')`` for displaying a view. Both are *technically* a function. But when you create a function in a class, it's called a method. From 977eb2561db4108b6ed3dfe97541de150e9b6429 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 08:35:49 +0900 Subject: [PATCH 1873/2325] docs: remove unneeded $data for view() $saveData is true by default, so we don't need to pass $data more than once. --- user_guide_src/source/tutorial/news_section/004.php | 4 ++-- user_guide_src/source/tutorial/news_section/006.php | 4 ++-- user_guide_src/source/tutorial/static_pages/002.php | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/tutorial/news_section/004.php b/user_guide_src/source/tutorial/news_section/004.php index b62562bfe351..9e823b6f7589 100644 --- a/user_guide_src/source/tutorial/news_section/004.php +++ b/user_guide_src/source/tutorial/news_section/004.php @@ -16,7 +16,7 @@ public function index() ]; return view('templates/header', $data) - . view('news/overview', $data) - . view('templates/footer', $data); + . view('news/overview') + . view('templates/footer'); } } diff --git a/user_guide_src/source/tutorial/news_section/006.php b/user_guide_src/source/tutorial/news_section/006.php index 8bfc123e43f7..94548ac9307f 100644 --- a/user_guide_src/source/tutorial/news_section/006.php +++ b/user_guide_src/source/tutorial/news_section/006.php @@ -19,7 +19,7 @@ public function view($slug = null) $data['title'] = $data['news']['title']; return view('templates/header', $data) - . view('news/view', $data) - . view('templates/footer', $data); + . view('news/view') + . view('templates/footer'); } } diff --git a/user_guide_src/source/tutorial/static_pages/002.php b/user_guide_src/source/tutorial/static_pages/002.php index 9f80c4556a58..5c8ec102a5a1 100644 --- a/user_guide_src/source/tutorial/static_pages/002.php +++ b/user_guide_src/source/tutorial/static_pages/002.php @@ -14,7 +14,7 @@ public function view($page = 'home') $data['title'] = ucfirst($page); // Capitalize the first letter return view('templates/header', $data) - . view('pages/' . $page, $data) - . view('templates/footer', $data); + . view('pages/' . $page) + . view('templates/footer'); } } From e0569f673f0c119b620f37981bf90dd19d8390a1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 3 Apr 2022 14:19:58 +0900 Subject: [PATCH 1874/2325] docs: replace echo with return echo() has side effects, so return is better. --- user_guide_src/source/cli/cli/001.php | 2 +- user_guide_src/source/incoming/controllers/008.php | 2 +- user_guide_src/source/incoming/controllers/013.php | 4 ++-- user_guide_src/source/incoming/controllers/014.php | 4 ++-- .../source/installation/upgrade_controllers/001.php | 2 +- .../source/installation/upgrade_file_upload/001.php | 11 +++++------ .../source/installation/upgrade_pagination/001.php | 2 +- .../source/installation/upgrade_view_parser.rst | 2 +- .../source/installation/upgrade_view_parser/001.php | 2 +- user_guide_src/source/installation/upgrade_views.rst | 4 ++-- user_guide_src/source/libraries/pagination/002.php | 2 +- user_guide_src/source/libraries/validation/001.php | 6 +++--- user_guide_src/source/outgoing/view_layouts/001.php | 2 +- user_guide_src/source/outgoing/view_parser.rst | 3 ++- user_guide_src/source/outgoing/view_parser/003.php | 2 +- user_guide_src/source/outgoing/view_parser/004.php | 2 +- user_guide_src/source/outgoing/view_parser/005.php | 2 +- user_guide_src/source/outgoing/view_parser/006.php | 2 +- user_guide_src/source/outgoing/view_parser/007.php | 2 +- user_guide_src/source/outgoing/view_parser/008.php | 2 +- user_guide_src/source/outgoing/view_parser/009.php | 2 +- user_guide_src/source/outgoing/view_parser/010.php | 6 ++++-- user_guide_src/source/outgoing/view_parser/018.php | 3 ++- user_guide_src/source/outgoing/view_parser/019.php | 3 ++- user_guide_src/source/outgoing/view_parser/020.php | 3 ++- user_guide_src/source/outgoing/view_parser/021.php | 3 ++- user_guide_src/source/outgoing/view_parser/022.php | 2 +- user_guide_src/source/outgoing/view_parser/023.php | 2 +- user_guide_src/source/outgoing/views.rst | 3 --- user_guide_src/source/outgoing/views/001.php | 2 +- user_guide_src/source/outgoing/views/002.php | 2 +- user_guide_src/source/outgoing/views/003.php | 8 ++++---- user_guide_src/source/outgoing/views/004.php | 2 +- user_guide_src/source/outgoing/views/005.php | 2 +- user_guide_src/source/outgoing/views/006.php | 2 +- user_guide_src/source/outgoing/views/007.php | 2 +- user_guide_src/source/outgoing/views/008.php | 2 +- user_guide_src/source/outgoing/views/009.php | 2 +- user_guide_src/source/outgoing/views/010.php | 2 +- user_guide_src/source/outgoing/views/011.php | 2 +- 40 files changed, 59 insertions(+), 56 deletions(-) diff --git a/user_guide_src/source/cli/cli/001.php b/user_guide_src/source/cli/cli/001.php index b407ee50b145..999a5482e4d6 100644 --- a/user_guide_src/source/cli/cli/001.php +++ b/user_guide_src/source/cli/cli/001.php @@ -8,6 +8,6 @@ class Tools extends Controller { public function message($to = 'World') { - echo "Hello {$to}!" . PHP_EOL; + return "Hello {$to}!" . PHP_EOL; } } diff --git a/user_guide_src/source/incoming/controllers/008.php b/user_guide_src/source/incoming/controllers/008.php index 926de1e9fbdf..3aa859567c44 100644 --- a/user_guide_src/source/incoming/controllers/008.php +++ b/user_guide_src/source/incoming/controllers/008.php @@ -6,6 +6,6 @@ class Helloworld extends BaseController { public function index() { - echo 'Hello World!'; + return 'Hello World!'; } } diff --git a/user_guide_src/source/incoming/controllers/013.php b/user_guide_src/source/incoming/controllers/013.php index e43c3e4f2b34..68d4450d4e3a 100644 --- a/user_guide_src/source/incoming/controllers/013.php +++ b/user_guide_src/source/incoming/controllers/013.php @@ -6,11 +6,11 @@ class Helloworld extends BaseController { public function index() { - echo 'Hello World!'; + return 'Hello World!'; } public function comment() { - echo 'I am not flat!'; + return 'I am not flat!'; } } diff --git a/user_guide_src/source/incoming/controllers/014.php b/user_guide_src/source/incoming/controllers/014.php index 319fd8471a7b..da295eb61836 100644 --- a/user_guide_src/source/incoming/controllers/014.php +++ b/user_guide_src/source/incoming/controllers/014.php @@ -6,7 +6,7 @@ class Products extends BaseController { public function shoes($sandals, $id) { - echo $sandals; - echo $id; + return $sandals + . $id; } } diff --git a/user_guide_src/source/installation/upgrade_controllers/001.php b/user_guide_src/source/installation/upgrade_controllers/001.php index 5f292b54d1b8..b90fe63c538f 100644 --- a/user_guide_src/source/installation/upgrade_controllers/001.php +++ b/user_guide_src/source/installation/upgrade_controllers/001.php @@ -6,6 +6,6 @@ class Helloworld extends BaseController { public function index($name) { - echo 'Hello ' . esc($name) . '!'; + return 'Hello ' . esc($name) . '!'; } } diff --git a/user_guide_src/source/installation/upgrade_file_upload/001.php b/user_guide_src/source/installation/upgrade_file_upload/001.php index 6a4e6c88e250..a8b727c29745 100644 --- a/user_guide_src/source/installation/upgrade_file_upload/001.php +++ b/user_guide_src/source/installation/upgrade_file_upload/001.php @@ -6,7 +6,7 @@ class Upload extends BaseController { public function index() { - echo view('upload_form', ['error' => ' ']); + return view('upload_form', ['error' => ' ']); } public function do_upload() @@ -20,11 +20,10 @@ public function do_upload() $file = $this->request->getFile('userfile'); if (! $path = $file->store()) { - echo view('upload_form', ['error' => 'upload failed']); - } else { - $data = ['upload_file_path' => $path]; - - echo view('upload_success', $data); + return view('upload_form', ['error' => 'upload failed']); } + $data = ['upload_file_path' => $path]; + + return view('upload_success', $data); } } diff --git a/user_guide_src/source/installation/upgrade_pagination/001.php b/user_guide_src/source/installation/upgrade_pagination/001.php index fa1b373a5fc6..62710360fca9 100644 --- a/user_guide_src/source/installation/upgrade_pagination/001.php +++ b/user_guide_src/source/installation/upgrade_pagination/001.php @@ -7,4 +7,4 @@ 'pager' => $model->pager, ]; -echo view('users/index', $data); +return view('users/index', $data); diff --git a/user_guide_src/source/installation/upgrade_view_parser.rst b/user_guide_src/source/installation/upgrade_view_parser.rst index 55e86fb357a4..c58aeb8dd491 100644 --- a/user_guide_src/source/installation/upgrade_view_parser.rst +++ b/user_guide_src/source/installation/upgrade_view_parser.rst @@ -19,7 +19,7 @@ What has been changed Upgrade Guide ============= 1. Wherever you use the View Parser Library replace ``$this->load->library('parser');`` with ``$parser = service('parser');``. -2. You have to change the render part in your controller from ``$this->parser->parse('blog_template', $data);`` to ``echo $parser->setData($data)->render('blog_template');``. +2. You have to change the render part in your controller from ``$this->parser->parse('blog_template', $data);`` to ``return $parser->setData($data)->render('blog_template');``. Code Example ============ diff --git a/user_guide_src/source/installation/upgrade_view_parser/001.php b/user_guide_src/source/installation/upgrade_view_parser/001.php index 27dc410b1708..9acf5e9449d8 100644 --- a/user_guide_src/source/installation/upgrade_view_parser/001.php +++ b/user_guide_src/source/installation/upgrade_view_parser/001.php @@ -7,4 +7,4 @@ 'blog_heading' => 'My Blog Heading', ]; -echo $parser->setData($data)->render('blog_template'); +return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/installation/upgrade_views.rst b/user_guide_src/source/installation/upgrade_views.rst index 8509705c76dc..29dcace6ee62 100644 --- a/user_guide_src/source/installation/upgrade_views.rst +++ b/user_guide_src/source/installation/upgrade_views.rst @@ -15,7 +15,7 @@ What has been changed ===================== - Your views look much like before, but they are invoked differently ... instead of CI3's - ``$this->load->view(x);``, you can use ``echo view(x);``. + ``$this->load->view(x);``, you can use ``return view(x);``. - CI4 supports *View Cells* to build your response in pieces, and *View Layouts* for page layout. - The template parser is still there, and substantially enhanced. @@ -24,7 +24,7 @@ Upgrade Guide 1. First, move all views to the folder **app/Views** 2. Change the loading syntax of views in every script where you load views: - - from ``$this->load->view('directory_name/file_name')`` to ``echo view('directory_name/file_name');`` + - from ``$this->load->view('directory_name/file_name')`` to ``return view('directory_name/file_name');`` - from ``$content = $this->load->view('file', $data, TRUE);`` to ``$content = view('file', $data);`` 3. (optional) You can change the echo syntax in views from ```` to ```` diff --git a/user_guide_src/source/libraries/pagination/002.php b/user_guide_src/source/libraries/pagination/002.php index baaa8471111f..c8cd31ebec5c 100644 --- a/user_guide_src/source/libraries/pagination/002.php +++ b/user_guide_src/source/libraries/pagination/002.php @@ -15,6 +15,6 @@ public function index() 'pager' => $model->pager, ]; - echo view('users/index', $data); + return view('users/index', $data); } } diff --git a/user_guide_src/source/libraries/validation/001.php b/user_guide_src/source/libraries/validation/001.php index e52362c46cea..41d51f1b8a25 100644 --- a/user_guide_src/source/libraries/validation/001.php +++ b/user_guide_src/source/libraries/validation/001.php @@ -11,11 +11,11 @@ public function index() helper(['form', 'url']); if (! $this->validate([])) { - echo view('Signup', [ + return view('Signup', [ 'validation' => $this->validator, ]); - } else { - echo view('Success'); } + + return view('Success'); } } diff --git a/user_guide_src/source/outgoing/view_layouts/001.php b/user_guide_src/source/outgoing/view_layouts/001.php index 2eed4c4f53dc..f6105365fa47 100644 --- a/user_guide_src/source/outgoing/view_layouts/001.php +++ b/user_guide_src/source/outgoing/view_layouts/001.php @@ -6,6 +6,6 @@ class MyController extends BaseController { public function index() { - echo view('some_view'); + return view('some_view'); } } diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index 961d8ea96c31..c0705e7fa257 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -550,7 +550,8 @@ An example with the iteration controlled in the view:: ['title' => 'Second Link', 'link' => '/second'], ] ]; - echo $parser->setData($data)->renderString($template); + + return $parser->setData($data)->renderString($template); Result:: diff --git a/user_guide_src/source/outgoing/view_parser/003.php b/user_guide_src/source/outgoing/view_parser/003.php index da4ef088f6bd..90f3c88273fc 100644 --- a/user_guide_src/source/outgoing/view_parser/003.php +++ b/user_guide_src/source/outgoing/view_parser/003.php @@ -5,4 +5,4 @@ 'blog_heading' => 'My Blog Heading', ]; -echo $parser->setData($data)->render('blog_template'); +return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/004.php b/user_guide_src/source/outgoing/view_parser/004.php index 70862b585adc..643f541a5b3e 100644 --- a/user_guide_src/source/outgoing/view_parser/004.php +++ b/user_guide_src/source/outgoing/view_parser/004.php @@ -1,6 +1,6 @@ render('blog_template', [ +return $parser->render('blog_template', [ 'cache' => HOUR, 'cache_name' => 'something_unique', ]); diff --git a/user_guide_src/source/outgoing/view_parser/005.php b/user_guide_src/source/outgoing/view_parser/005.php index e77c54268648..e85e49db45a2 100644 --- a/user_guide_src/source/outgoing/view_parser/005.php +++ b/user_guide_src/source/outgoing/view_parser/005.php @@ -3,5 +3,5 @@ $template = '{blog_title}'; $data = ['blog_title' => 'My ramblings']; -echo $parser->setData($data)->renderString($template); +return $parser->setData($data)->renderString($template); // Result: My ramblings diff --git a/user_guide_src/source/outgoing/view_parser/006.php b/user_guide_src/source/outgoing/view_parser/006.php index dfde61eec728..40d379aec2ea 100644 --- a/user_guide_src/source/outgoing/view_parser/006.php +++ b/user_guide_src/source/outgoing/view_parser/006.php @@ -12,4 +12,4 @@ ], ]; -echo $parser->setData($data)->render('blog_template'); +return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/007.php b/user_guide_src/source/outgoing/view_parser/007.php index b3ca937f711f..5128ed3cbe4a 100644 --- a/user_guide_src/source/outgoing/view_parser/007.php +++ b/user_guide_src/source/outgoing/view_parser/007.php @@ -8,4 +8,4 @@ 'blog_entries' => $query->getResultArray(), ]; -echo $parser->setData($data)->render('blog_template'); +return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/008.php b/user_guide_src/source/outgoing/view_parser/008.php index 4b0a6215830e..8cac9bbbaa9d 100644 --- a/user_guide_src/source/outgoing/view_parser/008.php +++ b/user_guide_src/source/outgoing/view_parser/008.php @@ -9,4 +9,4 @@ ], ]; -echo $parser->setData($data)->render('blog_template'); +return $parser->setData($data)->render('blog_template'); diff --git a/user_guide_src/source/outgoing/view_parser/009.php b/user_guide_src/source/outgoing/view_parser/009.php index 6b112fdd6829..6f4b96e82274 100644 --- a/user_guide_src/source/outgoing/view_parser/009.php +++ b/user_guide_src/source/outgoing/view_parser/009.php @@ -7,5 +7,5 @@ 'location' => ['city' => 'Red City', 'planet' => 'Mars'], ]; -echo $parser->setData($data)->renderString($template); +return $parser->setData($data)->renderString($template); // Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/010.php b/user_guide_src/source/outgoing/view_parser/010.php index 7fcd5bafbfec..4eb11fd6d908 100644 --- a/user_guide_src/source/outgoing/view_parser/010.php +++ b/user_guide_src/source/outgoing/view_parser/010.php @@ -7,8 +7,10 @@ 'location' => ['city' => 'Red City', 'planet' => 'Mars'], ]; -echo $parser->setData($data)->renderString($template, ['cascadeData' => false]); +return $parser->setData($data)->renderString($template, ['cascadeData' => false]); // Result: {name} lives in Red City on Mars. -echo $parser->setData($data)->renderString($template, ['cascadeData' => true]); +// or + +return $parser->setData($data)->renderString($template, ['cascadeData' => true]); // Result: George lives in Red City on Mars. diff --git a/user_guide_src/source/outgoing/view_parser/018.php b/user_guide_src/source/outgoing/view_parser/018.php index 0bb60828d691..5a88dd651c25 100644 --- a/user_guide_src/source/outgoing/view_parser/018.php +++ b/user_guide_src/source/outgoing/view_parser/018.php @@ -6,5 +6,6 @@ 'firstname' => 'John', 'lastname' => 'Doe', ]; -echo $parser->setData($data)->renderString($template); + +return $parser->setData($data)->renderString($template); // Result: Hello, John Doe diff --git a/user_guide_src/source/outgoing/view_parser/019.php b/user_guide_src/source/outgoing/view_parser/019.php index a3cb80300299..5f465be2296b 100644 --- a/user_guide_src/source/outgoing/view_parser/019.php +++ b/user_guide_src/source/outgoing/view_parser/019.php @@ -6,5 +6,6 @@ 'firstname' => 'John', 'lastname' => 'Doe', ]; -echo $parser->setData($data)->renderString($template); + +return $parser->setData($data)->renderString($template); // Result: Hello, John {initials} Doe diff --git a/user_guide_src/source/outgoing/view_parser/020.php b/user_guide_src/source/outgoing/view_parser/020.php index 62256192019d..fd072cbc0e5c 100644 --- a/user_guide_src/source/outgoing/view_parser/020.php +++ b/user_guide_src/source/outgoing/view_parser/020.php @@ -10,5 +10,6 @@ ['degree' => 'PhD'], ], ]; -echo $parser->setData($data)->renderString($template); + +return $parser->setData($data)->renderString($template); // Result: Hello, John Doe (Mr{degree} {/degrees}) diff --git a/user_guide_src/source/outgoing/view_parser/021.php b/user_guide_src/source/outgoing/view_parser/021.php index 977b8b958140..60fbb625da79 100644 --- a/user_guide_src/source/outgoing/view_parser/021.php +++ b/user_guide_src/source/outgoing/view_parser/021.php @@ -15,4 +15,5 @@ $data = [ 'menuitems' => $temp, ]; -echo $parser->setData($data)->renderString($template2); + +return $parser->setData($data)->renderString($template2); diff --git a/user_guide_src/source/outgoing/view_parser/022.php b/user_guide_src/source/outgoing/view_parser/022.php index 022450bb6fd6..1bdb256d92f1 100644 --- a/user_guide_src/source/outgoing/view_parser/022.php +++ b/user_guide_src/source/outgoing/view_parser/022.php @@ -1,3 +1,3 @@ render('myview'); +return $parser->render('myview'); diff --git a/user_guide_src/source/outgoing/view_parser/023.php b/user_guide_src/source/outgoing/view_parser/023.php index 022450bb6fd6..1bdb256d92f1 100644 --- a/user_guide_src/source/outgoing/view_parser/023.php +++ b/user_guide_src/source/outgoing/view_parser/023.php @@ -1,3 +1,3 @@ render('myview'); +return $parser->render('myview'); diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 55da9ed98a22..56f736f23545 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -51,9 +51,6 @@ If you visit your site using the URL you did earlier you should see your new vie example.com/index.php/blog/ -.. note:: While all of the examples show echo the view directly, you can also return the output from the view, instead, - and it will be appended to any captured output. - Loading Multiple Views ====================== diff --git a/user_guide_src/source/outgoing/views/001.php b/user_guide_src/source/outgoing/views/001.php index 90c817235bf5..c1b1ff23a6dd 100644 --- a/user_guide_src/source/outgoing/views/001.php +++ b/user_guide_src/source/outgoing/views/001.php @@ -1,3 +1,3 @@ 'Your title', ]; - echo view('header'); - echo view('menu'); - echo view('content', $data); - echo view('footer'); + return view('header') + . view('menu') + . view('content', $data) + . view('footer'); } } diff --git a/user_guide_src/source/outgoing/views/004.php b/user_guide_src/source/outgoing/views/004.php index d77e328657f3..7c665c263391 100644 --- a/user_guide_src/source/outgoing/views/004.php +++ b/user_guide_src/source/outgoing/views/004.php @@ -1,3 +1,3 @@ 60]); +return view('file_name', $data, ['cache' => 60]); diff --git a/user_guide_src/source/outgoing/views/007.php b/user_guide_src/source/outgoing/views/007.php index b1d22eb55260..1b020abbc5a5 100644 --- a/user_guide_src/source/outgoing/views/007.php +++ b/user_guide_src/source/outgoing/views/007.php @@ -1,4 +1,4 @@ 60, 'cache_name' => 'my_cached_view']); +return view('file_name', $data, ['cache' => 60, 'cache_name' => 'my_cached_view']); diff --git a/user_guide_src/source/outgoing/views/008.php b/user_guide_src/source/outgoing/views/008.php index c9b2ab2f5bbd..8f3218c7029b 100644 --- a/user_guide_src/source/outgoing/views/008.php +++ b/user_guide_src/source/outgoing/views/008.php @@ -6,4 +6,4 @@ 'message' => 'My Message', ]; -echo view('blog_view', $data); +return view('blog_view', $data); diff --git a/user_guide_src/source/outgoing/views/009.php b/user_guide_src/source/outgoing/views/009.php index 61963a40bbb2..008d1cf85d26 100644 --- a/user_guide_src/source/outgoing/views/009.php +++ b/user_guide_src/source/outgoing/views/009.php @@ -11,6 +11,6 @@ public function index() $data['title'] = 'My Real Title'; $data['heading'] = 'My Real Heading'; - echo view('blog_view', $data); + return view('blog_view', $data); } } diff --git a/user_guide_src/source/outgoing/views/010.php b/user_guide_src/source/outgoing/views/010.php index c7dda333df20..189b5dc9f190 100644 --- a/user_guide_src/source/outgoing/views/010.php +++ b/user_guide_src/source/outgoing/views/010.php @@ -6,4 +6,4 @@ 'message' => 'My Message', ]; -echo view('blog_view', $data, ['saveData' => true]); +return view('blog_view', $data, ['saveData' => true]); diff --git a/user_guide_src/source/outgoing/views/011.php b/user_guide_src/source/outgoing/views/011.php index e3ddaeba2075..bb1a5fc21725 100644 --- a/user_guide_src/source/outgoing/views/011.php +++ b/user_guide_src/source/outgoing/views/011.php @@ -14,6 +14,6 @@ public function index() 'heading' => 'My Real Heading', ]; - echo view('blog_view', $data); + return view('blog_view', $data); } } From 76beb9d37b5f78ebcdc000ba00c9444a09cea72b Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 09:55:59 +0900 Subject: [PATCH 1875/2325] docs: fix header level --- user_guide_src/source/concepts/services.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index 84860e65f5c3..ea9b9712fd39 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -40,7 +40,7 @@ error-resistant. .. note:: It is recommended to only create services within controllers. Other files, like models and libraries should have the dependencies either passed into the constructor or through a setter method. Convenience Functions ---------------------- +===================== Two functions have been provided for getting a service. These functions are always available. @@ -110,7 +110,7 @@ within the class, and, if not, creates a new one. All of the factory methods pro .. literalinclude:: services/010.php Service Discovery ------------------ +================= CodeIgniter can automatically discover any Config\\Services.php files you may have created within any defined namespaces. This allows simple use of any module Services files. In order for custom Services files to be discovered, they must From 1944a69dad76ca7bfc925640ae664fcef396834f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 09:56:57 +0900 Subject: [PATCH 1876/2325] docs: use full classname in sample code Relative classname might not work. --- user_guide_src/source/concepts/services/012.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/services/012.php b/user_guide_src/source/concepts/services/012.php index cc4b63b4e20c..bd3c89f971ec 100644 --- a/user_guide_src/source/concepts/services/012.php +++ b/user_guide_src/source/concepts/services/012.php @@ -1,3 +1,3 @@ Date: Mon, 4 Apr 2022 09:58:24 +0900 Subject: [PATCH 1877/2325] docs: add / at the end of the path The default value ends with /. --- user_guide_src/source/concepts/services/009.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/services/009.php b/user_guide_src/source/concepts/services/009.php index 1bdf73954e16..78e4d7c74caf 100644 --- a/user_guide_src/source/concepts/services/009.php +++ b/user_guide_src/source/concepts/services/009.php @@ -1,3 +1,3 @@ Date: Mon, 4 Apr 2022 10:00:13 +0900 Subject: [PATCH 1878/2325] docs: fix text decoration, etc. --- user_guide_src/source/concepts/services.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index ea9b9712fd39..b5678c024bc8 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -75,7 +75,7 @@ create a new class that implements the ``RouterCollectionInterface``: .. literalinclude:: services/006.php -Finally, modify **/app/Config/Services.php** to create a new instance of ``MyRouter`` +Finally, modify **app/Config/Services.php** to create a new instance of ``MyRouter`` instead of ``CodeIgniter\Router\RouterCollection``: .. literalinclude:: services/007.php @@ -87,7 +87,7 @@ In some instances, you will want the option to pass a setting to the class durin Since the services file is a very simple class, it is easy to make this work. A good example is the ``renderer`` service. By default, we want this class to be able -to find the views at ``APPPATH.views/``. We want the developer to have the option of +to find the views at ``APPPATH . views/``. We want the developer to have the option of changing that path, though, if their needs require it. So the class accepts the ``$viewPath`` as a constructor parameter. The service method looks like this: @@ -112,19 +112,19 @@ within the class, and, if not, creates a new one. All of the factory methods pro Service Discovery ================= -CodeIgniter can automatically discover any Config\\Services.php files you may have created within any defined namespaces. +CodeIgniter can automatically discover any **Config/Services.php** files you may have created within any defined namespaces. This allows simple use of any module Services files. In order for custom Services files to be discovered, they must meet these requirements: -- Its namespace must be defined in ``Config\Autoload.php`` -- Inside the namespace, the file must be found at ``Config\Services.php`` +- Its namespace must be defined in **app/Config/Autoload.php** +- Inside the namespace, the file must be found at **Config/Services.php** - It must extend ``CodeIgniter\Config\BaseService`` A small example should clarify this. -Imagine that you've created a new directory, ``Blog`` in your root directory. This will hold a **blog module** with controllers, +Imagine that you've created a new directory, **Blog** in your project root directory. This will hold a **Blog module** with controllers, models, etc, and you'd like to make some of the classes available as a service. The first step is to create a new file: -``Blog\Config\Services.php``. The skeleton of the file should be: +**Blog/Config/Services.php**. The skeleton of the file should be: .. literalinclude:: services/011.php From 31720766b8049ae7dee5471911334338fc81f7d5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 10:43:28 +0900 Subject: [PATCH 1879/2325] docs: add headings --- user_guide_src/source/concepts/services.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index b5678c024bc8..3539c16c7420 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -44,6 +44,9 @@ Convenience Functions Two functions have been provided for getting a service. These functions are always available. +service() +--------- + The first is ``service()`` which returns a new instance of the requested service. The only required parameter is the service name. This is the same as the method name within the Services file always returns a SHARED instance of the class, so calling the function multiple times should @@ -55,6 +58,9 @@ If the creation method requires additional parameters, they can be passed after .. literalinclude:: services/004.php +single_service() +---------------- + The second function, ``single_service()`` works just like ``service()`` but returns a new instance of the class: From f00e952e346b47d827ecab149b70daf4b3e03e45 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 10:52:07 +0900 Subject: [PATCH 1880/2325] docs: add sample code --- user_guide_src/source/concepts/services/003.php | 3 +++ user_guide_src/source/concepts/services/004.php | 3 +++ user_guide_src/source/concepts/services/005.php | 3 +++ 3 files changed, 9 insertions(+) diff --git a/user_guide_src/source/concepts/services/003.php b/user_guide_src/source/concepts/services/003.php index ebbd1d89c30d..a13e8ebf1696 100644 --- a/user_guide_src/source/concepts/services/003.php +++ b/user_guide_src/source/concepts/services/003.php @@ -1,3 +1,6 @@ Date: Mon, 4 Apr 2022 11:08:03 +0900 Subject: [PATCH 1881/2325] docs: add What is Services? and Why use Services? --- user_guide_src/source/concepts/services.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index 3539c16c7420..b5747e4a913a 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -9,10 +9,19 @@ Services Introduction ============ +What is Services? +----------------- + +The **Services** in CodeIgniter 4 provide the functionality to create and share new class instances. +It is implemented as the ``Config\Services`` class. + All of the core classes within CodeIgniter are provided as "services". This simply means that, instead of hard-coding a class name to load, the classes to call are defined within a very simple configuration file. This file acts as a type of factory to create new instances of the required class. +Why use Services? +----------------- + A quick example will probably make things clearer, so imagine that you need to pull in an instance of the Timer class. The simplest method would simply be to create a new instance of that class: From 11e97ad12b8cd3c0181c90d1d9682d8b35f87b25 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 11:10:44 +0900 Subject: [PATCH 1882/2325] docs: fix heading marks --- user_guide_src/source/concepts/services.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index b5747e4a913a..2ede82c668ac 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -7,10 +7,10 @@ Services :depth: 2 Introduction -============ +************ What is Services? ------------------ +================= The **Services** in CodeIgniter 4 provide the functionality to create and share new class instances. It is implemented as the ``Config\Services`` class. @@ -20,7 +20,7 @@ of hard-coding a class name to load, the classes to call are defined within a ve configuration file. This file acts as a type of factory to create new instances of the required class. Why use Services? ------------------ +================= A quick example will probably make things clearer, so imagine that you need to pull in an instance of the Timer class. The simplest method would simply be to create a new instance of that class: @@ -49,12 +49,12 @@ error-resistant. .. note:: It is recommended to only create services within controllers. Other files, like models and libraries should have the dependencies either passed into the constructor or through a setter method. Convenience Functions -===================== +********************* Two functions have been provided for getting a service. These functions are always available. service() ---------- +========= The first is ``service()`` which returns a new instance of the requested service. The only required parameter is the service name. This is the same as the method name within the Services @@ -68,7 +68,7 @@ If the creation method requires additional parameters, they can be passed after .. literalinclude:: services/004.php single_service() ----------------- +================ The second function, ``single_service()`` works just like ``service()`` but returns a new instance of the class: @@ -76,7 +76,7 @@ the class: .. literalinclude:: services/005.php Defining Services -================= +***************** To make services work well, you have to be able to rely on each class having a constant API, or `interface `_, to use. Almost all of @@ -96,7 +96,7 @@ instead of ``CodeIgniter\Router\RouterCollection``: .. literalinclude:: services/007.php Allowing Parameters -------------------- +=================== In some instances, you will want the option to pass a setting to the class during instantiation. Since the services file is a very simple class, it is easy to make this work. @@ -114,7 +114,7 @@ the path it uses: .. literalinclude:: services/009.php Shared Classes ------------------ +============== There are occasions where you need to require that only a single instance of a service is created. This is easily handled with the ``getSharedInstance()`` method that is called from within the @@ -125,7 +125,7 @@ within the class, and, if not, creates a new one. All of the factory methods pro .. literalinclude:: services/010.php Service Discovery -================= +***************** CodeIgniter can automatically discover any **Config/Services.php** files you may have created within any defined namespaces. This allows simple use of any module Services files. In order for custom Services files to be discovered, they must From 5fef49fe2ed5cf444e8d2c9dcb6ee0b2391a1db4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 11:26:26 +0900 Subject: [PATCH 1883/2325] docs: add How to Get a Service --- user_guide_src/source/concepts/services.rst | 19 ++++++++++++++++--- .../source/concepts/services/013.php | 3 +++ .../source/concepts/services/014.php | 3 +++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 user_guide_src/source/concepts/services/013.php create mode 100644 user_guide_src/source/concepts/services/014.php diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index 2ede82c668ac..b69a4e4c4f85 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -48,13 +48,26 @@ error-resistant. .. note:: It is recommended to only create services within controllers. Other files, like models and libraries should have the dependencies either passed into the constructor or through a setter method. +How to Get a Service +******************** + +As many CodeIgniter classes are provided as services, you can get them like the following: + +.. literalinclude:: services/013.php + +The ``$typography`` is an instance of the Typography class, and if you call ``\Config\Services::typography()`` again, you will get the exactly same instance. + +If you want to get a new instance of the Typography class, you need to pass ``false`` to the argument ``$getShared``: + +.. literalinclude:: services/014.php + Convenience Functions -********************* +===================== Two functions have been provided for getting a service. These functions are always available. service() -========= +--------- The first is ``service()`` which returns a new instance of the requested service. The only required parameter is the service name. This is the same as the method name within the Services @@ -68,7 +81,7 @@ If the creation method requires additional parameters, they can be passed after .. literalinclude:: services/004.php single_service() -================ +---------------- The second function, ``single_service()`` works just like ``service()`` but returns a new instance of the class: diff --git a/user_guide_src/source/concepts/services/013.php b/user_guide_src/source/concepts/services/013.php new file mode 100644 index 000000000000..0c82ed0e95fa --- /dev/null +++ b/user_guide_src/source/concepts/services/013.php @@ -0,0 +1,3 @@ + Date: Mon, 4 Apr 2022 12:36:06 +0900 Subject: [PATCH 1884/2325] docs: add Convenience Functions --- user_guide_src/source/concepts/factories.rst | 19 +++++++++++++++++++ .../source/concepts/factories/008.php | 6 ++++++ .../source/concepts/factories/009.php | 6 ++++++ 3 files changed, 31 insertions(+) create mode 100644 user_guide_src/source/concepts/factories/008.php create mode 100644 user_guide_src/source/concepts/factories/009.php diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 2ddab73f2216..05dd7559da03 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -35,6 +35,25 @@ you get back the instance as before: .. literalinclude:: factories/003.php +Convenience Functions +===================== + +Two functions for short cut of the Factories have been provided. These functions are always available. + +config() +-------- + +The first is ``config()`` which returns a new instance of a Config class. The only required parameter is the class name: + +.. literalinclude:: factories/008.php + +model() +-------- + +The second function, ``model()`` returns a new instance of a Model class. The only required parameter is the class name: + +.. literalinclude:: factories/009.php + Factory Parameters ================== diff --git a/user_guide_src/source/concepts/factories/008.php b/user_guide_src/source/concepts/factories/008.php new file mode 100644 index 000000000000..866daa36acb2 --- /dev/null +++ b/user_guide_src/source/concepts/factories/008.php @@ -0,0 +1,6 @@ + Date: Mon, 4 Apr 2022 12:37:48 +0900 Subject: [PATCH 1885/2325] docs: add What is Factories? --- user_guide_src/source/concepts/factories.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 05dd7559da03..f04317174273 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -9,8 +9,13 @@ Factories Introduction ============ -Like ``Services``, ``Factories`` are an extension of autoloading that helps keep your code -concise yet optimal, without having to pass around object instances between classes. At its +What is Factories? +------------------ + +Like :doc:`./services`, **Factories** are an extension of autoloading that helps keep your code +concise yet optimal, without having to pass around object instances between classes. + +At its simplest, Factories provide a common way to create a class instance and access it from anywhere. This is a great way to reuse object states and reduce memory load from keeping multiple instances loaded across your app. From c0884be3ff9b983318a2f9262cc3828f860f69b4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 13:44:20 +0900 Subject: [PATCH 1886/2325] docs: add explanation about Differences from Services and preferApp behavior --- user_guide_src/source/concepts/factories.rst | 46 +++++++++++++++---- .../source/concepts/factories/002.php | 2 +- .../source/concepts/factories/003.php | 2 +- .../source/concepts/factories/010.php | 3 ++ 4 files changed, 42 insertions(+), 11 deletions(-) create mode 100644 user_guide_src/source/concepts/factories/010.php diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index f04317174273..2e23e448a8f9 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -20,14 +20,32 @@ simplest, Factories provide a common way to create a class instance and access i anywhere. This is a great way to reuse object states and reduce memory load from keeping multiple instances loaded across your app. -Anything can be loaded by Factories, but the best examples are those classes that are used +Any class can be loaded by Factories, but the best examples are those classes that are used to work on or transmit common data. The framework itself uses Factories internally, e.g., to make sure the correct configuration is loaded when using the ``Config`` class. -Take a look at ``Models`` as an example. You can access the Factory specific to ``Models`` -by using the magic static method of the Factories class, ``Factories::models()``. Because of -the common path structure for namespaces and folders, Factories know that the model files -and classes are found within **Models**, so you can request a model by its shorthand base name: +Differences from Services +------------------------- + +Factories require a concrete class name to instantiate, and do not have code to create instances. + +So Factories are not good for creating complex instance that needs many dependencies, +and cannot change the class of the instance to be returned. + +On the other hand, Services have code to create instances, so it can create a complex instance +that needs other services or class instances. When you get a service, Services require a service name, +not a class name, so the returned instance can be changed without changing the client code. + +Example +------- + +Take a look at **Models** as an example. You can access the Factory specific to Models +by using the magic static method of the Factories class, ``Factories::models()``. + +By default, Factories first searches in the ``App`` namespace for the path corresponding to the magic static method name. +``Factories::models()`` searches the path **Models/**. + +In the following code, if you have ``App\Models\UserModel``, the instance will be returned: .. literalinclude:: factories/001.php @@ -35,7 +53,17 @@ Or you could also request a specific class: .. literalinclude:: factories/002.php -Next time you ask for the same class anywhere in your code, ``Factories`` will be sure +If you have only ``Blog\Models\UserModel``, the instance will be returned. +But if you have both ``App\Models\UserModel`` and ``Blog\Models\UserModel``, +The instance of ``App\Models\UserModel`` will be returned. + +If you want to get ``Blog\Models\UserModel``, you need the option ``preferApp``: + +.. literalinclude:: factories/010.php + +See :ref:`factories-options` for the details. + +Next time you ask for the same class anywhere in your code, Factories will be sure you get back the instance as before: .. literalinclude:: factories/003.php @@ -112,13 +140,13 @@ Configurations To set default component options, create a new Config files at **app/Config/Factory.php** that supplies options as an array property that matches the name of the component. For example, -if you wanted to ensure that all Filters used by your app were valid framework instances, -your **Factory.php** file might look like this: +if you wanted to ensure that all **Filters** used by your app were valid framework instances, +your **app/Config/Factory.php** file might look like this: .. literalinclude:: factories/005.php This would prevent conflict of an unrelated third-party module which happened to have an -unrelated "Filters" path in its namespace. +unrelated ``Filters`` path in its namespace. setOptions Method ----------------- diff --git a/user_guide_src/source/concepts/factories/002.php b/user_guide_src/source/concepts/factories/002.php index cbc19d8b2730..6a56bbe7a374 100644 --- a/user_guide_src/source/concepts/factories/002.php +++ b/user_guide_src/source/concepts/factories/002.php @@ -1,3 +1,3 @@ false]); From 221d484dd012db99371b0d7819bded4dc043bccc Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 09:23:08 +0900 Subject: [PATCH 1887/2325] docs: fix Parser saveData description The default value for $saveData is null, and Config\View::$saveData (true by default) will be set. --- user_guide_src/source/outgoing/view_parser.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/outgoing/view_parser.rst b/user_guide_src/source/outgoing/view_parser.rst index c0705e7fa257..3cefd845de95 100644 --- a/user_guide_src/source/outgoing/view_parser.rst +++ b/user_guide_src/source/outgoing/view_parser.rst @@ -106,7 +106,7 @@ Several options can be passed to the ``render()`` or ``renderString()`` methods. - ``cache_name`` - the ID used to save/retrieve a cached view result; defaults to the viewpath; ignored for renderString() - ``saveData`` - true if the view data parameters should be retained for subsequent calls; - default is **false** + default is **true** - ``cascadeData`` - true if pseudo-variable settings should be passed on to nested substitutions; default is **true** @@ -578,7 +578,7 @@ Class Reference .. php:class:: CodeIgniter\\View\\Parser - .. php:method:: render($view[, $options[, $saveData = false]]) + .. php:method:: render($view[, $options[, $saveData]]) :param string $view: File name of the view source :param array $options: Array of options, as key/value pairs @@ -600,7 +600,7 @@ Class Reference Any conditional substitutions are performed first, then remaining substitutions are performed for each data pair. - .. php:method:: renderString($template[, $options[, $saveData = false]]) + .. php:method:: renderString($template[, $options[, $saveData]]) :param string $template: View source provided as a string :param array $options: Array of options, as key/value pairs From b95708ed0600e4eddff4dd849869594931930479 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 09:28:30 +0900 Subject: [PATCH 1888/2325] docs: fix View saveData description The default is true. --- user_guide_src/source/outgoing/views.rst | 17 +++++++++++------ user_guide_src/source/outgoing/views/010.php | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 56f736f23545..903f1fef4727 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -123,15 +123,20 @@ Now open your view file and change the text to variables that correspond to the Then load the page at the URL you've been using and you should see the variables replaced. -The data passed in is only available during one call to `view`. If you call the function multiple times -in a single request, you will have to pass the desired data to each view. This keeps any data from "bleeding" into -other views, potentially causing issues. If you would prefer the data to persist, you can pass the `saveData` option -into the `$option` array in the third parameter. +The saveData Option +------------------- + +The data passed in is retained for subsequent calls to ``view()``. If you call the function multiple times +in a single request, you will not have to pass the desired data to each ``view()``. + +But this might not keep any data from "bleeding" into +other views, potentially causing issues. If you would prefer to clean the data after one call, you can pass the ``saveData`` option +into the ``$option`` array in the third parameter. .. literalinclude:: views/010.php -Additionally, if you would like the default functionality of the view function to be that it does save the data -between calls, you can set ``$saveData`` to **true** in **app/Config/Views.php**. +Additionally, if you would like the default functionality of the view function to be that it does clear the data +between calls, you can set ``$saveData`` to **false** in **app/Config/Views.php**. Creating Loops ============== diff --git a/user_guide_src/source/outgoing/views/010.php b/user_guide_src/source/outgoing/views/010.php index 189b5dc9f190..8411aa134e7b 100644 --- a/user_guide_src/source/outgoing/views/010.php +++ b/user_guide_src/source/outgoing/views/010.php @@ -6,4 +6,4 @@ 'message' => 'My Message', ]; -return view('blog_view', $data, ['saveData' => true]); +return view('blog_view', $data, ['saveData' => false]); From 510810c2b27a1a2adcb9f21d05fbdf057dce4a86 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 09:31:00 +0900 Subject: [PATCH 1889/2325] docs: decorate view() function --- user_guide_src/source/outgoing/views.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/outgoing/views.rst b/user_guide_src/source/outgoing/views.rst index 903f1fef4727..3eb80427fc2a 100644 --- a/user_guide_src/source/outgoing/views.rst +++ b/user_guide_src/source/outgoing/views.rst @@ -101,7 +101,7 @@ along ``cache_name`` and the cache ID you wish to use: Adding Dynamic Data to the View =============================== -Data is passed from the controller to the view by way of an array in the second parameter of the view function. +Data is passed from the controller to the view by way of an array in the second parameter of the ``view()`` function. Here's an example: .. literalinclude:: views/008.php @@ -135,7 +135,7 @@ into the ``$option`` array in the third parameter. .. literalinclude:: views/010.php -Additionally, if you would like the default functionality of the view function to be that it does clear the data +Additionally, if you would like the default functionality of the ``view()`` function to be that it does clear the data between calls, you can set ``$saveData`` to **false** in **app/Config/Views.php**. Creating Loops From 926fc6eeabdbc9553869b7b7fba466a1c15b41b7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 4 Apr 2022 20:25:14 +0900 Subject: [PATCH 1890/2325] fix: Publisher::discover() may loads incorrect classname --- system/Publisher/Publisher.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 5cd392d921a8..01a3c62db657 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -111,9 +111,9 @@ final public static function discover(string $directory = 'Publishers'): array // Loop over each file checking to see if it is a Publisher foreach (array_unique($files) as $file) { - $className = $locator->findQualifiedNameFromPath($file); + $className = $locator->getClassname($file); - if (is_string($className) && class_exists($className) && is_a($className, self::class, true)) { + if ($className !== '' && class_exists($className) && is_a($className, self::class, true)) { self::$discovered[$directory][] = new $className(); } } From 74fb4fb8788bd419016e8bccc53f1825814a721e Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 10:41:27 +0900 Subject: [PATCH 1891/2325] refactor: extract withErrors() method --- system/HTTP/RedirectResponse.php | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/system/HTTP/RedirectResponse.php b/system/HTTP/RedirectResponse.php index 54e1ae12f36d..b9cabbba6793 100644 --- a/system/HTTP/RedirectResponse.php +++ b/system/HTTP/RedirectResponse.php @@ -85,18 +85,35 @@ public function back(?int $code = null, string $method = 'auto') public function withInput() { $session = Services::session(); - $session->setFlashdata('_ci_old_input', [ 'get' => $_GET ?? [], 'post' => $_POST ?? [], ]); - // If the validation has any errors, transmit those back - // so they can be displayed when the validation is handled - // within a method different than displaying the form. + // @TODO Remove this in the future. + // See https://github.com/codeigniter4/CodeIgniter4/issues/5839#issuecomment-1086624600 + $this->withErrors(); + + return $this; + } + + /** + * Set validation errors in the session. + * + * If the validation has any errors, transmit those back + * so they can be displayed when the validation is handled + * within a method different than displaying the form. + * + * @TODO Make this method public when removing $this->withErrors() in withInput(). + * + * @return $this + */ + private function withErrors(): self + { $validation = Services::validation(); if ($validation->getErrors()) { + $session = Services::session(); $session->setFlashdata('_ci_validation_errors', serialize($validation->getErrors())); } From e4f1d8817af17b3106e6ea3fbe3a1e57870813c6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 11:10:01 +0900 Subject: [PATCH 1892/2325] fix: validation errors in model are not cleared when running validation again --- phpstan-baseline.neon.dist | 5 ----- system/BaseModel.php | 4 +++- tests/system/Models/ValidationModelTest.php | 23 +++++++++++++++++++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 1021eb445899..53d3710b7ea7 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -25,11 +25,6 @@ parameters: count: 1 path: system/Autoloader/Autoloader.php - - - message: "#^Method CodeIgniter\\\\Validation\\\\ValidationInterface\\:\\:run\\(\\) invoked with 3 parameters, 0\\-2 required\\.$#" - count: 1 - path: system/BaseModel.php - - message: "#^Property Config\\\\Cache\\:\\:\\$backupHandler \\(string\\) in isset\\(\\) is not nullable\\.$#" count: 1 diff --git a/system/BaseModel.php b/system/BaseModel.php index 64753be5b3e3..39bd9ce2cb4c 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -1344,7 +1344,9 @@ public function validate($data): bool return true; } - return $this->validation->setRules($rules, $this->validationMessages)->run($data, null, $this->DBGroup); + $this->validation->reset()->setRules($rules, $this->validationMessages); + + return $this->validation->run($data, null, $this->DBGroup); } /** diff --git a/tests/system/Models/ValidationModelTest.php b/tests/system/Models/ValidationModelTest.php index 0d60d36524ac..e7cc4a8d11e5 100644 --- a/tests/system/Models/ValidationModelTest.php +++ b/tests/system/Models/ValidationModelTest.php @@ -55,6 +55,29 @@ public function testValidationBasics(): void $this->assertSame('You forgot to name the baby.', $errors['name']); } + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5859 + */ + public function testValidationTwice(): void + { + $data = [ + 'name' => null, + 'description' => 'some great marketing stuff', + ]; + + $this->assertFalse($this->model->insert($data)); + + $errors = $this->model->errors(); + $this->assertSame('You forgot to name the baby.', $errors['name']); + + $data = [ + 'name' => 'some name', + 'description' => 'some great marketing stuff', + ]; + + $this->assertIsInt($this->model->insert($data)); + } + public function testValidationWithSetValidationRule(): void { $data = [ From 8f1ed45f1bb3d2df34665e80767d171bd4cef167 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 11:42:31 +0900 Subject: [PATCH 1893/2325] feat: add $includeDir option to get_filenames() --- system/Helpers/filesystem_helper.php | 23 ++++++++++++------- tests/system/Helpers/FilesystemHelperTest.php | 16 +++++++++++++ .../source/helpers/filesystem_helper.rst | 7 +++--- 3 files changed, 35 insertions(+), 11 deletions(-) diff --git a/system/Helpers/filesystem_helper.php b/system/Helpers/filesystem_helper.php index 89d4d507f961..4918e87e7bf2 100644 --- a/system/Helpers/filesystem_helper.php +++ b/system/Helpers/filesystem_helper.php @@ -194,9 +194,14 @@ function delete_files(string $path, bool $delDir = false, bool $htdocs = false, * @param string $sourceDir Path to source * @param bool|null $includePath Whether to include the path as part of the filename; false for no path, null for a relative path, true for full path * @param bool $hidden Whether to include hidden files (files beginning with a period) + * @param bool $includeDir Whether to include directories */ - function get_filenames(string $sourceDir, ?bool $includePath = false, bool $hidden = false): array - { + function get_filenames( + string $sourceDir, + ?bool $includePath = false, + bool $hidden = false, + bool $includeDir = true + ): array { $files = []; $sourceDir = realpath($sourceDir) ?: $sourceDir; @@ -212,12 +217,14 @@ function get_filenames(string $sourceDir, ?bool $includePath = false, bool $hidd continue; } - if ($includePath === false) { - $files[] = $basename; - } elseif ($includePath === null) { - $files[] = str_replace($sourceDir, '', $name); - } else { - $files[] = $name; + if ($includeDir || ! $object->isDir()) { + if ($includePath === false) { + $files[] = $basename; + } elseif ($includePath === null) { + $files[] = str_replace($sourceDir, '', $name); + } else { + $files[] = $name; + } } } } catch (Throwable $e) { diff --git a/tests/system/Helpers/FilesystemHelperTest.php b/tests/system/Helpers/FilesystemHelperTest.php index d20d93481e39..c9f5789a9d4c 100644 --- a/tests/system/Helpers/FilesystemHelperTest.php +++ b/tests/system/Helpers/FilesystemHelperTest.php @@ -305,6 +305,22 @@ public function testGetFilenames() $this->assertSame($expected, get_filenames($vfs->url(), false)); } + public function testGetFilenamesWithoutDirectories() + { + $vfs = vfsStream::setup('root', null, $this->structure); + + $filenames = get_filenames($vfs->url(), true, false, false); + + $expected = [ + 'vfs://root/boo/far', + 'vfs://root/boo/faz', + 'vfs://root/foo/bar', + 'vfs://root/foo/baz', + 'vfs://root/simpleFile', + ]; + $this->assertSame($expected, $filenames); + } + public function testGetFilenamesWithHidden() { $this->assertTrue(function_exists('get_filenames')); diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 4cb00fb23188..017ee9a82149 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -150,11 +150,12 @@ The following functions are available: .. note:: The files must be writable or owned by the system in order to be deleted. -.. php:function:: get_filenames($source_dir[, $include_path = false]) +.. php:function:: get_filenames($sourceDir[, $includePath = false[, $hidden = false[, $includeDir = true]]]) - :param string $source_dir: Directory path - :param bool|null $include_path: Whether to include the path as part of the filename; false for no path, null for the path relative to $source_dir, true for the full path + :param string $sourceDir: Directory path + :param bool|null $includePath: Whether to include the path as part of the filename; false for no path, null for the path relative to ``$sourceDir``, true for the full path :param bool $hidden: Whether to include hidden files (files beginning with a period) + :param bool $includeDir: Whether to include directories :returns: An array of file names :rtype: array From 7b442c6a49fb469de6998531433be82cb1ce3345 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 13:00:45 +0900 Subject: [PATCH 1894/2325] docs: fix function reference --- .../source/helpers/filesystem_helper.rst | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 4cb00fb23188..e45c7ce31565 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -21,10 +21,10 @@ Available Functions The following functions are available: -.. php:function:: directory_map($source_dir[, $directory_depth = 0[, $hidden = false]]) +.. php:function:: directory_map($sourceDir[, $directoryDepth = 0[, $hidden = false]]) - :param string $source_dir: Path to the source directory - :param int $directory_depth: Depth of directories to traverse (0 = fully recursive, 1 = current dir, etc) + :param string $sourceDir: Path to the source directory + :param int $directoryDepth: Depth of directories to traverse (0 = fully recursive, 1 = current dir, etc) :param bool $hidden: Whether to include hidden paths :returns: An array of files :rtype: array @@ -167,10 +167,10 @@ The following functions are available: .. literalinclude:: filesystem_helper/010.php -.. php:function:: get_dir_file_info($source_dir, $top_level_only) +.. php:function:: get_dir_file_info($sourceDir[, $topLevelOnly = true]) - :param string $source_dir: Directory path - :param bool $top_level_only: Whether to look only at the specified directory (excluding sub-directories) + :param string $sourceDir: Directory path + :param bool $topLevelOnly: Whether to look only at the specified directory (excluding sub-directories) :returns: An array containing info on the supplied directory's contents :rtype: array @@ -183,10 +183,10 @@ The following functions are available: .. literalinclude:: filesystem_helper/011.php -.. php:function:: get_file_info($file[, $returned_values = ['name', 'server_path', 'size', 'date']]) +.. php:function:: get_file_info($file[, $returnedValues = ['name', 'server_path', 'size', 'date']]) :param string $file: File path - :param array|string $returned_values: What type of info to return to be passed as array or comma separated string + :param array|string $returnedValues: What type of info to return to be passed as array or comma separated string :returns: An array containing info on the specified file or false on failure :rtype: array @@ -194,8 +194,8 @@ The following functions are available: information attributes for a file. Second parameter allows you to explicitly declare what information you want returned. - Valid ``$returned_values`` options are: `name`, `size`, `date`, `readable`, `writeable`, - `executable` and `fileperms`. + Valid ``$returnedValues`` options are: ``name``, ``size``, ``date``, ``readable``, ``writeable``, + ``executable`` and ``fileperms``. .. php:function:: symbolic_permissions($perms) @@ -230,10 +230,10 @@ The following functions are available: .. literalinclude:: filesystem_helper/014.php -.. php:function:: set_realpath($path[, $check_existence = false]) +.. php:function:: set_realpath($path[, $checkExistence = false]) :param string $path: Path - :param bool $check_existence: Whether to check if the path actually exists + :param bool $checkExistence: Whether to check if the path actually exists :returns: An absolute path :rtype: string From e19872ad2cc39b6f7142c1f024a7e2cd8f4020f6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 16:52:30 +0900 Subject: [PATCH 1895/2325] docs: remove HackerOne link CI4 does not use HackerOne. --- contributing/bug_report.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/contributing/bug_report.md b/contributing/bug_report.md index c564a9a734f4..43767cdd1766 100644 --- a/contributing/bug_report.md +++ b/contributing/bug_report.md @@ -27,15 +27,7 @@ have found a bug, again - please ask on the forums first. ## Security -Did you find a security issue in CodeIgniter? - -Please *don't* disclose it publicly, but e-mail us at -, or report it via our page on -[HackerOne](https://hackerone.com/codeigniter). - -If you've found a critical vulnerability, we'd be happy to credit you in -our -[ChangeLog](https://codeigniter4.github.io/CodeIgniter4/changelogs/index.html). +See [SECURITY.md](../SECURITY.md). ## Tips for a Good Issue Report From 70af24e461382a2c895a139f87e3c4960a111ba6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 17:21:12 +0900 Subject: [PATCH 1896/2325] chore: rename php-cs-fixer config files The php-cs-fixer configuration files are all in one place and easy to find. --- .github/workflows/test-coding-standards.yml | 4 ++-- .php-cs-fixer.dist.php | 4 ++-- ...r.php-cs-fixer.dist.php => .php-cs-fixer.no-header.php | 2 +- ....php-cs-fixer.dist.php => .php-cs-fixer.user-guide.php | 2 +- admin/pre-commit | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) rename .no-header.php-cs-fixer.dist.php => .php-cs-fixer.no-header.php (95%) rename .user-guide.php-cs-fixer.dist.php => .php-cs-fixer.user-guide.php (95%) diff --git a/.github/workflows/test-coding-standards.yml b/.github/workflows/test-coding-standards.yml index e5b4a2043342..5fa13728b37d 100644 --- a/.github/workflows/test-coding-standards.yml +++ b/.github/workflows/test-coding-standards.yml @@ -52,10 +52,10 @@ jobs: run: composer update --ansi --no-interaction - name: Run lint on `app/`, `admin/`, `public/` - run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --config=.no-header.php-cs-fixer.dist.php --using-cache=no --diff + run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --config=.php-cs-fixer.no-header.php --using-cache=no --diff - name: Run lint on `system/`, `tests`, `utils/`, and root PHP files run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --using-cache=no --diff - name: Run lint on `user_guide_src/source/` - run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --config=.user-guide.php-cs-fixer.dist.php --using-cache=no --diff + run: vendor/bin/php-cs-fixer fix --verbose --ansi --dry-run --config=.php-cs-fixer.user-guide.php --using-cache=no --diff diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 7caeaec1035c..02c6549b2c03 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -29,8 +29,8 @@ ->notName('#Foobar.php$#') ->append([ __FILE__, - __DIR__ . '/.no-header.php-cs-fixer.dist.php', - __DIR__ . '/.user-guide.php-cs-fixer.dist.php', + __DIR__ . '/.php-cs-fixer.no-header.php', + __DIR__ . '/.php-cs-fixer.user-guide.php', __DIR__ . '/rector.php', __DIR__ . '/spark', __DIR__ . '/user_guide_src/renumerate.php', diff --git a/.no-header.php-cs-fixer.dist.php b/.php-cs-fixer.no-header.php similarity index 95% rename from .no-header.php-cs-fixer.dist.php rename to .php-cs-fixer.no-header.php index 153ac5bd1328..6c136cd4b164 100644 --- a/.no-header.php-cs-fixer.dist.php +++ b/.php-cs-fixer.no-header.php @@ -33,7 +33,7 @@ $overrides = []; $options = [ - 'cacheFile' => 'build/.no-header.php-cs-fixer.cache', + 'cacheFile' => 'build/.php-cs-fixer.no-header.cache', 'finder' => $finder, 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ diff --git a/.user-guide.php-cs-fixer.dist.php b/.php-cs-fixer.user-guide.php similarity index 95% rename from .user-guide.php-cs-fixer.dist.php rename to .php-cs-fixer.user-guide.php index 900c26ec81e1..8081d73698ca 100644 --- a/.user-guide.php-cs-fixer.dist.php +++ b/.php-cs-fixer.user-guide.php @@ -37,7 +37,7 @@ ]; $options = [ - 'cacheFile' => 'build/.user-guide.php-cs-fixer.cache', + 'cacheFile' => 'build/.php-cs-fixer.user-guide.cache', 'finder' => $finder, 'customFixers' => FixerGenerator::create('vendor/nexusphp/cs-config/src/Fixer', 'Nexus\\CsConfig\\Fixer'), 'customRules' => [ diff --git a/admin/pre-commit b/admin/pre-commit index e8fdcff64499..1fa6b15e5984 100644 --- a/admin/pre-commit +++ b/admin/pre-commit @@ -42,9 +42,9 @@ if [ "$FILES" != "" ]; then # Run on whole codebase to skip on unnecessary filtering # Run first on app, admin, public if [ -d /proc/cygdrive ]; then - ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php + ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.php-cs-fixer.no-header.php else - php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php + php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.php-cs-fixer.no-header.php fi if [ $? != 0 ]; then @@ -66,9 +66,9 @@ if [ "$FILES" != "" ]; then # Next, run on user_guide_src/source PHP files if [ -d /proc/cygdrive ]; then - ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.user-guide.php-cs-fixer.dist.php + ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.php-cs-fixer.user-guide.php else - php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.user-guide.php-cs-fixer.dist.php + php ./vendor/bin/php-cs-fixer fix --verbose --dry-run --diff --config=.php-cs-fixer.user-guide.php fi if [ $? != 0 ]; then From b71ed71595ff7e0828a6ad97a9e6e0e1082f5df1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 08:50:23 +0900 Subject: [PATCH 1897/2325] docs: fix by proofreading Co-authored-by: MGatner --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 2e23e448a8f9..ac9f562732b0 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -57,7 +57,7 @@ If you have only ``Blog\Models\UserModel``, the instance will be returned. But if you have both ``App\Models\UserModel`` and ``Blog\Models\UserModel``, The instance of ``App\Models\UserModel`` will be returned. -If you want to get ``Blog\Models\UserModel``, you need the option ``preferApp``: +If you want to get ``Blog\Models\UserModel``, you need to disable the option ``preferApp``: .. literalinclude:: factories/010.php From b1a77e71cff780d9079beaf3d291bdd715d4e2a9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 08:50:40 +0900 Subject: [PATCH 1898/2325] docs: fix by proofreading Co-authored-by: MGatner --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index ac9f562732b0..ca1025168367 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -71,7 +71,7 @@ you get back the instance as before: Convenience Functions ===================== -Two functions for short cut of the Factories have been provided. These functions are always available. +Two shortcut functions for Factories have been provided. These functions are always available. config() -------- From 12aa1aaf21e651d93f6c102445e866c7fe849585 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 08:51:14 +0900 Subject: [PATCH 1899/2325] docs: fix by proofreading Co-authored-by: MGatner --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index ca1025168367..5f34b4a1bb5a 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -140,7 +140,7 @@ Configurations To set default component options, create a new Config files at **app/Config/Factory.php** that supplies options as an array property that matches the name of the component. For example, -if you wanted to ensure that all **Filters** used by your app were valid framework instances, +if you want to ensure that each ``Filter`` used by your app is an actual framework, your **app/Config/Factory.php** file might look like this: .. literalinclude:: factories/005.php From d41fbe26f89ef1d9df9158aaf305ba9b32fca3d1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 08:53:26 +0900 Subject: [PATCH 1900/2325] docs: remove duplicated "unrelated" --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 5f34b4a1bb5a..600a153d1a8c 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -145,7 +145,7 @@ your **app/Config/Factory.php** file might look like this: .. literalinclude:: factories/005.php -This would prevent conflict of an unrelated third-party module which happened to have an +This would prevent conflict of an third-party module which happened to have an unrelated ``Filters`` path in its namespace. setOptions Method From ac6a97d04c7345223427a7243dd11735672d3dba Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 09:05:57 +0900 Subject: [PATCH 1901/2325] docs: add more explanation for filters component --- user_guide_src/source/concepts/factories.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 600a153d1a8c..ff5ea4faf140 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -139,12 +139,17 @@ Configurations -------------- To set default component options, create a new Config files at **app/Config/Factory.php** -that supplies options as an array property that matches the name of the component. For example, -if you want to ensure that each ``Filter`` used by your app is an actual framework, +that supplies options as an array property that matches the name of the component. + +For example, if you want to create **Filters** by Factories, the component name wll be ``filters``. +And if you want to ensure that each filter is an instance of a class which implements CodeIgniter's ``FilterInterface``, your **app/Config/Factory.php** file might look like this: .. literalinclude:: factories/005.php +Now you can create a filter with code like ``Factories::filters('SomeFilter')``, +and the returned instance will surely be a CodeIgniter's filter. + This would prevent conflict of an third-party module which happened to have an unrelated ``Filters`` path in its namespace. From 6214ece43aaf6207bd3007822cf7ac0c3f6cefe8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 09:45:36 +0900 Subject: [PATCH 1902/2325] docs: revise the description to be more accurate The property $component does not exist. --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index ff5ea4faf140..569fbaa7db1e 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -131,7 +131,7 @@ Factories Behavior Options can be applied in one of three ways (listed in ascending priority): -* A configuration class ``Config\Factory`` with a ``$component`` property. +* A configuration class ``Config\Factory`` with a property that matches the name of a component. * The static method ``Factories::setOptions()``. * Passing options directly at call time with a parameter. From ea781ab2351e1b74bfae71884f90cbf58e3eaa72 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 5 Apr 2022 17:58:37 +0900 Subject: [PATCH 1903/2325] chore: update composer scripts --- composer.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.json b/composer.json index 8d77bc48cde8..2a0329252a46 100644 --- a/composer.json +++ b/composer.json @@ -62,14 +62,14 @@ "analyze": "phpstan analyse", "test": "phpunit", "cs": [ - "php-cs-fixer fix --verbose --dry-run --diff --config=.user-guide.php-cs-fixer.dist.php", - "php-cs-fixer fix --verbose --dry-run --diff --config=.no-header.php-cs-fixer.dist.php", - "php-cs-fixer fix --verbose --dry-run --diff" + "php-cs-fixer fix --ansi --verbose --dry-run --diff --config=.php-cs-fixer.user-guide.php", + "php-cs-fixer fix --ansi --verbose --dry-run --diff --config=.php-cs-fixer.no-header.php", + "php-cs-fixer fix --ansi --verbose --dry-run --diff" ], "cs-fix": [ - "php-cs-fixer fix --verbose --diff --config=.user-guide.php-cs-fixer.dist.php", - "php-cs-fixer fix --verbose --diff --config=.no-header.php-cs-fixer.dist.php", - "php-cs-fixer fix --verbose --diff" + "php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.user-guide.php", + "php-cs-fixer fix --ansi --verbose --diff --config=.php-cs-fixer.no-header.php", + "php-cs-fixer fix --ansi --verbose --diff" ] }, "scripts-descriptions": { From c01667dbe1eff42313cdf115003cd4a65eef2e5b Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 17:28:08 +0900 Subject: [PATCH 1904/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 569fbaa7db1e..62d40b3352c9 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -9,7 +9,7 @@ Factories Introduction ============ -What is Factories? +What are Factories? ------------------ Like :doc:`./services`, **Factories** are an extension of autoloading that helps keep your code From cd2abe85e60626a26cfc5cbcbfc6517ef15515f7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 17:29:04 +0900 Subject: [PATCH 1905/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/concepts/factories.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 62d40b3352c9..d33c49e2398b 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -27,10 +27,10 @@ make sure the correct configuration is loaded when using the ``Config`` class. Differences from Services ------------------------- -Factories require a concrete class name to instantiate, and do not have code to create instances. +Factories require a concrete class name to instantiate and do not have code to create instances. -So Factories are not good for creating complex instance that needs many dependencies, -and cannot change the class of the instance to be returned. +So, Factories are not good for creating a complex instance that needs many dependencies, +and you cannot change the class of the instance to be returned. On the other hand, Services have code to create instances, so it can create a complex instance that needs other services or class instances. When you get a service, Services require a service name, From 9dd0e02d0feda051865e99383ab775da6937b762 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 17:29:23 +0900 Subject: [PATCH 1906/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index d33c49e2398b..138b73c1342e 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -55,7 +55,7 @@ Or you could also request a specific class: If you have only ``Blog\Models\UserModel``, the instance will be returned. But if you have both ``App\Models\UserModel`` and ``Blog\Models\UserModel``, -The instance of ``App\Models\UserModel`` will be returned. +the instance of ``App\Models\UserModel`` will be returned. If you want to get ``Blog\Models\UserModel``, you need to disable the option ``preferApp``: From 1b1d03c6363bb0db9b0a935440d791fce2f54859 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 17:31:59 +0900 Subject: [PATCH 1907/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/concepts/services.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/services.rst b/user_guide_src/source/concepts/services.rst index b69a4e4c4f85..632ad10cedf0 100644 --- a/user_guide_src/source/concepts/services.rst +++ b/user_guide_src/source/concepts/services.rst @@ -115,7 +115,7 @@ In some instances, you will want the option to pass a setting to the class durin Since the services file is a very simple class, it is easy to make this work. A good example is the ``renderer`` service. By default, we want this class to be able -to find the views at ``APPPATH . views/``. We want the developer to have the option of +to find the views at ``APPPATH . 'views/'``. We want the developer to have the option of changing that path, though, if their needs require it. So the class accepts the ``$viewPath`` as a constructor parameter. The service method looks like this: From 606518ac686abfe275a40727f747199c8d921e60 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 17:33:37 +0900 Subject: [PATCH 1908/2325] docs: fix by proofreading Co-authored-by: John Paul E. Balandan, CPA <51850998+paulbalandan@users.noreply.github.com> --- user_guide_src/source/helpers/filesystem_helper.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/helpers/filesystem_helper.rst b/user_guide_src/source/helpers/filesystem_helper.rst index 017ee9a82149..6d7618b9d783 100644 --- a/user_guide_src/source/helpers/filesystem_helper.rst +++ b/user_guide_src/source/helpers/filesystem_helper.rst @@ -155,7 +155,7 @@ The following functions are available: :param string $sourceDir: Directory path :param bool|null $includePath: Whether to include the path as part of the filename; false for no path, null for the path relative to ``$sourceDir``, true for the full path :param bool $hidden: Whether to include hidden files (files beginning with a period) - :param bool $includeDir: Whether to include directories + :param bool $includeDir: Whether to include directories in the array output :returns: An array of file names :rtype: array From 3fe7b8a45a2455a4cb3b2e7a1e2aa47072f883ba Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 17:44:29 +0900 Subject: [PATCH 1909/2325] docs: add changelog --- user_guide_src/source/changelogs/v4.2.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 99f980d6b35e..0ed69ab0760a 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -37,6 +37,7 @@ Enhancements - Exception information logged through ``log_message()`` has now improved. It now includes the file and line where the exception originated. It also does not truncate the message anymore. - The log format has also changed. If users are depending on the log format in their apps, the new log format is "<1-based count> (): " - Added support for webp files to **app/Config/Mimes.php**. +- Added 4th parameter ``$includeDir`` to ``get_filenames()``. See :php:func:`get_filenames`. Changes ******* From 9f2d3ced709e1774128b03a9831424d90b26e29f Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 6 Apr 2022 20:23:33 +0900 Subject: [PATCH 1910/2325] docs: fix title underline factories.rst:13: WARNING: Title underline too short. --- user_guide_src/source/concepts/factories.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/factories.rst b/user_guide_src/source/concepts/factories.rst index 138b73c1342e..754f831257e3 100644 --- a/user_guide_src/source/concepts/factories.rst +++ b/user_guide_src/source/concepts/factories.rst @@ -10,7 +10,7 @@ Introduction ============ What are Factories? ------------------- +------------------- Like :doc:`./services`, **Factories** are an extension of autoloading that helps keep your code concise yet optimal, without having to pass around object instances between classes. From df954fae54dc76873b6a16e883aac791f9f0a48f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 Apr 2022 15:05:18 +0000 Subject: [PATCH 1911/2325] chore(deps-dev): update rector/rector requirement Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.12.19...0.12.20) --- 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 8d77bc48cde8..e21ae85ecff3 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.0", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.19" + "rector/rector": "0.12.20" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From 5ee5304c24cc96df3a2d6c3dcf0ca069454da40c Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 7 Apr 2022 08:47:57 +0900 Subject: [PATCH 1912/2325] docs: update `spark migrate:status` output --- user_guide_src/source/dbmgmt/migration.rst | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/dbmgmt/migration.rst b/user_guide_src/source/dbmgmt/migration.rst index cd5787328a96..ff81f4ff0708 100644 --- a/user_guide_src/source/dbmgmt/migration.rst +++ b/user_guide_src/source/dbmgmt/migration.rst @@ -162,8 +162,13 @@ You can use (refresh) with the following options: Displays a list of all migrations and the date and time they ran, or '--' if they have not been run:: > php spark migrate:status - Filename Migrated On - First_migration.php 2016-04-25 04:44:22 + +----------------------+-------------------+-----------------------+---------+---------------------+-------+ + | Namespace | Version | Filename | Group | Migrated On | Batch | + +----------------------+-------------------+-----------------------+---------+---------------------+-------+ + | App | 2022-04-06-234508 | CreateCiSessionsTable | default | 2022-04-06 18:45:14 | 2 | + | CodeIgniter\Settings | 2021-07-04-041948 | CreateSettingsTable | default | 2022-04-06 01:23:08 | 1 | + | CodeIgniter\Settings | 2021-11-14-143905 | AddContextColumn | default | 2022-04-06 01:23:08 | 1 | + +----------------------+-------------------+-----------------------+---------+---------------------+-------+ You can use (status) with the following options: From 180dca40ece4a328892bbdbf050f5d7394cec947 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 7 Apr 2022 08:48:31 +0900 Subject: [PATCH 1913/2325] docs: update deprecated command --- user_guide_src/source/libraries/sessions.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/sessions.rst b/user_guide_src/source/libraries/sessions.rst index 59557db92cf8..11ac22f12add 100644 --- a/user_guide_src/source/libraries/sessions.rst +++ b/user_guide_src/source/libraries/sessions.rst @@ -569,10 +569,10 @@ You can choose the Database group to use by adding a new line to the .. literalinclude:: sessions/040.php -If you'd rather not do all of this by hand, you can use the ``session:migration`` command +If you'd rather not do all of this by hand, you can use the ``make:migration --session`` command from the cli to generate a migration file for you:: - > php spark session:migration + > php spark make:migration --session > php spark migrate This command will take the **sessionSavePath** and **sessionMatchIP** settings into account From 7b58b7217eb556d2e91edae5f8b5813abfb16f59 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 7 Apr 2022 13:27:54 +0900 Subject: [PATCH 1914/2325] chore: update gitattributes --- .gitattributes | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitattributes b/.gitattributes index 79c65323dade..de04ad191549 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,17 +14,23 @@ contributing/ export-ignore .editorconfig export-ignore .nojekyll export-ignore export-ignore CODE_OF_CONDUCT.md export-ignore +CONTRIBUTING.md export-ignore PULL_REQUEST_TEMPLATE.md export-ignore stale.yml export-ignore Vagrantfile.dist export-ignore # They don't want our test files +tests/AutoReview/ export-ignore tests/system/ export-ignore utils/ export-ignore +depfile.yaml export-ignore rector.php export-ignore phpunit.xml.dist export-ignore +phpstan-baseline.neon.dist export-ignore phpstan.neon.dist export-ignore .php-cs-fixer.dist.php export-ignore +.php-cs-fixer.no-header.php export-ignore +.php-cs-fixer.user-guide.php export-ignore # The source user guide, either user_guide_src/ export-ignore From 53cdb671b8b4e04b7d4a0752dd3b6046819abb52 Mon Sep 17 00:00:00 2001 From: "Michael R. Krisnadhi" Date: Fri, 8 Apr 2022 16:08:14 +0700 Subject: [PATCH 1915/2325] clarify Models user guide Inform the $useAutoIncrement default value (which is 'true'), so developers would be aware of that option if they don't use auto-incremented INT's on primary keys, especially when triggering an 'afterInsert' event which will eventually cause the $data['id'] value to be 0 instead of the actual primary key (see 'system/Model.php' line 254 : https://github.com/codeigniter4/CodeIgniter4/blob/622d50aa2976b85f7cb1479faec7558cd9ec2341/system/Model.php#L254) --- user_guide_src/source/models/model.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index f55e60656c03..fa354d7c3aff 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -99,7 +99,8 @@ is used with methods like ``find()`` to know what column to match the specified Specifies if the table uses an auto-increment feature for ``$primaryKey``. If set to ``false`` then you are responsible for providing primary key value for every record in the table. This -feature may be handy when we want to implement 1:1 relation or use UUIDs for our model. +feature may be handy when we want to implement 1:1 relation or use UUIDs for our model. The +default value is ``true``. .. note:: If you set ``$useAutoIncrement`` to ``false``, then make sure to set your primary key in the database to ``unique``. This way you will make sure that all of Model's features From 3fc0c6b61bd318f73090cf1cc672ba303c7b09b2 Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Fri, 8 Apr 2022 20:34:42 +0700 Subject: [PATCH 1916/2325] add `literalinclude` for curlrequest -> debug --- user_guide_src/source/libraries/curlrequest.rst | 2 +- user_guide_src/source/libraries/curlrequest/034.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 user_guide_src/source/libraries/curlrequest/034.php diff --git a/user_guide_src/source/libraries/curlrequest.rst b/user_guide_src/source/libraries/curlrequest.rst index 3d0b91b511fb..b77d41e6b088 100644 --- a/user_guide_src/source/libraries/curlrequest.rst +++ b/user_guide_src/source/libraries/curlrequest.rst @@ -219,7 +219,7 @@ script execution. This is done by passing CURLOPT_VERBOSE and echoing the output server via ``spark serve`` you will see the output in the console. Otherwise, the output will be written to the server's error log. - $response->request('GET', 'http://example.com', ['debug' => true]); +.. literalinclude:: curlrequest/034.php You can pass a filename as the value for debug to have the output written to a file: diff --git a/user_guide_src/source/libraries/curlrequest/034.php b/user_guide_src/source/libraries/curlrequest/034.php new file mode 100644 index 000000000000..1560cd589fec --- /dev/null +++ b/user_guide_src/source/libraries/curlrequest/034.php @@ -0,0 +1,3 @@ +request('GET', 'http://example.com', ['debug' => true]); From fc8946faf361a6571beccba1b054fd33ecae581a Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Fri, 8 Apr 2022 20:44:35 +0700 Subject: [PATCH 1917/2325] fix parameters display for API response > `setResponseFormat($format)` method --- user_guide_src/source/outgoing/api_responses.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index 6d657e6bc765..bdb853563e2b 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -60,7 +60,7 @@ Class Reference *************** .. php:method:: setResponseFormat($format) - :param string $format The type of response to return, either ``json`` or ``xml`` + :param string $format: The type of response to return, either ``json`` or ``xml`` This defines the format to be used when formatting arrays in responses. If you provide a ``null`` value for ``$format``, it will be automatically determined through content negotiation. From 5161942e2c0211698ff7242f5df9d8e8aef1e757 Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Fri, 8 Apr 2022 21:07:41 +0700 Subject: [PATCH 1918/2325] fix paths --- user_guide_src/source/general/managing_apps.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index 0681b1b534e6..fc00dcd06985 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -25,7 +25,7 @@ your main **app/Config/Paths.php** and set a *full server path* in the You will need to modify two additional files in your project root, so that they can find the **Paths** configuration file: -- **/spark** runs command line apps; the path is specified on or about line 35: +- **/spark** runs command line apps; the path is specified on or about line 49: .. literalinclude:: managing_apps/002.php From 571923915b7b431d055407f51c1201a1979f2da9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Apr 2022 15:03:24 +0000 Subject: [PATCH 1919/2325] chore(deps): bump actions/upload-artifact from 2 to 3 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 2 to 3. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v2...v3) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/deploy-userguide-latest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-userguide-latest.yml b/.github/workflows/deploy-userguide-latest.yml index fb453f0c9694..8fc77b9f7698 100644 --- a/.github/workflows/deploy-userguide-latest.yml +++ b/.github/workflows/deploy-userguide-latest.yml @@ -29,7 +29,7 @@ jobs: # Create an artifact of the html output - name: Upload artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: HTML Documentation path: user_guide_src/build/html/ From 022563377e7e995fc7b6845e4a8e026d545ee876 Mon Sep 17 00:00:00 2001 From: Toto Prayogo Date: Sat, 9 Apr 2022 03:44:19 +0700 Subject: [PATCH 1920/2325] change `$request->` to `$client->` --- user_guide_src/source/libraries/curlrequest/020.php | 2 +- user_guide_src/source/libraries/curlrequest/021.php | 2 +- user_guide_src/source/libraries/curlrequest/022.php | 2 +- user_guide_src/source/libraries/curlrequest/023.php | 2 +- user_guide_src/source/libraries/curlrequest/030.php | 2 +- user_guide_src/source/libraries/curlrequest/031.php | 2 +- user_guide_src/source/libraries/curlrequest/034.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/libraries/curlrequest/020.php b/user_guide_src/source/libraries/curlrequest/020.php index 6e0b1e3726a7..14fad31cdea4 100644 --- a/user_guide_src/source/libraries/curlrequest/020.php +++ b/user_guide_src/source/libraries/curlrequest/020.php @@ -1,3 +1,3 @@ request('GET', 'http://example.com', ['connect_timeout' => 0]); +$client->request('GET', 'http://example.com', ['connect_timeout' => 0]); diff --git a/user_guide_src/source/libraries/curlrequest/021.php b/user_guide_src/source/libraries/curlrequest/021.php index 4acf82aa9e0b..051df32e1a37 100644 --- a/user_guide_src/source/libraries/curlrequest/021.php +++ b/user_guide_src/source/libraries/curlrequest/021.php @@ -1,3 +1,3 @@ request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); +$client->request('GET', 'http://example.com', ['cookie' => WRITEPATH . 'CookieSaver.txt']); diff --git a/user_guide_src/source/libraries/curlrequest/022.php b/user_guide_src/source/libraries/curlrequest/022.php index 6acbcf0a7784..69b0e4ed8bec 100644 --- a/user_guide_src/source/libraries/curlrequest/022.php +++ b/user_guide_src/source/libraries/curlrequest/022.php @@ -1,3 +1,3 @@ request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); +$client->request('GET', 'http://example.com', ['debug' => '/usr/local/curl_log.txt']); diff --git a/user_guide_src/source/libraries/curlrequest/023.php b/user_guide_src/source/libraries/curlrequest/023.php index b6846257ad83..61e6f6df5214 100644 --- a/user_guide_src/source/libraries/curlrequest/023.php +++ b/user_guide_src/source/libraries/curlrequest/023.php @@ -1,4 +1,4 @@ request('GET', 'http://example.com', ['delay' => 2000]); +$client->request('GET', 'http://example.com', ['delay' => 2000]); diff --git a/user_guide_src/source/libraries/curlrequest/030.php b/user_guide_src/source/libraries/curlrequest/030.php index 83bf718e33e4..16c0c6fd6c49 100644 --- a/user_guide_src/source/libraries/curlrequest/030.php +++ b/user_guide_src/source/libraries/curlrequest/030.php @@ -1,3 +1,3 @@ request('GET', 'http://example.com', ['timeout' => 5]); +$client->request('GET', 'http://example.com', ['timeout' => 5]); diff --git a/user_guide_src/source/libraries/curlrequest/031.php b/user_guide_src/source/libraries/curlrequest/031.php index 1709d6d90b9c..8023c84faa39 100644 --- a/user_guide_src/source/libraries/curlrequest/031.php +++ b/user_guide_src/source/libraries/curlrequest/031.php @@ -1,3 +1,3 @@ request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); +$client->request('GET', 'http://example.com', ['user_agent' => 'CodeIgniter Framework v4']); diff --git a/user_guide_src/source/libraries/curlrequest/034.php b/user_guide_src/source/libraries/curlrequest/034.php index 1560cd589fec..9e343aa9d9da 100644 --- a/user_guide_src/source/libraries/curlrequest/034.php +++ b/user_guide_src/source/libraries/curlrequest/034.php @@ -1,3 +1,3 @@ request('GET', 'http://example.com', ['debug' => true]); +$client->request('GET', 'http://example.com', ['debug' => true]); From 830750edd49d9fe5219ff2f581afdfec63e93c56 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 9 Apr 2022 09:04:37 +0900 Subject: [PATCH 1921/2325] feat: throws exception when controller name in routes contains `/` --- system/Language/en/Router.php | 1 + system/Router/Exceptions/RouterException.php | 10 ++++++++++ system/Router/Router.php | 5 +++++ tests/system/Router/RouterTest.php | 12 ++++++++++++ 4 files changed, 28 insertions(+) diff --git a/system/Language/en/Router.php b/system/Language/en/Router.php index 90aaa132b489..7d0b5cc99e25 100644 --- a/system/Language/en/Router.php +++ b/system/Language/en/Router.php @@ -14,4 +14,5 @@ 'invalidParameter' => 'A parameter does not match the expected type.', 'missingDefaultRoute' => 'Unable to determine what should be displayed. A default route has not been specified in the routing file.', 'invalidDynamicController' => 'A dynamic controller is not allowed for security reasons. Route handler: {0}', + 'invalidControllerName' => 'The namespace delimiter is a backslash (\), not a slash (/). Route handler: {0}', ]; diff --git a/system/Router/Exceptions/RouterException.php b/system/Router/Exceptions/RouterException.php index b50042b3421b..5a510e4716fe 100644 --- a/system/Router/Exceptions/RouterException.php +++ b/system/Router/Exceptions/RouterException.php @@ -68,4 +68,14 @@ public static function forDynamicController(string $handler) { return new static(lang('Router.invalidDynamicController', [$handler])); } + + /** + * Throw when controller name has `/`. + * + * @return RouterException + */ + public static function forInvalidControllerName(string $handler) + { + return new static(lang('Router.invalidControllerName', [$handler])); + } } diff --git a/system/Router/Router.php b/system/Router/Router.php index 42f2eb0c7a42..37c88114172e 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -426,6 +426,11 @@ protected function checkRoutes(string $uri): bool throw RouterException::forDynamicController($handler); } + // Checks `/` in controller name + if (strpos($controller, '/') !== false) { + throw RouterException::forInvalidControllerName($handler); + } + if (strpos($routeKey, '/') !== false) { $replacekey = str_replace('/(.*)', '', $routeKey); $handler = preg_replace('#^' . $routeKey . '$#u', $handler, $uri); diff --git a/tests/system/Router/RouterTest.php b/tests/system/Router/RouterTest.php index d3ca04422c41..38eb9b7ba48c 100644 --- a/tests/system/Router/RouterTest.php +++ b/tests/system/Router/RouterTest.php @@ -61,6 +61,7 @@ protected function setUp(): void 'closure/(:num)/(:alpha)' => static fn ($num, $str) => $num . '-' . $str, '{locale}/pages' => 'App\Pages::list_all', 'admin/admins' => 'App\Admin\Admins::list_all', + 'admin/admins/edit/(:any)' => 'App/Admin/Admins::edit_show/$1', '/some/slash' => 'App\Slash::index', 'objects/(:segment)/sort/(:segment)/([A-Z]{3,7})' => 'AdminList::objectsSortCreate/$1/$2/$3', '(:segment)/(:segment)/(:segment)' => '$2::$3/$1', @@ -402,6 +403,17 @@ public function testRouteResource() $this->assertSame('list_all', $router->methodName()); } + public function testRouteWithSlashInControllerName() + { + $this->expectExceptionMessage( + 'The namespace delimiter is a backslash (\), not a slash (/). Route handler: \App/Admin/Admins::edit_show/$1' + ); + + $router = new Router($this->collection, $this->request); + + $router->handle('admin/admins/edit/1'); + } + public function testRouteWithLeadingSlash() { $router = new Router($this->collection, $this->request); From 1640b8f89b069d66d1318768371ab0ed9cb554bf Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 9 Apr 2022 09:29:24 +0900 Subject: [PATCH 1922/2325] docs: fix heading level --- user_guide_src/source/outgoing/api_responses.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/outgoing/api_responses.rst b/user_guide_src/source/outgoing/api_responses.rst index bdb853563e2b..0500a8ee92dd 100644 --- a/user_guide_src/source/outgoing/api_responses.rst +++ b/user_guide_src/source/outgoing/api_responses.rst @@ -56,8 +56,10 @@ So, if your request asks for JSON formatted data in an **Accept** header, the da ``respond*`` or ``fail*`` methods will be formatted by the ``CodeIgniter\Format\JSONFormatter`` class. The resulting JSON data will be sent back to the client. +*************** Class Reference *************** + .. php:method:: setResponseFormat($format) :param string $format: The type of response to return, either ``json`` or ``xml`` From 7c137dc250553cb118435d50a52b03e48beeab65 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 9 Apr 2022 09:46:23 +0900 Subject: [PATCH 1923/2325] docs: add TOC --- user_guide_src/source/installation/upgrade_4xx.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index 03d72ac160eb..2166dda681a4 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -25,6 +25,10 @@ them one by one. **Do read the user guide** before embarking on a project conversion! +.. contents:: + :local: + :depth: 2 + General Adjustments =================== From fd6c6e5378c9358bd92713ee0d0f9d043e0fffcc Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 9 Apr 2022 09:46:45 +0900 Subject: [PATCH 1924/2325] docs: fix heading underlines --- .../source/installation/upgrade_4xx.rst | 31 ++++++++++++------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_4xx.rst b/user_guide_src/source/installation/upgrade_4xx.rst index 2166dda681a4..a97a2e339a29 100644 --- a/user_guide_src/source/installation/upgrade_4xx.rst +++ b/user_guide_src/source/installation/upgrade_4xx.rst @@ -30,18 +30,21 @@ them one by one. :depth: 2 General Adjustments -=================== +******************* -**Downloads** +Downloads +========= - CI4 is still available as a ready-to-run zip or tarball. - It can also be installed using Composer. -**Namespaces** +Namespaces +========== - CI4 is built for PHP 7.4+, and everything in the framework is namespaced, except for the helpers. -**Application Structure** +Application Structure +===================== - The **application** folder is renamed as **app** and the framework still has **system** folders, with the same interpretation as before. @@ -52,7 +55,8 @@ General Adjustments - There is no longer a nested **application/core** folder, as we have a different mechanism for extending framework components (see below). -**Model, View and Controller** +Model, View and Controller +========================== - CodeIgniter is based on the MVC concept. Thus, the changes on the Model, View and Controller are one of the most important things you have to handle. @@ -75,7 +79,8 @@ General Adjustments upgrade_views upgrade_controllers -**Class loading** +Class Loading +============= - There is no longer a CodeIgniter "superobject", with framework component references magically injected as properties of your controller. @@ -87,27 +92,31 @@ General Adjustments - You can configure the class loading to support whatever application structure you are most comfortable with, including the "HMVC" style. -**Libraries** +Libraries +========= - Your app classes can still go inside **app/Libraries**, but they don't have to. - Instead of CI3's ``$this->load->library(x);`` you can now use ``$this->x = new X();``, following namespaced conventions for your component. -**Helpers** +Helpers +======= - Helpers are pretty much the same as before, though some have been simplified. - In CI4, ``redirect()`` returns a ``RedirectResponse`` instance instead of redirecting and terminating script execution. You must return it. - `redirect() Documentation CodeIgniter 3.X `_ - `redirect() Documentation CodeIgniter 4.X <../general/common_functions.html#redirect>`_ -**Events** +Events +====== - Hooks have been replaced by Events. - Instead of CI3's ``$hook['post_controller_constructor']`` you now use ``Events::on('post_controller_constructor', ['MyClass', 'MyFunction']);``, with the namespace ``CodeIgniter\Events\Events;``. - Events are always enabled, and are available globally. -**Extending the framework** +Extending the Framework +======================= - You don't need a **core** folder to hold ``MY_...`` framework component extensions or replacements. @@ -118,7 +127,7 @@ General Adjustments your components instead of the default ones. Upgrading Libraries -=================== +******************* - Your app classes can still go inside **app/Libraries**, but they don't have to. - Instead of CI3's ``$this->load->library(x);`` you can now use ``$this->x = new X();``, From ab0d86b96726e89ce3a27b87d45190c7ea8b7968 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 9 Apr 2022 10:43:07 +0900 Subject: [PATCH 1925/2325] docs: add link to the detailed page --- user_guide_src/source/changelogs/v4.2.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 0ed69ab0760a..c0081761ffd4 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -27,7 +27,7 @@ Enhancements - Added the config ``$autoNonce`` in ``Config\ContentSecurityPolicy`` to disable the CSP placeholder replacement - Added the functions ``csp_script_nonce()`` and ``csp_style_nonce()`` to get nonce attributes - See :ref:`content-security-policy` for details. -- New View Decorators allow modifying the generated HTML prior to caching. +- New :doc:`../outgoing/view_decorators` allow modifying the generated HTML prior to caching. - Added Subqueries in the FROM section. See :ref:`query-builder-from-subquery`. - Added Subqueries in the SELECT section. See :ref:`query-builder-select`. - Added Validation Strict Rules. See :ref:`validation-traditional-and-strict-rules`. From 7f595062e2111b39a10a5300eca45cf8076908e8 Mon Sep 17 00:00:00 2001 From: Chl Date: Fri, 8 Apr 2022 23:31:04 +0200 Subject: [PATCH 1926/2325] script_tag: cosmetic for value-less attributes Some attributes are usually written without values, for example : `'; + return $script . 'type="text/javascript">'; } } diff --git a/tests/system/Helpers/HTMLHelperTest.php b/tests/system/Helpers/HTMLHelperTest.php index b3ed47d0c3e6..74b087228fdd 100755 --- a/tests/system/Helpers/HTMLHelperTest.php +++ b/tests/system/Helpers/HTMLHelperTest.php @@ -248,6 +248,27 @@ public function testScriptTagWithIndexpage() $this->assertSame($expected, script_tag($target, true)); } + public function testScriptTagWithSrc() + { + $target = ['src' => 'http://site.com/js/mystyles.js']; + $expected = ''; + $this->assertSame($expected, script_tag($target)); + } + + public function testScriptTagWithSrcWithoutProtocol() + { + $target = ['src' => 'js/mystyles.js']; + $expected = ''; + $this->assertSame($expected, script_tag($target)); + } + + public function testScriptTagWithSrcAndAttributes() + { + $target = ['src' => 'js/mystyles.js', 'charset' => 'UTF-8', 'defer' => '', 'async' => null]; + $expected = ''; + $this->assertSame($expected, script_tag($target)); + } + public function testLinkTag() { $target = 'css/mystyles.css'; diff --git a/user_guide_src/source/helpers/html_helper/011.php b/user_guide_src/source/helpers/html_helper/011.php index 126fd86c4952..f47bb7053770 100644 --- a/user_guide_src/source/helpers/html_helper/011.php +++ b/user_guide_src/source/helpers/html_helper/011.php @@ -1,6 +1,6 @@ 'js/printer.js']; +$script = ['src' => 'js/printer.js', 'defer' => null]; echo script_tag($script); -// +// From a8d5b894c9ae17f1a8c8721eae44c0da22bec87c Mon Sep 17 00:00:00 2001 From: Chl Date: Sun, 10 Apr 2022 03:10:15 +0200 Subject: [PATCH 1927/2325] coding style: cs-fixer is_null() rule --- system/Helpers/html_helper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index 0fc2f110399f..a15b18ff47e8 100755 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -208,7 +208,7 @@ function script_tag($src = '', bool $indexPage = false): string } } else { // for attributes without values, like async or defer, use NULL. - $script .= $k . (is_null($v) ? ' ' : '="' . $v . '" '); + $script .= $k . (null === $v ? ' ' : '="' . $v . '" '); } } From 16dde2391c09e725ea852685f41488d83d26f0d4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Apr 2022 18:16:27 +0900 Subject: [PATCH 1928/2325] fix: add Escaper Exception classes in $coreClassmap --- system/Config/AutoloadConfig.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/system/Config/AutoloadConfig.php b/system/Config/AutoloadConfig.php index 13a6721fd2e6..79cad2ab8d25 100644 --- a/system/Config/AutoloadConfig.php +++ b/system/Config/AutoloadConfig.php @@ -12,6 +12,9 @@ namespace CodeIgniter\Config; use Laminas\Escaper\Escaper; +use Laminas\Escaper\Exception\ExceptionInterface; +use Laminas\Escaper\Exception\InvalidArgumentException as EscaperInvalidArgumentException; +use Laminas\Escaper\Exception\RuntimeException; use Psr\Log\AbstractLogger; use Psr\Log\InvalidArgumentException; use Psr\Log\LoggerAwareInterface; @@ -103,15 +106,18 @@ class AutoloadConfig * @var array */ protected $coreClassmap = [ - AbstractLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php', - InvalidArgumentException::class => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php', - LoggerAwareInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php', - LoggerAwareTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php', - LoggerInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php', - LoggerTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php', - LogLevel::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php', - NullLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php', - Escaper::class => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php', + AbstractLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/AbstractLogger.php', + InvalidArgumentException::class => SYSTEMPATH . 'ThirdParty/PSR/Log/InvalidArgumentException.php', + LoggerAwareInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareInterface.php', + LoggerAwareTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerAwareTrait.php', + LoggerInterface::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerInterface.php', + LoggerTrait::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LoggerTrait.php', + LogLevel::class => SYSTEMPATH . 'ThirdParty/PSR/Log/LogLevel.php', + NullLogger::class => SYSTEMPATH . 'ThirdParty/PSR/Log/NullLogger.php', + ExceptionInterface::class => SYSTEMPATH . 'ThirdParty/Escaper/Exception/ExceptionInterface.php', + EscaperInvalidArgumentException::class => SYSTEMPATH . 'ThirdParty/Escaper/Exception/InvalidArgumentException.php', + RuntimeException::class => SYSTEMPATH . 'ThirdParty/Escaper/Exception/RuntimeException.php', + Escaper::class => SYSTEMPATH . 'ThirdParty/Escaper/Escaper.php', ]; /** From 61999b0205bb76825027d394ce54e00bf72eac16 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Apr 2022 11:57:03 +0900 Subject: [PATCH 1929/2325] fix: multiple CLI::color() inside CLI::write() change color of strings that shouldn't be affected --- system/CLI/CLI.php | 75 ++++++++++++++++++++++++------------ tests/system/CLI/CLITest.php | 22 ++++++++++- 2 files changed, 71 insertions(+), 26 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 347a894f7578..4a55d2f7ef00 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -473,6 +473,10 @@ public static function color(string $text, string $foreground, ?string $backgrou return $text; } + if ($text === '') { + return $text; + } + if (! array_key_exists($foreground, static::$foreground_colors)) { throw CLIException::forInvalidColor('foreground', $foreground); } @@ -481,6 +485,51 @@ public static function color(string $text, string $foreground, ?string $backgrou throw CLIException::forInvalidColor('background', $background); } + // Reset text + $newText = ''; + + // Detect if color method was already in use with this text + if (strpos($text, "\033[0m") !== false) { + $pattern = '/\\033\\[0;.+?\\033\\[0m/u'; + + preg_match_all($pattern, $text, $matches); + $coloredStrings = $matches[0]; + + // No colored string found. Invalid strings with no `\033[0;??`. + if ($coloredStrings === []) { + $newText .= self::getColoredText($text, $foreground, $background, $format); + + return $newText; + } + + $nonColoredText = preg_replace( + $pattern, + '<<__colored_string__>>', + $text + ); + $nonColoredChunks = preg_split( + '/<<__colored_string__>>/u', + $nonColoredText + ); + + foreach ($nonColoredChunks as $i => $chunk) { + if ($chunk !== '') { + $newText .= self::getColoredText($chunk, $foreground, $background, $format); + } + + if (isset($coloredStrings[$i])) { + $newText .= $coloredStrings[$i]; + } + } + } else { + $newText .= self::getColoredText($text, $foreground, $background, $format); + } + + return $newText; + } + + private static function getColoredText(string $text, string $foreground, ?string $background, ?string $format): string + { $string = "\033[" . static::$foreground_colors[$foreground] . 'm'; if ($background !== null) { @@ -491,31 +540,9 @@ public static function color(string $text, string $foreground, ?string $backgrou $string .= "\033[4m"; } - // Detect if color method was already in use with this text - if (strpos($text, "\033[0m") !== false) { - // Split the text into parts so that we can see - // if any part missing the color definition - $chunks = mb_split('\\033\\[0m', $text); - // Reset text - $text = ''; - - foreach ($chunks as $chunk) { - if ($chunk === '') { - continue; - } - - // If chunk doesn't have colors defined we need to add them - if (strpos($chunk, "\033[") === false) { - $chunk = static::color($chunk, $foreground, $background, $format); - // Add color reset before chunk and clear end of the string - $text .= rtrim("\033[0m" . $chunk, "\033[0m"); - } else { - $text .= $chunk; - } - } - } + $string .= $text . "\033[0m"; - return $string . $text . "\033[0m"; + return $string; } /** diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 107ac1463e67..0c2b81c0b3e4 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -122,6 +122,7 @@ public function testColorSupportOnNoColor() CLI::init(); // force re-check on env $this->assertSame('test', CLI::color('test', 'white', 'green')); + putenv($nocolor ? "NO_COLOR={$nocolor}" : 'NO_COLOR'); } @@ -132,6 +133,7 @@ public function testColorSupportOnHyperTerminals() CLI::init(); // force re-check on env $this->assertSame("\033[1;37m\033[42m\033[4mtest\033[0m", CLI::color('test', 'white', 'green', 'underline')); + putenv($termProgram ? "TERM_PROGRAM={$termProgram}" : 'TERM_PROGRAM'); } @@ -190,14 +192,30 @@ public function testWriteForeground() public function testWriteForegroundWithColorBefore() { CLI::write(CLI::color('green', 'green') . ' red', 'red'); - $expected = "\033[0;31m\033[0;32mgreen\033[0m\033[0;31m red\033[0m" . PHP_EOL; + + $expected = "\033[0;32mgreen\033[0m\033[0;31m red\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } public function testWriteForegroundWithColorAfter() { CLI::write('red ' . CLI::color('green', 'green'), 'red'); - $expected = "\033[0;31mred \033[0;32mgreen\033[0m" . PHP_EOL; + + $expected = "\033[0;31mred \033[0m\033[0;32mgreen\033[0m" . PHP_EOL; + $this->assertSame($expected, CITestStreamFilter::$buffer); + } + + /** + * @see https://github.com/codeigniter4/CodeIgniter4/issues/5892 + */ + public function testWriteForegroundWithColorTwice() + { + CLI::write( + CLI::color('green', 'green') . ' red ' . CLI::color('green', 'green'), + 'red' + ); + + $expected = "\033[0;32mgreen\033[0m\033[0;31m red \033[0m\033[0;32mgreen\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } From f406f4aee220b3b85474219b3a4bf0397e914f48 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Apr 2022 12:47:57 +0900 Subject: [PATCH 1930/2325] refactor: vendor/bin/rector process --- system/CLI/CLI.php | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 4a55d2f7ef00..b43d0005ff77 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -497,9 +497,7 @@ public static function color(string $text, string $foreground, ?string $backgrou // No colored string found. Invalid strings with no `\033[0;??`. if ($coloredStrings === []) { - $newText .= self::getColoredText($text, $foreground, $background, $format); - - return $newText; + return $newText . self::getColoredText($text, $foreground, $background, $format); } $nonColoredText = preg_replace( @@ -540,9 +538,7 @@ private static function getColoredText(string $text, string $foreground, ?string $string .= "\033[4m"; } - $string .= $text . "\033[0m"; - - return $string; + return $string . ($text . "\033[0m"); } /** From 7688add69c8b1e5e87daf04e173d937bd09e4f7f Mon Sep 17 00:00:00 2001 From: Pooya Parsa Dadashi Date: Wed, 13 Apr 2022 09:02:52 +0430 Subject: [PATCH 1931/2325] mailPath Alright! --- user_guide_src/source/libraries/email.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/email.rst b/user_guide_src/source/libraries/email.rst index b610e69a20df..1287f961713a 100644 --- a/user_guide_src/source/libraries/email.rst +++ b/user_guide_src/source/libraries/email.rst @@ -108,7 +108,7 @@ Preference Default Value Options Descript =================== ====================== ============================ ======================================================================= **userAgent** CodeIgniter None The "user agent". **protocol** mail mail, sendmail, or smtp The mail sending protocol. -**mailpath** /usr/sbin/sendmail None The server path to Sendmail. +**mailPath** /usr/sbin/sendmail None The server path to Sendmail. **SMTPHost** No Default None SMTP Server Address. **SMTPUser** No Default None SMTP Username. **SMTPPass** No Default None SMTP Password. From 8995da98a74748cbca558f13addcc422b743cc05 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Apr 2022 21:24:16 +0900 Subject: [PATCH 1932/2325] test: add line breaks --- tests/system/CLI/CLITest.php | 51 +++++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 0c2b81c0b3e4..2f569e5c81c5 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -39,18 +39,21 @@ protected function tearDown(): void public function testNew() { $actual = new CLI(); + $this->assertInstanceOf(CLI::class, $actual); } public function testBeep() { $this->expectOutputString("\x07"); + CLI::beep(); } public function testBeep4() { $this->expectOutputString("\x07\x07\x07\x07"); + CLI::beep(4); } @@ -96,6 +99,7 @@ public function testIsWindows() public function testNewLine() { $this->expectOutputString(''); + CLI::newLine(); } @@ -119,8 +123,8 @@ public function testColorSupportOnNoColor() { $nocolor = getenv('NO_COLOR'); putenv('NO_COLOR=1'); - CLI::init(); // force re-check on env + $this->assertSame('test', CLI::color('test', 'white', 'green')); putenv($nocolor ? "NO_COLOR={$nocolor}" : 'NO_COLOR'); @@ -130,8 +134,8 @@ public function testColorSupportOnHyperTerminals() { $termProgram = getenv('TERM_PROGRAM'); putenv('TERM_PROGRAM=Hyper'); - CLI::init(); // force re-check on env + $this->assertSame("\033[1;37m\033[42m\033[4mtest\033[0m", CLI::color('test', 'white', 'green', 'underline')); putenv($termProgram ? "TERM_PROGRAM={$termProgram}" : 'TERM_PROGRAM'); @@ -148,36 +152,41 @@ public function testColor() // After the tests on NO_COLOR and TERM_PROGRAM above, // the $isColored variable is rigged. So we reset this. CLI::init(); - $this->assertSame("\033[1;37m\033[42m\033[4mtest\033[0m", CLI::color('test', 'white', 'green', 'underline')); + + $this->assertSame( + "\033[1;37m\033[42m\033[4mtest\033[0m", + CLI::color('test', 'white', 'green', 'underline') + ); } public function testPrint() { CLI::print('test'); - $expected = 'test'; + $expected = 'test'; $this->assertSame($expected, CITestStreamFilter::$buffer); } public function testPrintForeground() { CLI::print('test', 'red'); - $expected = "\033[0;31mtest\033[0m"; + $expected = "\033[0;31mtest\033[0m"; $this->assertSame($expected, CITestStreamFilter::$buffer); } public function testPrintBackground() { CLI::print('test', 'red', 'green'); - $expected = "\033[0;31m\033[42mtest\033[0m"; + $expected = "\033[0;31m\033[42mtest\033[0m"; $this->assertSame($expected, CITestStreamFilter::$buffer); } public function testWrite() { CLI::write('test'); + $expected = PHP_EOL . 'test' . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } @@ -185,6 +194,7 @@ public function testWrite() public function testWriteForeground() { CLI::write('test', 'red'); + $expected = "\033[0;31mtest\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } @@ -222,6 +232,7 @@ public function testWriteForegroundWithColorTwice() public function testWriteBackground() { CLI::write('test', 'red', 'green'); + $expected = "\033[0;31m\033[42mtest\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } @@ -229,7 +240,9 @@ public function testWriteBackground() public function testError() { $this->stream_filter = stream_filter_append(STDERR, 'CITestStreamFilter'); + CLI::error('test'); + // red expected cuz stderr $expected = "\033[1;31mtest\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); @@ -238,7 +251,9 @@ public function testError() public function testErrorForeground() { $this->stream_filter = stream_filter_append(STDERR, 'CITestStreamFilter'); + CLI::error('test', 'purple'); + $expected = "\033[0;35mtest\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } @@ -246,7 +261,9 @@ public function testErrorForeground() public function testErrorBackground() { $this->stream_filter = stream_filter_append(STDERR, 'CITestStreamFilter'); + CLI::error('test', 'purple', 'green'); + $expected = "\033[0;35m\033[42mtest\033[0m" . PHP_EOL; $this->assertSame($expected, CITestStreamFilter::$buffer); } @@ -291,9 +308,18 @@ public function testShowProgressWithoutBar() public function testWrap() { $this->assertSame('', CLI::wrap('')); - $this->assertSame('1234' . PHP_EOL . ' 5678' . PHP_EOL . ' 90' . PHP_EOL . ' abc' . PHP_EOL . ' de' . PHP_EOL . ' fghij' . PHP_EOL . ' 0987654321', CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', 5, 1)); - $this->assertSame('1234 5678 90' . PHP_EOL . ' abc de fghij' . PHP_EOL . ' 0987654321', CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', 999, 2)); - $this->assertSame('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321')); + $this->assertSame( + '1234' . PHP_EOL . ' 5678' . PHP_EOL . ' 90' . PHP_EOL . ' abc' . PHP_EOL . ' de' . PHP_EOL . ' fghij' . PHP_EOL . ' 0987654321', + CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', 5, 1) + ); + $this->assertSame( + '1234 5678 90' . PHP_EOL . ' abc de fghij' . PHP_EOL . ' 0987654321', + CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', 999, 2) + ); + $this->assertSame( + '1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321', + CLI::wrap('1234 5678 90' . PHP_EOL . 'abc de fghij' . PHP_EOL . '0987654321') + ); } public function testParseCommand() @@ -305,6 +331,7 @@ public function testParseCommand() ]; $_SERVER['argc'] = 3; CLI::init(); + $this->assertNull(CLI::getSegment(3)); $this->assertSame('b', CLI::getSegment(1)); $this->assertSame('c', CLI::getSegment(2)); @@ -330,6 +357,7 @@ public function testParseCommandMixed() 'sure', ]; CLI::init(); + $this->assertNull(CLI::getSegment(7)); $this->assertSame('b', CLI::getSegment(1)); $this->assertSame('c', CLI::getSegment(2)); @@ -353,6 +381,7 @@ public function testParseCommandOption() 'd', ]; CLI::init(); + $this->assertSame(['parm' => 'pvalue'], CLI::getOptions()); $this->assertSame('pvalue', CLI::getOption('parm')); $this->assertSame('-parm pvalue ', CLI::getOptionString()); @@ -377,6 +406,7 @@ public function testParseCommandMultipleOptions() 'value 3', ]; CLI::init(); + $this->assertSame(['parm' => 'pvalue', 'p2' => null, 'p3' => 'value 3'], CLI::getOptions()); $this->assertSame('pvalue', CLI::getOption('parm')); $this->assertSame('-parm pvalue -p2 -p3 "value 3" ', CLI::getOptionString()); @@ -391,11 +421,13 @@ public function testWindow() $height = new ReflectionProperty(CLI::class, 'height'); $height->setAccessible(true); $height->setValue(null); + $this->assertIsInt(CLI::getHeight()); $width = new ReflectionProperty(CLI::class, 'width'); $width->setAccessible(true); $width->setValue(null); + $this->assertIsInt(CLI::getWidth()); } @@ -409,6 +441,7 @@ public function testWindow() public function testTable($tbody, $thead, $expected) { CLI::table($tbody, $thead); + $this->assertSame(CITestStreamFilter::$buffer, $expected); } From 1b26129b2443f7a083968b9bcf8f111e093878a5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 13 Apr 2022 21:28:55 +0900 Subject: [PATCH 1933/2325] test: add test --- tests/system/CLI/CLITest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 2f569e5c81c5..a8452cdfa7a6 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -159,6 +159,14 @@ public function testColor() ); } + public function testColorEmtpyString() + { + $this->assertSame( + '', + CLI::color('', 'white', 'green', 'underline') + ); + } + public function testPrint() { CLI::print('test'); From 768dd238f5eb85a516668f89bde8fc620e0a8022 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 14 Apr 2022 17:05:07 +0900 Subject: [PATCH 1934/2325] docs: improve Managing your Applications - add note for composer.json autoload.psr-4 - change example from Zip install to Composer install --- .../source/general/managing_apps.rst | 72 ++++++++++++++----- .../source/general/managing_apps/001.php | 2 + .../source/general/managing_apps/005.php | 12 ++++ 3 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 user_guide_src/source/general/managing_apps/005.php diff --git a/user_guide_src/source/general/managing_apps.rst b/user_guide_src/source/general/managing_apps.rst index fc00dcd06985..ddba276825d2 100644 --- a/user_guide_src/source/general/managing_apps.rst +++ b/user_guide_src/source/general/managing_apps.rst @@ -8,10 +8,27 @@ directory. It is possible, however, to have multiple sets of applications that share a single CodeIgniter installation, or even to rename or relocate your application directory. +.. important:: When you installed CodeIgniter v4.1.9 or before, and if there are ``App\\`` and ``Config\\`` namespaces in your ``/composer.json``'s ``autoload.psr-4`` like the following, you need to remove these lines, and run ``composer dump-autolod``. + + .. code-block:: text + + { + ... + "autoload": { + "psr-4": { + "App\\": "app", <-- Remove this line + "Config\\": "app/Config" <-- Remove this line + } + }, + ... + } + .. contents:: :local: :depth: 2 +.. _renaming-app-directory: + Renaming or Relocating the Application Directory ================================================ @@ -46,32 +63,49 @@ and **bar**. You could structure your application project directories like this: .. code-block:: text - /foo - /app - /public - /tests - /writable + foo/ + app/ + public/ + tests/ + writable/ + env + phpunit.xml.dist spark - /bar - /app - /public - /tests - /writable + bar/ + app/ + public/ + tests/ + writable/ + env + phpunit.xml.dist spark - /codeigniter - /system + vendor/ + autoload.php + codeigniter4/framework/ + composer.json + composer.lock + +.. note:: If you install CodeIgniter from the Zip file, the directory structure would be following: + + .. code-block:: text + + foo/ + bar/ + codeigniter4/system/ This would have two apps, **foo** and **bar**, both having standard application directories -and a **public** folder, and sharing a common **codeigniter** framework. +and a **public** folder, and sharing a common **codeigniter4/framework**. -The **index.php** inside each application would refer to its own configuration, -``../app/Config/Paths.php``, and the ``$systemDirectory`` variable in **app/Config/Paths.php** inside each -of those would be set to refer to the shared common **system** folder. +The ``$systemDirectory`` variable in **app/Config/Paths.php** inside each +of those would be set to refer to the shared common **codeigniter4/framework** folder: -If either of the applications had a command-line component, then you would also -modify **spark** inside each application's project folder, as directed above. +.. literalinclude:: managing_apps/005.php -When you use Composer autoloader, fix the ``COMPOSER_PATH`` constant in **app/Config/Constants.php** inside each +.. note:: If you install CodeIgniter from the Zip file, the ``$systemDirectory`` would be ``__DIR__ . '/../../../codeigniter4/system'``. + +And modify the ``COMPOSER_PATH`` constant in **app/Config/Constants.php** inside each of those: .. literalinclude:: managing_apps/004.php + +Only when you change the Application Directory, see :ref:`renaming-app-directory` and modify the paths in the **index.php** and **spark**. diff --git a/user_guide_src/source/general/managing_apps/001.php b/user_guide_src/source/general/managing_apps/001.php index c116317678be..da4991fd738d 100644 --- a/user_guide_src/source/general/managing_apps/001.php +++ b/user_guide_src/source/general/managing_apps/001.php @@ -4,6 +4,8 @@ class Paths { + // ... + public $appDirectory = '/path/to/your/app'; // ... diff --git a/user_guide_src/source/general/managing_apps/005.php b/user_guide_src/source/general/managing_apps/005.php new file mode 100644 index 000000000000..4f5cbf47244c --- /dev/null +++ b/user_guide_src/source/general/managing_apps/005.php @@ -0,0 +1,12 @@ + Date: Fri, 15 Apr 2022 11:16:07 +0900 Subject: [PATCH 1935/2325] docs: replace /app/ with app/ Because there are more places listed as app/. --- user_guide_src/source/cli/cli_commands.rst | 4 ++-- user_guide_src/source/concepts/autoloader.rst | 4 ++-- user_guide_src/source/concepts/mvc.rst | 8 ++++---- user_guide_src/source/general/configuration.rst | 6 +++--- user_guide_src/source/incoming/controllers.rst | 2 +- user_guide_src/source/libraries/throttler.rst | 2 +- user_guide_src/source/libraries/validation.rst | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 30d92a195390..524ab80f3644 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -88,7 +88,7 @@ File Location ============= Commands must be stored within a directory named **Commands**. However, that directory can be located anywhere -that the :doc:`Autoloader ` can locate it. This could be in **/app/Commands**, or +that the :doc:`Autoloader ` can locate it. This could be in **app/Commands**, or a directory that you keep commands in to use in all of your project development, like **Acme/Commands**. .. note:: When the commands are executed, the full CodeIgniter CLI environment has been loaded, making it @@ -98,7 +98,7 @@ An Example Command ================== Let's step through an example command whose only function is to report basic information about the application -itself, for demonstration purposes. Start by creating a new file at **/app/Commands/AppInfo.php**. It +itself, for demonstration purposes. Start by creating a new file at **app/Commands/AppInfo.php**. It should contain the following code: .. literalinclude:: cli_commands/002.php diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index b748e520fd98..06f6fa45025c 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -28,7 +28,7 @@ beginning of the framework's execution. Configuration ============= -Initial configuration is done in **/app/Config/Autoload.php**. This file contains two primary +Initial configuration is done in **app/Config/Autoload.php**. This file contains two primary arrays: one for the classmap, and one for PSR-4 compatible namespaces. Namespaces @@ -48,7 +48,7 @@ have a trailing slash. By default, the application folder is namespace to the ``App`` namespace. While you are not forced to namespace the controllers, libraries, or models in the application directory, if you do, they will be found under the ``App`` namespace. -You may change this namespace by editing the **/app/Config/Constants.php** file and setting the +You may change this namespace by editing the **app/Config/Constants.php** file and setting the new namespace value under the ``APP_NAMESPACE`` setting: .. literalinclude:: autoloader/002.php diff --git a/user_guide_src/source/concepts/mvc.rst b/user_guide_src/source/concepts/mvc.rst index 11aa8efcd0af..1338290cc8b0 100644 --- a/user_guide_src/source/concepts/mvc.rst +++ b/user_guide_src/source/concepts/mvc.rst @@ -37,11 +37,11 @@ Views get the data to display from the controllers, who pass it to the views as with simple ``echo`` calls. You can also display other views within a view, making it pretty simple to display a common header or footer on every page. -Views are generally stored in **/app/Views**, but can quickly become unwieldy if not organized in some fashion. +Views are generally stored in **app/Views**, but can quickly become unwieldy if not organized in some fashion. CodeIgniter does not enforce any type of organization, but a good rule of thumb would be to create a new directory in the **Views** directory for each controller. Then, name views by the method name. This makes them very easy to find later on. For example, a user's profile might be displayed in a controller named ``User``, and a method named ``profile``. -You might store the view file for this method in **/app/Views/User/Profile.php**. +You might store the view file for this method in **app/Views/User/Profile.php**. That type of organization works great as a base habit to get into. At times you might need to organize it differently. That's not a problem. As long as CodeIgniter can find the file, it can display it. @@ -61,7 +61,7 @@ it's saved to meet company standards, or formatting a column in a certain way be By keeping these business requirements in the model, you won't repeat code throughout several controllers and accidentally miss updating an area. -Models are typically stored in **/app/Models**, though they can use a namespace to be grouped however you need. +Models are typically stored in **app/Models**, though they can use a namespace to be grouped however you need. :doc:`Find out more about models ` @@ -77,7 +77,7 @@ The other responsibility of the controller is to handle everything that pertains authentication, web safety, encoding, etc. In short, the controller is where you make sure that people are allowed to be there, and they get the data they need in a format they can use. -Controllers are typically stored in **/app/Controllers**, though they can use a namespace to be grouped however +Controllers are typically stored in **app/Controllers**, though they can use a namespace to be grouped however you need. :doc:`Find out more about controllers ` diff --git a/user_guide_src/source/general/configuration.rst b/user_guide_src/source/general/configuration.rst index 85bdc91fe62c..88d389c456a2 100644 --- a/user_guide_src/source/general/configuration.rst +++ b/user_guide_src/source/general/configuration.rst @@ -9,7 +9,7 @@ the required settings are public properties. Unlike many other frameworks, CodeIgniter configurable items aren't contained in a single file. Instead, each class that needs configurable items will have a configuration file with the same name as the class that uses it. You will find -the application configuration files in the **/app/Config** folder. +the application configuration files in the **app/Config** folder. .. contents:: :local: @@ -33,7 +33,7 @@ All configuration object properties are public, so you access the settings like .. literalinclude:: configuration/003.php If no namespace is provided, it will look for the file in all defined namespaces -as well as **/app/Config/**. +as well as **app/Config/**. All of the configuration files that ship with CodeIgniter are namespaced with ``Config``. Using this namespace in your application will provide the best @@ -48,7 +48,7 @@ Creating Configuration Files ============================ When you need a new configuration, first you create a new file at your desired location. -The default file location (recommended for most cases) is **/app/Config**. +The default file location (recommended for most cases) is **app/Config**. The class should use the appropriate namespace, and it should extend ``CodeIgniter\Config\BaseConfig`` to ensure that it can receive environment-specific settings. diff --git a/user_guide_src/source/incoming/controllers.rst b/user_guide_src/source/incoming/controllers.rst index c5a963c81fdd..9074bf18046f 100644 --- a/user_guide_src/source/incoming/controllers.rst +++ b/user_guide_src/source/incoming/controllers.rst @@ -146,7 +146,7 @@ For security reasons be sure to declare any new utility methods as ``protected`` .. literalinclude:: controllers/008.php -Then save the file to your **/app/Controllers/** directory. +Then save the file to your **app/Controllers/** directory. .. important:: The file must be called **Helloworld.php**, with a capital ``H``. diff --git a/user_guide_src/source/libraries/throttler.rst b/user_guide_src/source/libraries/throttler.rst index df0dfeb29d37..27a3283dae6e 100644 --- a/user_guide_src/source/libraries/throttler.rst +++ b/user_guide_src/source/libraries/throttler.rst @@ -64,7 +64,7 @@ Applying the Filter We don't necessarily need to throttle every page on the site. For many web applications, this makes the most sense to apply only to POST requests, though API's might want to limit every request made by a user. In order to apply -this to incoming requests, you need to edit **/app/Config/Filters.php** and first add an alias to the +this to incoming requests, you need to edit **app/Config/Filters.php** and first add an alias to the filter: .. literalinclude:: throttler/003.php diff --git a/user_guide_src/source/libraries/validation.rst b/user_guide_src/source/libraries/validation.rst index 8d3204804e92..641058b29a87 100644 --- a/user_guide_src/source/libraries/validation.rst +++ b/user_guide_src/source/libraries/validation.rst @@ -498,7 +498,7 @@ Creating the Views The first step is to create custom views. These can be placed anywhere that the ``view()`` method can locate them, which means the standard View directory, or any namespaced View folder will work. For example, you could create -a new view at **/app/Views/_errors_list.php**: +a new view at **app/Views/_errors_list.php**: .. literalinclude:: validation/030.php From 33ef2742a96880e7eb1819305c7737f2ec59e94f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 11:29:10 +0900 Subject: [PATCH 1936/2325] docs: small improvement --- user_guide_src/source/intro/requirements.rst | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/intro/requirements.rst b/user_guide_src/source/intro/requirements.rst index a55b8c46d0d9..974cf108c406 100644 --- a/user_guide_src/source/intro/requirements.rst +++ b/user_guide_src/source/intro/requirements.rst @@ -7,7 +7,10 @@ Server Requirements installed. The following PHP extensions should be enabled on your server: -``php-json``, ``php-mysqlnd``, ``php-xml`` + + - ``php-json`` + - ``php-mysqlnd`` (if you use MySQL) + - ``php-xml`` In order to use the :doc:`CURLRequest `, you will need `libcurl `_ installed. @@ -15,7 +18,7 @@ In order to use the :doc:`CURLRequest `, you will need A database is required for most web application programming. Currently supported databases are: - - MySQL (5.1+) via the *MySQLi* driver + - MySQL via the *MySQLi* driver (version 5.1 and above only) - PostgreSQL via the *Postgre* driver - SQLite3 via the *SQLite3* driver - MSSQL via the *SQLSRV* driver (version 2005 and above only) From 6c01476b8323b18c8838d3371cddaf643e44b4b8 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 11:56:03 +0900 Subject: [PATCH 1937/2325] docs: add TOC --- user_guide_src/source/concepts/autoloader.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index b748e520fd98..ecd4428a0cfa 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -2,6 +2,10 @@ Autoloading Files ################# +.. contents:: + :local: + :depth: 2 + Every application consists of a large number of classes in many different locations. The framework provides classes for core functionality. Your application will have a number of libraries, models, and other entities to make it work. You might have third-party From a5c8c50cae82cb1acefcc83447eefc89c363eb68 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 11:56:18 +0900 Subject: [PATCH 1938/2325] docs: remove out of dated description The core classes are not added to the classmap. --- user_guide_src/source/concepts/autoloader.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index ecd4428a0cfa..577a70bf2430 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -18,8 +18,6 @@ It can locate individual namespaced classes that adhere to `PSR-4 `_ autoloading directory structures. -For performance improvement, the core CodeIgniter components have been added to the classmap. - The autoloader works great by itself, but can also work with other autoloaders, like `Composer `_, or even your own custom autoloaders, if needed. Because they're all registered through From 5d737089b8e90fb6665404a1881fdf83cb944956 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 11:58:10 +0900 Subject: [PATCH 1939/2325] docs: remove unneeded description We don't need a trailing back slash, so escaping back slashes is not needed. Double-quotes have nothing to do with escaping. --- user_guide_src/source/concepts/autoloader.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index 577a70bf2430..7e931c677995 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -43,9 +43,8 @@ those classes can be found in: .. literalinclude:: autoloader/001.php -The key of each row is the namespace itself. This does not need a trailing slash. If you use double-quotes -to define the array, be sure to escape the backward slash. That means that it would be ``My\\App``, -not ``My\App``. The value is the location to the directory the classes can be found in. They should +The key of each row is the namespace itself. This does not need a trailing slash. +The value is the location to the directory the classes can be found in. They should have a trailing slash. By default, the application folder is namespace to the ``App`` namespace. While you are not forced to namespace the controllers, From 43fb2fc9b94ca90f8b7a52f8b48582cb20992273 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 12:04:00 +0900 Subject: [PATCH 1940/2325] docs: add `back` --- user_guide_src/source/concepts/autoloader.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index 7e931c677995..5dd349065860 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -43,7 +43,7 @@ those classes can be found in: .. literalinclude:: autoloader/001.php -The key of each row is the namespace itself. This does not need a trailing slash. +The key of each row is the namespace itself. This does not need a trailing back slash. The value is the location to the directory the classes can be found in. They should have a trailing slash. From c2bb64594ada1e76b3ad862f3d0f1909a0e24f5e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 12:04:26 +0900 Subject: [PATCH 1941/2325] docs: fix the file path text decration --- user_guide_src/source/concepts/autoloader.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/concepts/autoloader.rst b/user_guide_src/source/concepts/autoloader.rst index 5dd349065860..3c68567486da 100644 --- a/user_guide_src/source/concepts/autoloader.rst +++ b/user_guide_src/source/concepts/autoloader.rst @@ -76,7 +76,7 @@ Composer Support Composer support is automatically initialized by default. By default, it looks for Composer's autoload file at ``ROOTPATH . 'vendor/autoload.php'``. If you need to change the location of that file for any reason, you can modify -the value defined in ``Config\Constants.php``. +the value defined in **app/Config/Constants.php**. .. note:: If the same namespace is defined in both CodeIgniter and Composer, CodeIgniter's autoloader will be the first one to get a chance to locate the file. From 0208c720f256ee0b3257f1b9c6efd9fdb65548fd Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 15 Apr 2022 14:00:25 +0900 Subject: [PATCH 1942/2325] fix: Composer PSR-4 overwrites Config\Autoload::$psr4 --- system/Autoloader/Autoloader.php | 2 +- tests/system/Autoloader/AutoloaderTest.php | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 520e669be685..311428fe4165 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -328,7 +328,7 @@ private function loadComposerNamespaces(ClassLoader $composer): void $newPaths[rtrim($key, '\\ ')] = $value; } - $this->prefixes = array_merge($this->prefixes, $newPaths); + $this->addNamespace($newPaths); } private function loadComposerClassmap(ClassLoader $composer): void diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 82e0307affad..1279910d2289 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -233,6 +233,23 @@ public function testFindsComposerRoutes() $this->assertArrayHasKey('Laminas\\Escaper', $namespaces); } + public function testComposerNamespaceDoesNotOverwriteConfigAutoloadPsr4() + { + $config = new Autoload(); + $config->psr4 = [ + 'Psr\Log' => '/Config/Autoload/Psr/Log/', + ]; + $modules = new Modules(); + $modules->discoverInComposer = true; + + $this->loader = new Autoloader(); + $this->loader->initialize($config, $modules); + + $namespaces = $this->loader->getNamespace(); + $this->assertSame('/Config/Autoload/Psr/Log/', $namespaces['Psr\Log'][0]); + $this->assertStringContainsString(VENDORPATH, $namespaces['Psr\Log'][1]); + } + public function testFindsComposerRoutesWithComposerPathNotFound() { $composerPath = COMPOSER_PATH; From c3ecc1971d1b6b1bbacfe67372c48b6eb07f15d7 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 8 Apr 2022 01:12:00 +0700 Subject: [PATCH 1943/2325] [PHPStan] Prepare for PHPStan 1.6.x-dev --- composer.json | 2 +- phpstan.neon.dist | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 578156bd017c..e6935404bae9 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "nexusphp/tachycardia": "^1.0", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan": "1.6.x-dev", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", "rector/rector": "0.12.20" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 8aa28016ca33..cbacdfb82745 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -7,6 +7,10 @@ services: class: Utils\PHPStan\CheckFrameworkExceptionInstantiationViaNamedConstructorRule tags: - phpstan.rules.rule + - + class: PhpParser\NodeVisitor\NodeConnectingVisitor + tags: + - phpstan.parser.richParserNodeVisitor includes: - phpstan-baseline.neon.dist From fc9a7b8fbd6274768069fa2da42d2ffd316fd213 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Fri, 15 Apr 2022 20:36:37 +0700 Subject: [PATCH 1944/2325] set conditional tag --- composer.json | 2 +- phpstan.neon.dist | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index e6935404bae9..d3e0b85bdee8 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "mikey179/vfsstream": "^1.6", "nexusphp/cs-config": "^3.3", "nexusphp/tachycardia": "^1.0", - "phpstan/phpstan": "1.6.x-dev", + "phpstan/phpstan": "^1.5.6", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", "rector/rector": "0.12.20" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index cbacdfb82745..e4832b125ae2 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -1,3 +1,7 @@ +conditionalTags: + PhpParser\NodeVisitor\NodeConnectingVisitor: + phpstan.parser.richParserNodeVisitor: true + services: - class: Utils\PHPStan\CheckUseStatementsAfterLicenseRule @@ -7,10 +11,6 @@ services: class: Utils\PHPStan\CheckFrameworkExceptionInstantiationViaNamedConstructorRule tags: - phpstan.rules.rule - - - class: PhpParser\NodeVisitor\NodeConnectingVisitor - tags: - - phpstan.parser.richParserNodeVisitor includes: - phpstan-baseline.neon.dist From 9a60eb3d57671ffe2d69413136c8bcd2aba4c775 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Dadashi Date: Sun, 17 Apr 2022 01:18:58 +0330 Subject: [PATCH 1945/2325] docs:Correction due to 404 Not Found --- tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/README.md b/tests/README.md index 0df329864c6b..80f9439d1e6d 100644 --- a/tests/README.md +++ b/tests/README.md @@ -18,7 +18,7 @@ If running under OS X or Linux, you can create a symbolic link to make running t > ln -s ./vendor/bin/phpunit ./phpunit -You also need to install [XDebug](https://xdebug.org/index.php) in order +You also need to install [XDebug](https://xdebug.org/docs/install) in order for code coverage to be calculated successfully. ## Setting Up From ae56d6c66260064b4d1c71629c3fb12d81d79d77 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 08:15:27 +0900 Subject: [PATCH 1946/2325] docs: remove out of dated comment --- system/CLI/CLI.php | 1 - 1 file changed, 1 deletion(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index b43d0005ff77..f017346604a7 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -485,7 +485,6 @@ public static function color(string $text, string $foreground, ?string $backgrou throw CLIException::forInvalidColor('background', $background); } - // Reset text $newText = ''; // Detect if color method was already in use with this text From 63207331448887c8ff81e675b7ac80b34cac15ed Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 08:17:48 +0900 Subject: [PATCH 1947/2325] refactor: combine if statements --- system/CLI/CLI.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index f017346604a7..ae61d50e41d4 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -469,11 +469,7 @@ public static function clearScreen() */ public static function color(string $text, string $foreground, ?string $background = null, ?string $format = null): string { - if (! static::$isColored) { - return $text; - } - - if ($text === '') { + if (! static::$isColored || $text === '') { return $text; } From 9dcb39cb1e2d87bffb0cdc8c85be55253af2041d Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 08:18:18 +0900 Subject: [PATCH 1948/2325] refacter: remove unneeded parentheses --- system/CLI/CLI.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index ae61d50e41d4..d88374e80944 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -533,7 +533,7 @@ private static function getColoredText(string $text, string $foreground, ?string $string .= "\033[4m"; } - return $string . ($text . "\033[0m"); + return $string . $text . "\033[0m"; } /** From 2aa93487f2d22365eb18237b48e2fdbea3ddce44 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 08:27:32 +0900 Subject: [PATCH 1949/2325] docs: fix heading underlines --- user_guide_src/source/cli/cli_library.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 4ea8e71e4996..8d269aeead09 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -15,7 +15,7 @@ CodeIgniter's CLI library makes creating interactive command-line scripts simple :depth: 2 Initializing the Class -====================== +********************** You do not need to create an instance of the CLI library, since all of it's methods are static. Instead, you simply need to ensure your controller can locate it via a ``use`` statement above your class: @@ -25,7 +25,7 @@ need to ensure your controller can locate it via a ``use`` statement above your The class is automatically initialized when the file is loaded the first time. Getting Input from the User -=========================== +*************************** Sometimes you need to ask the user for more information. They might not have provided optional command-line arguments, or the script may have encountered an existing file and needs confirmation before overwriting. This is @@ -66,7 +66,7 @@ Named keys are also possible: Finally, you can pass :ref:`validation ` rules to the answer input as the third parameter, the acceptable answers are automatically restricted to the passed options. Providing Feedback -================== +****************** **write()** From 85670436edbc7a605f85d8898d61dec374455481 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 08:31:59 +0900 Subject: [PATCH 1950/2325] docs: change method names to headings Otherwise, I can't link to it. --- user_guide_src/source/cli/cli_library.rst | 33 +++++++++++++++-------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 8d269aeead09..bfb3a2479903 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -52,7 +52,8 @@ Validation rules can also be written in the array syntax: .. literalinclude:: cli_library/006.php -**promptByKey()** +promptByKey() +============= Predefined answers (options) for prompt sometimes need to be described or are too complex to select via their value. ``promptByKey()`` allows the user to select an option by its key instead of its value: @@ -68,7 +69,8 @@ Finally, you can pass :ref:`validation ` rules to the answer input a Providing Feedback ****************** -**write()** +write() +======= Several methods are provided for you to provide feedback to your users. This can be as simple as a single status update or a complex table of information that wraps to the user's terminal window. At the core of this is the ``write()`` @@ -116,7 +118,8 @@ And a smaller number are available as background colors: * light_gray * magenta -**print()** +print() +======= Print functions identically to the ``write()`` method, except that it does not force a newline either before or after. Instead it prints it to the screen wherever the cursor is currently. This allows you to print multiple items all on @@ -125,7 +128,8 @@ print "Done" on the same line: .. literalinclude:: cli_library/012.php -**color()** +color() +======= While the ``write()`` command will write a single line to the terminal, ending it with a EOL character, you can use the ``color()`` method to make a string fragment that can be used in the same way, except that it will not force @@ -137,7 +141,8 @@ it inside of a ``write()`` method to create a string of a different color inside This example would write a single line to the window, with ``fileA`` in yellow, followed by a tab, and then ``/path/to/file`` in white text. -**error()** +error() +======= If you need to output errors, you should use the appropriately named ``error()`` method. This writes light-red text to STDERR, instead of STDOUT, like ``write()`` and ``color()`` do. This can be useful if you have scripts watching @@ -146,7 +151,8 @@ exactly as you would the ``write()`` method: .. literalinclude:: cli_library/014.php -**wrap()** +wrap() +====== This command will take a string, start printing it on the current line, and wrap it to a set length on new lines. This might be useful when displaying a list of options with descriptions that you want to wrap in the current @@ -179,13 +185,15 @@ Would create something like this: industry's standard dummy text ever since the -**newLine()** +newLine() +========= The ``newLine()`` method displays a blank line to the user. It does not take any parameters: .. literalinclude:: cli_library/018.php -**clearScreen()** +clearScreen() +============= You can clear the current terminal window with the ``clearScreen()`` method. In most versions of Windows, this will simply insert 40 blank lines since Windows doesn't support this feature. Windows 10 bash integration should change @@ -193,7 +201,8 @@ this: .. literalinclude:: cli_library/019.php -**showProgress()** +showProgress() +============== If you have a long-running task that you would like to keep the user updated with the progress, you can use the ``showProgress()`` method which displays something like the following: @@ -210,7 +219,8 @@ pass ``false`` as the first parameter and the progress bar will be removed. .. literalinclude:: cli_library/020.php -**table()** +table() +======= .. literalinclude:: cli_library/021.php @@ -223,7 +233,8 @@ pass ``false`` as the first parameter and the progress bar will be removed. | 8 | Another great item title | 2017-11-16 13:46:54 | 0 | +----+--------------------------+---------------------+--------+ -**wait()** +wait() +====== Waits a certain number of seconds, optionally showing a wait message and waiting for a key press. From c0ca99f51475e25d3fb87d9a7ed02dd74baf4725 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 08:38:10 +0900 Subject: [PATCH 1951/2325] docs: add changelog --- user_guide_src/source/changelogs/v4.2.0.rst | 1 + user_guide_src/source/cli/cli_library.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index c0081761ffd4..449ad50f970d 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -18,6 +18,7 @@ BREAKING - ``spark`` - The method signature of ``CodeIgniter\CLI\CommandRunner::_remap()`` has been changed to fix a bug. - The ``CodeIgniter\Autoloader\Autoloader::initialize()`` has changed the behavior to fix a bug. It used to use Composer classmap only when ``$modules->discoverInComposer`` is true. Now it always uses the Composer classmap if Composer is available. +- The color code output by :ref:`CLI::color() ` has been changed to fix a bug. Enhancements ************ diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index bfb3a2479903..29bc6b252f88 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -128,6 +128,8 @@ print "Done" on the same line: .. literalinclude:: cli_library/012.php +.. _cli-library-color: + color() ======= From 4ad1edfdbb16ec7fc7dc903f832dd975e2063b4b Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 13:07:27 +0900 Subject: [PATCH 1952/2325] docs: fix heading underline level --- user_guide_src/source/models/model.rst | 46 +++++++++++++------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index fa354d7c3aff..e626662bef2d 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -7,7 +7,7 @@ Using CodeIgniter's Model :depth: 2 Models -====== +****** The CodeIgniter's Model provides convenience features and additional functionality that people commonly use to make working with a **single table** in your database more convenient. @@ -17,7 +17,7 @@ methods for much of the standard ways you would need to interact with a database updating records, deleting records, and more. Accessing Models -================ +**************** Models are typically stored in the ``app/Models`` directory. They should have a namespace that matches their location within the directory, like ``namespace App\Models``. @@ -27,7 +27,7 @@ You can access models within your classes by creating a new instance or using th .. literalinclude:: model/001.php CodeIgniter's Model -=================== +******************* CodeIgniter does provide a model class that provides a few nice features, including: @@ -41,7 +41,7 @@ This class provides a solid base from which to build your own models, allowing y rapidly build out your application's model layer. Creating Your Model -=================== +******************* To take advantage of CodeIgniter's model, you would simply create a new model class that extends ``CodeIgniter\Model``: @@ -58,7 +58,7 @@ extra steps without repeating the constructor parameters, for example extending .. literalinclude:: model/003.php Connecting to the Database --------------------------- +========================== When the class is first instantiated, if no database connection instance is passed to the constructor, it will automatically connect to the default database group, as set in the configuration. You can @@ -72,7 +72,7 @@ You would replace "group_name" with the name of a defined database group from th configuration file. Configuring Your Model ----------------------- +====================== The model class has a few configuration options that can be set to allow the class' methods to work seamlessly for you. The first two are used by all of the CRUD methods to determine @@ -190,10 +190,10 @@ time specified in the property name. Whether the callbacks defined above should be used. Working With Data -================= +***************** Finding Data ------------- +============ Several functions are provided for doing basic CRUD work on your tables, including ``find()``, ``insert()``, ``update()``, ``delete()`` and more. @@ -258,7 +258,7 @@ the next **find*()** methods to return only soft deleted rows: .. literalinclude:: model/014.php Saving Data ------------ +=========== **insert()** @@ -316,7 +316,7 @@ model's ``save()`` method to inspect the class, grab any public and private prop that provides several handy features that make developing Entities simpler. Deleting Data -------------- +============= **delete()** @@ -343,7 +343,7 @@ Cleans out the database table by permanently removing all rows that have 'delete .. literalinclude:: model/026.php Validating Data ---------------- +=============== For many people, validating data in the model is the preferred way to ensure the data is kept to a single standard, without duplicating code. The Model class provides a way to automatically have all data validated @@ -416,7 +416,7 @@ and simply set ``$validationRules`` to the name of the validation rule group you .. literalinclude:: model/034.php Retrieving Validation Rules ---------------------------- +=========================== You can retrieve a model's validation rules by accessing its ``validationRules`` property: @@ -435,7 +435,7 @@ value an array of fieldnames of interest: .. literalinclude:: model/037.php Validation Placeholders ------------------------ +======================= The model provides a simple method to replace parts of your rules based on data that's being passed into it. This sounds fairly obscure but can be especially handy with the ``is_unique`` validation rule. Placeholders are simply @@ -459,7 +459,7 @@ This can also be used to create more dynamic rules at runtime, as long as you ta keys passed in don't conflict with your form data. Protecting Fields ------------------ +================= To help protect against Mass Assignment Attacks, the Model class **requires** that you list all of the field names that can be changed during inserts and updates in the ``$allowedFields`` class property. Any data provided @@ -474,7 +474,7 @@ testing, migrations, or seeds. In these cases, you can turn the protection on or .. literalinclude:: model/042.php Working With Query Builder --------------------------- +========================== You can get access to a shared instance of the Query Builder for that model's database connection any time you need it: @@ -501,7 +501,7 @@ very elegant use: .. literalinclude:: model/046.php Runtime Return Type Changes ----------------------------- +=========================== You can specify the format that data should be returned as when using the **find*()** methods as the class property, ``$returnType``. There may be times that you would like the data back in a different format, though. The Model @@ -523,7 +523,7 @@ Returns data from the next **find*()** method as standard objects or custom clas .. literalinclude:: model/048.php Processing Large Amounts of Data --------------------------------- +================================ Sometimes, you need to process large amounts of data and would run the risk of running out of memory. To make this simpler, you may use the chunk() method to get smaller chunks of data that you can then @@ -535,7 +535,7 @@ This is best used during cronjobs, data exports, or other large tasks. .. literalinclude:: model/049.php Model Events -============ +************ There are several points within the model's execution that you can specify multiple callback methods to run. These methods can be used to normalize data, hash passwords, save related entities, and much more. The following @@ -543,7 +543,7 @@ points in the model's execution can be affected, each through a class property: ``$beforeUpdate``, ``$afterUpdate``, ``$afterFind``, and ``$afterDelete``. Defining Callbacks ------------------- +================== You specify the callbacks by first creating a new class method in your model to use. This class will always receive a ``$data`` array as its only parameter. The exact contents of the ``$data`` array will vary between events, but @@ -555,7 +555,7 @@ must return the original $data array so other callbacks have the full informatio .. literalinclude:: model/050.php Specifying Callbacks To Run ---------------------------- +=========================== You specify when to run the callbacks by adding the method name to the appropriate class property (``$beforeInsert``, ``$afterUpdate``, etc). Multiple callbacks can be added to a single event and they will be processed one after the other. You can @@ -572,7 +572,7 @@ You may also change this setting temporarily for a single model call sing the `` .. literalinclude:: model/053.php Event Parameters ----------------- +================ Since the exact data passed to each callback varies a bit, here are the details on what is in the ``$data`` parameter passed to each event: @@ -607,7 +607,7 @@ afterDelete **id** = primary key of row being deleted. ================ ========================================================================================================= Modifying Find* Data --------------------- +==================== The ``beforeFind`` and ``afterFind`` methods can both return a modified set of data to override the normal response from the model. For ``afterFind`` any changes made to ``data`` in the return array will automatically be passed back @@ -617,7 +617,7 @@ boolean, ``returnData``: .. literalinclude:: model/054.php Manual Model Creation -===================== +********************* You do not need to extend any special class to create a model for your application. All you need is to get an instance of the database connection and you're good to go. This allows you to bypass the features CodeIgniter's From f3a34f72ff38fe9fb9ebfe95beb84daf512b043c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 18 Apr 2022 13:08:21 +0900 Subject: [PATCH 1953/2325] docs: change **foo** to headings You can link to headings, but cannot link to `**foo**`. --- user_guide_src/source/models/model.rst | 101 ++++++++++++++++--------- 1 file changed, 67 insertions(+), 34 deletions(-) diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index e626662bef2d..84fdbf4be249 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -80,13 +80,15 @@ what table to use and how we can find the required records: .. literalinclude:: model/005.php -**$table** +$table +------ Specifies the database table that this model primarily works with. This only applies to the built-in CRUD methods. You are not restricted to using only this table in your own queries. -**$primaryKey** +$primaryKey +----------- This is the name of the column that uniquely identifies the records in this table. This does not necessarily have to match the primary key that is specified in the database, but @@ -95,7 +97,8 @@ is used with methods like ``find()`` to know what column to match the specified .. note:: All Models must have a primaryKey specified to allow all of the features to work as expected. -**$useAutoIncrement** +$useAutoIncrement +----------------- Specifies if the table uses an auto-increment feature for ``$primaryKey``. If set to ``false`` then you are responsible for providing primary key value for every record in the table. This @@ -106,7 +109,8 @@ default value is ``true``. key in the database to ``unique``. This way you will make sure that all of Model's features will still work the same as before. -**$returnType** +$returnType +----------- The Model's CRUD methods will take a step of work away from you and automatically return the resulting data, instead of the Result object. This setting allows you to define @@ -114,7 +118,8 @@ the type of data that is returned. Valid values are '**array**' (the default), ' qualified name of a class** that can be used with the Result object's ``getCustomResultObject()`` method. -**$useSoftDeletes** +$useSoftDeletes +--------------- If true, then any ``delete()`` method calls will set ``deleted_at`` in the database, instead of actually deleting the row. This can preserve data when it might be referenced elsewhere, or @@ -126,66 +131,81 @@ This requires either a DATETIME or INTEGER field in the database as per the mode ``$dateFormat`` setting. The default field name is ``deleted_at`` however this name can be configured to any name of your choice by using ``$deletedField`` property. -**$allowedFields** +$allowedFields +-------------- This array should be updated with the field names that can be set during ``save()``, ``insert()``, or ``update()`` methods. Any field names other than these will be discarded. This helps to protect against just taking input from a form and throwing it all at the model, resulting in potential mass assignment vulnerabilities. -**$useTimestamps** +$useTimestamps +-------------- This boolean value determines whether the current date is automatically added to all inserts and updates. If true, will set the current time in the format specified by ``$dateFormat``. This requires that the table have columns named **created_at** and **updated_at** in the appropriate data type. -**$createdField** +$createdField +------------- Specifies which database field to use for data record create timestamp. Leave it empty to avoid updating it (even if ``$useTimestamps`` is enabled). -**$updatedField** +$updatedField +------------- Specifies which database field should use for keep data record update timestamp. Leave it empty to avoid update it (even ``$useTimestamps`` is enabled). -**$dateFormat** +$dateFormat +----------- This value works with ``$useTimestamps`` and ``$useSoftDeletes`` to ensure that the correct type of date value gets inserted into the database. By default, this creates DATETIME values, but valid options are: ``'datetime'``, ``'date'``, or ``'int'`` (a PHP timestamp). Using **useSoftDeletes** or -**useTimestamps** with an invalid or missing dateFormat will cause an exception. +useTimestamps with an invalid or missing dateFormat will cause an exception. -**$validationRules** +$validationRules +---------------- Contains either an array of validation rules as described in :ref:`validation-array` or a string containing the name of a validation group, as described in the same section. Described in more detail below. -**$validationMessages** +$validationMessages +------------------- Contains an array of custom error messages that should be used during validation, as described in :ref:`validation-custom-errors`. Described in more detail below. -**$skipValidation** +$skipValidation +--------------- Whether validation should be skipped during all **inserts** and **updates**. The default value is false, meaning that data will always attempt to be validated. This is primarily used by the ``skipValidation()`` method, but may be changed to ``true`` so this model will never validate. -**$beforeInsert** -**$afterInsert** -**$beforeUpdate** -**$afterUpdate** -**$afterFind** -**$afterDelete** +$beforeInsert +------------- +$afterInsert +------------ +$beforeUpdate +------------- +$afterUpdate +------------ +$afterFind +---------- +$afterDelete +------------ These arrays allow you to specify callback methods that will be run on the data at the time specified in the property name. -**$allowCallbacks** +$allowCallbacks +--------------- Whether the callbacks defined above should be used. @@ -198,7 +218,8 @@ Finding Data Several functions are provided for doing basic CRUD work on your tables, including ``find()``, ``insert()``, ``update()``, ``delete()`` and more. -**find()** +find() +------ Returns a single row where the primary key matches the value passed in as the first parameter: @@ -214,7 +235,8 @@ of just one: If no parameters are passed in, will return all rows in that model's table, effectively acting like ``findAll()``, though less explicit. -**findColumn()** +findColumn() +------------ Returns null or an indexed array of column values: @@ -222,7 +244,8 @@ Returns null or an indexed array of column values: ``$column_name`` should be a name of single column else you will get the DataException. -**findAll()** +findAll() +--------- Returns all results: @@ -237,20 +260,23 @@ parameters, respectively: .. literalinclude:: model/011.php -**first()** +first() +------- Returns the first row in the result set. This is best used in combination with the query builder. .. literalinclude:: model/012.php -**withDeleted()** +withDeleted() +------------- If ``$useSoftDeletes`` is true, then the **find*()** methods will not return any rows where 'deleted_at IS NOT NULL'. To temporarily override this, you can use the ``withDeleted()`` method prior to calling the **find*()** method. .. literalinclude:: model/013.php -**onlyDeleted()** +onlyDeleted() +------------- Whereas ``withDeleted()`` will return both deleted and not-deleted rows, this method modifies the next **find*()** methods to return only soft deleted rows: @@ -260,7 +286,8 @@ the next **find*()** methods to return only soft deleted rows: Saving Data =========== -**insert()** +insert() +-------- An associative array of data is passed into this method as the only parameter to create a new row of data in the database. The array's keys must match the name of the columns in a ``$table``, while @@ -268,7 +295,8 @@ the array's values are the values to save for that key: .. literalinclude:: model/015.php -**update()** +update() +-------- Updates an existing record in the database. The first parameter is the ``$primaryKey`` of the record to update. An associative array of data is passed into this method as the second parameter. The array's keys must match the name @@ -285,7 +313,8 @@ update command, with the added benefit of validation, events, etc: .. literalinclude:: model/018.php -**save()** +save() +------ This is a wrapper around the ``insert()`` and ``update()`` methods that handle inserting or updating the record automatically, based on whether it finds an array key matching the **primary key** value: @@ -318,7 +347,8 @@ model's ``save()`` method to inspect the class, grab any public and private prop Deleting Data ============= -**delete()** +delete() +-------- Takes a primary key value as the first parameter and deletes the matching record from the model's table: @@ -336,7 +366,8 @@ previously: .. literalinclude:: model/025.php -**purgeDeleted()** +purgeDeleted() +-------------- Cleans out the database table by permanently removing all rows that have 'deleted_at IS NOT NULL'. @@ -510,13 +541,15 @@ provides methods that allow you to do just that. .. note:: These methods only change the return type for the next **find*()** method call. After that, it is reset to its default value. -**asArray()** +asArray() +--------- Returns data from the next **find*()** method as associative arrays: .. literalinclude:: model/047.php -**asObject()** +asObject() +---------- Returns data from the next **find*()** method as standard objects or custom class intances: From 8f1b0c80f73745abfeb9354e491391cdb41a0863 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Apr 2022 15:02:55 +0000 Subject: [PATCH 1954/2325] chore(deps-dev): update rector/rector requirement Updates the requirements on [rector/rector](https://github.com/rectorphp/rector) to permit the latest version. - [Release notes](https://github.com/rectorphp/rector/releases) - [Commits](https://github.com/rectorphp/rector/compare/0.12.20...0.12.21) --- 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 d3e0b85bdee8..9c1ee4adb46e 100644 --- a/composer.json +++ b/composer.json @@ -24,7 +24,7 @@ "phpstan/phpstan": "^1.5.6", "phpunit/phpunit": "^9.1", "predis/predis": "^1.1", - "rector/rector": "0.12.20" + "rector/rector": "0.12.21" }, "suggest": { "ext-fileinfo": "Improves mime type detection for files" From 185754ed87b80dc846810097bd38e147a9bac4fb Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Mon, 18 Apr 2022 22:15:59 +0700 Subject: [PATCH 1955/2325] clean up removed service and updated to use new RectorConfig --- rector.php | 98 ++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 51 deletions(-) diff --git a/rector.php b/rector.php index 9ee8a4217d21..79aa188aa94f 100644 --- a/rector.php +++ b/rector.php @@ -21,12 +21,11 @@ use Rector\CodeQuality\Rector\If_\ShortenElseIfRector; use Rector\CodeQuality\Rector\If_\SimplifyIfElseToTernaryRector; use Rector\CodeQuality\Rector\If_\SimplifyIfReturnBoolRector; -use Rector\CodeQuality\Rector\Return_\SimplifyUselessVariableRector; use Rector\CodeQuality\Rector\Ternary\UnnecessaryTernaryExpressionRector; use Rector\CodingStyle\Rector\ClassMethod\FuncGetArgsToVariadicParamRector; use Rector\CodingStyle\Rector\ClassMethod\MakeInheritedMethodVisibilitySameAsParentRector; use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; -use Rector\Core\Configuration\Option; +use Rector\Config\RectorConfig; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPromotedPropertyRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; @@ -45,31 +44,31 @@ use Rector\PSR4\Rector\FileWithoutNamespace\NormalizeNamespaceByPSR4ComposerAutoloadRector; use Rector\Set\ValueObject\LevelSetList; use Rector\Set\ValueObject\SetList; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Utils\Rector\PassStrictParameterToFunctionParameterRector; use Utils\Rector\RemoveErrorSuppressInTryCatchStmtsRector; use Utils\Rector\RemoveVarTagFromClassConstantRector; use Utils\Rector\UnderscoreToCamelCaseVariableNameRector; -return static function (ContainerConfigurator $containerConfigurator): void { - $containerConfigurator->import(SetList::DEAD_CODE); - $containerConfigurator->import(LevelSetList::UP_TO_PHP_74); - $containerConfigurator->import(PHPUnitSetList::PHPUNIT_SPECIFIC_METHOD); - $containerConfigurator->import(PHPUnitSetList::PHPUNIT_80); +return static function (RectorConfig $rectorConfig): void { + $rectorConfig->sets([ + SetList::DEAD_CODE, + LevelSetList::UP_TO_PHP_74, + PHPUnitSetList::PHPUNIT_SPECIFIC_METHOD, + PHPUnitSetList::PHPUNIT_80, + ]); - $parameters = $containerConfigurator->parameters(); + $rectorConfig->parallel(); - $parameters->set(Option::PARALLEL, true); // paths to refactor; solid alternative to CLI arguments - $parameters->set(Option::PATHS, [__DIR__ . '/app', __DIR__ . '/system', __DIR__ . '/tests', __DIR__ . '/utils/Rector']); + $rectorConfig->paths([__DIR__ . '/app', __DIR__ . '/system', __DIR__ . '/tests', __DIR__ . '/utils/Rector']); // do you need to include constants, class aliases or custom autoloader? files listed will be executed - $parameters->set(Option::BOOTSTRAP_FILES, [ + $rectorConfig->bootstrapFiles([ __DIR__ . '/system/Test/bootstrap.php', ]); // is there a file you need to skip? - $parameters->set(Option::SKIP, [ + $rectorConfig->skip([ __DIR__ . '/app/Views', __DIR__ . '/system/Debug/Toolbar/Views/toolbar.tpl.php', __DIR__ . '/system/ThirdParty', @@ -124,42 +123,39 @@ ]); // auto import fully qualified class names - $parameters->set(Option::AUTO_IMPORT_NAMES, true); - - $services = $containerConfigurator->services(); - $services->set(UnderscoreToCamelCaseVariableNameRector::class); - $services->set(SimplifyUselessVariableRector::class); - $services->set(RemoveAlwaysElseRector::class); - $services->set(PassStrictParameterToFunctionParameterRector::class); - $services->set(CountArrayToEmptyArrayComparisonRector::class); - $services->set(ForToForeachRector::class); - $services->set(ChangeNestedForeachIfsToEarlyContinueRector::class); - $services->set(ChangeIfElseValueAssignToEarlyReturnRector::class); - $services->set(SimplifyStrposLowerRector::class); - $services->set(CombineIfRector::class); - $services->set(SimplifyIfReturnBoolRector::class); - $services->set(InlineIfToExplicitIfRector::class); - $services->set(PreparedValueToEarlyReturnRector::class); - $services->set(ShortenElseIfRector::class); - $services->set(SimplifyIfElseToTernaryRector::class); - $services->set(UnusedForeachValueToArrayKeysRector::class); - $services->set(ChangeArrayPushToArrayAssignRector::class); - $services->set(UnnecessaryTernaryExpressionRector::class); - $services->set(RemoveErrorSuppressInTryCatchStmtsRector::class); - $services->set(RemoveVarTagFromClassConstantRector::class); - $services->set(AddPregQuoteDelimiterRector::class); - $services->set(SimplifyRegexPatternRector::class); - $services->set(FuncGetArgsToVariadicParamRector::class); - $services->set(MakeInheritedMethodVisibilitySameAsParentRector::class); - $services->set(SimplifyEmptyArrayCheckRector::class); - $services->set(NormalizeNamespaceByPSR4ComposerAutoloadRector::class); - $services->set(StringClassNameToClassConstantRector::class) - ->configure([ - 'Error', - 'Exception', - 'InvalidArgumentException', - 'Closure', - 'stdClass', - 'SQLite3', - ]); + $rectorConfig->importNames(); + + $rectorConfig->rule(UnderscoreToCamelCaseVariableNameRector::class); + $rectorConfig->rule(RemoveAlwaysElseRector::class); + $rectorConfig->rule(PassStrictParameterToFunctionParameterRector::class); + $rectorConfig->rule(CountArrayToEmptyArrayComparisonRector::class); + $rectorConfig->rule(ForToForeachRector::class); + $rectorConfig->rule(ChangeNestedForeachIfsToEarlyContinueRector::class); + $rectorConfig->rule(ChangeIfElseValueAssignToEarlyReturnRector::class); + $rectorConfig->rule(SimplifyStrposLowerRector::class); + $rectorConfig->rule(CombineIfRector::class); + $rectorConfig->rule(SimplifyIfReturnBoolRector::class); + $rectorConfig->rule(InlineIfToExplicitIfRector::class); + $rectorConfig->rule(PreparedValueToEarlyReturnRector::class); + $rectorConfig->rule(ShortenElseIfRector::class); + $rectorConfig->rule(SimplifyIfElseToTernaryRector::class); + $rectorConfig->rule(UnusedForeachValueToArrayKeysRector::class); + $rectorConfig->rule(ChangeArrayPushToArrayAssignRector::class); + $rectorConfig->rule(UnnecessaryTernaryExpressionRector::class); + $rectorConfig->rule(RemoveErrorSuppressInTryCatchStmtsRector::class); + $rectorConfig->rule(RemoveVarTagFromClassConstantRector::class); + $rectorConfig->rule(AddPregQuoteDelimiterRector::class); + $rectorConfig->rule(SimplifyRegexPatternRector::class); + $rectorConfig->rule(FuncGetArgsToVariadicParamRector::class); + $rectorConfig->rule(MakeInheritedMethodVisibilitySameAsParentRector::class); + $rectorConfig->rule(SimplifyEmptyArrayCheckRector::class); + $rectorConfig->rule(NormalizeNamespaceByPSR4ComposerAutoloadRector::class); + $rectorConfig->ruleWithConfiguration(StringClassNameToClassConstantRector::class, [ + 'Error', + 'Exception', + 'InvalidArgumentException', + 'Closure', + 'stdClass', + 'SQLite3', + ]); }; From 4fd7ac58307590112e6bdb6add99c1d9d085e57f Mon Sep 17 00:00:00 2001 From: Chl Date: Mon, 18 Apr 2022 16:43:20 +0200 Subject: [PATCH 1956/2325] script_tag: changelog, doc + test with default arg --- system/Helpers/html_helper.php | 4 ++-- tests/system/Helpers/HTMLHelperTest.php | 10 ++++++++++ user_guide_src/source/changelogs/v4.2.0.rst | 1 + user_guide_src/source/helpers/html_helper.rst | 4 ++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index a15b18ff47e8..c2e48d890fef 100755 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -189,8 +189,8 @@ function doctype(string $type = 'html5'): string * * Generates link to a JS file * - * @param mixed $src Script source or an array - * @param bool $indexPage Should indexPage be added to the JS path + * @param array|string $src Script source or an array of attributes + * @param bool $indexPage Should indexPage be added to the JS path */ function script_tag($src = '', bool $indexPage = false): string { diff --git a/tests/system/Helpers/HTMLHelperTest.php b/tests/system/Helpers/HTMLHelperTest.php index 74b087228fdd..d539d7421be6 100755 --- a/tests/system/Helpers/HTMLHelperTest.php +++ b/tests/system/Helpers/HTMLHelperTest.php @@ -269,6 +269,16 @@ public function testScriptTagWithSrcAndAttributes() $this->assertSame($expected, script_tag($target)); } + /** + * This test has probably no real-world value but may help detecting + * a change in the default behaviour. + */ + public function testScriptTagWithoutAnyArg() + { + $expected = ''; + $this->assertSame($expected, script_tag()); + } + public function testLinkTag() { $target = 'css/mystyles.css'; diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 0ed69ab0760a..fa88608dc355 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -38,6 +38,7 @@ Enhancements - The log format has also changed. If users are depending on the log format in their apps, the new log format is "<1-based count> (): " - Added support for webp files to **app/Config/Mimes.php**. - Added 4th parameter ``$includeDir`` to ``get_filenames()``. See :php:func:`get_filenames`. +- HTML helper ``script_tag()`` now uses ``null`` values to write boolean attributes in minimized form: `` + - -
    -
    -

    getCode() ? ' #' . $exception->getCode() : '') ?>

    -

    - getMessage())) ?> - getMessage())) ?>" - rel="noreferrer" target="_blank">search → -

    -
    -
    - - -
    -

    at line

    - - -
    - -
    - -
    - -
    - - - -
    - - -
    - -
      - $row) : ?> - -
    1. -

      - - - +

      +
      +

      getCode() ? ' #' . $exception->getCode() : '') ?>

      +

      + getMessage())) ?> + getMessage())) ?>" + rel="noreferrer" target="_blank">search → +

      +
      +
      + + +
      +

      at line

      + + +
      + +
      + +
      + +
      + + + +
      + + +
      + +
        + $row) : ?> + +
      1. +

        + + + - - {PHP internal code} - - - - -   —   - - - ( arguments ) -

        -
    - - + {PHP internal code} + + + + +   —   + + + ( arguments ) +
    +
    + + $value) : ?> - - - - - - -
    name : "#{$key}") ?>
    - - - () - - - - -   —   () - -

    - - - -
    - -
    - - - - - - - - - -
    - - + name : "#{$key}") ?> +
    + + + + +
    + + () + + + + +   —   () + +

    + + + +
    + +
    + + + + + + + + + +
    + + -

    $

    - - - - - - - - - - $value) : ?> - - - - - - -
    KeyValue
    - - - -
    - -
    - - - - - - -

    Constants

    - - - - - - - - - - $value) : ?> - - - - - - -
    KeyValue
    - - - -
    - -
    - -
    - - -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    PathgetUri()) ?>
    HTTP MethodgetMethod())) ?>
    IP AddressgetIPAddress()) ?>
    Is AJAX Request?isAJAX() ? 'yes' : 'no' ?>
    Is CLI Request?isCLI() ? 'yes' : 'no' ?>
    Is Secure Request?isSecure() ? 'yes' : 'no' ?>
    User AgentgetUserAgent()->getAgentString()) ?>
    - - - - - $ + + + + + + + + + + $value) : ?> + + + + + + +
    KeyValue
    + + + +
    + +
    + + + + + + +

    Constants

    + + + + + + + + + + $value) : ?> + + + + + + +
    KeyValue
    + + + +
    + +
    + +
    + + +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    PathgetUri()) ?>
    HTTP MethodgetMethod())) ?>
    IP AddressgetIPAddress()) ?>
    Is AJAX Request?isAJAX() ? 'yes' : 'no' ?>
    Is CLI Request?isCLI() ? 'yes' : 'no' ?>
    Is Secure Request?isSecure() ? 'yes' : 'no' ?>
    User AgentgetUserAgent()->getAgentString()) ?>
    + + + + + - - -

    $

    - - - - - - - - - - $value) : ?> - - - - - - -
    KeyValue
    - - - -
    - -
    - - - - - -
    - No $_GET, $_POST, or $_COOKIE Information to show. -
    - - - - getHeaders(); ?> - - -

    Headers

    - - - - - - - - - - - + +

    $

    + +
    HeaderValue
    + + + + + + + + $value) : ?> + + + + + + +
    KeyValue
    + + + +
    + +
    + + + + + +
    + No $_GET, $_POST, or $_COOKIE Information to show. +
    + + + + getHeaders(); ?> + + +

    Headers

    + + + + + + + + + + + - - - - - - - - -
    HeaderValue
    getName(), 'html') ?>getValueLine(), 'html') ?>
    - - -
    - - - + + getName(), 'html') ?> + getValueLine(), 'html') ?> + + + + + + + + + + + setStatusCode(http_response_code()); ?> -
    - - - - - -
    Response StatusgetStatusCode() . ' - ' . $response->getReasonPhrase()) ?>
    - - getHeaders(); ?> - - - -

    Headers

    - - - - - - - - - - $value) : ?> - - - - - - -
    HeaderValue
    getHeaderLine($name), 'html') ?>
    - - -
    - - -
    - - -
      - -
    1. - -
    -
    - - -
    - - - - - - - - - - - - - - - - -
    Memory Usage
    Peak Memory Usage:
    Memory Limit:
    - -
    - - - - - - +
    + + + + + +
    Response StatusgetStatusCode() . ' - ' . $response->getReasonPhrase()) ?>
    + + getHeaders(); ?> + + + +

    Headers

    + + + + + + + + + + $value) : ?> + + + + + + +
    HeaderValue
    getHeaderLine($name), 'html') ?>
    + + +
    + + +
    + + +
      + +
    1. + +
    +
    + + +
    + + + + + + + + + + + + + + + + +
    Memory Usage
    Peak Memory Usage:
    Memory Limit:
    + +
    + + + + + + diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php index cca49c2ed9c3..9faa4a15b783 100644 --- a/app/Views/errors/html/production.php +++ b/app/Views/errors/html/production.php @@ -1,24 +1,24 @@ - - + + - Whoops! + Whoops! - + -
    +
    -

    Whoops!

    +

    Whoops!

    -

    We seem to have hit a snag. Please try again later...

    +

    We seem to have hit a snag. Please try again later...

    -
    +
    diff --git a/app/Views/welcome_message.php b/app/Views/welcome_message.php index b982f58aa158..c66a9615c6be 100644 --- a/app/Views/welcome_message.php +++ b/app/Views/welcome_message.php @@ -1,229 +1,229 @@ - - Welcome to CodeIgniter 4! - - - - - - - + + Welcome to CodeIgniter 4! + + + + + + +
    - - -
    - -

    Welcome to CodeIgniter

    - -

    The small framework with powerful features

    - -
    + + +
    + +

    Welcome to CodeIgniter

    + +

    The small framework with powerful features

    + +
    @@ -231,91 +231,91 @@
    -

    About this page

    +

    About this page

    -

    The page you are looking at is being generated dynamically by CodeIgniter.

    +

    The page you are looking at is being generated dynamically by CodeIgniter.

    -

    If you would like to edit this page you will find it located at:

    +

    If you would like to edit this page you will find it located at:

    -
    app/Views/welcome_message.php
    +
    app/Views/welcome_message.php
    -

    The corresponding controller for this page can be found at:

    +

    The corresponding controller for this page can be found at:

    -
    app/Controllers/Home.php
    +
    app/Controllers/Home.php
    -
    +
    -

    Go further

    +

    Go further

    -

    - - Learn -

    +

    + + Learn +

    -

    The User Guide contains an introduction, tutorial, a number of "how to" - guides, and then reference documentation for the components that make up - the framework. Check the User Guide !

    +

    The User Guide contains an introduction, tutorial, a number of "how to" + guides, and then reference documentation for the components that make up + the framework. Check the User Guide !

    -

    - - Discuss -

    +

    + + Discuss +

    -

    CodeIgniter is a community-developed open source project, with several - venues for the community members to gather and exchange ideas. View all - the threads on CodeIgniter's forum, or chat on Slack !

    +

    CodeIgniter is a community-developed open source project, with several + venues for the community members to gather and exchange ideas. View all + the threads on CodeIgniter's forum, or chat on Slack !

    -

    - - Contribute -

    +

    + + Contribute +

    -

    CodeIgniter is a community driven project and accepts contributions - of code and documentation from the community. Why not - - join us ?

    +

    CodeIgniter is a community driven project and accepts contributions + of code and documentation from the community. Why not + + join us ?

    -
    +
    -
    +
    -

    Page rendered in {elapsed_time} seconds

    +

    Page rendered in {elapsed_time} seconds

    -

    Environment:

    +

    Environment:

    -
    +
    -
    +
    -

    © CodeIgniter Foundation. CodeIgniter is open source project released under the MIT - open source licence.

    +

    © CodeIgniter Foundation. CodeIgniter is open source project released under the MIT + open source licence.

    -
    +
    diff --git a/app/index.html b/app/index.html index b702fbc3967b..69df4e1dff68 100644 --- a/app/index.html +++ b/app/index.html @@ -1,7 +1,7 @@ - 403 Forbidden + 403 Forbidden diff --git a/system/Debug/Toolbar/Views/_config.tpl b/system/Debug/Toolbar/Views/_config.tpl index 3934cf62ebee..b6c7e0c3d86f 100644 --- a/system/Debug/Toolbar/Views/_config.tpl +++ b/system/Debug/Toolbar/Views/_config.tpl @@ -1,48 +1,48 @@

    - Read the CodeIgniter docs... + Read the CodeIgniter docs...

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    CodeIgniter Version:{ ciVersion }
    PHP Version:{ phpVersion }
    PHP SAPI:{ phpSAPI }
    Environment:{ environment }
    Base URL: - { if $baseURL == '' } -
    - The $baseURL should always be set manually to prevent possible URL personification from external parties. -
    - { else } - { baseURL } - { endif } -
    Timezone:{ timezone }
    Locale:{ locale }
    Content Security Policy Enabled:{ if $cspEnabled } Yes { else } No { endif }
    CodeIgniter Version:{ ciVersion }
    PHP Version:{ phpVersion }
    PHP SAPI:{ phpSAPI }
    Environment:{ environment }
    Base URL: + { if $baseURL == '' } +
    + The $baseURL should always be set manually to prevent possible URL personification from external parties. +
    + { else } + { baseURL } + { endif } +
    Timezone:{ timezone }
    Locale:{ locale }
    Content Security Policy Enabled:{ if $cspEnabled } Yes { else } No { endif }
    diff --git a/system/Debug/Toolbar/Views/toolbar.js b/system/Debug/Toolbar/Views/toolbar.js index 3bd05d5e9592..7805a99dda05 100644 --- a/system/Debug/Toolbar/Views/toolbar.js +++ b/system/Debug/Toolbar/Views/toolbar.js @@ -4,684 +4,684 @@ var ciDebugBar = { - toolbarContainer : null, - toolbar : null, - icon : null, - - init : function () { - this.toolbarContainer = document.getElementById('toolbarContainer'); - this.toolbar = document.getElementById('debug-bar'); - this.icon = document.getElementById('debug-icon'); - - ciDebugBar.createListeners(); - ciDebugBar.setToolbarState(); - ciDebugBar.setToolbarPosition(); - ciDebugBar.setToolbarTheme(); - ciDebugBar.toggleViewsHints(); - ciDebugBar.routerLink(); - - document.getElementById('debug-bar-link').addEventListener('click', ciDebugBar.toggleToolbar, true); - document.getElementById('debug-icon-link').addEventListener('click', ciDebugBar.toggleToolbar, true); - - // Allows to highlight the row of the current history request - var btn = this.toolbar.querySelector('button[data-time="' + localStorage.getItem('debugbar-time') + '"]'); - ciDebugBar.addClass(btn.parentNode.parentNode, 'current'); - - historyLoad = this.toolbar.getElementsByClassName('ci-history-load'); - - for (var i = 0; i < historyLoad.length; i++) - { - historyLoad[i].addEventListener('click', function () { - loadDoc(this.getAttribute('data-time')); - }, true); - } - - // Display the active Tab on page load - var tab = ciDebugBar.readCookie('debug-bar-tab'); - if (document.getElementById(tab)) - { - var el = document.getElementById(tab); - el.style.display = 'block'; - ciDebugBar.addClass(el, 'active'); - tab = document.querySelector('[data-tab=' + tab + ']'); - if (tab) - { - ciDebugBar.addClass(tab.parentNode, 'active'); - } - } - }, - - createListeners : function () { - var buttons = [].slice.call(this.toolbar.querySelectorAll('.ci-label a')); - - for (var i = 0; i < buttons.length; i++) - { - buttons[i].addEventListener('click', ciDebugBar.showTab, true); - } - - // Hook up generic toggle via data attributes `data-toggle="foo"` - var links = this.toolbar.querySelectorAll('[data-toggle]'); - for (var i = 0; i < links.length; i++) - { - links[i].addEventListener('click', ciDebugBar.toggleRows, true); - } - }, - - showTab: function () { - // Get the target tab, if any - var tab = document.getElementById(this.getAttribute('data-tab')); - - // If the label have not a tab stops here - if (! tab) - { - return; - } - - // Remove debug-bar-tab cookie - ciDebugBar.createCookie('debug-bar-tab', '', -1); - - // Check our current state. - var state = tab.style.display; - - // Hide all tabs - var tabs = document.querySelectorAll('#debug-bar .tab'); - - for (var i = 0; i < tabs.length; i++) - { - tabs[i].style.display = 'none'; - } - - // Mark all labels as inactive - var labels = document.querySelectorAll('#debug-bar .ci-label'); - - for (var i = 0; i < labels.length; i++) - { - ciDebugBar.removeClass(labels[i], 'active'); - } - - // Show/hide the selected tab - if (state != 'block') - { - tab.style.display = 'block'; - ciDebugBar.addClass(this.parentNode, 'active'); - // Create debug-bar-tab cookie to persistent state - ciDebugBar.createCookie('debug-bar-tab', this.getAttribute('data-tab'), 365); - } - }, - - addClass : function (el, className) { - if (el.classList) - { - el.classList.add(className); - } - else - { - el.className += ' ' + className; - } - }, - - removeClass : function (el, className) { - if (el.classList) - { - el.classList.remove(className); - } - else - { - el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); - } - }, - - /** - * Toggle display of another object based on - * the data-toggle value of this object - * - * @param event - */ - toggleRows : function(event) { - if(event.target) - { - let row = event.target.closest('tr'); - let target = document.getElementById(row.getAttribute('data-toggle')); - target.style.display = target.style.display === 'none' ? 'table-row' : 'none'; - } - }, - - /** - * Toggle display of a data table - * - * @param obj - */ - toggleDataTable : function (obj) { - if (typeof obj == 'string') - { - obj = document.getElementById(obj + '_table'); - } - - if (obj) - { - obj.style.display = obj.style.display === 'none' ? 'block' : 'none'; - } - }, - - /** - * Toggle display of timeline child elements - * - * @param obj - */ - toggleChildRows : function (obj) { - if (typeof obj == 'string') - { - par = document.getElementById(obj + '_parent') - obj = document.getElementById(obj + '_children'); - } - - if (par && obj) - { - obj.style.display = obj.style.display === 'none' ? '' : 'none'; - par.classList.toggle('timeline-parent-open'); - } - }, - - - //-------------------------------------------------------------------- - - /** - * Toggle tool bar from full to icon and icon to full - */ - toggleToolbar : function () { - var open = ciDebugBar.toolbar.style.display != 'none'; - - ciDebugBar.icon.style.display = open == true ? 'inline-block' : 'none'; - ciDebugBar.toolbar.style.display = open == false ? 'inline-block' : 'none'; - - // Remember it for other page loads on this site - ciDebugBar.createCookie('debug-bar-state', '', -1); - ciDebugBar.createCookie('debug-bar-state', open == true ? 'minimized' : 'open' , 365); - }, - - /** - * Sets the initial state of the toolbar (open or minimized) when - * the page is first loaded to allow it to remember the state between refreshes. - */ - setToolbarState: function () { - var open = ciDebugBar.readCookie('debug-bar-state'); - - ciDebugBar.icon.style.display = open != 'open' ? 'inline-block' : 'none'; - ciDebugBar.toolbar.style.display = open == 'open' ? 'inline-block' : 'none'; - }, - - toggleViewsHints: function () { - // Avoid toggle hints on history requests that are not the initial - if (localStorage.getItem('debugbar-time') != localStorage.getItem('debugbar-time-new')) - { - var a = document.querySelector('a[data-tab="ci-views"]'); - a.href = '#'; - return; - } - - var nodeList = []; // [ Element, NewElement( 1 )/OldElement( 0 ) ] - var sortedComments = []; - var comments = []; - - var getComments = function () { - var nodes = []; - var result = []; - var xpathResults = document.evaluate( "//comment()[starts-with(., ' DEBUG-VIEW')]", document, null, XPathResult.ANY_TYPE, null); - var nextNode = xpathResults.iterateNext(); - while ( nextNode ) - { - nodes.push( nextNode ); - nextNode = xpathResults.iterateNext(); - } - - // sort comment by opening and closing tags - for (var i = 0; i < nodes.length; ++i) - { - // get file path + name to use as key - var path = nodes[i].nodeValue.substring( 18, nodes[i].nodeValue.length - 1 ); - - if ( nodes[i].nodeValue[12] === 'S' ) // simple check for start comment - { - // create new entry - result[path] = [ nodes[i], null ]; - } - else if (result[path]) - { - // add to existing entry - result[path][1] = nodes[i]; - } - } - - return result; - }; - - // find node that has TargetNode as parentNode - var getParentNode = function ( node, targetNode ) { - if ( node.parentNode === null ) - { - return null; - } - - if ( node.parentNode !== targetNode ) - { - return getParentNode( node.parentNode, targetNode ); - } - - return node; - }; - - // define invalid & outer ( also invalid ) elements - const INVALID_ELEMENTS = [ 'NOSCRIPT', 'SCRIPT', 'STYLE' ]; - const OUTER_ELEMENTS = [ 'HTML', 'BODY', 'HEAD' ]; - - var getValidElementInner = function ( node, reverse ) { - // handle invalid tags - if ( OUTER_ELEMENTS.indexOf( node.nodeName ) !== -1 ) - { - for (var i = 0; i < document.body.children.length; ++i) - { - var index = reverse ? document.body.children.length - ( i + 1 ) : i; - var element = document.body.children[index]; - - // skip invalid tags - if ( INVALID_ELEMENTS.indexOf( element.nodeName ) !== -1 ) - { - continue; - } - - return [ element, reverse ]; - } - - return null; - } - - // get to next valid element - while ( node !== null && INVALID_ELEMENTS.indexOf( node.nodeName ) !== -1 ) - { - node = reverse ? node.previousElementSibling : node.nextElementSibling; - } - - // return non array if we couldnt find something - if ( node === null ) - { - return null; - } - - return [ node, reverse ]; - }; - - // get next valid element ( to be safe to add divs ) - // @return [ element, skip element ] or null if we couldnt find a valid place - var getValidElement = function ( nodeElement ) { - if (nodeElement) - { - if ( nodeElement.nextElementSibling !== null ) - { - return getValidElementInner( nodeElement.nextElementSibling, false ) - || getValidElementInner( nodeElement.previousElementSibling, true ); - } - if ( nodeElement.previousElementSibling !== null ) - { - return getValidElementInner( nodeElement.previousElementSibling, true ); - } - } - - // something went wrong! -> element is not in DOM - return null; - }; - - function showHints() - { - // Had AJAX? Reset view blocks - sortedComments = getComments(); - - for (var key in sortedComments) - { - var startElement = getValidElement( sortedComments[key][0] ); - var endElement = getValidElement( sortedComments[key][1] ); - - // skip if we couldnt get a valid element - if ( startElement === null || endElement === null ) - { - continue; - } - - // find element which has same parent as startelement - var jointParent = getParentNode( endElement[0], startElement[0].parentNode ); - if ( jointParent === null ) - { - // find element which has same parent as endelement - jointParent = getParentNode( startElement[0], endElement[0].parentNode ); - if ( jointParent === null ) - { - // both tries failed - continue; - } - else - { - startElement[0] = jointParent; - } - } - else - { - endElement[0] = jointParent; - } - - var debugDiv = document.createElement( 'div' ); // holder - var debugPath = document.createElement( 'div' ); // path - var childArray = startElement[0].parentNode.childNodes; // target child array - var parent = startElement[0].parentNode; - var start, end; - - // setup container - debugDiv.classList.add( 'debug-view' ); - debugDiv.classList.add( 'show-view' ); - debugPath.classList.add( 'debug-view-path' ); - debugPath.innerText = key; - debugDiv.appendChild( debugPath ); - - // calc distance between them - // start - for (var i = 0; i < childArray.length; ++i) - { - // check for comment ( start & end ) -> if its before valid start element - if ( childArray[i] === sortedComments[key][1] || - childArray[i] === sortedComments[key][0] || - childArray[i] === startElement[0] ) - { - start = i; - if ( childArray[i] === sortedComments[key][0] ) - { - start++; // increase to skip the start comment - } - break; - } - } - // adjust if we want to skip the start element - if ( startElement[1] ) - { - start++; - } - - // end - for (var i = start; i < childArray.length; ++i) - { - if ( childArray[i] === endElement[0] ) - { - end = i; - // dont break to check for end comment after end valid element - } - else if ( childArray[i] === sortedComments[key][1] ) - { - // if we found the end comment, we can break - end = i; - break; - } - } - - // move elements - var number = end - start; - if ( endElement[1] ) - { - number++; - } - for (var i = 0; i < number; ++i) - { - if ( INVALID_ELEMENTS.indexOf( childArray[start] ) !== -1 ) - { - // skip invalid childs that can cause problems if moved - start++; - continue; - } - debugDiv.appendChild( childArray[start] ); - } - - // add container to DOM - nodeList.push( parent.insertBefore( debugDiv, childArray[start] ) ); - } - - ciDebugBar.createCookie('debug-view', 'show', 365); - ciDebugBar.addClass(btn, 'active'); - } - - function hideHints() - { - for (var i = 0; i < nodeList.length; ++i) - { - var index; - - // find index - for (var j = 0; j < nodeList[i].parentNode.childNodes.length; ++j) - { - if ( nodeList[i].parentNode.childNodes[j] === nodeList[i] ) - { - index = j; - break; - } - } - - // move child back - while ( nodeList[i].childNodes.length !== 1 ) - { - nodeList[i].parentNode.insertBefore( nodeList[i].childNodes[1], nodeList[i].parentNode.childNodes[index].nextSibling ); - index++; - } - - nodeList[i].parentNode.removeChild( nodeList[i] ); - } - nodeList.length = 0; - - ciDebugBar.createCookie('debug-view', '', -1); - ciDebugBar.removeClass(btn, 'active'); - } - - var btn = document.querySelector('[data-tab=ci-views]'); - - // If the Views Collector is inactive stops here - if (! btn) - { - return; - } - - btn.parentNode.onclick = function () { - if (ciDebugBar.readCookie('debug-view')) - { - hideHints(); - } - else - { - showHints(); - } - }; - - // Determine Hints state on page load - if (ciDebugBar.readCookie('debug-view')) - { - showHints(); - } - }, - - setToolbarPosition: function () { - var btnPosition = this.toolbar.querySelector('#toolbar-position'); - - if (ciDebugBar.readCookie('debug-bar-position') === 'top') - { - ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top'); - ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top'); - } - - btnPosition.addEventListener('click', function () { - var position = ciDebugBar.readCookie('debug-bar-position'); - - ciDebugBar.createCookie('debug-bar-position', '', -1); - - if (!position || position === 'bottom') - { - ciDebugBar.createCookie('debug-bar-position', 'top', 365); - ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top'); - ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top'); - } - else - { - ciDebugBar.createCookie('debug-bar-position', 'bottom', 365); - ciDebugBar.removeClass(ciDebugBar.icon, 'fixed-top'); - ciDebugBar.removeClass(ciDebugBar.toolbar, 'fixed-top'); - } - }, true); - }, - - setToolbarTheme: function () { - var btnTheme = this.toolbar.querySelector('#toolbar-theme'); - var isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches; - var isLightMode = window.matchMedia("(prefers-color-scheme: light)").matches; - - // If a cookie is set with a value, we force the color scheme - if (ciDebugBar.readCookie('debug-bar-theme') === 'dark') - { - ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'light'); - ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'dark'); - } - else if (ciDebugBar.readCookie('debug-bar-theme') === 'light') - { - ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'dark'); - ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'light'); - } - - btnTheme.addEventListener('click', function () { - var theme = ciDebugBar.readCookie('debug-bar-theme'); - - if (!theme && window.matchMedia("(prefers-color-scheme: dark)").matches) - { - // If there is no cookie, and "prefers-color-scheme" is set to "dark" - // It means that the user wants to switch to light mode - ciDebugBar.createCookie('debug-bar-theme', 'light', 365); - ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'dark'); - ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'light'); - } - else - { - if (theme === 'dark') - { - ciDebugBar.createCookie('debug-bar-theme', 'light', 365); - ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'dark'); - ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'light'); - } - else - { - // In any other cases: if there is no cookie, or the cookie is set to - // "light", or the "prefers-color-scheme" is "light"... - ciDebugBar.createCookie('debug-bar-theme', 'dark', 365); - ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'light'); - ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'dark'); - } - } - }, true); - }, - - /** - * Helper to create a cookie. - * - * @param name - * @param value - * @param days - */ - createCookie : function (name,value,days) { - if (days) - { - var date = new Date(); - - date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); - - var expires = "; expires=" + date.toGMTString(); - } - else - { - var expires = ""; - } - - document.cookie = name + "=" + value + expires + "; path=/; samesite=Lax"; - }, - - readCookie : function (name) { - var nameEQ = name + "="; - var ca = document.cookie.split(';'); - - for (var i = 0; i < ca.length; i++) - { - var c = ca[i]; - while (c.charAt(0) == ' ') - { - c = c.substring(1,c.length); - } - if (c.indexOf(nameEQ) == 0) - { - return c.substring(nameEQ.length,c.length); - } - } - return null; - }, - - trimSlash: function (text) { - return text.replace(/^\/|\/$/g, ''); - }, - - routerLink: function () { - var row, _location; - var rowGet = this.toolbar.querySelectorAll('td[data-debugbar-route="GET"]'); - var patt = /\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)/; - - for (var i = 0; i < rowGet.length; i++) - { - row = rowGet[i]; - if (!/\/\(.+?\)/.test(rowGet[i].innerText)) - { - row.style = 'cursor: pointer;'; - row.setAttribute('title', location.origin + '/' + ciDebugBar.trimSlash(row.innerText)); - row.addEventListener('click', function (ev) { - _location = location.origin + '/' + ciDebugBar.trimSlash(ev.target.innerText); - var redirectWindow = window.open(_location, '_blank'); - redirectWindow.location; - }); - } - else - { - row.innerHTML = '
    ' + row.innerText + '
    ' - + '
    ' - + row.innerText.replace(patt, '') - + '' - + '
    '; - } - } - - rowGet = this.toolbar.querySelectorAll('td[data-debugbar-route="GET"] form'); - for (var i = 0; i < rowGet.length; i++) - { - row = rowGet[i]; - - row.addEventListener('submit', function (event) { - event.preventDefault() - var inputArray = [], t = 0; - var input = event.target.querySelectorAll('input[type=text]'); - var tpl = event.target.getAttribute('data-debugbar-route-tpl'); - - for (var n = 0; n < input.length; n++) - { - if (input[n].value.length > 0) - { - inputArray.push(input[n].value); - } - } - - if (inputArray.length > 0) - { - _location = location.origin + '/' + tpl.replace(/\?/g, function () { - return inputArray[t++] - }); - - var redirectWindow = window.open(_location, '_blank'); - redirectWindow.location; - } - }) - } - } + toolbarContainer : null, + toolbar : null, + icon : null, + + init : function () { + this.toolbarContainer = document.getElementById('toolbarContainer'); + this.toolbar = document.getElementById('debug-bar'); + this.icon = document.getElementById('debug-icon'); + + ciDebugBar.createListeners(); + ciDebugBar.setToolbarState(); + ciDebugBar.setToolbarPosition(); + ciDebugBar.setToolbarTheme(); + ciDebugBar.toggleViewsHints(); + ciDebugBar.routerLink(); + + document.getElementById('debug-bar-link').addEventListener('click', ciDebugBar.toggleToolbar, true); + document.getElementById('debug-icon-link').addEventListener('click', ciDebugBar.toggleToolbar, true); + + // Allows to highlight the row of the current history request + var btn = this.toolbar.querySelector('button[data-time="' + localStorage.getItem('debugbar-time') + '"]'); + ciDebugBar.addClass(btn.parentNode.parentNode, 'current'); + + historyLoad = this.toolbar.getElementsByClassName('ci-history-load'); + + for (var i = 0; i < historyLoad.length; i++) + { + historyLoad[i].addEventListener('click', function () { + loadDoc(this.getAttribute('data-time')); + }, true); + } + + // Display the active Tab on page load + var tab = ciDebugBar.readCookie('debug-bar-tab'); + if (document.getElementById(tab)) + { + var el = document.getElementById(tab); + el.style.display = 'block'; + ciDebugBar.addClass(el, 'active'); + tab = document.querySelector('[data-tab=' + tab + ']'); + if (tab) + { + ciDebugBar.addClass(tab.parentNode, 'active'); + } + } + }, + + createListeners : function () { + var buttons = [].slice.call(this.toolbar.querySelectorAll('.ci-label a')); + + for (var i = 0; i < buttons.length; i++) + { + buttons[i].addEventListener('click', ciDebugBar.showTab, true); + } + + // Hook up generic toggle via data attributes `data-toggle="foo"` + var links = this.toolbar.querySelectorAll('[data-toggle]'); + for (var i = 0; i < links.length; i++) + { + links[i].addEventListener('click', ciDebugBar.toggleRows, true); + } + }, + + showTab: function () { + // Get the target tab, if any + var tab = document.getElementById(this.getAttribute('data-tab')); + + // If the label have not a tab stops here + if (! tab) + { + return; + } + + // Remove debug-bar-tab cookie + ciDebugBar.createCookie('debug-bar-tab', '', -1); + + // Check our current state. + var state = tab.style.display; + + // Hide all tabs + var tabs = document.querySelectorAll('#debug-bar .tab'); + + for (var i = 0; i < tabs.length; i++) + { + tabs[i].style.display = 'none'; + } + + // Mark all labels as inactive + var labels = document.querySelectorAll('#debug-bar .ci-label'); + + for (var i = 0; i < labels.length; i++) + { + ciDebugBar.removeClass(labels[i], 'active'); + } + + // Show/hide the selected tab + if (state != 'block') + { + tab.style.display = 'block'; + ciDebugBar.addClass(this.parentNode, 'active'); + // Create debug-bar-tab cookie to persistent state + ciDebugBar.createCookie('debug-bar-tab', this.getAttribute('data-tab'), 365); + } + }, + + addClass : function (el, className) { + if (el.classList) + { + el.classList.add(className); + } + else + { + el.className += ' ' + className; + } + }, + + removeClass : function (el, className) { + if (el.classList) + { + el.classList.remove(className); + } + else + { + el.className = el.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' '); + } + }, + + /** + * Toggle display of another object based on + * the data-toggle value of this object + * + * @param event + */ + toggleRows : function(event) { + if(event.target) + { + let row = event.target.closest('tr'); + let target = document.getElementById(row.getAttribute('data-toggle')); + target.style.display = target.style.display === 'none' ? 'table-row' : 'none'; + } + }, + + /** + * Toggle display of a data table + * + * @param obj + */ + toggleDataTable : function (obj) { + if (typeof obj == 'string') + { + obj = document.getElementById(obj + '_table'); + } + + if (obj) + { + obj.style.display = obj.style.display === 'none' ? 'block' : 'none'; + } + }, + + /** + * Toggle display of timeline child elements + * + * @param obj + */ + toggleChildRows : function (obj) { + if (typeof obj == 'string') + { + par = document.getElementById(obj + '_parent') + obj = document.getElementById(obj + '_children'); + } + + if (par && obj) + { + obj.style.display = obj.style.display === 'none' ? '' : 'none'; + par.classList.toggle('timeline-parent-open'); + } + }, + + + //-------------------------------------------------------------------- + + /** + * Toggle tool bar from full to icon and icon to full + */ + toggleToolbar : function () { + var open = ciDebugBar.toolbar.style.display != 'none'; + + ciDebugBar.icon.style.display = open == true ? 'inline-block' : 'none'; + ciDebugBar.toolbar.style.display = open == false ? 'inline-block' : 'none'; + + // Remember it for other page loads on this site + ciDebugBar.createCookie('debug-bar-state', '', -1); + ciDebugBar.createCookie('debug-bar-state', open == true ? 'minimized' : 'open' , 365); + }, + + /** + * Sets the initial state of the toolbar (open or minimized) when + * the page is first loaded to allow it to remember the state between refreshes. + */ + setToolbarState: function () { + var open = ciDebugBar.readCookie('debug-bar-state'); + + ciDebugBar.icon.style.display = open != 'open' ? 'inline-block' : 'none'; + ciDebugBar.toolbar.style.display = open == 'open' ? 'inline-block' : 'none'; + }, + + toggleViewsHints: function () { + // Avoid toggle hints on history requests that are not the initial + if (localStorage.getItem('debugbar-time') != localStorage.getItem('debugbar-time-new')) + { + var a = document.querySelector('a[data-tab="ci-views"]'); + a.href = '#'; + return; + } + + var nodeList = []; // [ Element, NewElement( 1 )/OldElement( 0 ) ] + var sortedComments = []; + var comments = []; + + var getComments = function () { + var nodes = []; + var result = []; + var xpathResults = document.evaluate( "//comment()[starts-with(., ' DEBUG-VIEW')]", document, null, XPathResult.ANY_TYPE, null); + var nextNode = xpathResults.iterateNext(); + while ( nextNode ) + { + nodes.push( nextNode ); + nextNode = xpathResults.iterateNext(); + } + + // sort comment by opening and closing tags + for (var i = 0; i < nodes.length; ++i) + { + // get file path + name to use as key + var path = nodes[i].nodeValue.substring( 18, nodes[i].nodeValue.length - 1 ); + + if ( nodes[i].nodeValue[12] === 'S' ) // simple check for start comment + { + // create new entry + result[path] = [ nodes[i], null ]; + } + else if (result[path]) + { + // add to existing entry + result[path][1] = nodes[i]; + } + } + + return result; + }; + + // find node that has TargetNode as parentNode + var getParentNode = function ( node, targetNode ) { + if ( node.parentNode === null ) + { + return null; + } + + if ( node.parentNode !== targetNode ) + { + return getParentNode( node.parentNode, targetNode ); + } + + return node; + }; + + // define invalid & outer ( also invalid ) elements + const INVALID_ELEMENTS = [ 'NOSCRIPT', 'SCRIPT', 'STYLE' ]; + const OUTER_ELEMENTS = [ 'HTML', 'BODY', 'HEAD' ]; + + var getValidElementInner = function ( node, reverse ) { + // handle invalid tags + if ( OUTER_ELEMENTS.indexOf( node.nodeName ) !== -1 ) + { + for (var i = 0; i < document.body.children.length; ++i) + { + var index = reverse ? document.body.children.length - ( i + 1 ) : i; + var element = document.body.children[index]; + + // skip invalid tags + if ( INVALID_ELEMENTS.indexOf( element.nodeName ) !== -1 ) + { + continue; + } + + return [ element, reverse ]; + } + + return null; + } + + // get to next valid element + while ( node !== null && INVALID_ELEMENTS.indexOf( node.nodeName ) !== -1 ) + { + node = reverse ? node.previousElementSibling : node.nextElementSibling; + } + + // return non array if we couldnt find something + if ( node === null ) + { + return null; + } + + return [ node, reverse ]; + }; + + // get next valid element ( to be safe to add divs ) + // @return [ element, skip element ] or null if we couldnt find a valid place + var getValidElement = function ( nodeElement ) { + if (nodeElement) + { + if ( nodeElement.nextElementSibling !== null ) + { + return getValidElementInner( nodeElement.nextElementSibling, false ) + || getValidElementInner( nodeElement.previousElementSibling, true ); + } + if ( nodeElement.previousElementSibling !== null ) + { + return getValidElementInner( nodeElement.previousElementSibling, true ); + } + } + + // something went wrong! -> element is not in DOM + return null; + }; + + function showHints() + { + // Had AJAX? Reset view blocks + sortedComments = getComments(); + + for (var key in sortedComments) + { + var startElement = getValidElement( sortedComments[key][0] ); + var endElement = getValidElement( sortedComments[key][1] ); + + // skip if we couldnt get a valid element + if ( startElement === null || endElement === null ) + { + continue; + } + + // find element which has same parent as startelement + var jointParent = getParentNode( endElement[0], startElement[0].parentNode ); + if ( jointParent === null ) + { + // find element which has same parent as endelement + jointParent = getParentNode( startElement[0], endElement[0].parentNode ); + if ( jointParent === null ) + { + // both tries failed + continue; + } + else + { + startElement[0] = jointParent; + } + } + else + { + endElement[0] = jointParent; + } + + var debugDiv = document.createElement( 'div' ); // holder + var debugPath = document.createElement( 'div' ); // path + var childArray = startElement[0].parentNode.childNodes; // target child array + var parent = startElement[0].parentNode; + var start, end; + + // setup container + debugDiv.classList.add( 'debug-view' ); + debugDiv.classList.add( 'show-view' ); + debugPath.classList.add( 'debug-view-path' ); + debugPath.innerText = key; + debugDiv.appendChild( debugPath ); + + // calc distance between them + // start + for (var i = 0; i < childArray.length; ++i) + { + // check for comment ( start & end ) -> if its before valid start element + if ( childArray[i] === sortedComments[key][1] || + childArray[i] === sortedComments[key][0] || + childArray[i] === startElement[0] ) + { + start = i; + if ( childArray[i] === sortedComments[key][0] ) + { + start++; // increase to skip the start comment + } + break; + } + } + // adjust if we want to skip the start element + if ( startElement[1] ) + { + start++; + } + + // end + for (var i = start; i < childArray.length; ++i) + { + if ( childArray[i] === endElement[0] ) + { + end = i; + // dont break to check for end comment after end valid element + } + else if ( childArray[i] === sortedComments[key][1] ) + { + // if we found the end comment, we can break + end = i; + break; + } + } + + // move elements + var number = end - start; + if ( endElement[1] ) + { + number++; + } + for (var i = 0; i < number; ++i) + { + if ( INVALID_ELEMENTS.indexOf( childArray[start] ) !== -1 ) + { + // skip invalid childs that can cause problems if moved + start++; + continue; + } + debugDiv.appendChild( childArray[start] ); + } + + // add container to DOM + nodeList.push( parent.insertBefore( debugDiv, childArray[start] ) ); + } + + ciDebugBar.createCookie('debug-view', 'show', 365); + ciDebugBar.addClass(btn, 'active'); + } + + function hideHints() + { + for (var i = 0; i < nodeList.length; ++i) + { + var index; + + // find index + for (var j = 0; j < nodeList[i].parentNode.childNodes.length; ++j) + { + if ( nodeList[i].parentNode.childNodes[j] === nodeList[i] ) + { + index = j; + break; + } + } + + // move child back + while ( nodeList[i].childNodes.length !== 1 ) + { + nodeList[i].parentNode.insertBefore( nodeList[i].childNodes[1], nodeList[i].parentNode.childNodes[index].nextSibling ); + index++; + } + + nodeList[i].parentNode.removeChild( nodeList[i] ); + } + nodeList.length = 0; + + ciDebugBar.createCookie('debug-view', '', -1); + ciDebugBar.removeClass(btn, 'active'); + } + + var btn = document.querySelector('[data-tab=ci-views]'); + + // If the Views Collector is inactive stops here + if (! btn) + { + return; + } + + btn.parentNode.onclick = function () { + if (ciDebugBar.readCookie('debug-view')) + { + hideHints(); + } + else + { + showHints(); + } + }; + + // Determine Hints state on page load + if (ciDebugBar.readCookie('debug-view')) + { + showHints(); + } + }, + + setToolbarPosition: function () { + var btnPosition = this.toolbar.querySelector('#toolbar-position'); + + if (ciDebugBar.readCookie('debug-bar-position') === 'top') + { + ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top'); + ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top'); + } + + btnPosition.addEventListener('click', function () { + var position = ciDebugBar.readCookie('debug-bar-position'); + + ciDebugBar.createCookie('debug-bar-position', '', -1); + + if (!position || position === 'bottom') + { + ciDebugBar.createCookie('debug-bar-position', 'top', 365); + ciDebugBar.addClass(ciDebugBar.icon, 'fixed-top'); + ciDebugBar.addClass(ciDebugBar.toolbar, 'fixed-top'); + } + else + { + ciDebugBar.createCookie('debug-bar-position', 'bottom', 365); + ciDebugBar.removeClass(ciDebugBar.icon, 'fixed-top'); + ciDebugBar.removeClass(ciDebugBar.toolbar, 'fixed-top'); + } + }, true); + }, + + setToolbarTheme: function () { + var btnTheme = this.toolbar.querySelector('#toolbar-theme'); + var isDarkMode = window.matchMedia("(prefers-color-scheme: dark)").matches; + var isLightMode = window.matchMedia("(prefers-color-scheme: light)").matches; + + // If a cookie is set with a value, we force the color scheme + if (ciDebugBar.readCookie('debug-bar-theme') === 'dark') + { + ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'light'); + ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'dark'); + } + else if (ciDebugBar.readCookie('debug-bar-theme') === 'light') + { + ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'dark'); + ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'light'); + } + + btnTheme.addEventListener('click', function () { + var theme = ciDebugBar.readCookie('debug-bar-theme'); + + if (!theme && window.matchMedia("(prefers-color-scheme: dark)").matches) + { + // If there is no cookie, and "prefers-color-scheme" is set to "dark" + // It means that the user wants to switch to light mode + ciDebugBar.createCookie('debug-bar-theme', 'light', 365); + ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'dark'); + ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'light'); + } + else + { + if (theme === 'dark') + { + ciDebugBar.createCookie('debug-bar-theme', 'light', 365); + ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'dark'); + ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'light'); + } + else + { + // In any other cases: if there is no cookie, or the cookie is set to + // "light", or the "prefers-color-scheme" is "light"... + ciDebugBar.createCookie('debug-bar-theme', 'dark', 365); + ciDebugBar.removeClass(ciDebugBar.toolbarContainer, 'light'); + ciDebugBar.addClass(ciDebugBar.toolbarContainer, 'dark'); + } + } + }, true); + }, + + /** + * Helper to create a cookie. + * + * @param name + * @param value + * @param days + */ + createCookie : function (name,value,days) { + if (days) + { + var date = new Date(); + + date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000)); + + var expires = "; expires=" + date.toGMTString(); + } + else + { + var expires = ""; + } + + document.cookie = name + "=" + value + expires + "; path=/; samesite=Lax"; + }, + + readCookie : function (name) { + var nameEQ = name + "="; + var ca = document.cookie.split(';'); + + for (var i = 0; i < ca.length; i++) + { + var c = ca[i]; + while (c.charAt(0) == ' ') + { + c = c.substring(1,c.length); + } + if (c.indexOf(nameEQ) == 0) + { + return c.substring(nameEQ.length,c.length); + } + } + return null; + }, + + trimSlash: function (text) { + return text.replace(/^\/|\/$/g, ''); + }, + + routerLink: function () { + var row, _location; + var rowGet = this.toolbar.querySelectorAll('td[data-debugbar-route="GET"]'); + var patt = /\((?:[^)(]+|\((?:[^)(]+|\([^)(]*\))*\))*\)/; + + for (var i = 0; i < rowGet.length; i++) + { + row = rowGet[i]; + if (!/\/\(.+?\)/.test(rowGet[i].innerText)) + { + row.style = 'cursor: pointer;'; + row.setAttribute('title', location.origin + '/' + ciDebugBar.trimSlash(row.innerText)); + row.addEventListener('click', function (ev) { + _location = location.origin + '/' + ciDebugBar.trimSlash(ev.target.innerText); + var redirectWindow = window.open(_location, '_blank'); + redirectWindow.location; + }); + } + else + { + row.innerHTML = '
    ' + row.innerText + '
    ' + + '
    ' + + row.innerText.replace(patt, '') + + '' + + '
    '; + } + } + + rowGet = this.toolbar.querySelectorAll('td[data-debugbar-route="GET"] form'); + for (var i = 0; i < rowGet.length; i++) + { + row = rowGet[i]; + + row.addEventListener('submit', function (event) { + event.preventDefault() + var inputArray = [], t = 0; + var input = event.target.querySelectorAll('input[type=text]'); + var tpl = event.target.getAttribute('data-debugbar-route-tpl'); + + for (var n = 0; n < input.length; n++) + { + if (input[n].value.length > 0) + { + inputArray.push(input[n].value); + } + } + + if (inputArray.length > 0) + { + _location = location.origin + '/' + tpl.replace(/\?/g, function () { + return inputArray[t++] + }); + + var redirectWindow = window.open(_location, '_blank'); + redirectWindow.location; + } + }) + } + } }; diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php index 077fc9f070ba..0e73076f0e02 100644 --- a/system/Debug/Toolbar/Views/toolbar.tpl.php +++ b/system/Debug/Toolbar/Views/toolbar.tpl.php @@ -19,250 +19,250 @@ */ ?>
    -
    - - 🔅 - - - - ms   MB - - +
    + + 🔅 + + + + ms   MB + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - Vars - - + + + + Vars + + -

    - - - - - - -

    +

    + + + + + + +

    - - - - -
    + + + + +
    - -
    - - - - - - - - - - - - - renderTimeline($collectors, $startTime, $segmentCount, $segmentDuration, $styles) ?> - -
    NAMECOMPONENTDURATION ms
    -
    + +
    + + + + + + + + + + + + + renderTimeline($collectors, $startTime, $segmentCount, $segmentDuration, $styles) ?> + +
    NAMECOMPONENTDURATION ms
    +
    - - - - -
    -

    + + + + +
    +

    - setData($c['display'])->render("_{$c['titleSafe']}.tpl") ?> -
    - - - + setData($c['display'])->render("_{$c['titleSafe']}.tpl") ?> +
    + + + - -
    + +
    - - - $items) : ?> + + + $items) : ?> - -

    -
    + +

    +
    - + - - - $value) : ?> - - - - - - -
    + + + $value) : ?> + + + + + + +
    - -

    No data to display.

    - - - + +

    No data to display.

    + + + - - -

    Session User Data

    -
    + + +

    Session User Data

    +
    - - - - - $value) : ?> - - - - - - -
    - -

    No data to display.

    - - -

    Session doesn't seem to be active.

    - + + + + + $value) : ?> + + + + + + +
    + +

    No data to display.

    + + +

    Session doesn't seem to be active.

    + -

    Request ( )

    +

    Request ( )

    - - -

    $_GET

    -
    + + +

    $_GET

    +
    - - - $value) : ?> - - - - - - -
    - + + + $value) : ?> + + + + + + +
    + - - -

    $_POST

    -
    + + +

    $_POST

    +
    - - - $value) : ?> - - - - - - -
    - + + + $value) : ?> + + + + + + +
    + - - -

    Headers

    -
    + + +

    Headers

    +
    - - - $value) : ?> - - - - - - -
    - + + + $value) : ?> + + + + + + +
    + - - -

    Cookies

    -
    + + +

    Cookies

    +
    - - - $value) : ?> - - - - - - - - + + + $value) : ?> + + + + + + + + -

    Response - ( ) -

    +

    Response + ( ) +

    - - -

    Headers

    -
    + + +

    Headers

    +
    - - - $value) : ?> - - - - - - -
    - -
    + + + $value) : ?> + + + + + + +
    + +
    - -
    -

    System Configuration

    + +
    +

    System Configuration

    - setData($config)->render('_config.tpl') ?> -
    + setData($config)->render('_config.tpl') ?> +