From 31f4f5e10d9001c025bebce3dd2c733faf2aed38 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Thu, 9 Jun 2022 10:38:42 +0100 Subject: [PATCH 001/970] Add useSupportedLocalesOnly property with accessors --- system/Router/RouteCollection.php | 23 ++++++++++++++++++++++ system/Router/RouteCollectionInterface.php | 5 +++++ system/Router/Router.php | 5 +++++ 3 files changed, 33 insertions(+) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 4998a16c9ba6..8ab2aeeabb1e 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -223,6 +223,11 @@ class RouteCollection implements RouteCollectionInterface */ private ?string $httpHost = null; + /** + * Flag to limit or not the routes with {locale} placeholder to App::$supportedLocales + */ + protected bool $useSupportedLocalesOnly = false; + /** * Constructor */ @@ -1466,4 +1471,22 @@ public function getRegisteredControllers(?string $verb = '*'): array return array_unique($controllers); } + + /** + * Set The flag that limit or not the routes with {locale} placeholder to App::$supportedLocales + */ + public function useSupportedLocalesOnly(bool $useOnly): self + { + $this->useSupportedLocalesOnly = $useOnly; + + return $this; + } + + /** + * Get the flag that limit or not the routes with {locale} placeholder to App::$supportedLocales + */ + public function shouldUseSupportedLocalesOnly(): bool + { + return $this->useSupportedLocalesOnly; + } } diff --git a/system/Router/RouteCollectionInterface.php b/system/Router/RouteCollectionInterface.php index e5e4350a5db6..d7df5195bf17 100644 --- a/system/Router/RouteCollectionInterface.php +++ b/system/Router/RouteCollectionInterface.php @@ -184,4 +184,9 @@ public function isRedirect(string $from): bool; * Grabs the HTTP status code from a redirecting Route. */ public function getRedirectCode(string $from): int; + + /** + * Get the flag that limit or not the routes with {locale} placeholder to App::$supportedLocales + */ + public function shouldUseSupportedLocalesOnly(): bool; } diff --git a/system/Router/Router.php b/system/Router/Router.php index 43b899fb56be..bbffe67f4fcb 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -439,6 +439,11 @@ protected function checkRoutes(string $uri): bool $matched ); + if ($this->collection->shouldUseSupportedLocalesOnly() + && ! in_array($matched['locale'], config('App')->supportedLocales, true)) { + return false; + } + $this->detectedLocale = $matched['locale']; unset($matched); } From d3ac5d42c09c8f0ce9472b7943b482e6fa099804 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Thu, 9 Jun 2022 10:39:59 +0100 Subject: [PATCH 002/970] Add tests --- tests/system/Router/RouteCollectionTest.php | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/system/Router/RouteCollectionTest.php b/tests/system/Router/RouteCollectionTest.php index f367a203473e..5dcb8e89c4d1 100644 --- a/tests/system/Router/RouteCollectionTest.php +++ b/tests/system/Router/RouteCollectionTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Router; use CodeIgniter\Config\Services; +use CodeIgniter\Exceptions\PageNotFoundException; use CodeIgniter\Test\CIUnitTestCase; use Config\Modules; use Tests\Support\Controllers\Hello; @@ -1678,4 +1679,18 @@ public function testGetRegisteredControllersDoesNotReturnClosures() $expects = []; $this->assertSame($expects, $routes); } + + public function testUseSupportedLocalesOnly() + { + config('App')->supportedLocales = ['en']; + + $routes = $this->getCollector(); + $routes->useSupportedLocalesOnly(true); + $routes->get('{locale}/products', 'Products::list'); + + $router = new Router($routes, Services::request()); + + $this->expectException(PageNotFoundException::class); + $router->handle('fr/products'); + } } From 8c91c44692ccdc5eb0990ad85e82d8d1848df723 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Thu, 9 Jun 2022 10:41:18 +0100 Subject: [PATCH 003/970] Add docs --- user_guide_src/source/outgoing/localization.rst | 8 ++++++-- user_guide_src/source/outgoing/localization/018.php | 3 +++ 2 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 user_guide_src/source/outgoing/localization/018.php diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 0a5845580459..c8c87a6c556b 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -81,8 +81,12 @@ segment will be your locale: 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. -.. note:: If the value doesn't match a valid locale as defined in the App configuration file, the default - locale will be used in it's place. +If the value doesn't match a valid locale as defined in the App configuration file, the default +locale will be used in it's place, unless you set to use only the supported locales defined in the App configuration +file: + +.. literalinclude:: localization/018.php + Retrieving the Current Locale ============================= diff --git a/user_guide_src/source/outgoing/localization/018.php b/user_guide_src/source/outgoing/localization/018.php new file mode 100644 index 000000000000..107d2a157881 --- /dev/null +++ b/user_guide_src/source/outgoing/localization/018.php @@ -0,0 +1,3 @@ +useSupportedLocalesOnly(true); From 6f4c2e9077d49b7f3484f01589dc89771ff226e2 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Sat, 11 Jun 2022 17:26:47 +0100 Subject: [PATCH 004/970] Add Exception PageNotFoundException::forLocaleNotSupported --- system/Exceptions/PageNotFoundException.php | 5 +++++ system/Language/en/HTTP.php | 1 + system/Router/Router.php | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/system/Exceptions/PageNotFoundException.php b/system/Exceptions/PageNotFoundException.php index 2a773f1785dc..daa98a5ddf02 100644 --- a/system/Exceptions/PageNotFoundException.php +++ b/system/Exceptions/PageNotFoundException.php @@ -45,6 +45,11 @@ public static function forMethodNotFound(string $method) return new static(self::lang('HTTP.methodNotFound', [$method])); } + public static function forLocaleNotSupported(string $locale) + { + return new static(self::lang('HTTP.localeNotSupported', [$locale])); + } + /** * Get translated system message * diff --git a/system/Language/en/HTTP.php b/system/Language/en/HTTP.php index 8902b8ea4d89..49899f5d76c9 100644 --- a/system/Language/en/HTTP.php +++ b/system/Language/en/HTTP.php @@ -52,6 +52,7 @@ 'emptyController' => 'No Controller specified.', 'controllerNotFound' => 'Controller or its method is not found: {0}::{1}', 'methodNotFound' => 'Controller method is not found: {0}', + 'localeNotSupported' => 'Locale is not supported: {0}', // CSRF // @deprecated use `Security.disallowedAction` diff --git a/system/Router/Router.php b/system/Router/Router.php index bbffe67f4fcb..c653608d08c3 100644 --- a/system/Router/Router.php +++ b/system/Router/Router.php @@ -441,7 +441,10 @@ protected function checkRoutes(string $uri): bool if ($this->collection->shouldUseSupportedLocalesOnly() && ! in_array($matched['locale'], config('App')->supportedLocales, true)) { - return false; + + // Throw exception to prevent the autorouter, if enabled, + // from trying to find a route + throw PageNotFoundException::forLocaleNotSupported($matched['locale']); } $this->detectedLocale = $matched['locale']; From 37559cd86db92c3637c762aac42c5bb75b39208f Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Sun, 12 Jun 2022 06:46:24 +0100 Subject: [PATCH 005/970] Update user_guide_src/source/outgoing/localization.rst Co-authored-by: kenjis --- user_guide_src/source/outgoing/localization.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index c8c87a6c556b..7a4385da0485 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -81,7 +81,7 @@ segment will be your locale: 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. -If the value doesn't match a valid locale as defined in the App configuration file, the default +If the value doesn't match a valid locale as defined in ``$supportedLocales`` in **app/Config/App.php**, the default locale will be used in it's place, unless you set to use only the supported locales defined in the App configuration file: From 7b124a141f046cff528c867f10abfbd2073c2cc2 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 11 Jun 2022 19:50:49 +0800 Subject: [PATCH 006/970] Adding StreamFilterTrait --- system/Test/Filters/CITestStreamFilter.php | 13 ++- system/Test/StreamFilterTrait.php | 97 +++++++++++++++++++ tests/system/CLI/CLITest.php | 47 ++++----- tests/system/CLI/CommandRunnerTest.php | 42 ++++---- tests/system/CLI/ConsoleTest.php | 26 ++--- tests/system/Commands/ClearCacheTest.php | 16 +-- tests/system/Commands/ClearDebugbarTest.php | 18 ++-- tests/system/Commands/ClearLogsTest.php | 15 +-- .../system/Commands/CommandGeneratorTest.php | 23 +++-- tests/system/Commands/CommandTest.php | 16 +-- tests/system/Commands/ConfigGeneratorTest.php | 15 ++- .../Commands/ConfigurableSortImportsTest.php | 19 ++-- .../Commands/ControllerGeneratorTest.php | 25 +++-- tests/system/Commands/CreateDatabaseTest.php | 21 ++-- .../Commands/Database/MigrateStatusTest.php | 22 ++--- .../Commands/Database/ShowTableInfoTest.php | 15 ++- .../system/Commands/DatabaseCommandsTest.php | 17 ++-- tests/system/Commands/EntityGeneratorTest.php | 15 ++- .../Commands/EnvironmentCommandTest.php | 34 ++++--- tests/system/Commands/FilterGeneratorTest.php | 15 ++- tests/system/Commands/GenerateKeyTest.php | 15 +-- tests/system/Commands/GeneratorsTest.php | 31 +++--- tests/system/Commands/HelpCommandTest.php | 14 +-- tests/system/Commands/InfoCacheTest.php | 14 +-- .../Commands/MigrationGeneratorTest.php | 23 +++-- .../Commands/MigrationIntegrationTest.php | 20 ++-- tests/system/Commands/ModelGeneratorTest.php | 27 +++--- tests/system/Commands/PublishCommandTest.php | 16 +-- tests/system/Commands/RoutesTest.php | 15 ++- .../system/Commands/ScaffoldGeneratorTest.php | 49 +++++----- tests/system/Commands/SeederGeneratorTest.php | 19 ++-- .../Commands/ValidationGeneratorTest.php | 15 ++- .../Debug/Toolbar/Collectors/HistoryTest.php | 13 +-- tests/system/Test/TestCaseTest.php | 11 ++- 34 files changed, 443 insertions(+), 350 deletions(-) create mode 100644 system/Test/StreamFilterTrait.php diff --git a/system/Test/Filters/CITestStreamFilter.php b/system/Test/Filters/CITestStreamFilter.php index 46e895ab19b8..8873adc0598e 100644 --- a/system/Test/Filters/CITestStreamFilter.php +++ b/system/Test/Filters/CITestStreamFilter.php @@ -26,6 +26,8 @@ class CITestStreamFilter extends php_user_filter */ public static $buffer = ''; + protected static bool $registered = false; + /** * This method is called whenever data is read from or written to the * attached stream (such as with fread() or fwrite()). @@ -45,6 +47,13 @@ public function filter($in, $out, &$consumed, $closing): int return PSFS_PASS_ON; } -} -stream_filter_register('CITestStreamFilter', CITestStreamFilter::class); // @codeCoverageIgnore + public static function init(): void + { + if (! static::$registered) { + static::$registered = stream_filter_register('CITestStreamFilter', self::class); // @codeCoverageIgnore + } + + static::$buffer = ''; + } +} diff --git a/system/Test/StreamFilterTrait.php b/system/Test/StreamFilterTrait.php new file mode 100644 index 000000000000..26f79d466975 --- /dev/null +++ b/system/Test/StreamFilterTrait.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Test; + +use CodeIgniter\Test\Filters\CITestStreamFilter; + +trait StreamFilterTrait +{ + /** + * @var resource|null + */ + protected $streamFilterOutResource; + + /** + * @var resource|null + */ + protected $streamFilterErrResource; + + /** + * @return $this + */ + protected function appendStreamOutputFilter() + { + $this->removeStreamOutputFilter(); + + $this->streamFilterOutResource = stream_filter_append(STDOUT, 'CITestStreamFilter'); + + return $this; + } + + /** + * @return $this + */ + protected function appendStreamErrorFilter() + { + $this->removeStreamErrorFilter(); + + $this->streamFilterErrResource = stream_filter_append(STDERR, 'CITestStreamFilter'); + + return $this; + } + + /** + * @return $this + */ + protected function removeStreamOutputFilter() + { + if (is_resource($this->streamFilterOutResource)) { + stream_filter_remove($this->streamFilterOutResource); + $this->streamFilterOutResource = null; + } + + return $this; + } + + /** + * @return $this + */ + protected function removeStreamErrorFilter() + { + if (is_resource($this->streamFilterErrResource)) { + stream_filter_remove($this->streamFilterErrResource); + $this->streamFilterErrResource = null; + } + + return $this; + } + + /** + * @return $this + */ + protected function registerStreamFilterClass() + { + CITestStreamFilter::init(); + + return $this; + } + + protected function getStreamFilterBuffer(): string + { + return CITestStreamFilter::$buffer; + } + + protected function resetStreamFilterBuffer(): void + { + CITestStreamFilter::$buffer = ''; + } +} diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index a8452cdfa7a6..e4aed4b6b87c 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\CLI; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use ReflectionProperty; use RuntimeException; @@ -21,19 +21,20 @@ */ final class CLITest extends CIUnitTestCase { - private $stream_filter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->stream_filter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testNew() @@ -172,7 +173,7 @@ public function testPrint() CLI::print('test'); $expected = 'test'; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testPrintForeground() @@ -180,7 +181,7 @@ public function testPrintForeground() CLI::print('test', 'red'); $expected = "\033[0;31mtest\033[0m"; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testPrintBackground() @@ -188,7 +189,7 @@ public function testPrintBackground() CLI::print('test', 'red', 'green'); $expected = "\033[0;31m\033[42mtest\033[0m"; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testWrite() @@ -196,7 +197,7 @@ public function testWrite() CLI::write('test'); $expected = PHP_EOL . 'test' . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testWriteForeground() @@ -204,7 +205,7 @@ public function testWriteForeground() CLI::write('test', 'red'); $expected = "\033[0;31mtest\033[0m" . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testWriteForegroundWithColorBefore() @@ -212,7 +213,7 @@ public function testWriteForegroundWithColorBefore() CLI::write(CLI::color('green', 'green') . ' red', 'red'); $expected = "\033[0;32mgreen\033[0m\033[0;31m red\033[0m" . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testWriteForegroundWithColorAfter() @@ -220,7 +221,7 @@ public function testWriteForegroundWithColorAfter() CLI::write('red ' . CLI::color('green', 'green'), 'red'); $expected = "\033[0;31mred \033[0m\033[0;32mgreen\033[0m" . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } /** @@ -234,7 +235,7 @@ public function testWriteForegroundWithColorTwice() ); $expected = "\033[0;32mgreen\033[0m\033[0;31m red \033[0m\033[0;32mgreen\033[0m" . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testWriteBackground() @@ -242,38 +243,32 @@ public function testWriteBackground() CLI::write('test', 'red', 'green'); $expected = "\033[0;31m\033[42mtest\033[0m" . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } 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); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } 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); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } 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); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testShowProgress() @@ -299,7 +294,7 @@ public function testShowProgress() "\033[1A[\033[32m##########\033[0m] 100% Complete" . PHP_EOL . 'third.' . PHP_EOL . "[\033[32m#.........\033[0m] 5% Complete" . PHP_EOL; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testShowProgressWithoutBar() @@ -310,7 +305,7 @@ public function testShowProgressWithoutBar() CLI::showProgress(false, 20); $expected = 'first.' . PHP_EOL . "\007\007\007"; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } public function testWrap() @@ -450,7 +445,7 @@ public function testTable($tbody, $thead, $expected) { CLI::table($tbody, $thead); - $this->assertSame(CITestStreamFilter::$buffer, $expected); + $this->assertSame($this->getStreamFilterBuffer(), $expected); } public function tableProvider() diff --git a/tests/system/CLI/CommandRunnerTest.php b/tests/system/CLI/CommandRunnerTest.php index 892b7b5ff516..432e907b111c 100644 --- a/tests/system/CLI/CommandRunnerTest.php +++ b/tests/system/CLI/CommandRunnerTest.php @@ -13,7 +13,7 @@ use CodeIgniter\Log\Logger; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Services; /** @@ -21,10 +21,7 @@ */ final class CommandRunnerTest extends CIUnitTestCase { - /** - * @var resource - */ - private $streamFilter; + use StreamFilterTrait; private static Logger $logger; private static CommandRunner $runner; @@ -41,56 +38,51 @@ protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testGoodCommand() { self::$runner->index(['list']); - $result = CITestStreamFilter::$buffer; // make sure the result looks like a command list - $this->assertStringContainsString('Lists the available commands.', $result); - $this->assertStringContainsString('Displays basic usage information.', $result); + $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); } public function testDefaultCommand() { self::$runner->index([]); - $result = CITestStreamFilter::$buffer; // make sure the result looks like basic help - $this->assertStringContainsString('Lists the available commands.', $result); - $this->assertStringContainsString('Displays basic usage information.', $result); + $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); } public function testHelpCommand() { self::$runner->index(['help']); - $result = CITestStreamFilter::$buffer; // make sure the result looks like basic help - $this->assertStringContainsString('Displays basic usage information.', $result); - $this->assertStringContainsString('help command_name', $result); + $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('help command_name', $this->getStreamFilterBuffer()); } public function testHelpCommandDetails() { self::$runner->index(['help', 'session:migration']); - $result = CITestStreamFilter::$buffer; // make sure the result looks like more detailed help - $this->assertStringContainsString('Description:', $result); - $this->assertStringContainsString('Usage:', $result); - $this->assertStringContainsString('Options:', $result); + $this->assertStringContainsString('Description:', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Usage:', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Options:', $this->getStreamFilterBuffer()); } public function testCommandProperties() @@ -107,7 +99,7 @@ public function testEmptyCommand() self::$runner->index([null, 'list']); // make sure the result looks like a command list - $this->assertStringContainsString('Lists the available commands.', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); } public function testBadCommand() @@ -115,6 +107,6 @@ public function testBadCommand() self::$runner->index(['bogus']); // make sure the result looks like a command list - $this->assertStringContainsString('Command "bogus" not found', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Command "bogus" not found', $this->getStreamFilterBuffer()); } } diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index 61905e71c613..ac4cb5223176 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -15,23 +15,22 @@ use CodeIgniter\Config\DotEnv; use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; use CodeIgniter\Test\Mock\MockCLIConfig; use CodeIgniter\Test\Mock\MockCodeIgniter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ConsoleTest extends CIUnitTestCase { - private $stream_filter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->registerStreamFilterClass()->appendStreamOutputFilter(); $this->env = new DotEnv(ROOTPATH); $this->env->load(); @@ -54,7 +53,7 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->stream_filter); + $this->removeStreamOutputFilter(); } public function testNew() @@ -67,16 +66,20 @@ public function testHeader() { $console = new Console($this->app); $console->showHeader(); - $result = CITestStreamFilter::$buffer; - $this->assertGreaterThan(0, strpos($result, sprintf('CodeIgniter v%s Command Line Tool', CodeIgniter::CI_VERSION))); + $this->assertGreaterThan( + 0, + strpos( + $this->getStreamFilterBuffer(), + sprintf('CodeIgniter v%s Command Line Tool', CodeIgniter::CI_VERSION) + ) + ); } public function testNoHeader() { $console = new Console($this->app); $console->showHeader(true); - $result = CITestStreamFilter::$buffer; - $this->assertSame('', $result); + $this->assertSame('', $this->getStreamFilterBuffer()); } public function testRun() @@ -86,13 +89,12 @@ public function testRun() $console = new Console($this->app); $console->run(true); - $result = CITestStreamFilter::$buffer; // close open buffer ob_end_clean(); // make sure the result looks like a command list - $this->assertStringContainsString('Lists the available commands.', $result); - $this->assertStringContainsString('Displays basic usage information.', $result); + $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); } } diff --git a/tests/system/Commands/ClearCacheTest.php b/tests/system/Commands/ClearCacheTest.php index 9f988a9d864e..2ddcef152cb8 100644 --- a/tests/system/Commands/ClearCacheTest.php +++ b/tests/system/Commands/ClearCacheTest.php @@ -13,7 +13,7 @@ use CodeIgniter\Cache\CacheFactory; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Services; /** @@ -21,15 +21,15 @@ */ final class ClearCacheTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); // Make sure we are testing with the correct handler (override injections) Services::injectMock('cache', CacheFactory::getHandler(config('Cache'))); @@ -37,14 +37,14 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testClearCacheInvalidHandler() { command('cache:clear junk'); - $this->assertStringContainsString('junk is not a valid cache handler.', CITestStreamFilter::$buffer); + $this->assertStringContainsString('junk is not a valid cache handler.', $this->getStreamFilterBuffer()); } public function testClearCacheWorks() @@ -55,6 +55,6 @@ public function testClearCacheWorks() command('cache:clear'); $this->assertNull(cache('foo')); - $this->assertStringContainsString('Cache cleared.', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Cache cleared.', $this->getStreamFilterBuffer()); } } diff --git a/tests/system/Commands/ClearDebugbarTest.php b/tests/system/Commands/ClearDebugbarTest.php index 2a5490a68390..54120eb0fac4 100644 --- a/tests/system/Commands/ClearDebugbarTest.php +++ b/tests/system/Commands/ClearDebugbarTest.php @@ -12,29 +12,31 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ClearDebugbarTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private $time; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - $this->time = time(); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); + + $this->time = time(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } protected function createDummyDebugbarJson() @@ -61,7 +63,7 @@ public function testClearDebugbarWorks() $this->assertFileExists(WRITEPATH . 'debugbar' . DIRECTORY_SEPARATOR . "debugbar_{$this->time}.json"); command('debugbar:clear'); - $result = CITestStreamFilter::$buffer; + $result = $this->getStreamFilterBuffer(); $this->assertFileDoesNotExist(WRITEPATH . 'debugbar' . DIRECTORY_SEPARATOR . "debugbar_{$this->time}.json"); $this->assertFileExists(WRITEPATH . 'debugbar' . DIRECTORY_SEPARATOR . '.gitkeep'); diff --git a/tests/system/Commands/ClearLogsTest.php b/tests/system/Commands/ClearLogsTest.php index 4fb1badba8cf..2135f9bd50d2 100644 --- a/tests/system/Commands/ClearLogsTest.php +++ b/tests/system/Commands/ClearLogsTest.php @@ -12,23 +12,24 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ClearLogsTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private $date; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); // test runs on other tests may log errors since default threshold // is now 4, so set this to a safe distance @@ -37,7 +38,7 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } protected function createDummyLogFiles() @@ -65,7 +66,7 @@ public function testClearLogsWorks() $this->assertFileExists(WRITEPATH . 'logs' . DIRECTORY_SEPARATOR . "log-{$this->date}.log"); command('logs:clear -force'); - $result = CITestStreamFilter::$buffer; + $result = $this->getStreamFilterBuffer(); $this->assertFileDoesNotExist(WRITEPATH . 'logs' . DIRECTORY_SEPARATOR . "log-{$this->date}.log"); $this->assertFileExists(WRITEPATH . 'logs' . DIRECTORY_SEPARATOR . 'index.html'); diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php index 211bc373abf9..3f27e662e6b3 100644 --- a/tests/system/Commands/CommandGeneratorTest.php +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class CommandGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); $dir = dirname($file); @@ -98,7 +97,7 @@ public function testGenerateCommandWithOptionGroup() { command('make:command deliver -group Deliverables'); $file = APPPATH . 'Commands/Deliver.php'; - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists($file); $contents = $this->getFileContents($file); @@ -108,7 +107,7 @@ public function testGenerateCommandWithOptionGroup() public function testGenerateCommandWithOptionSuffix() { command('make:command publish -suffix'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Commands/PublishCommand.php'; $this->assertFileExists($file); } @@ -119,7 +118,7 @@ public function testGenerateCommandWithOptionSuffix() public function testGeneratorPreservesCase(): void { command('make:model TestModule'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Models/TestModule.php'); } @@ -129,7 +128,7 @@ public function testGeneratorPreservesCase(): void public function testGeneratorPreservesCaseButChangesComponentName(): void { command('make:controller TestModulecontroller'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/TestModuleController.php'); } diff --git a/tests/system/Commands/CommandTest.php b/tests/system/Commands/CommandTest.php index 9dbe62c3427c..d61ced18d222 100644 --- a/tests/system/Commands/CommandTest.php +++ b/tests/system/Commands/CommandTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Services; use Tests\Support\Commands\ParamsReveal; @@ -21,7 +21,8 @@ */ final class CommandTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private $logger; private $commands; @@ -31,10 +32,9 @@ protected function setUp(): void parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); $this->logger = Services::logger(); $this->commands = Services::commands(); @@ -42,12 +42,12 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } protected function getBuffer() { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } public function testListCommands() diff --git a/tests/system/Commands/ConfigGeneratorTest.php b/tests/system/Commands/ConfigGeneratorTest.php index 30e4130c014e..a1765eaa97c7 100644 --- a/tests/system/Commands/ConfigGeneratorTest.php +++ b/tests/system/Commands/ConfigGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ConfigGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { unlink($file); diff --git a/tests/system/Commands/ConfigurableSortImportsTest.php b/tests/system/Commands/ConfigurableSortImportsTest.php index f5f8dd947e4b..209002fdfe2d 100644 --- a/tests/system/Commands/ConfigurableSortImportsTest.php +++ b/tests/system/Commands/ConfigurableSortImportsTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ConfigurableSortImportsTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testPublishLanguageWithoutOptions() @@ -41,7 +40,7 @@ public function testPublishLanguageWithoutOptions() command('publish:language'); $file = APPPATH . 'Language/en/Foobar.php'; - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists($file); $this->assertNotSame(sha1_file(SUPPORTPATH . 'Commands/Foobar.php'), sha1_file($file)); if (is_file($file)) { @@ -54,7 +53,7 @@ public function testEnabledSortImportsWillDisruptLanguageFilePublish() command('publish:language --lang es'); $file = APPPATH . 'Language/es/Foobar.php'; - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists($file); $this->assertNotSame(sha1_file(SUPPORTPATH . 'Commands/Foobar.php'), sha1_file($file)); if (is_file($file)) { @@ -71,7 +70,7 @@ public function testDisabledSortImportsWillNotAffectLanguageFilesPublish() command('publish:language --lang ar --sort off'); $file = APPPATH . 'Language/ar/Foobar.php'; - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists($file); $this->assertSame(sha1_file(SUPPORTPATH . 'Commands/Foobar.php'), sha1_file($file)); if (is_file($file)) { diff --git a/tests/system/Commands/ControllerGeneratorTest.php b/tests/system/Commands/ControllerGeneratorTest.php index 6065e687560d..a249a8a97a7c 100644 --- a/tests/system/Commands/ControllerGeneratorTest.php +++ b/tests/system/Commands/ControllerGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ControllerGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { unlink($file); @@ -52,7 +51,7 @@ protected function getFileContents(string $filepath): string public function testGenerateController() { command('make:controller user'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Controllers/User.php'; $this->assertFileExists($file); $this->assertStringContainsString('extends BaseController', $this->getFileContents($file)); @@ -61,7 +60,7 @@ public function testGenerateController() public function testGenerateControllerWithOptionBare() { command('make:controller blog -bare'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Controllers/Blog.php'; $this->assertFileExists($file); $this->assertStringContainsString('extends Controller', $this->getFileContents($file)); @@ -70,7 +69,7 @@ public function testGenerateControllerWithOptionBare() public function testGenerateControllerWithOptionRestful() { command('make:controller order -restful'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Controllers/Order.php'; $this->assertFileExists($file); $this->assertStringContainsString('extends ResourceController', $this->getFileContents($file)); @@ -79,7 +78,7 @@ public function testGenerateControllerWithOptionRestful() public function testGenerateControllerWithOptionRestfulPresenter() { command('make:controller pay -restful presenter'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Controllers/Pay.php'; $this->assertFileExists($file); $this->assertStringContainsString('extends ResourcePresenter', $this->getFileContents($file)); @@ -88,7 +87,7 @@ public function testGenerateControllerWithOptionRestfulPresenter() public function testGenerateControllerWithOptionSuffix() { command('make:controller dashboard -suffix'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/DashboardController.php'); } } diff --git a/tests/system/Commands/CreateDatabaseTest.php b/tests/system/Commands/CreateDatabaseTest.php index 1d0270f367b9..af0af597f974 100644 --- a/tests/system/Commands/CreateDatabaseTest.php +++ b/tests/system/Commands/CreateDatabaseTest.php @@ -16,7 +16,7 @@ use CodeIgniter\Database\OCI8\Connection as OCI8Connection; use CodeIgniter\Database\SQLite3\Connection as SQLite3Connection; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Database; /** @@ -24,16 +24,17 @@ */ final class CreateDatabaseTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private BaseConnection $connection; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); - $this->connection = Database::connect(); + $this->connection = Database::connect(); parent::setUp(); @@ -53,14 +54,14 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); parent::tearDown(); } protected function getBuffer() { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } public function testCreateDatabase() @@ -80,7 +81,7 @@ public function testSqliteDatabaseDuplicated() } command('db:create foobar'); - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); command('db:create foobar --ext db'); $this->assertStringContainsString('already exists.', $this->getBuffer()); @@ -93,7 +94,7 @@ public function testOtherDriverDuplicatedDatabase() } command('db:create foobar'); - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); command('db:create foobar'); $this->assertStringContainsString('Unable to create the specified database.', $this->getBuffer()); diff --git a/tests/system/Commands/Database/MigrateStatusTest.php b/tests/system/Commands/Database/MigrateStatusTest.php index 8f6997d01127..b211e7f34143 100644 --- a/tests/system/Commands/Database/MigrateStatusTest.php +++ b/tests/system/Commands/Database/MigrateStatusTest.php @@ -12,14 +12,15 @@ namespace CodeIgniter\Commands\Database; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class MigrateStatusTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private string $migrationFileFrom = SUPPORTPATH . 'MigrationTestMigrations/Database/Migrations/2018-01-24-102301_Some_migration.php'; private string $migrationFileTo = APPPATH . 'Database/Migrations/2018-01-24-102301_Some_migration.php'; @@ -45,10 +46,9 @@ protected function setUp(): void ); file_put_contents($this->migrationFileTo, $contents); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void @@ -62,17 +62,17 @@ protected function tearDown(): void @unlink($this->migrationFileTo); } - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testMigrateAllWithWithTwoNamespaces(): void { command('migrate --all'); - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); command('migrate:status'); - $result = str_replace(["\033[0;33m", "\033[0m"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;33m", "\033[0m"], '', $this->getStreamFilterBuffer()); $result = preg_replace('/\d{4}-\d\d-\d\d \d\d:\d\d:\d\d/', 'YYYY-MM-DD HH:MM:SS', $result); $expected = <<<'EOL' +---------------+-------------------+--------------------+-------+---------------------+-------+ @@ -91,11 +91,11 @@ public function testMigrateWithWithTwoNamespaces(): void { command('migrate -n App'); command('migrate -n Tests\\\\Support'); - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); command('migrate:status'); - $result = str_replace(["\033[0;33m", "\033[0m"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;33m", "\033[0m"], '', $this->getStreamFilterBuffer()); $result = preg_replace('/\d{4}-\d\d-\d\d \d\d:\d\d:\d\d/', 'YYYY-MM-DD HH:MM:SS', $result); $expected = <<<'EOL' +---------------+-------------------+--------------------+-------+---------------------+-------+ diff --git a/tests/system/Commands/Database/ShowTableInfoTest.php b/tests/system/Commands/Database/ShowTableInfoTest.php index 2824588695c7..9fde90ef1ca2 100644 --- a/tests/system/Commands/Database/ShowTableInfoTest.php +++ b/tests/system/Commands/Database/ShowTableInfoTest.php @@ -13,7 +13,7 @@ use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Database; use Tests\Support\Database\Seeds\CITestSeeder; @@ -23,25 +23,24 @@ final class ShowTableInfoTest extends CIUnitTestCase { use DatabaseTestTrait; + use StreamFilterTrait; - private $streamFilter; protected $migrateOnce = true; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { parent::tearDown(); - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } private function getResultWithoutControlCode(): string @@ -49,7 +48,7 @@ private function getResultWithoutControlCode(): string return str_replace( ["\033[0;30m", "\033[0;33m", "\033[43m", "\033[0m"], '', - CITestStreamFilter::$buffer + $this->getStreamFilterBuffer() ); } diff --git a/tests/system/Commands/DatabaseCommandsTest.php b/tests/system/Commands/DatabaseCommandsTest.php index b80fcd5f0bb8..bd0fbe2c47f4 100644 --- a/tests/system/Commands/DatabaseCommandsTest.php +++ b/tests/system/Commands/DatabaseCommandsTest.php @@ -12,21 +12,20 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class DatabaseCommandsTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); parent::setUp(); } @@ -34,19 +33,19 @@ protected function setUp(): void protected function tearDown(): void { command('migrate:rollback'); - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); parent::tearDown(); } protected function getBuffer(): string { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } protected function clearBuffer(): void { - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); } public function testMigrate() diff --git a/tests/system/Commands/EntityGeneratorTest.php b/tests/system/Commands/EntityGeneratorTest.php index 724d3145db15..f71f47f905db 100644 --- a/tests/system/Commands/EntityGeneratorTest.php +++ b/tests/system/Commands/EntityGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class EntityGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); $dir = dirname($file); if (is_file($file)) { diff --git a/tests/system/Commands/EnvironmentCommandTest.php b/tests/system/Commands/EnvironmentCommandTest.php index e877c1144ae6..7ffd901e6aac 100644 --- a/tests/system/Commands/EnvironmentCommandTest.php +++ b/tests/system/Commands/EnvironmentCommandTest.php @@ -12,24 +12,24 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class EnvironmentCommandTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private string $envPath = ROOTPATH . '.env'; private string $backupEnvPath = ROOTPATH . '.env.backup'; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); if (is_file($this->envPath)) { rename($this->envPath, $this->backupEnvPath); @@ -39,7 +39,7 @@ protected function setUp(): void protected function tearDown(): void { parent::tearDown(); - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); if (is_file($this->envPath)) { unlink($this->envPath); @@ -55,20 +55,23 @@ protected function tearDown(): void public function testUsingCommandWithNoArgumentsGivesCurrentEnvironment(): void { command('env'); - $this->assertStringContainsString('testing', CITestStreamFilter::$buffer); - $this->assertStringContainsString(ENVIRONMENT, CITestStreamFilter::$buffer); + $this->assertStringContainsString('testing', $this->getStreamFilterBuffer()); + $this->assertStringContainsString(ENVIRONMENT, $this->getStreamFilterBuffer()); } public function testProvidingTestingAsEnvGivesErrorMessage(): void { command('env testing'); - $this->assertStringContainsString('The "testing" environment is reserved for PHPUnit testing.', CITestStreamFilter::$buffer); + $this->assertStringContainsString( + 'The "testing" environment is reserved for PHPUnit testing.', + $this->getStreamFilterBuffer() + ); } public function testProvidingUnknownEnvGivesErrorMessage(): void { command('env foobar'); - $this->assertStringContainsString('Invalid environment type "foobar".', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Invalid environment type "foobar".', $this->getStreamFilterBuffer()); } public function testDefaultShippedEnvIsMissing() @@ -77,8 +80,11 @@ public function testDefaultShippedEnvIsMissing() command('env development'); rename(ROOTPATH . 'lostenv', ROOTPATH . 'env'); - $this->assertStringContainsString('Both default shipped', CITestStreamFilter::$buffer); - $this->assertStringContainsString('It is impossible to write the new environment type.', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Both default shipped', $this->getStreamFilterBuffer()); + $this->assertStringContainsString( + 'It is impossible to write the new environment type.', + $this->getStreamFilterBuffer() + ); } public function testSettingNewEnvIsSuccess(): void @@ -87,7 +93,7 @@ public function testSettingNewEnvIsSuccess(): void $_SERVER['CI_ENVIRONMENT'] = 'production'; command('env development'); - $this->assertStringContainsString('Environment is successfully changed to', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Environment is successfully changed to', $this->getStreamFilterBuffer()); $this->assertStringContainsString('CI_ENVIRONMENT = development', file_get_contents($this->envPath)); } } diff --git a/tests/system/Commands/FilterGeneratorTest.php b/tests/system/Commands/FilterGeneratorTest.php index 40f90fc3b046..ffafcb02cc3d 100644 --- a/tests/system/Commands/FilterGeneratorTest.php +++ b/tests/system/Commands/FilterGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class FilterGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamErrorFilter() + ->appendStreamOutputFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamErrorFilter()->removeStreamOutputFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { unlink($file); diff --git a/tests/system/Commands/GenerateKeyTest.php b/tests/system/Commands/GenerateKeyTest.php index e4f05fddad95..5f390cb1a152 100644 --- a/tests/system/Commands/GenerateKeyTest.php +++ b/tests/system/Commands/GenerateKeyTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal @@ -21,7 +21,8 @@ */ final class GenerateKeyTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private string $envPath; private string $backupEnvPath; @@ -29,9 +30,9 @@ protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); $this->envPath = ROOTPATH . '.env'; $this->backupEnvPath = ROOTPATH . '.env.backup'; @@ -45,7 +46,7 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); if (is_file($this->envPath)) { unlink($this->envPath); @@ -63,7 +64,7 @@ protected function tearDown(): void */ protected function getBuffer(): string { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } protected function resetEnvironment() diff --git a/tests/system/Commands/GeneratorsTest.php b/tests/system/Commands/GeneratorsTest.php index 29df4ee924c5..4f96317fa0e6 100644 --- a/tests/system/Commands/GeneratorsTest.php +++ b/tests/system/Commands/GeneratorsTest.php @@ -12,32 +12,31 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class GeneratorsTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testGenerateFileCreated() { command('make:seeder categories'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Database/Seeds/Categories.php'; if (is_file($file)) { unlink($file); @@ -47,10 +46,10 @@ public function testGenerateFileCreated() public function testGenerateFileExists() { command('make:filter items'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); - CITestStreamFilter::$buffer = ''; + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); + $this->resetStreamFilterBuffer(); command('make:filter items'); - $this->assertStringContainsString('File exists: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File exists: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Filters/Items.php'; if (is_file($file)) { unlink($file); @@ -60,10 +59,10 @@ public function testGenerateFileExists() public function testGenerateFileOverwritten() { command('make:controller products'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); - CITestStreamFilter::$buffer = ''; + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); + $this->resetStreamFilterBuffer(); command('make:controller products -force'); - $this->assertStringContainsString('File overwritten: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File overwritten: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Controllers/Products.php'; if (is_file($file)) { unlink($file); @@ -79,7 +78,7 @@ public function testGenerateFileFailsOnUnwritableDirectory() chmod(APPPATH . 'Filters', 0444); command('make:filter permissions'); - $this->assertStringContainsString('Error while creating file: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Error while creating file: ', $this->getStreamFilterBuffer()); chmod(APPPATH . 'Filters', 0755); } @@ -87,7 +86,7 @@ public function testGenerateFileFailsOnUnwritableDirectory() public function testGenerateFailsOnUndefinedNamespace() { command('make:model cars -namespace CodeIgnite'); - $this->assertStringContainsString('Namespace "CodeIgnite" is not defined.', CITestStreamFilter::$buffer); + $this->assertStringContainsString('Namespace "CodeIgnite" is not defined.', $this->getStreamFilterBuffer()); } public function testGenerateFileInSubfolders() diff --git a/tests/system/Commands/HelpCommandTest.php b/tests/system/Commands/HelpCommandTest.php index 13ce4b14e62c..a80bad665a19 100644 --- a/tests/system/Commands/HelpCommandTest.php +++ b/tests/system/Commands/HelpCommandTest.php @@ -12,32 +12,32 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class HelpCommandTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } protected function getBuffer() { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } public function testHelpCommand() diff --git a/tests/system/Commands/InfoCacheTest.php b/tests/system/Commands/InfoCacheTest.php index 8ea6ddbcb7ef..0704fe564c12 100644 --- a/tests/system/Commands/InfoCacheTest.php +++ b/tests/system/Commands/InfoCacheTest.php @@ -13,7 +13,7 @@ use CodeIgniter\Cache\CacheFactory; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Services; /** @@ -21,15 +21,15 @@ */ final class InfoCacheTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); // Make sure we are testing with the correct handler (override injections) Services::injectMock('cache', CacheFactory::getHandler(config('Cache'))); @@ -37,7 +37,7 @@ protected function setUp(): void protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); // restore default cache handler config('Cache')->handler = 'file'; @@ -45,7 +45,7 @@ protected function tearDown(): void protected function getBuffer() { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } public function testInfoCacheErrorsOnInvalidHandler() diff --git a/tests/system/Commands/MigrationGeneratorTest.php b/tests/system/Commands/MigrationGeneratorTest.php index e1d895779bb1..395b328041b1 100644 --- a/tests/system/Commands/MigrationGeneratorTest.php +++ b/tests/system/Commands/MigrationGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class MigrationGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamErrorFilter() + ->appendStreamOutputFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { unlink($file); @@ -43,24 +42,24 @@ protected function tearDown(): void public function testGenerateMigration() { command('make:migration database'); - $this->assertStringContainsString('_Database.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_Database.php', $this->getStreamFilterBuffer()); } public function testGenerateMigrationWithOptionSession() { command('make:migration -session'); - $this->assertStringContainsString('_CreateCiSessionsTable.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_CreateCiSessionsTable.php', $this->getStreamFilterBuffer()); } public function testGenerateMigrationWithOptionTable() { command('make:migration -session -table logger'); - $this->assertStringContainsString('_CreateLoggerTable.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_CreateLoggerTable.php', $this->getStreamFilterBuffer()); } public function testGenerateMigrationWithOptionSuffix() { command('make:migration database -suffix'); - $this->assertStringContainsString('_DatabaseMigration.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_DatabaseMigration.php', $this->getStreamFilterBuffer()); } } diff --git a/tests/system/Commands/MigrationIntegrationTest.php b/tests/system/Commands/MigrationIntegrationTest.php index c0970b5c317d..e58de9bd3391 100644 --- a/tests/system/Commands/MigrationIntegrationTest.php +++ b/tests/system/Commands/MigrationIntegrationTest.php @@ -12,14 +12,15 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class MigrationIntegrationTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; + private string $migrationFileFrom = SUPPORTPATH . 'Database/Migrations/20160428212500_Create_test_tables.php'; private string $migrationFileTo = APPPATH . 'Database/Migrations/20160428212500_Create_test_tables.php'; @@ -41,10 +42,9 @@ protected function setUp(): void $contents = str_replace('namespace Tests\Support\Database\Migrations;', 'namespace App\Database\Migrations;', $contents); file_put_contents($this->migrationFileTo, $contents); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void @@ -55,7 +55,7 @@ protected function tearDown(): void @unlink($this->migrationFileTo); } - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } public function testMigrationWithRollbackHasSameNameFormat(): void @@ -63,15 +63,15 @@ public function testMigrationWithRollbackHasSameNameFormat(): void command('migrate -n App'); $this->assertStringContainsString( '(App) 20160428212500_App\Database\Migrations\Migration_Create_test_tables', - CITestStreamFilter::$buffer + $this->getStreamFilterBuffer() ); - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); command('migrate:rollback -n App'); $this->assertStringContainsString( '(App) 20160428212500_App\Database\Migrations\Migration_Create_test_tables', - CITestStreamFilter::$buffer + $this->getStreamFilterBuffer() ); } } diff --git a/tests/system/Commands/ModelGeneratorTest.php b/tests/system/Commands/ModelGeneratorTest.php index 2d00460c53ee..2f35b2e7a201 100644 --- a/tests/system/Commands/ModelGeneratorTest.php +++ b/tests/system/Commands/ModelGeneratorTest.php @@ -12,30 +12,29 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ModelGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { parent::tearDown(); - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { @@ -55,7 +54,7 @@ private function getFileContent(string $filepath): string public function testGenerateModel() { command('make:model user --table users'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); $this->assertStringContainsString('extends Model', $this->getFileContent($file)); @@ -67,7 +66,7 @@ public function testGenerateModel() public function testGenerateModelWithOptionTable() { command('make:model cars -table utilisateur'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Models/Cars.php'; $this->assertFileExists($file); $this->assertStringContainsString('protected $table = \'utilisateur\';', $this->getFileContent($file)); @@ -76,7 +75,7 @@ public function testGenerateModelWithOptionTable() public function testGenerateModelWithOptionDBGroup() { command('make:model user -dbgroup testing'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); $this->assertStringContainsString('protected $DBGroup = \'testing\';', $this->getFileContent($file)); @@ -85,7 +84,7 @@ public function testGenerateModelWithOptionDBGroup() public function testGenerateModelWithOptionReturnArray() { command('make:model user --return array'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); $this->assertStringContainsString('protected $returnType = \'array\';', $this->getFileContent($file)); @@ -94,7 +93,7 @@ public function testGenerateModelWithOptionReturnArray() public function testGenerateModelWithOptionReturnObject() { command('make:model user --return object'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); $this->assertStringContainsString('protected $returnType = \'object\';', $this->getFileContent($file)); @@ -103,7 +102,7 @@ public function testGenerateModelWithOptionReturnObject() public function testGenerateModelWithOptionReturnEntity() { command('make:model user --return entity'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $file = APPPATH . 'Models/User.php'; $this->assertFileExists($file); diff --git a/tests/system/Commands/PublishCommandTest.php b/tests/system/Commands/PublishCommandTest.php index ea7b09e73511..03c695b4e8e7 100644 --- a/tests/system/Commands/PublishCommandTest.php +++ b/tests/system/Commands/PublishCommandTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Tests\Support\Publishers\TestPublisher; /** @@ -20,22 +20,22 @@ */ final class PublishCommandTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { parent::tearDown(); - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); TestPublisher::setResult(true); } @@ -47,7 +47,7 @@ public function testDefault() TestPublisher::class, 0, WRITEPATH, - ]), CITestStreamFilter::$buffer); + ]), $this->getStreamFilterBuffer()); } public function testFailure() @@ -59,6 +59,6 @@ public function testFailure() $this->assertStringContainsString(lang('Publisher.publishFailure', [ TestPublisher::class, WRITEPATH, - ]), CITestStreamFilter::$buffer); + ]), $this->getStreamFilterBuffer()); } } diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index 744914770019..bcfab0b4d95f 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Services; /** @@ -20,7 +20,7 @@ */ final class RoutesTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { @@ -28,22 +28,21 @@ protected function setUp(): void parent::setUp(); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); $this->resetServices(); } protected function getBuffer() { - return CITestStreamFilter::$buffer; + return $this->getStreamFilterBuffer(); } public function testRoutesCommand() diff --git a/tests/system/Commands/ScaffoldGeneratorTest.php b/tests/system/Commands/ScaffoldGeneratorTest.php index 0bea3539d7b6..cbc23eaf47ad 100644 --- a/tests/system/Commands/ScaffoldGeneratorTest.php +++ b/tests/system/Commands/ScaffoldGeneratorTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use Config\Autoload; use Config\Modules; use Config\Services; @@ -22,22 +22,21 @@ */ final class ScaffoldGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { $this->resetServices(); Services::autoloader()->initialize(new Autoload(), new Modules()); - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } protected function getFileContents(string $filepath): string @@ -55,14 +54,14 @@ public function testCreateComponentProducesManyFiles() $dir = '\\' . DIRECTORY_SEPARATOR; $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; - preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + preg_match('/' . $migration . '/u', $this->getStreamFilterBuffer(), $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); // Files check - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/People.php'); $this->assertFileExists(APPPATH . 'Models/People.php'); - $this->assertStringContainsString('_People.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_People.php', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/People.php'); // Options check @@ -78,13 +77,13 @@ public function testCreateComponentWithManyOptions() $dir = '\\' . DIRECTORY_SEPARATOR; $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; - preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + preg_match('/' . $migration . '/u', $this->getStreamFilterBuffer(), $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); // Files check - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/User.php'); - $this->assertStringContainsString('_User.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_User.php', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/User.php'); $this->assertFileExists(APPPATH . 'Entities/User.php'); $this->assertFileExists(APPPATH . 'Models/User.php'); @@ -107,13 +106,13 @@ public function testCreateComponentWithOptionSuffix() $dir = '\\' . DIRECTORY_SEPARATOR; $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; - preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + preg_match('/' . $migration . '/u', $this->getStreamFilterBuffer(), $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); // Files check - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/OrderController.php'); - $this->assertStringContainsString('_OrderMigration.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_OrderMigration.php', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/OrderSeeder.php'); $this->assertFileExists(APPPATH . 'Models/OrderModel.php'); @@ -127,28 +126,28 @@ public function testCreateComponentWithOptionSuffix() public function testCreateComponentWithOptionForce() { command('make:controller fixer'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertStringContainsString('extends BaseController', $this->getFileContents(APPPATH . 'Controllers/Fixer.php')); $this->assertFileExists(APPPATH . 'Controllers/Fixer.php'); - CITestStreamFilter::$buffer = ''; + $this->resetStreamFilterBuffer(); command('make:scaffold fixer -bare -force'); $dir = '\\' . DIRECTORY_SEPARATOR; $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; - preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + preg_match('/' . $migration . '/u', $this->getStreamFilterBuffer(), $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); // Files check - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/Fixer.php'); - $this->assertStringContainsString('_Fixer.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_Fixer.php', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/Fixer.php'); $this->assertFileExists(APPPATH . 'Models/Fixer.php'); // Options check $this->assertStringContainsString('extends Controller', $this->getFileContents(APPPATH . 'Controllers/Fixer.php')); - $this->assertStringContainsString('File overwritten: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File overwritten: ', $this->getStreamFilterBuffer()); // Clean up unlink(APPPATH . 'Controllers/Fixer.php'); @@ -163,13 +162,13 @@ public function testCreateComponentWithOptionNamespace() $dir = '\\' . DIRECTORY_SEPARATOR; $migration = "APPPATH{$dir}Database{$dir}Migrations{$dir}(.*)\\.php"; - preg_match('/' . $migration . '/u', CITestStreamFilter::$buffer, $matches); + preg_match('/' . $migration . '/u', $this->getStreamFilterBuffer(), $matches); $matches[0] = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, $matches[0]); // Files check - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Controllers/Product.php'); - $this->assertStringContainsString('_Product.php', CITestStreamFilter::$buffer); + $this->assertStringContainsString('_Product.php', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/Product.php'); $this->assertFileExists(APPPATH . 'Models/Product.php'); diff --git a/tests/system/Commands/SeederGeneratorTest.php b/tests/system/Commands/SeederGeneratorTest.php index 92ad9548b7ab..291db60e32ae 100644 --- a/tests/system/Commands/SeederGeneratorTest.php +++ b/tests/system/Commands/SeederGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class SeederGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { unlink($file); @@ -43,14 +42,14 @@ protected function tearDown(): void public function testGenerateSeeder() { command('make:seeder cars'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/Cars.php'); } public function testGenerateSeederWithOptionSuffix() { command('make:seeder cars -suffix'); - $this->assertStringContainsString('File created: ', CITestStreamFilter::$buffer); + $this->assertStringContainsString('File created: ', $this->getStreamFilterBuffer()); $this->assertFileExists(APPPATH . 'Database/Seeds/CarsSeeder.php'); } } diff --git a/tests/system/Commands/ValidationGeneratorTest.php b/tests/system/Commands/ValidationGeneratorTest.php index 0b2f7de6d500..a8ae5ce17019 100644 --- a/tests/system/Commands/ValidationGeneratorTest.php +++ b/tests/system/Commands/ValidationGeneratorTest.php @@ -12,28 +12,27 @@ namespace CodeIgniter\Commands; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; /** * @internal */ final class ValidationGeneratorTest extends CIUnitTestCase { - private $streamFilter; + use StreamFilterTrait; protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', CITestStreamFilter::$buffer); + $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); $dir = dirname($file); if (is_file($file)) { diff --git a/tests/system/Debug/Toolbar/Collectors/HistoryTest.php b/tests/system/Debug/Toolbar/Collectors/HistoryTest.php index ac1b4907a2f7..531d87fc58f7 100644 --- a/tests/system/Debug/Toolbar/Collectors/HistoryTest.php +++ b/tests/system/Debug/Toolbar/Collectors/HistoryTest.php @@ -12,7 +12,7 @@ namespace CodeIgniter\Debug\Toolbar\Collectors; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; use DateTime; /** @@ -20,18 +20,19 @@ */ final class HistoryTest extends CIUnitTestCase { + use StreamFilterTrait; + private const STEP = 0.000001; private float $time; - private $streamFilter; protected function setUp(): void { parent::setUp(); - CITestStreamFilter::$buffer = ''; - $this->streamFilter = stream_filter_append(STDOUT, 'CITestStreamFilter'); - $this->streamFilter = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); $this->time = (float) sprintf('%.6f', microtime(true)); } @@ -40,7 +41,7 @@ protected function tearDown(): void { command('debugbar:clear'); - stream_filter_remove($this->streamFilter); + $this->removeStreamOutputFilter()->removeStreamErrorFilter(); } private function createDummyDebugbarJson() diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index 5db2832fa12d..aaca2d58540f 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -14,7 +14,7 @@ use CodeIgniter\CLI\CLI; use CodeIgniter\Events\Events; use CodeIgniter\HTTP\Response; -use CodeIgniter\Test\Filters\CITestStreamFilter; + use Config\App; /** @@ -22,6 +22,8 @@ */ final class TestCaseTest extends CIUnitTestCase { + use StreamFilterTrait; + public function testGetPrivatePropertyWithObject() { $obj = new __TestForReflectionHelper(); @@ -48,12 +50,11 @@ public function testEventTriggering() public function testStreamFilter() { - CITestStreamFilter::$buffer = ''; - $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->registerStreamFilterClass()->appendStreamOutputFilter(); CLI::write('first.'); $expected = "first.\n"; - $this->assertSame($expected, CITestStreamFilter::$buffer); - stream_filter_remove($this->stream_filter); + $this->assertSame($expected, $this->getStreamFilterBuffer()); + $this->removeStreamOutputFilter(); } /** From 91bbe1cf775270174a86d95eea7a94379aed3aec Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 11 Jun 2022 20:30:47 +0800 Subject: [PATCH 007/970] StreamFilterTrait update doc --- user_guide_src/source/testing/overview.rst | 20 +++++++++++++++++-- .../source/testing/overview/018.php | 16 ++++++++++----- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index af7fc550bea7..2cc1f14aa01c 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -253,10 +253,26 @@ component name: Stream Filters ============== -**CITestStreamFilter** provides an alternate to these helper methods. +**StreamFilterTrait** provides an alternate to these helper methods. 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. +might be helpful. The ``StreamFilterTrait`` helps you capture the output from the stream of your choice. + +**Overview of methods** + +``StreamFilterTrait::registerStreamFilterClass()`` Registering a filter to capture streams. + +``StreamFilterTrait::appendStreamOutputFilter()`` Adding a filter to the output stream. + +``StreamFilterTrait::appendStreamErrorFilter()`` Adding a filter to the error stream. + +``StreamFilterTrait::removeStreamOutputFilter()`` Removing the filter from the output stream. + +``StreamFilterTrait::removeStreamErrorFilter()`` Removing the filter from the error stream. + +``StreamFilterTrait::getStreamFilterBuffer()`` Get the captured data from the buffer. + +``StreamFilterTrait::resetStreamFilterBuffer()`` Reset captured data. An example demonstrating this inside one of your test cases: diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index 179b049e6a3c..282c0f12039f 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -2,26 +2,32 @@ use CodeIgniter\CLI\CLI; use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\Filters\CITestStreamFilter; +use CodeIgniter\Test\StreamFilterTrait; final class SomeTest extends CIUnitTestCase { + use StreamFilterTrait; + protected function setUp(): void { - CITestStreamFilter::$buffer = ''; - $this->stream_filter = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->registerStreamFilterClass() + ->appendStreamOutputFilter() + ->appendStreamErrorFilter(); } protected function tearDown(): void { - stream_filter_remove($this->stream_filter); + $this->removeStreamOutputFilter() + ->removeStreamErrorFilter(); } public function testSomeOutput(): void { + $this->resetStreamFilterBuffer(); + CLI::write('first.'); $expected = "first.\n"; - $this->assertSame($expected, CITestStreamFilter::$buffer); + $this->assertSame($expected, $this->getStreamFilterBuffer()); } } From 6e034f40520a99575f724865c1eb25f563189271 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 11 Jun 2022 20:44:41 +0800 Subject: [PATCH 008/970] StreamFilterTrait properties --- system/Test/StreamFilterTrait.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Test/StreamFilterTrait.php b/system/Test/StreamFilterTrait.php index 26f79d466975..991ef3be3b9b 100644 --- a/system/Test/StreamFilterTrait.php +++ b/system/Test/StreamFilterTrait.php @@ -18,12 +18,12 @@ trait StreamFilterTrait /** * @var resource|null */ - protected $streamFilterOutResource; + private $streamFilterOutResource; /** * @var resource|null */ - protected $streamFilterErrResource; + private $streamFilterErrResource; /** * @return $this From 4da82dbfeecb8ed7f0c4f4b7377336bbefb3aec7 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sun, 12 Jun 2022 01:30:59 +0800 Subject: [PATCH 009/970] Renaming the methods of the trait. --- system/Test/StreamFilterTrait.php | 32 +++++++++---------- tests/system/CLI/CLITest.php | 6 ++-- tests/system/CLI/CommandRunnerTest.php | 6 ++-- tests/system/CLI/ConsoleTest.php | 4 +-- tests/system/Commands/ClearCacheTest.php | 6 ++-- tests/system/Commands/ClearDebugbarTest.php | 6 ++-- tests/system/Commands/ClearLogsTest.php | 6 ++-- .../system/Commands/CommandGeneratorTest.php | 6 ++-- tests/system/Commands/CommandTest.php | 6 ++-- tests/system/Commands/ConfigGeneratorTest.php | 6 ++-- .../Commands/ConfigurableSortImportsTest.php | 6 ++-- .../Commands/ControllerGeneratorTest.php | 6 ++-- tests/system/Commands/CreateDatabaseTest.php | 6 ++-- .../Commands/Database/MigrateStatusTest.php | 6 ++-- .../Commands/Database/ShowTableInfoTest.php | 6 ++-- .../system/Commands/DatabaseCommandsTest.php | 6 ++-- tests/system/Commands/EntityGeneratorTest.php | 6 ++-- .../Commands/EnvironmentCommandTest.php | 6 ++-- tests/system/Commands/FilterGeneratorTest.php | 6 ++-- tests/system/Commands/GenerateKeyTest.php | 6 ++-- tests/system/Commands/GeneratorsTest.php | 6 ++-- tests/system/Commands/HelpCommandTest.php | 6 ++-- tests/system/Commands/InfoCacheTest.php | 6 ++-- .../Commands/MigrationGeneratorTest.php | 6 ++-- .../Commands/MigrationIntegrationTest.php | 6 ++-- tests/system/Commands/ModelGeneratorTest.php | 6 ++-- tests/system/Commands/PublishCommandTest.php | 6 ++-- tests/system/Commands/RoutesTest.php | 6 ++-- .../system/Commands/ScaffoldGeneratorTest.php | 6 ++-- tests/system/Commands/SeederGeneratorTest.php | 6 ++-- .../Commands/ValidationGeneratorTest.php | 6 ++-- .../Debug/Toolbar/Collectors/HistoryTest.php | 6 ++-- tests/system/Test/TestCaseTest.php | 4 +-- user_guide_src/source/testing/overview.rst | 8 ++--- .../source/testing/overview/018.php | 8 ++--- 35 files changed, 118 insertions(+), 118 deletions(-) diff --git a/system/Test/StreamFilterTrait.php b/system/Test/StreamFilterTrait.php index 991ef3be3b9b..f8d423fdee4e 100644 --- a/system/Test/StreamFilterTrait.php +++ b/system/Test/StreamFilterTrait.php @@ -18,21 +18,21 @@ trait StreamFilterTrait /** * @var resource|null */ - private $streamFilterOutResource; + private $outputStreamFilterResource; /** * @var resource|null */ - private $streamFilterErrResource; + private $errorStreamFilterResource; /** * @return $this */ - protected function appendStreamOutputFilter() + protected function appendOutputStreamFilter() { - $this->removeStreamOutputFilter(); + $this->removeOutputStreamFilter(); - $this->streamFilterOutResource = stream_filter_append(STDOUT, 'CITestStreamFilter'); + $this->outputStreamFilterResource = stream_filter_append(STDOUT, 'CITestStreamFilter'); return $this; } @@ -40,11 +40,11 @@ protected function appendStreamOutputFilter() /** * @return $this */ - protected function appendStreamErrorFilter() + protected function appendErrorStreamFilter() { - $this->removeStreamErrorFilter(); + $this->removeErrorStreamFilter(); - $this->streamFilterErrResource = stream_filter_append(STDERR, 'CITestStreamFilter'); + $this->errorStreamFilterResource = stream_filter_append(STDERR, 'CITestStreamFilter'); return $this; } @@ -52,11 +52,11 @@ protected function appendStreamErrorFilter() /** * @return $this */ - protected function removeStreamOutputFilter() + protected function removeOutputStreamFilter() { - if (is_resource($this->streamFilterOutResource)) { - stream_filter_remove($this->streamFilterOutResource); - $this->streamFilterOutResource = null; + if (is_resource($this->outputStreamFilterResource)) { + stream_filter_remove($this->outputStreamFilterResource); + $this->outputStreamFilterResource = null; } return $this; @@ -65,11 +65,11 @@ protected function removeStreamOutputFilter() /** * @return $this */ - protected function removeStreamErrorFilter() + protected function removeErrorStreamFilter() { - if (is_resource($this->streamFilterErrResource)) { - stream_filter_remove($this->streamFilterErrResource); - $this->streamFilterErrResource = null; + if (is_resource($this->errorStreamFilterResource)) { + stream_filter_remove($this->errorStreamFilterResource); + $this->errorStreamFilterResource = null; } return $this; diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index e4aed4b6b87c..04904dac055f 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -28,13 +28,13 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testNew() diff --git a/tests/system/CLI/CommandRunnerTest.php b/tests/system/CLI/CommandRunnerTest.php index 432e907b111c..04152f606a93 100644 --- a/tests/system/CLI/CommandRunnerTest.php +++ b/tests/system/CLI/CommandRunnerTest.php @@ -39,13 +39,13 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testGoodCommand() diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index ac4cb5223176..4fe5d0086074 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -30,7 +30,7 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass()->appendStreamOutputFilter(); + $this->registerStreamFilterClass()->appendOutputStreamFilter(); $this->env = new DotEnv(ROOTPATH); $this->env->load(); @@ -53,7 +53,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter(); + $this->removeOutputStreamFilter(); } public function testNew() diff --git a/tests/system/Commands/ClearCacheTest.php b/tests/system/Commands/ClearCacheTest.php index 2ddcef152cb8..0fe18105a5bc 100644 --- a/tests/system/Commands/ClearCacheTest.php +++ b/tests/system/Commands/ClearCacheTest.php @@ -28,8 +28,8 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); // Make sure we are testing with the correct handler (override injections) Services::injectMock('cache', CacheFactory::getHandler(config('Cache'))); @@ -37,7 +37,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testClearCacheInvalidHandler() diff --git a/tests/system/Commands/ClearDebugbarTest.php b/tests/system/Commands/ClearDebugbarTest.php index 54120eb0fac4..b430dff81e20 100644 --- a/tests/system/Commands/ClearDebugbarTest.php +++ b/tests/system/Commands/ClearDebugbarTest.php @@ -28,15 +28,15 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); $this->time = time(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } protected function createDummyDebugbarJson() diff --git a/tests/system/Commands/ClearLogsTest.php b/tests/system/Commands/ClearLogsTest.php index 2135f9bd50d2..4949da6d2ee7 100644 --- a/tests/system/Commands/ClearLogsTest.php +++ b/tests/system/Commands/ClearLogsTest.php @@ -28,8 +28,8 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); // test runs on other tests may log errors since default threshold // is now 4, so set this to a safe distance @@ -38,7 +38,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } protected function createDummyLogFiles() diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php index 3f27e662e6b3..b0ce235a6d49 100644 --- a/tests/system/Commands/CommandGeneratorTest.php +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -24,13 +24,13 @@ final class CommandGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/CommandTest.php b/tests/system/Commands/CommandTest.php index d61ced18d222..f67775fdf66b 100644 --- a/tests/system/Commands/CommandTest.php +++ b/tests/system/Commands/CommandTest.php @@ -33,8 +33,8 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); $this->logger = Services::logger(); $this->commands = Services::commands(); @@ -42,7 +42,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } protected function getBuffer() diff --git a/tests/system/Commands/ConfigGeneratorTest.php b/tests/system/Commands/ConfigGeneratorTest.php index a1765eaa97c7..5006f855955a 100644 --- a/tests/system/Commands/ConfigGeneratorTest.php +++ b/tests/system/Commands/ConfigGeneratorTest.php @@ -24,13 +24,13 @@ final class ConfigGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/ConfigurableSortImportsTest.php b/tests/system/Commands/ConfigurableSortImportsTest.php index 209002fdfe2d..1dbda9eea3b0 100644 --- a/tests/system/Commands/ConfigurableSortImportsTest.php +++ b/tests/system/Commands/ConfigurableSortImportsTest.php @@ -26,13 +26,13 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testPublishLanguageWithoutOptions() diff --git a/tests/system/Commands/ControllerGeneratorTest.php b/tests/system/Commands/ControllerGeneratorTest.php index a249a8a97a7c..9cb7e2ed07e8 100644 --- a/tests/system/Commands/ControllerGeneratorTest.php +++ b/tests/system/Commands/ControllerGeneratorTest.php @@ -24,13 +24,13 @@ final class ControllerGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/CreateDatabaseTest.php b/tests/system/Commands/CreateDatabaseTest.php index af0af597f974..f1945e463e34 100644 --- a/tests/system/Commands/CreateDatabaseTest.php +++ b/tests/system/Commands/CreateDatabaseTest.php @@ -31,8 +31,8 @@ final class CreateDatabaseTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); $this->connection = Database::connect(); @@ -54,7 +54,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); parent::tearDown(); } diff --git a/tests/system/Commands/Database/MigrateStatusTest.php b/tests/system/Commands/Database/MigrateStatusTest.php index b211e7f34143..17724c538366 100644 --- a/tests/system/Commands/Database/MigrateStatusTest.php +++ b/tests/system/Commands/Database/MigrateStatusTest.php @@ -47,8 +47,8 @@ protected function setUp(): void file_put_contents($this->migrationFileTo, $contents); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void @@ -62,7 +62,7 @@ protected function tearDown(): void @unlink($this->migrationFileTo); } - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testMigrateAllWithWithTwoNamespaces(): void diff --git a/tests/system/Commands/Database/ShowTableInfoTest.php b/tests/system/Commands/Database/ShowTableInfoTest.php index 9fde90ef1ca2..134ea0ea743c 100644 --- a/tests/system/Commands/Database/ShowTableInfoTest.php +++ b/tests/system/Commands/Database/ShowTableInfoTest.php @@ -32,15 +32,15 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { parent::tearDown(); - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } private function getResultWithoutControlCode(): string diff --git a/tests/system/Commands/DatabaseCommandsTest.php b/tests/system/Commands/DatabaseCommandsTest.php index bd0fbe2c47f4..867c24621cfe 100644 --- a/tests/system/Commands/DatabaseCommandsTest.php +++ b/tests/system/Commands/DatabaseCommandsTest.php @@ -24,8 +24,8 @@ final class DatabaseCommandsTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); parent::setUp(); } @@ -33,7 +33,7 @@ protected function setUp(): void protected function tearDown(): void { command('migrate:rollback'); - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); parent::tearDown(); } diff --git a/tests/system/Commands/EntityGeneratorTest.php b/tests/system/Commands/EntityGeneratorTest.php index f71f47f905db..76f2ebc16b62 100644 --- a/tests/system/Commands/EntityGeneratorTest.php +++ b/tests/system/Commands/EntityGeneratorTest.php @@ -24,13 +24,13 @@ final class EntityGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/EnvironmentCommandTest.php b/tests/system/Commands/EnvironmentCommandTest.php index 7ffd901e6aac..e28b6810a1a2 100644 --- a/tests/system/Commands/EnvironmentCommandTest.php +++ b/tests/system/Commands/EnvironmentCommandTest.php @@ -28,8 +28,8 @@ protected function setUp(): void { parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); if (is_file($this->envPath)) { rename($this->envPath, $this->backupEnvPath); @@ -39,7 +39,7 @@ protected function setUp(): void protected function tearDown(): void { parent::tearDown(); - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); if (is_file($this->envPath)) { unlink($this->envPath); diff --git a/tests/system/Commands/FilterGeneratorTest.php b/tests/system/Commands/FilterGeneratorTest.php index ffafcb02cc3d..cf9bc806a44b 100644 --- a/tests/system/Commands/FilterGeneratorTest.php +++ b/tests/system/Commands/FilterGeneratorTest.php @@ -24,13 +24,13 @@ final class FilterGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamErrorFilter() - ->appendStreamOutputFilter(); + ->appendErrorStreamFilter() + ->appendOutputStreamFilter(); } protected function tearDown(): void { - $this->removeStreamErrorFilter()->removeStreamOutputFilter(); + $this->removeErrorStreamFilter()->removeOutputStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/GenerateKeyTest.php b/tests/system/Commands/GenerateKeyTest.php index 5f390cb1a152..bcf8ce28c218 100644 --- a/tests/system/Commands/GenerateKeyTest.php +++ b/tests/system/Commands/GenerateKeyTest.php @@ -31,8 +31,8 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); $this->envPath = ROOTPATH . '.env'; $this->backupEnvPath = ROOTPATH . '.env.backup'; @@ -46,7 +46,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); if (is_file($this->envPath)) { unlink($this->envPath); diff --git a/tests/system/Commands/GeneratorsTest.php b/tests/system/Commands/GeneratorsTest.php index 4f96317fa0e6..c62093d2700a 100644 --- a/tests/system/Commands/GeneratorsTest.php +++ b/tests/system/Commands/GeneratorsTest.php @@ -24,13 +24,13 @@ final class GeneratorsTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testGenerateFileCreated() diff --git a/tests/system/Commands/HelpCommandTest.php b/tests/system/Commands/HelpCommandTest.php index a80bad665a19..76fda392baef 100644 --- a/tests/system/Commands/HelpCommandTest.php +++ b/tests/system/Commands/HelpCommandTest.php @@ -26,13 +26,13 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } protected function getBuffer() diff --git a/tests/system/Commands/InfoCacheTest.php b/tests/system/Commands/InfoCacheTest.php index 0704fe564c12..170408debaf7 100644 --- a/tests/system/Commands/InfoCacheTest.php +++ b/tests/system/Commands/InfoCacheTest.php @@ -28,8 +28,8 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); // Make sure we are testing with the correct handler (override injections) Services::injectMock('cache', CacheFactory::getHandler(config('Cache'))); @@ -37,7 +37,7 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); // restore default cache handler config('Cache')->handler = 'file'; diff --git a/tests/system/Commands/MigrationGeneratorTest.php b/tests/system/Commands/MigrationGeneratorTest.php index 395b328041b1..80125f609cc6 100644 --- a/tests/system/Commands/MigrationGeneratorTest.php +++ b/tests/system/Commands/MigrationGeneratorTest.php @@ -24,13 +24,13 @@ final class MigrationGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamErrorFilter() - ->appendStreamOutputFilter(); + ->appendErrorStreamFilter() + ->appendOutputStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/MigrationIntegrationTest.php b/tests/system/Commands/MigrationIntegrationTest.php index e58de9bd3391..d435fb43fcb5 100644 --- a/tests/system/Commands/MigrationIntegrationTest.php +++ b/tests/system/Commands/MigrationIntegrationTest.php @@ -43,8 +43,8 @@ protected function setUp(): void file_put_contents($this->migrationFileTo, $contents); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void @@ -55,7 +55,7 @@ protected function tearDown(): void @unlink($this->migrationFileTo); } - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testMigrationWithRollbackHasSameNameFormat(): void diff --git a/tests/system/Commands/ModelGeneratorTest.php b/tests/system/Commands/ModelGeneratorTest.php index 2f35b2e7a201..29813beef6d0 100644 --- a/tests/system/Commands/ModelGeneratorTest.php +++ b/tests/system/Commands/ModelGeneratorTest.php @@ -25,14 +25,14 @@ protected function setUp(): void { parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { parent::tearDown(); - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/PublishCommandTest.php b/tests/system/Commands/PublishCommandTest.php index 03c695b4e8e7..750f4d16dd1e 100644 --- a/tests/system/Commands/PublishCommandTest.php +++ b/tests/system/Commands/PublishCommandTest.php @@ -27,15 +27,15 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { parent::tearDown(); - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); TestPublisher::setResult(true); } diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index bcfab0b4d95f..e309a965c21b 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -29,13 +29,13 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $this->resetServices(); } diff --git a/tests/system/Commands/ScaffoldGeneratorTest.php b/tests/system/Commands/ScaffoldGeneratorTest.php index cbc23eaf47ad..2cbd75b487a8 100644 --- a/tests/system/Commands/ScaffoldGeneratorTest.php +++ b/tests/system/Commands/ScaffoldGeneratorTest.php @@ -30,13 +30,13 @@ protected function setUp(): void Services::autoloader()->initialize(new Autoload(), new Modules()); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } protected function getFileContents(string $filepath): string diff --git a/tests/system/Commands/SeederGeneratorTest.php b/tests/system/Commands/SeederGeneratorTest.php index 291db60e32ae..fef989b2348d 100644 --- a/tests/system/Commands/SeederGeneratorTest.php +++ b/tests/system/Commands/SeederGeneratorTest.php @@ -24,13 +24,13 @@ final class SeederGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/ValidationGeneratorTest.php b/tests/system/Commands/ValidationGeneratorTest.php index a8ae5ce17019..63926e91c9ee 100644 --- a/tests/system/Commands/ValidationGeneratorTest.php +++ b/tests/system/Commands/ValidationGeneratorTest.php @@ -24,13 +24,13 @@ final class ValidationGeneratorTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Debug/Toolbar/Collectors/HistoryTest.php b/tests/system/Debug/Toolbar/Collectors/HistoryTest.php index 531d87fc58f7..6aed814886af 100644 --- a/tests/system/Debug/Toolbar/Collectors/HistoryTest.php +++ b/tests/system/Debug/Toolbar/Collectors/HistoryTest.php @@ -31,8 +31,8 @@ protected function setUp(): void parent::setUp(); $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); $this->time = (float) sprintf('%.6f', microtime(true)); } @@ -41,7 +41,7 @@ protected function tearDown(): void { command('debugbar:clear'); - $this->removeStreamOutputFilter()->removeStreamErrorFilter(); + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } private function createDummyDebugbarJson() diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index aaca2d58540f..d774bab71595 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -50,11 +50,11 @@ public function testEventTriggering() public function testStreamFilter() { - $this->registerStreamFilterClass()->appendStreamOutputFilter(); + $this->registerStreamFilterClass()->appendOutputStreamFilter(); CLI::write('first.'); $expected = "first.\n"; $this->assertSame($expected, $this->getStreamFilterBuffer()); - $this->removeStreamOutputFilter(); + $this->removeOutputStreamFilter(); } /** diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index 2cc1f14aa01c..b000dda2b9ab 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -262,13 +262,13 @@ might be helpful. The ``StreamFilterTrait`` helps you capture the output from th ``StreamFilterTrait::registerStreamFilterClass()`` Registering a filter to capture streams. -``StreamFilterTrait::appendStreamOutputFilter()`` Adding a filter to the output stream. +``StreamFilterTrait::appendOutputStreamFilter()`` Adding a filter to the output stream. -``StreamFilterTrait::appendStreamErrorFilter()`` Adding a filter to the error stream. +``StreamFilterTrait::appendErrorStreamFilter()`` Adding a filter to the error stream. -``StreamFilterTrait::removeStreamOutputFilter()`` Removing the filter from the output stream. +``StreamFilterTrait::removeOutputStreamFilter()`` Removing the filter from the output stream. -``StreamFilterTrait::removeStreamErrorFilter()`` Removing the filter from the error stream. +``StreamFilterTrait::removeErrorStreamFilter()`` Removing the filter from the error stream. ``StreamFilterTrait::getStreamFilterBuffer()`` Get the captured data from the buffer. diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index 282c0f12039f..d7c28a701487 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -11,14 +11,14 @@ final class SomeTest extends CIUnitTestCase protected function setUp(): void { $this->registerStreamFilterClass() - ->appendStreamOutputFilter() - ->appendStreamErrorFilter(); + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeStreamOutputFilter() - ->removeStreamErrorFilter(); + $this->removeOutputStreamFilter() + ->removeErrorStreamFilter(); } public function testSomeOutput(): void From 9cea09a1ec2876e141adf9b2a6d80f0b3909372d Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Wed, 15 Jun 2022 13:19:38 +0800 Subject: [PATCH 010/970] rebase upstream/4.3 --- system/Test/Filters/CITestStreamFilter.php | 2 +- system/Test/StreamFilterTrait.php | 14 +++++++- tests/system/CLI/CLITest.php | 14 -------- tests/system/CLI/CommandRunnerTest.php | 14 -------- tests/system/CLI/ConsoleTest.php | 7 ---- 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 | 14 -------- .../Commands/ControllerGeneratorTest.php | 9 ----- tests/system/Commands/CreateDatabaseTest.php | 11 ------ .../Commands/Database/MigrateStatusTest.php | 6 ---- .../Commands/Database/ShowTableInfoTest.php | 16 --------- .../system/Commands/DatabaseCommandsTest.php | 10 ------ tests/system/Commands/EntityGeneratorTest.php | 9 ----- .../Commands/EnvironmentCommandTest.php | 4 --- tests/system/Commands/FilterGeneratorTest.php | 9 ----- tests/system/Commands/GenerateKeyTest.php | 6 ---- tests/system/Commands/GeneratorsTest.php | 12 ------- tests/system/Commands/HelpCommandTest.php | 14 -------- tests/system/Commands/InfoCacheTest.php | 6 ---- .../Commands/MigrationGeneratorTest.php | 9 ----- .../Commands/MigrationIntegrationTest.php | 6 ---- tests/system/Commands/ModelGeneratorTest.php | 9 ----- tests/system/Commands/PublishCommandTest.php | 10 ------ tests/system/Commands/RoutesTest.php | 8 +---- .../system/Commands/ScaffoldGeneratorTest.php | 9 +---- tests/system/Commands/SeederGeneratorTest.php | 9 +---- .../Commands/ValidationGeneratorTest.php | 9 +---- .../Debug/Toolbar/Collectors/HistoryTest.php | 6 +--- tests/system/Test/TestCaseTest.php | 2 -- user_guide_src/source/changelogs/index.rst | 1 + user_guide_src/source/changelogs/v4.3.0.rst | 35 +++++++++++++++++++ user_guide_src/source/testing/overview.rst | 25 +++++++------ .../source/testing/overview/018.php | 13 ------- 38 files changed, 67 insertions(+), 315 deletions(-) create mode 100644 user_guide_src/source/changelogs/v4.3.0.rst diff --git a/system/Test/Filters/CITestStreamFilter.php b/system/Test/Filters/CITestStreamFilter.php index 8873adc0598e..564ec6fb51d1 100644 --- a/system/Test/Filters/CITestStreamFilter.php +++ b/system/Test/Filters/CITestStreamFilter.php @@ -48,7 +48,7 @@ public function filter($in, $out, &$consumed, $closing): int return PSFS_PASS_ON; } - public static function init(): void + public static function registration(): void { if (! static::$registered) { static::$registered = stream_filter_register('CITestStreamFilter', self::class); // @codeCoverageIgnore diff --git a/system/Test/StreamFilterTrait.php b/system/Test/StreamFilterTrait.php index f8d423fdee4e..732c6afdcc78 100644 --- a/system/Test/StreamFilterTrait.php +++ b/system/Test/StreamFilterTrait.php @@ -25,6 +25,18 @@ trait StreamFilterTrait */ private $errorStreamFilterResource; + protected function setUpStreamFilterTrait(): void + { + $this->registerStreamFilterClass() + ->appendOutputStreamFilter() + ->appendErrorStreamFilter(); + } + + protected function tearDownStreamFilterTrait(): void + { + $this->removeOutputStreamFilter()->removeErrorStreamFilter(); + } + /** * @return $this */ @@ -80,7 +92,7 @@ protected function removeErrorStreamFilter() */ protected function registerStreamFilterClass() { - CITestStreamFilter::init(); + CITestStreamFilter::registration(); return $this; } diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 04904dac055f..da4524ae47a8 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -23,20 +23,6 @@ final class CLITest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - public function testNew() { $actual = new CLI(); diff --git a/tests/system/CLI/CommandRunnerTest.php b/tests/system/CLI/CommandRunnerTest.php index 04152f606a93..825d0b85579e 100644 --- a/tests/system/CLI/CommandRunnerTest.php +++ b/tests/system/CLI/CommandRunnerTest.php @@ -34,20 +34,6 @@ public static function setUpBeforeClass(): void self::$runner->initController(service('request'), service('response'), self::$logger); } - protected function setUp(): void - { - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - public function testGoodCommand() { self::$runner->index(['list']); diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index 4fe5d0086074..685f56bac733 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -30,8 +30,6 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass()->appendOutputStreamFilter(); - $this->env = new DotEnv(ROOTPATH); $this->env->load(); @@ -51,11 +49,6 @@ protected function setUp(): void $this->app->setContext('spark'); } - protected function tearDown(): void - { - $this->removeOutputStreamFilter(); - } - public function testNew() { $console = new Console($this->app); diff --git a/tests/system/Commands/ClearCacheTest.php b/tests/system/Commands/ClearCacheTest.php index 0fe18105a5bc..62eeb4753095 100644 --- a/tests/system/Commands/ClearCacheTest.php +++ b/tests/system/Commands/ClearCacheTest.php @@ -27,19 +27,10 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - // Make sure we are testing with the correct handler (override injections) Services::injectMock('cache', CacheFactory::getHandler(config('Cache'))); } - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - public function testClearCacheInvalidHandler() { command('cache:clear junk'); diff --git a/tests/system/Commands/ClearDebugbarTest.php b/tests/system/Commands/ClearDebugbarTest.php index b430dff81e20..e388905ae1d9 100644 --- a/tests/system/Commands/ClearDebugbarTest.php +++ b/tests/system/Commands/ClearDebugbarTest.php @@ -27,18 +27,9 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - $this->time = time(); } - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - protected function createDummyDebugbarJson() { $time = $this->time; diff --git a/tests/system/Commands/ClearLogsTest.php b/tests/system/Commands/ClearLogsTest.php index 4949da6d2ee7..16e00286fcc3 100644 --- a/tests/system/Commands/ClearLogsTest.php +++ b/tests/system/Commands/ClearLogsTest.php @@ -27,20 +27,11 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - // test runs on other tests may log errors since default threshold // is now 4, so set this to a safe distance $this->date = date('Y-m-d', strtotime('+1 year')); } - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - protected function createDummyLogFiles() { $date = $this->date; diff --git a/tests/system/Commands/CommandGeneratorTest.php b/tests/system/Commands/CommandGeneratorTest.php index b0ce235a6d49..054b3ec30d7c 100644 --- a/tests/system/Commands/CommandGeneratorTest.php +++ b/tests/system/Commands/CommandGeneratorTest.php @@ -21,17 +21,8 @@ final class CommandGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); $dir = dirname($file); diff --git a/tests/system/Commands/CommandTest.php b/tests/system/Commands/CommandTest.php index f67775fdf66b..7a8c39940dc0 100644 --- a/tests/system/Commands/CommandTest.php +++ b/tests/system/Commands/CommandTest.php @@ -32,19 +32,10 @@ protected function setUp(): void parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - $this->logger = Services::logger(); $this->commands = Services::commands(); } - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - protected function getBuffer() { return $this->getStreamFilterBuffer(); diff --git a/tests/system/Commands/ConfigGeneratorTest.php b/tests/system/Commands/ConfigGeneratorTest.php index 5006f855955a..36fdae1848e2 100644 --- a/tests/system/Commands/ConfigGeneratorTest.php +++ b/tests/system/Commands/ConfigGeneratorTest.php @@ -21,17 +21,8 @@ final class ConfigGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { diff --git a/tests/system/Commands/ConfigurableSortImportsTest.php b/tests/system/Commands/ConfigurableSortImportsTest.php index 1dbda9eea3b0..2371bafa0276 100644 --- a/tests/system/Commands/ConfigurableSortImportsTest.php +++ b/tests/system/Commands/ConfigurableSortImportsTest.php @@ -21,20 +21,6 @@ final class ConfigurableSortImportsTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - public function testPublishLanguageWithoutOptions() { command('publish:language'); diff --git a/tests/system/Commands/ControllerGeneratorTest.php b/tests/system/Commands/ControllerGeneratorTest.php index 9cb7e2ed07e8..14cdbc933dd3 100644 --- a/tests/system/Commands/ControllerGeneratorTest.php +++ b/tests/system/Commands/ControllerGeneratorTest.php @@ -21,17 +21,8 @@ final class ControllerGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { diff --git a/tests/system/Commands/CreateDatabaseTest.php b/tests/system/Commands/CreateDatabaseTest.php index f1945e463e34..809abe4dd086 100644 --- a/tests/system/Commands/CreateDatabaseTest.php +++ b/tests/system/Commands/CreateDatabaseTest.php @@ -30,10 +30,6 @@ final class CreateDatabaseTest extends CIUnitTestCase protected function setUp(): void { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - $this->connection = Database::connect(); parent::setUp(); @@ -52,13 +48,6 @@ protected function setUp(): void } } - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - - parent::tearDown(); - } - protected function getBuffer() { return $this->getStreamFilterBuffer(); diff --git a/tests/system/Commands/Database/MigrateStatusTest.php b/tests/system/Commands/Database/MigrateStatusTest.php index 17724c538366..3167db912150 100644 --- a/tests/system/Commands/Database/MigrateStatusTest.php +++ b/tests/system/Commands/Database/MigrateStatusTest.php @@ -45,10 +45,6 @@ protected function setUp(): void $contents ); file_put_contents($this->migrationFileTo, $contents); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); } protected function tearDown(): void @@ -61,8 +57,6 @@ protected function tearDown(): void if (is_file($this->migrationFileTo)) { @unlink($this->migrationFileTo); } - - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testMigrateAllWithWithTwoNamespaces(): void diff --git a/tests/system/Commands/Database/ShowTableInfoTest.php b/tests/system/Commands/Database/ShowTableInfoTest.php index 134ea0ea743c..dd1e1a423fba 100644 --- a/tests/system/Commands/Database/ShowTableInfoTest.php +++ b/tests/system/Commands/Database/ShowTableInfoTest.php @@ -27,22 +27,6 @@ final class ShowTableInfoTest extends CIUnitTestCase protected $migrateOnce = true; - protected function setUp(): void - { - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - parent::tearDown(); - - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - private function getResultWithoutControlCode(): string { return str_replace( diff --git a/tests/system/Commands/DatabaseCommandsTest.php b/tests/system/Commands/DatabaseCommandsTest.php index 867c24621cfe..7afd849a12c7 100644 --- a/tests/system/Commands/DatabaseCommandsTest.php +++ b/tests/system/Commands/DatabaseCommandsTest.php @@ -21,19 +21,9 @@ final class DatabaseCommandsTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - - parent::setUp(); - } - protected function tearDown(): void { command('migrate:rollback'); - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); parent::tearDown(); } diff --git a/tests/system/Commands/EntityGeneratorTest.php b/tests/system/Commands/EntityGeneratorTest.php index 76f2ebc16b62..1c4e0e279e7a 100644 --- a/tests/system/Commands/EntityGeneratorTest.php +++ b/tests/system/Commands/EntityGeneratorTest.php @@ -21,17 +21,8 @@ final class EntityGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); $dir = dirname($file); diff --git a/tests/system/Commands/EnvironmentCommandTest.php b/tests/system/Commands/EnvironmentCommandTest.php index e28b6810a1a2..9660ec1420df 100644 --- a/tests/system/Commands/EnvironmentCommandTest.php +++ b/tests/system/Commands/EnvironmentCommandTest.php @@ -27,9 +27,6 @@ final class EnvironmentCommandTest extends CIUnitTestCase protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); if (is_file($this->envPath)) { rename($this->envPath, $this->backupEnvPath); @@ -39,7 +36,6 @@ protected function setUp(): void protected function tearDown(): void { parent::tearDown(); - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); if (is_file($this->envPath)) { unlink($this->envPath); diff --git a/tests/system/Commands/FilterGeneratorTest.php b/tests/system/Commands/FilterGeneratorTest.php index cf9bc806a44b..a952ba48aec7 100644 --- a/tests/system/Commands/FilterGeneratorTest.php +++ b/tests/system/Commands/FilterGeneratorTest.php @@ -21,17 +21,8 @@ final class FilterGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendErrorStreamFilter() - ->appendOutputStreamFilter(); - } - protected function tearDown(): void { - $this->removeErrorStreamFilter()->removeOutputStreamFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { diff --git a/tests/system/Commands/GenerateKeyTest.php b/tests/system/Commands/GenerateKeyTest.php index bcf8ce28c218..f69e7ad1afc9 100644 --- a/tests/system/Commands/GenerateKeyTest.php +++ b/tests/system/Commands/GenerateKeyTest.php @@ -30,10 +30,6 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - $this->envPath = ROOTPATH . '.env'; $this->backupEnvPath = ROOTPATH . '.env.backup'; @@ -46,8 +42,6 @@ protected function setUp(): void protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - if (is_file($this->envPath)) { unlink($this->envPath); } diff --git a/tests/system/Commands/GeneratorsTest.php b/tests/system/Commands/GeneratorsTest.php index c62093d2700a..929535b37c88 100644 --- a/tests/system/Commands/GeneratorsTest.php +++ b/tests/system/Commands/GeneratorsTest.php @@ -21,18 +21,6 @@ final class GeneratorsTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - public function testGenerateFileCreated() { command('make:seeder categories'); diff --git a/tests/system/Commands/HelpCommandTest.php b/tests/system/Commands/HelpCommandTest.php index 76fda392baef..d37b146360f2 100644 --- a/tests/system/Commands/HelpCommandTest.php +++ b/tests/system/Commands/HelpCommandTest.php @@ -21,20 +21,6 @@ final class HelpCommandTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - } - protected function getBuffer() { return $this->getStreamFilterBuffer(); diff --git a/tests/system/Commands/InfoCacheTest.php b/tests/system/Commands/InfoCacheTest.php index 170408debaf7..0822ebe73194 100644 --- a/tests/system/Commands/InfoCacheTest.php +++ b/tests/system/Commands/InfoCacheTest.php @@ -27,18 +27,12 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - // Make sure we are testing with the correct handler (override injections) Services::injectMock('cache', CacheFactory::getHandler(config('Cache'))); } protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - // restore default cache handler config('Cache')->handler = 'file'; } diff --git a/tests/system/Commands/MigrationGeneratorTest.php b/tests/system/Commands/MigrationGeneratorTest.php index 80125f609cc6..14255929069e 100644 --- a/tests/system/Commands/MigrationGeneratorTest.php +++ b/tests/system/Commands/MigrationGeneratorTest.php @@ -21,17 +21,8 @@ final class MigrationGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendErrorStreamFilter() - ->appendOutputStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); if (is_file($file)) { diff --git a/tests/system/Commands/MigrationIntegrationTest.php b/tests/system/Commands/MigrationIntegrationTest.php index d435fb43fcb5..97b8fe71f376 100644 --- a/tests/system/Commands/MigrationIntegrationTest.php +++ b/tests/system/Commands/MigrationIntegrationTest.php @@ -41,10 +41,6 @@ protected function setUp(): void $contents = file_get_contents($this->migrationFileTo); $contents = str_replace('namespace Tests\Support\Database\Migrations;', 'namespace App\Database\Migrations;', $contents); file_put_contents($this->migrationFileTo, $contents); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); } protected function tearDown(): void @@ -54,8 +50,6 @@ protected function tearDown(): void if (is_file($this->migrationFileTo)) { @unlink($this->migrationFileTo); } - - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); } public function testMigrationWithRollbackHasSameNameFormat(): void diff --git a/tests/system/Commands/ModelGeneratorTest.php b/tests/system/Commands/ModelGeneratorTest.php index 29813beef6d0..51d24d37494b 100644 --- a/tests/system/Commands/ModelGeneratorTest.php +++ b/tests/system/Commands/ModelGeneratorTest.php @@ -21,18 +21,9 @@ final class ModelGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { parent::tearDown(); - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/PublishCommandTest.php b/tests/system/Commands/PublishCommandTest.php index 750f4d16dd1e..1fec3ea2f635 100644 --- a/tests/system/Commands/PublishCommandTest.php +++ b/tests/system/Commands/PublishCommandTest.php @@ -22,20 +22,10 @@ final class PublishCommandTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { parent::tearDown(); - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); TestPublisher::setResult(true); } diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index e309a965c21b..c761a1eb2eb0 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -25,19 +25,13 @@ final class RoutesTest extends CIUnitTestCase protected function setUp(): void { $this->resetServices(); - parent::setUp(); - - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); } protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); - $this->resetServices(); + parent::tearDown(); } protected function getBuffer() diff --git a/tests/system/Commands/ScaffoldGeneratorTest.php b/tests/system/Commands/ScaffoldGeneratorTest.php index 2cbd75b487a8..bd3c789f4902 100644 --- a/tests/system/Commands/ScaffoldGeneratorTest.php +++ b/tests/system/Commands/ScaffoldGeneratorTest.php @@ -29,14 +29,7 @@ protected function setUp(): void $this->resetServices(); Services::autoloader()->initialize(new Autoload(), new Modules()); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); + parent::setUp(); } protected function getFileContents(string $filepath): string diff --git a/tests/system/Commands/SeederGeneratorTest.php b/tests/system/Commands/SeederGeneratorTest.php index fef989b2348d..97498607576a 100644 --- a/tests/system/Commands/SeederGeneratorTest.php +++ b/tests/system/Commands/SeederGeneratorTest.php @@ -21,16 +21,9 @@ final class SeederGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); + parent::tearDown(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Commands/ValidationGeneratorTest.php b/tests/system/Commands/ValidationGeneratorTest.php index 63926e91c9ee..02393aa84f80 100644 --- a/tests/system/Commands/ValidationGeneratorTest.php +++ b/tests/system/Commands/ValidationGeneratorTest.php @@ -21,16 +21,9 @@ final class ValidationGeneratorTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - protected function tearDown(): void { - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); + parent::tearDown(); $result = str_replace(["\033[0;32m", "\033[0m", "\n"], '', $this->getStreamFilterBuffer()); $file = str_replace('APPPATH' . DIRECTORY_SEPARATOR, APPPATH, trim(substr($result, 14))); diff --git a/tests/system/Debug/Toolbar/Collectors/HistoryTest.php b/tests/system/Debug/Toolbar/Collectors/HistoryTest.php index 6aed814886af..8c12ff4ee375 100644 --- a/tests/system/Debug/Toolbar/Collectors/HistoryTest.php +++ b/tests/system/Debug/Toolbar/Collectors/HistoryTest.php @@ -30,10 +30,6 @@ protected function setUp(): void { parent::setUp(); - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - $this->time = (float) sprintf('%.6f', microtime(true)); } @@ -41,7 +37,7 @@ protected function tearDown(): void { command('debugbar:clear'); - $this->removeOutputStreamFilter()->removeErrorStreamFilter(); + parent::tearDown(); } private function createDummyDebugbarJson() diff --git a/tests/system/Test/TestCaseTest.php b/tests/system/Test/TestCaseTest.php index d774bab71595..46db68ad3575 100644 --- a/tests/system/Test/TestCaseTest.php +++ b/tests/system/Test/TestCaseTest.php @@ -50,11 +50,9 @@ public function testEventTriggering() public function testStreamFilter() { - $this->registerStreamFilterClass()->appendOutputStreamFilter(); CLI::write('first.'); $expected = "first.\n"; $this->assertSame($expected, $this->getStreamFilterBuffer()); - $this->removeOutputStreamFilter(); } /** diff --git a/user_guide_src/source/changelogs/index.rst b/user_guide_src/source/changelogs/index.rst index edef0a8e2208..2db7bb4ad37b 100644 --- a/user_guide_src/source/changelogs/index.rst +++ b/user_guide_src/source/changelogs/index.rst @@ -12,6 +12,7 @@ See all the changes. .. toctree:: :titlesonly: + v4.3.0 v4.2.1 v4.2.0 v4.1.9 diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst new file mode 100644 index 000000000000..67cdcca7bf8b --- /dev/null +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -0,0 +1,35 @@ +Version 4.3.0 +############# + +Release Date: Unreleased + +**4.3.0 release of CodeIgniter4** + +.. contents:: + :local: + :depth: 2 + +BREAKING +******** + +none. + +Enhancements +************ + +- Added the ``StreamFilterTrait`` to make it easier to work with capturing data from STDOUT and STDERR streams. See :ref:`testing-overview-stream-filters`. + +Changes +******* + +none. + +Deprecations +************ + +none. + +Bugs Fixed +********** + +none. diff --git a/user_guide_src/source/testing/overview.rst b/user_guide_src/source/testing/overview.rst index b000dda2b9ab..54e874b8dbaf 100644 --- a/user_guide_src/source/testing/overview.rst +++ b/user_guide_src/source/testing/overview.rst @@ -103,6 +103,8 @@ parent as well so extended test cases do not interfere with staging: .. literalinclude:: overview/003.php +.. _testing-overview-traits: + Traits ------ @@ -250,6 +252,8 @@ component name: .. note:: All component Factories are reset by default between each test. Modify your test case's ``$setUpMethods`` if you need instances to persist. +.. _testing-overview-stream-filters: + Stream Filters ============== @@ -260,20 +264,15 @@ might be helpful. The ``StreamFilterTrait`` helps you capture the output from th **Overview of methods** -``StreamFilterTrait::registerStreamFilterClass()`` Registering a filter to capture streams. - -``StreamFilterTrait::appendOutputStreamFilter()`` Adding a filter to the output stream. - -``StreamFilterTrait::appendErrorStreamFilter()`` Adding a filter to the error stream. - -``StreamFilterTrait::removeOutputStreamFilter()`` Removing the filter from the output stream. - -``StreamFilterTrait::removeErrorStreamFilter()`` Removing the filter from the error stream. - -``StreamFilterTrait::getStreamFilterBuffer()`` Get the captured data from the buffer. - -``StreamFilterTrait::resetStreamFilterBuffer()`` Reset captured data. +- ``StreamFilterTrait::getStreamFilterBuffer()`` Get the captured data from the buffer. +- ``StreamFilterTrait::resetStreamFilterBuffer()`` Reset captured data. An example demonstrating this inside one of your test cases: .. literalinclude:: overview/018.php + +The ``StreamFilterTrait`` has a configurator that is called automatically. +See :ref:`Testing Traits `. + +If you override the ``setUp()`` or ``tearDown()`` methods in your test, then you must call the ``parent::setUp()`` and +``parent::tearDown()`` methods respectively to configure the ``StreamFilterTrait``. diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index d7c28a701487..449320a457d5 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -8,19 +8,6 @@ final class SomeTest extends CIUnitTestCase { use StreamFilterTrait; - protected function setUp(): void - { - $this->registerStreamFilterClass() - ->appendOutputStreamFilter() - ->appendErrorStreamFilter(); - } - - protected function tearDown(): void - { - $this->removeOutputStreamFilter() - ->removeErrorStreamFilter(); - } - public function testSomeOutput(): void { $this->resetStreamFilterBuffer(); From 50c3a142d37e9bf2a481540cf847b1e384ec9ae7 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Wed, 15 Jun 2022 12:46:08 +0800 Subject: [PATCH 011/970] change doc example --- user_guide_src/source/testing/overview/018.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/testing/overview/018.php b/user_guide_src/source/testing/overview/018.php index 449320a457d5..09f1f4e42f2d 100644 --- a/user_guide_src/source/testing/overview/018.php +++ b/user_guide_src/source/testing/overview/018.php @@ -10,11 +10,14 @@ final class SomeTest extends CIUnitTestCase public function testSomeOutput(): void { + CLI::write('first.'); + + $this->assertSame("\nfirst.\n", $this->getStreamFilterBuffer()); + $this->resetStreamFilterBuffer(); - CLI::write('first.'); + CLI::write('second.'); - $expected = "first.\n"; - $this->assertSame($expected, $this->getStreamFilterBuffer()); + $this->assertSame("second.\n", $this->getStreamFilterBuffer()); } } From 070c0a2ad63aa03f3018074f2e245956c3dfa6ef Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Tue, 14 Jun 2022 21:37:23 +0100 Subject: [PATCH 012/970] Add events for insertBatch() and updateBatch() methods --- system/BaseModel.php | 72 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 70 insertions(+), 2 deletions(-) diff --git a/system/BaseModel.php b/system/BaseModel.php index 39bd9ce2cb4c..3fda3464ecca 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -258,6 +258,34 @@ abstract class BaseModel */ protected $afterUpdate = []; + /** + * Callbacks for beforeInsertBatch + * + * @var array + */ + protected $beforeInsertBatch = []; + + /** + * Callbacks for afterInsertBatch + * + * @var array + */ + protected $afterInsertBatch = []; + + /** + * Callbacks for beforeUpdateBatch + * + * @var array + */ + protected $beforeUpdateBatch = []; + + /** + * Callbacks for afterUpdateBatch + * + * @var array + */ + protected $afterUpdateBatch = []; + /** * Callbacks for beforeFind * @@ -811,7 +839,27 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch } } - return $this->doInsertBatch($set, $escape, $batchSize, $testing); + $eventData = ['data' => $set]; + + if ($this->tempAllowCallbacks) { + $eventData = $this->trigger('beforeInsertBatch', $eventData); + } + + $result = $this->doInsertBatch($eventData['data'], $escape, $batchSize, $testing); + + $eventData = [ + 'data' => $eventData['data'], + 'result' => $result, + ]; + + if ($this->tempAllowCallbacks) { + // Trigger afterInsert events with the inserted data and new ID + $this->trigger('afterInsertBatch', $eventData); + } + + $this->tempAllowCallbacks = $this->allowCallbacks; + + return $result; } /** @@ -928,7 +976,27 @@ public function updateBatch(?array $set = null, ?string $index = null, int $batc } } - return $this->doUpdateBatch($set, $index, $batchSize, $returnSQL); + $eventData = ['data' => $set]; + + if ($this->tempAllowCallbacks) { + $eventData = $this->trigger('beforeUpdateBatch', $eventData); + } + + $result = $this->doUpdateBatch($eventData['data'], $index, $batchSize, $returnSQL); + + $eventData = [ + 'data' => $eventData['data'], + 'result' => $result, + ]; + + if ($this->tempAllowCallbacks) { + // Trigger afterInsert events with the inserted data and new ID + $this->trigger('afterUpdateBatch', $eventData); + } + + $this->tempAllowCallbacks = $this->allowCallbacks; + + return $result; } /** From fffd9c74bc2efc5fe54721c72cbc9b2403620f47 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Tue, 14 Jun 2022 21:38:20 +0100 Subject: [PATCH 013/970] Add tests --- tests/_support/Models/EventModel.php | 52 +++++++++++++++++++++---- tests/system/Models/EventsModelTest.php | 40 +++++++++++++++++++ 2 files changed, 84 insertions(+), 8 deletions(-) diff --git a/tests/_support/Models/EventModel.php b/tests/_support/Models/EventModel.php index c3e0a145509b..69234cf60445 100644 --- a/tests/_support/Models/EventModel.php +++ b/tests/_support/Models/EventModel.php @@ -25,14 +25,18 @@ class EventModel extends Model 'country', 'deleted_at', ]; - protected $beforeInsert = ['beforeInsertMethod']; - protected $afterInsert = ['afterInsertMethod']; - protected $beforeUpdate = ['beforeUpdateMethod']; - protected $afterUpdate = ['afterUpdateMethod']; - protected $beforeDelete = ['beforeDeleteMethod']; - protected $afterDelete = ['afterDeleteMethod']; - protected $beforeFind = ['beforeFindMethod']; - protected $afterFind = ['afterFindMethod']; + protected $beforeInsert = ['beforeInsertMethod']; + protected $afterInsert = ['afterInsertMethod']; + protected $beforeInsertBatch = ['beforeInsertBatchMethod']; + protected $afterInsertBatch = ['afterInsertBatchMethod']; + protected $beforeUpdate = ['beforeUpdateMethod']; + protected $afterUpdate = ['afterUpdateMethod']; + protected $beforeUpdateBatch = ['beforeUpdateBatchMethod']; + protected $afterUpdateBatch = ['afterUpdateBatchMethod']; + protected $beforeDelete = ['beforeDeleteMethod']; + protected $afterDelete = ['afterDeleteMethod']; + protected $beforeFind = ['beforeFindMethod']; + protected $afterFind = ['afterFindMethod']; // Cache of the most recent eventData from a trigger public $eventData; @@ -59,6 +63,22 @@ protected function afterInsertMethod(array $data) return $data; } + protected function beforeInsertBatchMethod(array $data) + { + $this->tokens[] = 'beforeInsertBatch'; + $this->eventData = $data; + + return $data; + } + + protected function afterInsertBatchMethod(array $data) + { + $this->tokens[] = 'afterInsertBatch'; + $this->eventData = $data; + + return $data; + } + protected function beforeUpdateMethod(array $data) { $this->tokens[] = 'beforeUpdate'; @@ -75,6 +95,22 @@ protected function afterUpdateMethod(array $data) return $data; } + protected function beforeUpdateBatchMethod(array $data) + { + $this->tokens[] = 'beforeUpdateBatch'; + $this->eventData = $data; + + return $data; + } + + protected function afterUpdateBatchMethod(array $data) + { + $this->tokens[] = 'afterUpdateBatch'; + $this->eventData = $data; + + return $data; + } + protected function beforeDeleteMethod(array $data) { $this->tokens[] = 'beforeDelete'; diff --git a/tests/system/Models/EventsModelTest.php b/tests/system/Models/EventsModelTest.php index 09194396099c..7cf2442036c8 100644 --- a/tests/system/Models/EventsModelTest.php +++ b/tests/system/Models/EventsModelTest.php @@ -170,4 +170,44 @@ public function testInvalidEventException(): void $this->expectExceptionMessage('anotherBeforeInsertMethod is not a valid Model Event callback.'); $this->model->insert($data); } + + public function testInsertBatchEvent(): void + { + $data = [ + [ + 'name' => 'Foo', + 'email' => 'foo@example.com', + 'country' => 'US', + 'deleted' => 0, + ], + [ + 'name' => 'Bar', + 'email' => 'bar@example.com', + 'country' => 'US', + 'deleted' => 0, + ], + ]; + + $this->model->insertBatch($data); + $this->assertTrue($this->model->hasToken('beforeInsertBatch')); + $this->assertTrue($this->model->hasToken('afterInsertBatch')); + } + + public function testUpdateBatchEvent(): void + { + $data = [ + [ + 'name' => 'Derek Jones', + 'country' => 'Greece', + ], + [ + 'name' => 'Ahmadinejad', + 'country' => 'Greece', + ], + ]; + + $this->model->updateBatch($data, 'name'); + $this->assertTrue($this->model->hasToken('beforeUpdateBatch')); + $this->assertTrue($this->model->hasToken('afterUpdateBatch')); + } } From 46e149ce7028247cff539390c6a64dda12f886e0 Mon Sep 17 00:00:00 2001 From: Paulo Esteves Date: Tue, 14 Jun 2022 21:38:38 +0100 Subject: [PATCH 014/970] Update documentation --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/models/model.rst | 33 ++++++++++++++++----- 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 67cdcca7bf8b..260636dfdae8 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -18,6 +18,7 @@ Enhancements ************ - Added the ``StreamFilterTrait`` to make it easier to work with capturing data from STDOUT and STDERR streams. See :ref:`testing-overview-stream-filters`. +- Added before and after events to ``BaseModel::insertBatch()`` and ``BaseModel::updateBatch()`` methods. See :ref:`model-events-callbacks`. Changes ******* diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 18eb6630a7ec..c148d1aee610 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -196,10 +196,18 @@ $beforeInsert ------------- $afterInsert ------------ +$beforeInsertBatch +------------------ +$afterInsertBatch +----------------- $beforeUpdate ------------- $afterUpdate ------------ +$beforeUpdateBatch +------------------ +$afterUpdateBatch +----------------- $afterFind ---------- $afterDelete @@ -573,13 +581,16 @@ This is best used during cronjobs, data exports, or other large tasks. .. literalinclude:: model/049.php +.. _model-events-callbacks: + 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``. +``$beforeInsertBatch``, ``$afterInsertBatch``, ``$beforeUpdate``, ``$afterUpdate``, ``$beforeUpdateBatch``, +``$afterUpdateBatch``, ``$afterFind``, and ``$afterDelete``. Defining Callbacks ================== @@ -616,20 +627,28 @@ 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: -================ ========================================================================================================= -Event $data contents -================ ========================================================================================================= +================= ========================================================================================================= +Event $data contents +================= ========================================================================================================= beforeInsert **data** = the key/value pairs that are being inserted. If an object or Entity class is passed to the insert method, it is first converted to an array. afterInsert **id** = the primary key of the new row, or 0 on failure. **data** = the key/value pairs being inserted. **result** = the results of the insert() method used through the Query Builder. +beforeInsertBatch **data** = associative array of values that are being inserted. If an object or Entity class is passed to the + insertBatch method, it is first converted to an array. +afterInsertBatch **data** = the associative array of values being inserted. + **result** = the results of the insertbatch() method used through the Query Builder. beforeUpdate **id** = the array of primary keys of the rows being updated. - **data** = the key/value pairs that are being inserted. If an object or Entity class is passed to the - insert method, it is first converted to an array. + **data** = the key/value pairs that are being updated. If an object or Entity class is passed to the + update method, it is first converted to an array. afterUpdate **id** = the array of primary keys of the rows being updated. **data** = the key/value pairs being updated. **result** = the results of the update() method used through the Query Builder. +beforeUpdateBatch **data** = associative array of values that are being updated. If an object or Entity class is passed to the + updateBatch method, it is first converted to an array. +afterUpdateBatch **data** = the key/value pairs being updated. + **result** = the results of the updateBatch() method used through the Query Builder. beforeFind The name of the calling **method**, whether a **singleton** was requested, and these additional fields: - first() No additional fields - find() **id** = the primary key of the row being searched for. @@ -643,7 +662,7 @@ afterDelete **id** = primary key of row being deleted. **purge** = boolean whether soft-delete rows should be hard deleted. **result** = the result of the delete() call on the Query Builder. **data** = unused. -================ ========================================================================================================= +================= ========================================================================================================= Modifying Find* Data ==================== From 903f24d0ee92a24ca4ee12ba113fcdd33619e109 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Jun 2022 15:58:08 +0900 Subject: [PATCH 015/970] docs: add useSupportedLocalesOnly in changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/outgoing/localization.rst | 3 +++ 2 files changed, 4 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 260636dfdae8..a9c5bc64f000 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -19,6 +19,7 @@ Enhancements - Added the ``StreamFilterTrait`` to make it easier to work with capturing data from STDOUT and STDERR streams. See :ref:`testing-overview-stream-filters`. - Added before and after events to ``BaseModel::insertBatch()`` and ``BaseModel::updateBatch()`` methods. See :ref:`model-events-callbacks`. +- Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization ` Changes ******* diff --git a/user_guide_src/source/outgoing/localization.rst b/user_guide_src/source/outgoing/localization.rst index 7a4385da0485..2a1f3f5b4197 100644 --- a/user_guide_src/source/outgoing/localization.rst +++ b/user_guide_src/source/outgoing/localization.rst @@ -69,6 +69,8 @@ the following example, the **en** locale would be used if no match is found: .. literalinclude:: localization/003.php +.. _localization-in-routes: + In Routes --------- @@ -87,6 +89,7 @@ file: .. literalinclude:: localization/018.php +.. note:: ``useSupportedLocalesOnly()`` can be used since v4.3.0. Retrieving the Current Locale ============================= From 775fa7d4e329209042269ae8c1bebb543c9d1c42 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 11 Jun 2022 04:52:38 +0800 Subject: [PATCH 016/970] Extracting the call handler for Spark commands from application. --- spark | 9 ++-- system/CLI/Console.php | 31 +++++------ system/CodeIgniter.php | 91 ++++++++++---------------------- system/Config/Routes.php | 3 +- tests/system/CLI/ConsoleTest.php | 61 ++++++++++++++------- 5 files changed, 86 insertions(+), 109 deletions(-) diff --git a/spark b/spark index 225422aace74..6d4d762b38fc 100755 --- a/spark +++ b/spark @@ -69,10 +69,9 @@ require_once SYSTEMPATH . 'Config/DotEnv.php'; // Grab our CodeIgniter $app = Config\Services::codeigniter(); $app->initialize(); -$app->setContext('spark'); // Grab our Console -$console = new CodeIgniter\CLI\Console($app); +$console = new CodeIgniter\CLI\Console(); // Show basic information before we do anything else. if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) { @@ -83,8 +82,6 @@ if (is_int($suppress = array_search('--no-header', $_SERVER['argv'], true))) { $console->showHeader($suppress); // fire off the command in the main framework. -$response = $console->run(); +$exit = $console->run(); -if ($response->getStatusCode() >= 300) { - exit($response->getStatusCode()); -} +exit(is_int($exit) ? $exit : EXIT_SUCCESS); diff --git a/system/CLI/Console.php b/system/CLI/Console.php index 0bf8a0f7ce0a..a114127cab8f 100644 --- a/system/CLI/Console.php +++ b/system/CLI/Console.php @@ -12,6 +12,7 @@ namespace CodeIgniter\CLI; use CodeIgniter\CodeIgniter; +use Config\Services; use Exception; /** @@ -19,18 +20,6 @@ */ class Console { - /** - * Main CodeIgniter instance. - * - * @var CodeIgniter - */ - protected $app; - - public function __construct(CodeIgniter $app) - { - $this->app = $app; - } - /** * Runs the current command discovered on the CLI. * @@ -38,14 +27,13 @@ public function __construct(CodeIgniter $app) * * @return mixed */ - public function run(bool $useSafeOutput = false) + public function run() { - $path = CLI::getURI() ?: 'list'; - - // Set the path for the application to route to. - $this->app->setPath("ci{$path}"); + $runner = Services::commands(); + $params = array_merge(CLI::getSegments(), CLI::getOptions()); + $command = array_shift($params) ?? 'list'; - return $this->app->useSafeOutput($useSafeOutput)->run(); + return $runner->run($command, $params); } /** @@ -57,7 +45,12 @@ public function showHeader(bool $suppress = false) return; } - CLI::write(sprintf('CodeIgniter v%s Command Line Tool - Server Time: %s UTC%s', CodeIgniter::CI_VERSION, date('Y-m-d H:i:s'), date('P')), 'green'); + CLI::write(sprintf( + 'CodeIgniter v%s Command Line Tool - Server Time: %s UTC%s', + CodeIgniter::CI_VERSION, + date('Y-m-d H:i:s'), + date('P') + ), 'green'); CLI::newLine(); } } diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 82b08e318879..f16415516203 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -147,9 +147,8 @@ class CodeIgniter * Context * web: Invoked by HTTP request * php-cli: Invoked by CLI via `php public/index.php` - * spark: Invoked by CLI via the `spark` command * - * @phpstan-var 'php-cli'|'spark'|'web' + * @phpstan-var 'php-cli'|'web' */ protected ?string $context = null; @@ -307,7 +306,10 @@ protected function initializeKint() public function run(?RouteCollectionInterface $routes = null, bool $returnResponse = false) { if ($this->context === null) { - throw new LogicException('Context must be set before run() is called. If you are upgrading from 4.1.x, you need to merge `public/index.php` and `spark` file from `vendor/codeigniter4/framework`.'); + throw new LogicException( + 'Context must be set before run() is called. If you are upgrading from 4.1.x, ' + . 'you need to merge `public/index.php` and `spark` file from `vendor/codeigniter4/framework`.' + ); } $this->startBenchmark(); @@ -342,11 +344,6 @@ public function run(?RouteCollectionInterface $routes = null, bool $returnRespon return; } - // spark command has nothing to do with HTTP redirect and 404 - if ($this->isSparked()) { - return $this->handleRequest($routes, $cacheConfig, $returnResponse); - } - try { return $this->handleRequest($routes, $cacheConfig, $returnResponse); } catch (RedirectException $e) { @@ -380,14 +377,6 @@ public function useSafeOutput(bool $safe = true) return $this; } - /** - * Invoked via spark command? - */ - private function isSparked(): bool - { - return $this->context === 'spark'; - } - /** * Invoked via php-cli command? */ @@ -435,21 +424,18 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache } } - // Never run filters when running through Spark cli - if (! $this->isSparked()) { - // Run "before" filters - $this->benchmark->start('before_filters'); - $possibleResponse = $filters->run($uri, 'before'); - $this->benchmark->stop('before_filters'); + // 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) { - return $returnResponse ? $possibleResponse : $possibleResponse->pretend($this->useSafeOutput)->send(); - } + // If a ResponseInterface instance is returned then send it back to the client and stop + if ($possibleResponse instanceof ResponseInterface) { + return $returnResponse ? $possibleResponse : $possibleResponse->pretend($this->useSafeOutput)->send(); + } - if ($possibleResponse instanceof Request) { - $this->request = $possibleResponse; - } + if ($possibleResponse instanceof Request) { + $this->request = $possibleResponse; } $returned = $this->startController(); @@ -476,22 +462,12 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache // so it can be used with the output. $this->gatherOutput($cacheConfig, $returned); - // Never run filters when running through Spark cli - if (! $this->isSparked()) { - $filters->setResponse($this->response); + $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; - - // Set response code for CLI command failures - if (is_numeric($returned) || $returned === false) { - $response->setStatusCode(400); - } - } + // Run "after" filters + $this->benchmark->start('after_filters'); + $response = $filters->run($uri, 'after'); + $this->benchmark->stop('after_filters'); if ($response instanceof ResponseInterface) { $this->response = $response; @@ -595,7 +571,7 @@ protected function getRequestObject() return; } - if ($this->isSparked() || $this->isPhpCli()) { + if ($this->isPhpCli()) { $this->request = Services::clirequest($this->config); } else { $this->request = Services::request($this->config); @@ -871,9 +847,7 @@ protected function createController() * CI4 supports three types of requests: * 1. Web: URI segments become parameters, sent to Controllers via Routes, * output controlled by Headers to browser - * 2. Spark: accessed by CLI via the spark command, arguments are Command arguments, - * sent to Commands by CommandRunner, output controlled by CLI class - * 3. PHP CLI: accessed by CLI via php public/index.php, arguments become URI segments, + * 2. PHP CLI: accessed by CLI via php public/index.php, arguments become URI segments, * sent to Controllers via Routes, output varies * * @param mixed $class @@ -882,21 +856,12 @@ protected function createController() */ protected function runController($class) { - if ($this->isSparked()) { - // This is a Spark request - /** @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(); + // 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'); @@ -1095,7 +1060,7 @@ protected function callExit($code) /** * Sets the app context. * - * @phpstan-param 'php-cli'|'spark'|'web' $context + * @phpstan-param 'php-cli'|'web' $context * * @return $this */ diff --git a/system/Config/Routes.php b/system/Config/Routes.php index 0f16b675a8ad..114974005dce 100644 --- a/system/Config/Routes.php +++ b/system/Config/Routes.php @@ -8,7 +8,6 @@ * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ - /* * System URI Routing * @@ -20,4 +19,4 @@ */ // CLI Catchall - uses a _remap to call Commands -$routes->cli('ci(:any)', '\CodeIgniter\CLI\CommandRunner::index/$1'); +// $routes->cli('ci(:any)', '\CodeIgniter\CLI\CommandRunner::index/$1'); diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index 685f56bac733..aff85170403b 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -13,7 +13,6 @@ use CodeIgniter\CodeIgniter; use CodeIgniter\Config\DotEnv; -use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\Mock\MockCLIConfig; use CodeIgniter\Test\Mock\MockCodeIgniter; @@ -38,26 +37,19 @@ protected function setUp(): void $_SERVER['app.baseURL'] = 'http://example.com/'; } - $_SERVER['argv'] = [ - 'spark', - 'list', - ]; - $_SERVER['argc'] = 2; - CLI::init(); - $this->app = new MockCodeIgniter(new MockCLIConfig()); - $this->app->setContext('spark'); + $this->app->initialize(); } public function testNew() { - $console = new Console($this->app); + $console = new Console(); $this->assertInstanceOf(Console::class, $console); } public function testHeader() { - $console = new Console($this->app); + $console = new Console(); $console->showHeader(); $this->assertGreaterThan( 0, @@ -70,24 +62,55 @@ public function testHeader() public function testNoHeader() { - $console = new Console($this->app); + $console = new Console(); $console->showHeader(true); $this->assertSame('', $this->getStreamFilterBuffer()); } public function testRun() { - $request = new CLIRequest(config('App')); - $this->app->setRequest($request); - - $console = new Console($this->app); - $console->run(true); + $this->initCLI(); - // close open buffer - ob_end_clean(); + $console = new Console(); + $console->run(); // make sure the result looks like a command list $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); } + + public function testBadCommand() + { + $this->initCLI('bogus'); + + $console = new Console(); + $console->run(); + + // make sure the result looks like a command list + $this->assertStringContainsString('Command "bogus" not found', $this->getStreamFilterBuffer()); + } + + public function testHelpCommandDetails() + { + $this->initCLI('help', 'session:migration'); + + $console = new Console(); + $console->run(); + + // make sure the result looks like more detailed help + $this->assertStringContainsString('Description:', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Usage:', $this->getStreamFilterBuffer()); + $this->assertStringContainsString('Options:', $this->getStreamFilterBuffer()); + } + + /** + * @param array $command + */ + protected function initCLI(...$command): void + { + $_SERVER['argv'] = ['spark', ...$command]; + $_SERVER['argc'] = count($_SERVER['argv']); + + CLI::init(); + } } From be9b0546d5ce9e5ed6cdadd52104db36ebe28f4c Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Fri, 17 Jun 2022 00:39:04 +0800 Subject: [PATCH 017/970] spark-rework: docs&conf. --- app/Config/Routes.php | 6 -- system/CLI/CommandRunner.php | 75 -------------- system/Config/Routes.php | 22 ----- tests/system/CLI/CommandRunnerTest.php | 98 ------------------- tests/system/CLI/ConsoleTest.php | 6 -- user_guide_src/source/changelogs/v4.3.0.rst | 12 ++- user_guide_src/source/cli/cli_controllers.rst | 3 + user_guide_src/source/incoming/routing.rst | 5 +- 8 files changed, 16 insertions(+), 211 deletions(-) delete mode 100644 system/CLI/CommandRunner.php delete mode 100644 system/Config/Routes.php delete mode 100644 tests/system/CLI/CommandRunnerTest.php diff --git a/app/Config/Routes.php b/app/Config/Routes.php index ff2ac645cb9a..71b7a86de469 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -5,12 +5,6 @@ // Create a new instance of our RouteCollection class. $routes = Services::routes(); -// Load the system's routing file first, so that the app and ENVIRONMENT -// can override as needed. -if (is_file(SYSTEMPATH . 'Config/Routes.php')) { - require SYSTEMPATH . 'Config/Routes.php'; -} - /* * -------------------------------------------------------------------- * Router Setup diff --git a/system/CLI/CommandRunner.php b/system/CLI/CommandRunner.php deleted file mode 100644 index ef4ed057b606..000000000000 --- a/system/CLI/CommandRunner.php +++ /dev/null @@ -1,75 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ - -namespace CodeIgniter\CLI; - -use CodeIgniter\Controller; -use Config\Services; -use ReflectionException; - -/** - * Command runner - */ -class CommandRunner extends Controller -{ - /** - * Instance of class managing the collection of commands - * - * @var Commands - */ - protected $commands; - - /** - * Constructor - */ - public function __construct() - { - $this->commands = Services::commands(); - } - - /** - * We map all un-routed CLI methods through this function - * so we have the chance to look for a Command first. - * - * @param string $method - * @param array $params - * - * @throws ReflectionException - * - * @return mixed - */ - public function _remap($method, $params) - { - return $this->index($params); - } - - /** - * Default command. - * - * @throws ReflectionException - * - * @return mixed - */ - public function index(array $params) - { - $command = array_shift($params) ?? 'list'; - - return $this->commands->run($command, $params); - } - - /** - * Allows access to the current commands that have been found. - */ - public function getCommands(): array - { - return $this->commands->getCommands(); - } -} diff --git a/system/Config/Routes.php b/system/Config/Routes.php deleted file mode 100644 index 114974005dce..000000000000 --- a/system/Config/Routes.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view - * the LICENSE file that was distributed with this source code. - */ -/* - * System URI Routing - * - * This file contains any routing to system tools, such as command-line - * tools for migrations, etc. - * - * It is called by Config\Routes, and has the $routes RouteCollection - * already loaded up and ready for us to use. - */ - -// CLI Catchall - uses a _remap to call Commands -// $routes->cli('ci(:any)', '\CodeIgniter\CLI\CommandRunner::index/$1'); diff --git a/tests/system/CLI/CommandRunnerTest.php b/tests/system/CLI/CommandRunnerTest.php deleted file mode 100644 index 825d0b85579e..000000000000 --- a/tests/system/CLI/CommandRunnerTest.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. - */ - -namespace CodeIgniter\CLI; - -use CodeIgniter\Log\Logger; -use CodeIgniter\Test\CIUnitTestCase; -use CodeIgniter\Test\StreamFilterTrait; -use Config\Services; - -/** - * @internal - */ -final class CommandRunnerTest extends CIUnitTestCase -{ - use StreamFilterTrait; - - private static Logger $logger; - private static CommandRunner $runner; - - public static function setUpBeforeClass(): void - { - self::$logger = service('logger'); - self::$runner = new CommandRunner(); - - self::$runner->initController(service('request'), service('response'), self::$logger); - } - - public function testGoodCommand() - { - self::$runner->index(['list']); - - // make sure the result looks like a command list - $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); - $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); - } - - public function testDefaultCommand() - { - self::$runner->index([]); - - // make sure the result looks like basic help - $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); - $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); - } - - public function testHelpCommand() - { - self::$runner->index(['help']); - - // make sure the result looks like basic help - $this->assertStringContainsString('Displays basic usage information.', $this->getStreamFilterBuffer()); - $this->assertStringContainsString('help command_name', $this->getStreamFilterBuffer()); - } - - public function testHelpCommandDetails() - { - self::$runner->index(['help', 'session:migration']); - - // make sure the result looks like more detailed help - $this->assertStringContainsString('Description:', $this->getStreamFilterBuffer()); - $this->assertStringContainsString('Usage:', $this->getStreamFilterBuffer()); - $this->assertStringContainsString('Options:', $this->getStreamFilterBuffer()); - } - - public function testCommandProperties() - { - $commands = self::$runner->getCommands(); - $command = new $commands['help']['class'](self::$logger, Services::commands()); - - $this->assertSame('Displays basic usage information.', $command->description); - $this->assertNull($command->notdescription); - } - - public function testEmptyCommand() - { - self::$runner->index([null, 'list']); - - // make sure the result looks like a command list - $this->assertStringContainsString('Lists the available commands.', $this->getStreamFilterBuffer()); - } - - public function testBadCommand() - { - self::$runner->index(['bogus']); - - // make sure the result looks like a command list - $this->assertStringContainsString('Command "bogus" not found', $this->getStreamFilterBuffer()); - } -} diff --git a/tests/system/CLI/ConsoleTest.php b/tests/system/CLI/ConsoleTest.php index aff85170403b..513f59d1ef7f 100644 --- a/tests/system/CLI/ConsoleTest.php +++ b/tests/system/CLI/ConsoleTest.php @@ -41,12 +41,6 @@ protected function setUp(): void $this->app->initialize(); } - public function testNew() - { - $console = new Console(); - $this->assertInstanceOf(Console::class, $console); - } - public function testHeader() { $console = new Console(); diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index a9c5bc64f000..79a71bb07b46 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -12,7 +12,9 @@ Release Date: Unreleased BREAKING ******** -none. +Behavior Changes +================ +- The ``spark`` file has been changed due to a change in the processing of Spark commands. Enhancements ************ @@ -20,11 +22,17 @@ Enhancements - Added the ``StreamFilterTrait`` to make it easier to work with capturing data from STDOUT and STDERR streams. See :ref:`testing-overview-stream-filters`. - Added before and after events to ``BaseModel::insertBatch()`` and ``BaseModel::updateBatch()`` methods. See :ref:`model-events-callbacks`. - Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization ` +- The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. Changes ******* -none. +- Changed the processing of Spark commands: + - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. + - The ``CodeIgniter::isSparked()`` method has been removed. + - The ``CodeIgniter\CLI\CommandRunner`` class has been removed due to a change in Spark commands processing. + - The system route configuration file ``system/Config/Routes.php`` has been removed. + - The route configuration file ``app/Config/Routes.php`` has been changed. Removed include of system routes configuration file. Deprecations ************ diff --git a/user_guide_src/source/cli/cli_controllers.rst b/user_guide_src/source/cli/cli_controllers.rst index c4230091de7c..d40c0b4ca490 100644 --- a/user_guide_src/source/cli/cli_controllers.rst +++ b/user_guide_src/source/cli/cli_controllers.rst @@ -85,3 +85,6 @@ If you want to make sure running via CLI, check the return value of :php:func:`i However, CodeIgniter provides additional tools to make creating CLI-accessible scripts even more pleasant, include CLI-only routing, and a library that helps you with CLI-only tools. + +.. note:: It is recommended to use Spark Commands for CLI scripts instead of calling controllers via CLI. + See the :doc:`spark_commands` page for detailed information. \ No newline at end of file diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index dc27a5aeb8e3..a0d941fe676a 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -327,6 +327,9 @@ available from the command line: .. 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. +.. note:: It is recommended to use Spark Commands instead of CLI routes. + See the :doc:`spark_commands` page for detailed information. + Global Options ============== @@ -716,7 +719,6 @@ The output is like the following: +--------+------------------+------------------------------------------+----------------+-----------------------+ | GET | / | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | | GET | feed | (Closure) | invalidchars | secureheaders toolbar | - | CLI | ci(.*) | \CodeIgniter\CLI\CommandRunner::index/$1 | | | | auto | / | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | | auto | home | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | | auto | home/index[/...] | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | @@ -734,7 +736,6 @@ When you use Auto Routing (Improved), the output is like the following: +-----------+-------------------------+------------------------------------------+----------------+---------------+ | Method | Route | Handler | Before Filters | After Filters | +-----------+-------------------------+------------------------------------------+----------------+---------------+ - | CLI | ci(.*) | \CodeIgniter\CLI\CommandRunner::index/$1 | | | | GET(auto) | product/list/../..[/..] | \App\Controllers\Product::getList | | toolbar | +-----------+-------------------------+------------------------------------------+----------------+---------------+ From ef4e60f6254b33509ad418abc5a8e4cf5c1b7027 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Fri, 17 Jun 2022 01:16:31 +0800 Subject: [PATCH 018/970] spark-rework: exit code --- user_guide_src/source/cli/cli_commands.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 8766673b15d8..542cef9b6b4e 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -82,6 +82,12 @@ Our demo command might have a ``run()`` method something like: See the :doc:`CLI Library ` page for detailed information. +Command termination +=================== + +By default, the command terminates with a success code of ``0``. To change the exit code, for example on error, +the ``run()`` method must return an integer in the range 0 - 254. `PHP exit `_. + *********** BaseCommand *********** From b5511c4f374f87058bc8250d74a365a5d09ef3cb Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Jun 2022 16:41:34 +0900 Subject: [PATCH 019/970] feat: improve namespaces command --- system/Commands/Utilities/Namespaces.php | 78 ++++++++++++++--- .../Commands/Utilities/NamespacesTest.php | 83 +++++++++++++++++++ 2 files changed, 151 insertions(+), 10 deletions(-) create mode 100644 tests/system/Commands/Utilities/NamespacesTest.php diff --git a/system/Commands/Utilities/Namespaces.php b/system/Commands/Utilities/Namespaces.php index 989f02036e86..d97847966fd8 100644 --- a/system/Commands/Utilities/Namespaces.php +++ b/system/Commands/Utilities/Namespaces.php @@ -14,6 +14,7 @@ use CodeIgniter\CLI\BaseCommand; use CodeIgniter\CLI\CLI; use Config\Autoload; +use Config\Services; /** * Lists namespaces set in Config\Autoload with their @@ -63,33 +64,90 @@ class Namespaces extends BaseCommand * * @var array */ - protected $options = []; + protected $options = [ + '-c' => 'Show only CodeIgniter config namespaces.', + '-r' => 'Show raw path strings.', + '-m' => 'Specify max length of the path strings to output. Default: 60.', + ]; /** * Displays the help for the spark cli script itself. */ public function run(array $params) { + $params['m'] = (int) ($params['m'] ?? 60); + + $tbody = array_key_exists('c', $params) ? $this->outputCINamespaces($params) : $this->outputAllNamespaces($params); + + $thead = [ + 'Namespace', + 'Path', + 'Found?', + ]; + + CLI::table($tbody, $thead); + } + + private function outputAllNamespaces(array $params): array + { + $maxLength = $params['m']; + + $autoloader = Services::autoloader(); + + $tbody = []; + + foreach ($autoloader->getNamespace() as $ns => $paths) { + foreach ($paths as $path) { + if (array_key_exists('r', $params)) { + $pathOutput = $this->truncate($path, $maxLength); + } else { + $pathOutput = $this->truncate(clean_path($path), $maxLength); + } + + $tbody[] = [ + $ns, + $pathOutput, + is_dir($path) ? 'Yes' : 'MISSING', + ]; + } + } + + return $tbody; + } + + private function truncate(string $string, int $max): string + { + $length = strlen($string); + + if ($length > $max) { + return substr($string, 0, $max - 3) . '...'; + } + + return $string; + } + + private function outputCINamespaces(array $params): array + { + $maxLength = $params['m']; + $config = new Autoload(); $tbody = []; foreach ($config->psr4 as $ns => $path) { - $path = realpath($path) ?: $path; + if (array_key_exists('r', $params)) { + $pathOutput = $this->truncate($path, $maxLength); + } else { + $pathOutput = $this->truncate(clean_path($path), $maxLength); + } $tbody[] = [ $ns, - realpath($path) ?: $path, + $pathOutput, is_dir($path) ? 'Yes' : 'MISSING', ]; } - $thead = [ - 'Namespace', - 'Path', - 'Found?', - ]; - - CLI::table($tbody, $thead); + return $tbody; } } diff --git a/tests/system/Commands/Utilities/NamespacesTest.php b/tests/system/Commands/Utilities/NamespacesTest.php new file mode 100644 index 000000000000..bd86522149d4 --- /dev/null +++ b/tests/system/Commands/Utilities/NamespacesTest.php @@ -0,0 +1,83 @@ + + * + * 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\Test\CIUnitTestCase; +use CodeIgniter\Test\Filters\CITestStreamFilter; + +/** + * @internal + */ +final class NamespacesTest extends CIUnitTestCase +{ + private $streamFilter; + + protected function setUp(): void + { + $this->resetServices(); + + 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); + + $this->resetServices(); + } + + protected function getBuffer() + { + return CITestStreamFilter::$buffer; + } + + public function testNamespacesCommandCodeIgniterOnly() + { + command('namespaces -c'); + + $expected = <<<'EOL' + +---------------+-------------------------+--------+ + | Namespace | Path | Found? | + +---------------+-------------------------+--------+ + | CodeIgniter | ROOTPATH/system | Yes | + | App | ROOTPATH/app | Yes | + | Config | APPPATH/Config | Yes | + | Tests\Support | ROOTPATH/tests/_support | Yes | + +---------------+-------------------------+--------+ + EOL; + + $this->assertStringContainsString($expected, $this->getBuffer()); + } + + public function testNamespacesCommandAllNamespaces() + { + command('namespaces'); + + $this->assertStringContainsString( + '|CodeIgniter|ROOTPATH/system|Yes|', + str_replace(' ', '', $this->getBuffer()) + ); + $this->assertStringContainsString( + '|App|ROOTPATH/app|Yes|', + str_replace(' ', '', $this->getBuffer()) + ); + $this->assertStringContainsString( + '|Config|APPPATH/Config|Yes|', + str_replace(' ', '', $this->getBuffer()) + ); + } +} From 0dc8b110b16018a28a4f177f8dce352192679b49 Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Fri, 17 Jun 2022 19:07:50 +0800 Subject: [PATCH 020/970] spark-rework: upgrade_430.rst & other docs --- user_guide_src/source/cli/cli_commands.rst | 12 +++- user_guide_src/source/incoming/routing.rst | 2 +- .../source/installation/upgrade_430.rst | 62 +++++++++++++++++++ 3 files changed, 72 insertions(+), 4 deletions(-) create mode 100644 user_guide_src/source/installation/upgrade_430.rst diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index 542cef9b6b4e..b51fe5ca2afb 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -83,10 +83,16 @@ Our demo command might have a ``run()`` method something like: See the :doc:`CLI Library ` page for detailed information. Command termination -=================== +------------------- -By default, the command terminates with a success code of ``0``. To change the exit code, for example on error, -the ``run()`` method must return an integer in the range 0 - 254. `PHP exit `_. +By default, the command exits with a success code of ``0``. If an error is encountered while executing a command, +you can terminate the command by using the ``return`` language construct with an exit code in the ``run()`` method. + +For example, ``return EXIT_ERROR;`` + +This approach can help with debugging at the system level, if the command, for example, is run via crontab. + +You can use the ``EXIT_*`` exit code constants defined in the ``app/Config/Constants.php`` file. *********** BaseCommand diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index a0d941fe676a..26c247cf7978 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -328,7 +328,7 @@ available from the command line: anyone could access the command with the help of auto-routing via HTTP. .. note:: It is recommended to use Spark Commands instead of CLI routes. - See the :doc:`spark_commands` page for detailed information. + See the :doc:`../cli/spark_commands` page for detailed information. Global Options ============== diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst new file mode 100644 index 000000000000..2f35abf47156 --- /dev/null +++ b/user_guide_src/source/installation/upgrade_430.rst @@ -0,0 +1,62 @@ +############################# +Upgrading from 4.2.1 to 4.3.0 +############################# + +Please refer to the upgrade instructions corresponding to your installation method. + +- :ref:`Composer Installation App Starter Upgrading ` +- :ref:`Composer Installation Adding CodeIgniter4 to an Existing Project Upgrading ` +- :ref:`Manual Installation Upgrading ` + +.. contents:: + :local: + :depth: 2 + +Mandatory File Changes +********************** + +spark +===== + +The following files received significant changes and +**you must merge the updated versions** with your application: + +* ``spark`` + +.. important:: If you do not update this file, Spark commands will not work at all after running ``composer update``. + + The upgrade procedure, for example, is as follows:: + + > composer update + > cp vendor/codeigniter4/framework/spark . + +Breaking Enhancements +********************* + +- Since the launch of Spark Commands was extracted from ``CodeIgniter\CodeIgniter``, there may be problems running these commands if the ``Services::codeigniter()`` service has been overridden. + +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 `_. + +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`` + * Due to the fact that the approach to running Spark Commands has changed, there is no longer a need to load the internal routes of the framework. + +All Changes +=========== + +This is a list of all files in the **project space** that received changes; +many will be simple comments or formatting that have no effect on the runtime: + +* app/Config/Routes.php +* spark From 15021055e3d59aca564a656c71c7d9d0c344084b Mon Sep 17 00:00:00 2001 From: Andrey Pyzhikov <5071@mail.ru> Date: Sat, 18 Jun 2022 16:56:50 +0800 Subject: [PATCH 021/970] spark-rework: docs --- user_guide_src/source/cli/cli_commands.rst | 2 +- user_guide_src/source/installation/upgrading.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/cli/cli_commands.rst b/user_guide_src/source/cli/cli_commands.rst index b51fe5ca2afb..22ba6ab2fb09 100644 --- a/user_guide_src/source/cli/cli_commands.rst +++ b/user_guide_src/source/cli/cli_commands.rst @@ -82,7 +82,7 @@ Our demo command might have a ``run()`` method something like: See the :doc:`CLI Library ` page for detailed information. -Command termination +Command Termination ------------------- By default, the command exits with a success code of ``0``. If an error is encountered while executing a command, diff --git a/user_guide_src/source/installation/upgrading.rst b/user_guide_src/source/installation/upgrading.rst index 3570419e19c2..baa5b424c395 100644 --- a/user_guide_src/source/installation/upgrading.rst +++ b/user_guide_src/source/installation/upgrading.rst @@ -12,6 +12,7 @@ upgrading from. .. toctree:: :titlesonly: + upgrade_430 upgrade_421 upgrade_420 upgrade_418 From de059c907a4e9c46b4478fadcaf6fa02c18be6ed Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Jun 2022 17:17:13 +0900 Subject: [PATCH 022/970] fix: is_image causes PHP 8.1 deprecated error ErrorException : mb_strpos(): Passing null to parameter #1 ($haystack) of type string is deprecated .../CodeIgniter4/system/Validation/FileRules.php:138 --- system/Validation/FileRules.php | 2 +- tests/_support/Validation/uploads/abc77tz | 0 tests/system/Validation/FileRulesTest.php | 3 +++ tests/system/Validation/StrictRules/FileRulesTest.php | 3 +++ 4 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 tests/_support/Validation/uploads/abc77tz diff --git a/system/Validation/FileRules.php b/system/Validation/FileRules.php index ea1a6f678379..2becb34b1950 100644 --- a/system/Validation/FileRules.php +++ b/system/Validation/FileRules.php @@ -133,7 +133,7 @@ public function is_image(?string $blank, string $params): bool // We know that our mimes list always has the first mime // start with `image` even when then are multiple accepted types. - $type = Mimes::guessTypeFromExtension($file->getExtension()); + $type = Mimes::guessTypeFromExtension($file->getExtension()) ?? ''; if (mb_strpos($type, 'image') !== 0) { return false; diff --git a/tests/_support/Validation/uploads/abc77tz b/tests/_support/Validation/uploads/abc77tz new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/system/Validation/FileRulesTest.php b/tests/system/Validation/FileRulesTest.php index 0a2f5356efd8..8c5ce6e142ac 100644 --- a/tests/system/Validation/FileRulesTest.php +++ b/tests/system/Validation/FileRulesTest.php @@ -41,7 +41,9 @@ final class FileRulesTest extends CIUnitTestCase protected function setUp(): void { + $this->resetServices(); parent::setUp(); + $this->validation = new Validation((object) $this->config, Services::renderer()); $this->validation->reset(); @@ -229,6 +231,7 @@ public function testIsntImage(): void 'type' => 'application/address', 'error' => UPLOAD_ERR_OK, ]; + $this->validation->setRules(['avatar' => 'is_image[stuff]']); $this->assertFalse($this->validation->run([])); } diff --git a/tests/system/Validation/StrictRules/FileRulesTest.php b/tests/system/Validation/StrictRules/FileRulesTest.php index 73e536d205e4..3446d9f62010 100644 --- a/tests/system/Validation/StrictRules/FileRulesTest.php +++ b/tests/system/Validation/StrictRules/FileRulesTest.php @@ -42,7 +42,9 @@ final class FileRulesTest extends CIUnitTestCase protected function setUp(): void { + $this->resetServices(); parent::setUp(); + $this->validation = new Validation((object) $this->config, Services::renderer()); $this->validation->reset(); @@ -230,6 +232,7 @@ public function testIsntImage(): void 'type' => 'application/address', 'error' => UPLOAD_ERR_OK, ]; + $this->validation->setRules(['avatar' => 'is_image[stuff]']); $this->assertFalse($this->validation->run([])); } From 2a526ccaed154e793c310323f6172ecf3ca3c78a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Jun 2022 19:05:58 +0900 Subject: [PATCH 023/970] docs: add auto-routing by dafault in Highlights This is an important config change. --- 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 fc4088e715a8..081b4b8997a4 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -13,6 +13,7 @@ Highlights ********** - Update minimal PHP requirement to 7.4. +- To make the default configuration more secure, auto-routing has been changed to disabled by default. - **OCI8 Driver for Oracle Database** (*contributed by* `ytetsuro `_). See `Database`_. - **Improved Auto Routing** (opt-in) (*contributed by* `kenjis `_). See `New Improved Auto Routing`_. - Query Builder **Subqueries** and **UNION** support (*contributed by* `Andrey Pyzhikov `_). See `Database`_. From 3aac298f6a3e406173594c2e1dca96d0b1a2482d Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Jun 2022 19:06:57 +0900 Subject: [PATCH 024/970] docs: change in order of importance --- user_guide_src/source/changelogs/v4.2.0.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 081b4b8997a4..2270c38e3f1b 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -135,11 +135,11 @@ Changes ******* - Update minimal PHP requirement to 7.4. -- The current version of Content Security Policy (CSP) outputs one nonce for script and one for style tags. The previous version outputted one nonce for each tag. -- 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. +- To make the default configuration more secure, auto-routing has been changed to disabled by default. - 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. +- The current version of Content Security Policy (CSP) outputs one nonce for script and one for style tags. The previous version outputted one nonce for each tag. +- 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. Deprecations ************ From 84d21a73ab19943145ab1faff60445a6631bd814 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 11 Jun 2022 09:18:38 +0900 Subject: [PATCH 025/970] feat: add method to insert empty data in Model --- system/BaseModel.php | 24 +++++++++++++++++--- system/Model.php | 13 ++++++++++- tests/system/Models/InsertModelTest.php | 30 +++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 4 deletions(-) diff --git a/system/BaseModel.php b/system/BaseModel.php index 3fda3464ecca..793f2f787bd7 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -314,6 +314,11 @@ abstract class BaseModel */ protected $afterDelete = []; + /** + * Whether to prohibit inserting empty data. + */ + protected bool $prohibitInsertEmpty = true; + public function __construct(?ValidationInterface $validation = null) { $this->tempReturnType = $this->returnType; @@ -742,7 +747,7 @@ public function insert($data = null, bool $returnID = true) // doProtectFields() can further remove elements from // $data so we need to check for empty dataset again - if (empty($data)) { + if ($this->prohibitInsertEmpty && empty($data)) { throw DataException::forEmptyDataset('insert'); } @@ -765,6 +770,9 @@ public function insert($data = null, bool $returnID = true) $result = $this->doInsert($eventData['data']); + // Reset $prohibitInsertEmpty value. + $this->prohibitInsertEmpty = true; + $eventData = [ 'id' => $this->insertID, 'data' => $eventData['data'], @@ -1640,7 +1648,7 @@ protected function transformDataToArray($data, string $type): array throw new InvalidArgumentException(sprintf('Invalid type "%s" used upon transforming data to array.', $type)); } - if (empty($data)) { + if ($this->prohibitInsertEmpty && empty($data)) { throw DataException::forEmptyDataset($type); } @@ -1659,7 +1667,7 @@ protected function transformDataToArray($data, string $type): array } // If it's still empty here, means $data is no change or is empty object - if (empty($data)) { + if ($this->prohibitInsertEmpty && empty($data)) { throw DataException::forEmptyDataset($type); } @@ -1765,4 +1773,14 @@ protected function fillPlaceholders(array $rules, array $data): array return $rules; } + + /** + * Permits inserting empty date in the next insertion. + */ + public function permitInsertEmpty(): self + { + $this->prohibitInsertEmpty = false; + + return $this; + } } diff --git a/system/Model.php b/system/Model.php index 4b2087d9dfed..776906178611 100644 --- a/system/Model.php +++ b/system/Model.php @@ -275,7 +275,18 @@ protected function doInsert(array $data) $builder->set($key, $val, $escape[$key] ?? null); } - $result = $builder->insert(); + if (! $this->prohibitInsertEmpty && empty($data)) { + $table = $this->db->protectIdentifiers($this->table, true, null, false); + if ($this->db->getPlatform() === 'MySQLi') { + $sql = 'INSERT INTO ' . $table . ' VALUES ()'; + } else { + $sql = 'INSERT INTO ' . $table . ' DEFAULT VALUES'; + } + + $result = $this->db->query($sql); + } else { + $result = $builder->insert(); + } // If insertion succeeded then save the insert ID if ($result) { diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index a648c73da5b3..0b3833f2d079 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -14,6 +14,8 @@ use CodeIgniter\Database\Exceptions\DataException; use CodeIgniter\Entity\Entity; use CodeIgniter\I18n\Time; +use CodeIgniter\Model; +use Config\Database; use stdClass; use Tests\Support\Entity\User; use Tests\Support\Models\JobModel; @@ -202,6 +204,34 @@ public function testInsertArrayWithNoDataException(): void $this->createModel(UserModel::class)->insert([]); } + public function testInsertPermitInsertNoData(): void + { + $forge = Database::forge(); + $forge->addField([ + 'id' => ['type' => 'INTEGER', 'constraint' => 11, 'auto_increment' => true], + 'created_at' => ['type' => 'INTEGER', 'constraint' => 11, 'null' => true], + 'updated_at' => ['type' => 'INTEGER', 'constraint' => 11, 'null' => true], + ])->addKey('id', true)->createTable('insert_no_data', true); + + $model = new class () extends Model { + protected $table = 'insert_no_data'; + protected $allowedFields = [ + 'updated_at', + ]; + }; + + $model->permitInsertEmpty()->insert([]); + + $this->seeInDatabase('insert_no_data', ['id' => $model->getInsertID()]); + + $forge->dropTable('insert_no_data'); + + $this->expectException(DataException::class); + $this->expectExceptionMessage('There is no data to insert.'); + + $model->insert([]); + } + public function testInsertObjectWithNoDataException(): void { $data = new stdClass(); From 923fa57bbdb609be89a532518910b62463c0c98f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Jun 2022 13:21:06 +0900 Subject: [PATCH 026/970] feat: change method & property name and behavior Now allowEmptyInserts() is a normal setter. --- system/BaseModel.php | 19 ++++++++----------- system/Model.php | 2 +- tests/system/Models/InsertModelTest.php | 3 ++- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/system/BaseModel.php b/system/BaseModel.php index 793f2f787bd7..f0a795d901de 100644 --- a/system/BaseModel.php +++ b/system/BaseModel.php @@ -315,9 +315,9 @@ abstract class BaseModel protected $afterDelete = []; /** - * Whether to prohibit inserting empty data. + * Whether to allow inserting empty data. */ - protected bool $prohibitInsertEmpty = true; + protected bool $allowEmptyInserts = false; public function __construct(?ValidationInterface $validation = null) { @@ -747,7 +747,7 @@ public function insert($data = null, bool $returnID = true) // doProtectFields() can further remove elements from // $data so we need to check for empty dataset again - if ($this->prohibitInsertEmpty && empty($data)) { + if (! $this->allowEmptyInserts && empty($data)) { throw DataException::forEmptyDataset('insert'); } @@ -770,9 +770,6 @@ public function insert($data = null, bool $returnID = true) $result = $this->doInsert($eventData['data']); - // Reset $prohibitInsertEmpty value. - $this->prohibitInsertEmpty = true; - $eventData = [ 'id' => $this->insertID, 'data' => $eventData['data'], @@ -1648,7 +1645,7 @@ protected function transformDataToArray($data, string $type): array throw new InvalidArgumentException(sprintf('Invalid type "%s" used upon transforming data to array.', $type)); } - if ($this->prohibitInsertEmpty && empty($data)) { + if (! $this->allowEmptyInserts && empty($data)) { throw DataException::forEmptyDataset($type); } @@ -1667,7 +1664,7 @@ protected function transformDataToArray($data, string $type): array } // If it's still empty here, means $data is no change or is empty object - if ($this->prohibitInsertEmpty && empty($data)) { + if (! $this->allowEmptyInserts && empty($data)) { throw DataException::forEmptyDataset($type); } @@ -1775,11 +1772,11 @@ protected function fillPlaceholders(array $rules, array $data): array } /** - * Permits inserting empty date in the next insertion. + * Sets $allowEmptyInserts. */ - public function permitInsertEmpty(): self + public function allowEmptyInserts(bool $value = true): self { - $this->prohibitInsertEmpty = false; + $this->allowEmptyInserts = $value; return $this; } diff --git a/system/Model.php b/system/Model.php index 776906178611..0d462f9eb93f 100644 --- a/system/Model.php +++ b/system/Model.php @@ -275,7 +275,7 @@ protected function doInsert(array $data) $builder->set($key, $val, $escape[$key] ?? null); } - if (! $this->prohibitInsertEmpty && empty($data)) { + if ($this->allowEmptyInserts && empty($data)) { $table = $this->db->protectIdentifiers($this->table, true, null, false); if ($this->db->getPlatform() === 'MySQLi') { $sql = 'INSERT INTO ' . $table . ' VALUES ()'; diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 0b3833f2d079..7cf1ceb87dde 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -220,7 +220,7 @@ public function testInsertPermitInsertNoData(): void ]; }; - $model->permitInsertEmpty()->insert([]); + $model->allowEmptyInserts()->insert([]); $this->seeInDatabase('insert_no_data', ['id' => $model->getInsertID()]); @@ -229,6 +229,7 @@ public function testInsertPermitInsertNoData(): void $this->expectException(DataException::class); $this->expectExceptionMessage('There is no data to insert.'); + $model->allowEmptyInserts(false); $model->insert([]); } From 7a8af5891f6d1f11fa997aedc2293fba9e424bf6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 12 Jun 2022 17:19:11 +0900 Subject: [PATCH 027/970] fix: OCI8 does not support `DEFAULT VALUES` Co-authored-by: ytetsuro --- system/Model.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/system/Model.php b/system/Model.php index 0d462f9eb93f..59fbef240668 100644 --- a/system/Model.php +++ b/system/Model.php @@ -279,6 +279,22 @@ protected function doInsert(array $data) $table = $this->db->protectIdentifiers($this->table, true, null, false); if ($this->db->getPlatform() === 'MySQLi') { $sql = 'INSERT INTO ' . $table . ' VALUES ()'; + } elseif ($this->db->getPlatform() === 'OCI8') { + $allFields = $this->db->protectIdentifiers( + array_map( + static fn ($row) => $row->name, + $this->db->getFieldData($this->table) + ), + false, + true + ); + + $sql = sprintf( + 'INSERT INTO %s (%s) VALUES (%s)', + $table, + implode(',', $allFields), + substr(str_repeat(',DEFAULT', count($allFields)), 1) + ); } else { $sql = 'INSERT INTO ' . $table . ' DEFAULT VALUES'; } From a48cba9c259bb75b80b897bb7605bde5e0e82ef1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 15 Jun 2022 16:19:26 +0900 Subject: [PATCH 028/970] docs: add docs --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/models/model.rst | 11 +++++++++++ user_guide_src/source/models/model/056.php | 3 +++ 3 files changed, 15 insertions(+) create mode 100644 user_guide_src/source/models/model/056.php diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 79a71bb07b46..0b5a0c91d403 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -21,6 +21,7 @@ Enhancements - Added the ``StreamFilterTrait`` to make it easier to work with capturing data from STDOUT and STDERR streams. See :ref:`testing-overview-stream-filters`. - Added before and after events to ``BaseModel::insertBatch()`` and ``BaseModel::updateBatch()`` methods. See :ref:`model-events-callbacks`. +- Added ``Model::allowEmptyInserts()`` method to insert empty data. See :ref:`Using CodeIgniter's Model ` - Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization ` - The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. diff --git a/user_guide_src/source/models/model.rst b/user_guide_src/source/models/model.rst index 9f89344aac78..252b3f26b006 100644 --- a/user_guide_src/source/models/model.rst +++ b/user_guide_src/source/models/model.rst @@ -310,6 +310,17 @@ the array's values are the values to save for that key: You can retrieve the last inserted row's primary key using the ``getInsertID()`` method. +.. _model-allow-empty-inserts: + +allowEmptyInserts() +------------------- + +Since v4.3.0, you can use ``allowEmptyInserts()`` method to insert empty data. The Model throws an exception when you try to insert empty data by default. But if you call this method, the check will no longer be performed. + +.. literalinclude:: model/056.php + +You can enable the check again by calling ``allowEmptyInserts(false)``. + update() -------- diff --git a/user_guide_src/source/models/model/056.php b/user_guide_src/source/models/model/056.php new file mode 100644 index 000000000000..9635a1c1d095 --- /dev/null +++ b/user_guide_src/source/models/model/056.php @@ -0,0 +1,3 @@ +allowEmptyInserts()->insert([]); From 0815370ebdd4c0347a325e5f9be11db12e478c94 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Jun 2022 11:09:12 +0900 Subject: [PATCH 029/970] config: always set DBDebug to true --- app/Config/Database.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Config/Database.php b/app/Config/Database.php index 87d73b13ad44..c6ed959b3d38 100644 --- a/app/Config/Database.php +++ b/app/Config/Database.php @@ -39,7 +39,7 @@ class Database extends Config 'DBDriver' => 'MySQLi', 'DBPrefix' => '', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', @@ -65,7 +65,7 @@ class Database extends Config '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'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', From ee9f231b6d3b8bd381b28482e35ff07abbcc6fbe Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Jun 2022 11:11:11 +0900 Subject: [PATCH 030/970] docs: revise description to be more accurate --- system/Database/BaseConnection.php | 2 +- user_guide_src/source/database/configuration.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 0e103a515f00..7e52235de1f3 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -124,7 +124,7 @@ abstract class BaseConnection implements ConnectionInterface /** * Debug flag * - * Whether to display error messages. + * Whether to throw Exception or not when an error occurs. * * @var bool */ diff --git a/user_guide_src/source/database/configuration.rst b/user_guide_src/source/database/configuration.rst index eb24f7342fde..150af7cf2dbe 100644 --- a/user_guide_src/source/database/configuration.rst +++ b/user_guide_src/source/database/configuration.rst @@ -118,7 +118,7 @@ Explanation of Values: :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. +**DBDebug** true/false (boolean) - Whether to throw exceptions or not when database errors occur. **charset** The character set used in communicating with the database. **DBCollat** The character collation used in communicating with the database (``MySQLi`` only) **swapPre** A default table prefix that should be swapped with ``DBPrefix``. This is useful for distributed From ade71e48f1cb58b9b81f84f9a74cd46d0d118b49 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 17 Jun 2022 11:19:56 +0900 Subject: [PATCH 031/970] docs: update sample code --- user_guide_src/source/database/connecting/006.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/database/connecting/006.php b/user_guide_src/source/database/connecting/006.php index f0d7d969cbf5..55e8010730d2 100644 --- a/user_guide_src/source/database/connecting/006.php +++ b/user_guide_src/source/database/connecting/006.php @@ -9,7 +9,7 @@ 'DBDriver' => 'MySQLi', 'DBPrefix' => '', 'pConnect' => false, - 'DBDebug' => (ENVIRONMENT !== 'production'), + 'DBDebug' => true, 'charset' => 'utf8', 'DBCollat' => 'utf8_general_ci', 'swapPre' => '', From bb68d0348b41d033ed692393ff09f64322f269e3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Jun 2022 15:40:14 +0900 Subject: [PATCH 032/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 0b5a0c91d403..1b5ba694f768 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -28,6 +28,7 @@ Enhancements Changes ******* +- Be consistent in the behaviors regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. - Changed the processing of Spark commands: - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. - The ``CodeIgniter::isSparked()`` method has been removed. From ea8ff2b782f947841e348a23558a35197d9fac41 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 09:05:29 +0900 Subject: [PATCH 033/970] docs: fix by proofreading Co-authored-by: MGatner --- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 1b5ba694f768..62b3b203394c 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -28,7 +28,7 @@ Enhancements Changes ******* -- Be consistent in the behaviors regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. +- To be consistent in behavior regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. - Changed the processing of Spark commands: - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. - The ``CodeIgniter::isSparked()`` method has been removed. From d1bc12731417e7f19d6bac1d1399a530f7f2a987 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 20 Jun 2022 16:03:48 +0900 Subject: [PATCH 034/970] fix: throws DatabaseException in query() and execute() --- system/Database/BaseConnection.php | 9 ++++++--- system/Database/MySQLi/Connection.php | 2 +- system/Database/OCI8/Connection.php | 2 +- system/Database/Postgre/Connection.php | 3 ++- system/Database/SQLSRV/Connection.php | 4 ++-- system/Database/SQLite3/Connection.php | 3 ++- tests/system/Database/Live/BadQueryTest.php | 5 ++--- tests/system/Database/Live/DbDebugTest.php | 3 ++- 8 files changed, 18 insertions(+), 13 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index 7ee8b7621c60..e980ba163193 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -14,7 +14,6 @@ use Closure; use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Events\Events; -use Exception; use stdClass; use Throwable; @@ -616,7 +615,7 @@ public function query(string $sql, $binds = null, bool $setEscapeFlags = true, s try { $exception = null; $this->resultID = $this->simpleQuery($query->getQuery()); - } catch (Exception $exception) { + } catch (DatabaseException $exception) { $this->resultID = false; } @@ -647,7 +646,11 @@ public function query(string $sql, $binds = null, bool $setEscapeFlags = true, s Events::trigger('DBQuery', $query); if ($exception !== null) { - throw $exception; + throw new DatabaseException( + $exception->getMessage(), + $exception->getCode(), + $exception + ); } return false; diff --git a/system/Database/MySQLi/Connection.php b/system/Database/MySQLi/Connection.php index 5badaf1c4881..14458aeaed1c 100644 --- a/system/Database/MySQLi/Connection.php +++ b/system/Database/MySQLi/Connection.php @@ -294,7 +294,7 @@ protected function execute(string $sql) log_message('error', $e->getMessage()); if ($this->DBDebug) { - throw $e; + throw new DatabaseException($e->getMessage(), $e->getCode(), $e); } } diff --git a/system/Database/OCI8/Connection.php b/system/Database/OCI8/Connection.php index dc0b26f57c0e..783a4b9ab641 100644 --- a/system/Database/OCI8/Connection.php +++ b/system/Database/OCI8/Connection.php @@ -207,7 +207,7 @@ protected function execute(string $sql) log_message('error', $e->getMessage()); if ($this->DBDebug) { - throw $e; + throw new DatabaseException($e->getMessage(), $e->getCode(), $e); } } diff --git a/system/Database/Postgre/Connection.php b/system/Database/Postgre/Connection.php index 6827ba70b54f..b7c0631f7650 100644 --- a/system/Database/Postgre/Connection.php +++ b/system/Database/Postgre/Connection.php @@ -135,8 +135,9 @@ protected function execute(string $sql) return pg_query($this->connID, $sql); } catch (ErrorException $e) { log_message('error', $e); + if ($this->DBDebug) { - throw $e; + throw new DatabaseException($e->getMessage(), $e->getCode(), $e); } } diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index f180ca4f6b3b..7d8e2b2975f1 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -13,7 +13,6 @@ use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\Exceptions\DatabaseException; -use Exception; use stdClass; /** @@ -457,8 +456,9 @@ protected function execute(string $sql) $error = $this->error(); log_message('error', $error['message']); + if ($this->DBDebug) { - throw new Exception($error['message']); + throw new DatabaseException($error['message']); } } diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 9f7b0baae1b3..7a0a2339abe5 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -130,8 +130,9 @@ protected function execute(string $sql) : $this->connID->query($sql); } catch (ErrorException $e) { log_message('error', $e); + if ($this->DBDebug) { - throw $e; + throw new DatabaseException($e->getMessage(), $e->getCode(), $e); } } diff --git a/tests/system/Database/Live/BadQueryTest.php b/tests/system/Database/Live/BadQueryTest.php index 86189c8b9f87..6ae58b182ad2 100644 --- a/tests/system/Database/Live/BadQueryTest.php +++ b/tests/system/Database/Live/BadQueryTest.php @@ -11,9 +11,9 @@ namespace CodeIgniter\Database\Live; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; -use Exception; use Tests\Support\Database\Seeds\CITestSeeder; /** @@ -32,8 +32,7 @@ public function testBadQueryDebugTrue() { $this->enableDBDebug(); - // expect an exception, class and message varies by DBMS - $this->expectException(Exception::class); + $this->expectException(DatabaseException::class); $this->db->query('SELECT * FROM table_does_not_exist'); diff --git a/tests/system/Database/Live/DbDebugTest.php b/tests/system/Database/Live/DbDebugTest.php index 0322ce192961..3f781cad4979 100644 --- a/tests/system/Database/Live/DbDebugTest.php +++ b/tests/system/Database/Live/DbDebugTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Database\Live; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; @@ -29,7 +30,7 @@ public function testDBDebugTrue() { $this->enableDBDebug(); - $this->expectException('Exception'); + $this->expectException(DatabaseException::class); $this->db->simpleQuery('SELECT * FROM db_error'); } From a8d7dcc7029ac478f6df4bafc8d2edd20672bd16 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 09:47:16 +0900 Subject: [PATCH 035/970] fix: throws DatabaseException in execute() --- system/Database/BasePreparedQuery.php | 9 ++++++++- tests/system/Database/Live/PreparedQueryTest.php | 14 ++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/system/Database/BasePreparedQuery.php b/system/Database/BasePreparedQuery.php index ce5a208a1ef3..a709c21fab69 100644 --- a/system/Database/BasePreparedQuery.php +++ b/system/Database/BasePreparedQuery.php @@ -11,8 +11,11 @@ namespace CodeIgniter\Database; +use ArgumentCountError; use BadMethodCallException; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Events\Events; +use ErrorException; /** * Base prepared query @@ -108,7 +111,11 @@ public function execute(...$data) // Execute the Query. $startTime = microtime(true); - $this->_execute($data); + try { + $this->_execute($data); + } catch (ArgumentCountError|ErrorException $e) { + throw new DatabaseException($e->getMessage(), $e->getCode(), $e); + } // Update our query object $query = clone $this->query; diff --git a/tests/system/Database/Live/PreparedQueryTest.php b/tests/system/Database/Live/PreparedQueryTest.php index 9169f2446c8d..3d61d1769232 100644 --- a/tests/system/Database/Live/PreparedQueryTest.php +++ b/tests/system/Database/Live/PreparedQueryTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Database\Live; use CodeIgniter\Database\BasePreparedQuery; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Query; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\DatabaseTestTrait; @@ -134,4 +135,17 @@ public function testExecuteRunsQueryAndReturnsManualResultObject() $this->seeInDatabase($this->db->DBPrefix . 'user', ['name' => 'foo', 'email' => 'foo@example.com']); $this->seeInDatabase($this->db->DBPrefix . 'user', ['name' => 'bar', 'email' => 'bar@example.com']); } + + public function testExecuteRunsInvalidQuery() + { + $this->expectException(DatabaseException::class); + + // Not null `country` is missing + $this->query = $this->db->prepare(static fn ($db) => $db->table('user')->insert([ + 'name' => 'a', + 'email' => 'b@example.com', + ])); + + $this->query->execute('foo', 'foo@example.com', 'US'); + } } From 8fbd94b38166e50bd556a0f09faa1ba564378967 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 11:38:03 +0900 Subject: [PATCH 036/970] fix: throws DatabaseException in SQLSRV execute() --- system/Database/SQLSRV/PreparedQuery.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/system/Database/SQLSRV/PreparedQuery.php b/system/Database/SQLSRV/PreparedQuery.php index e91fa78ea35f..7af30621125a 100755 --- a/system/Database/SQLSRV/PreparedQuery.php +++ b/system/Database/SQLSRV/PreparedQuery.php @@ -13,6 +13,7 @@ use BadMethodCallException; use CodeIgniter\Database\BasePreparedQuery; +use CodeIgniter\Database\Exceptions\DatabaseException; use Exception; /** @@ -82,6 +83,16 @@ public function _execute(array $data): bool $this->result = sqlsrv_execute($this->statement); + if ($this->result === false && $this->db->DBDebug) { + $errors = []; + + foreach (sqlsrv_errors() as $error) { + $errors[] = $error['message'] . ' SQLSTATE: ' . $error['SQLSTATE'] . ', code: ' . $error['code']; + } + + throw new DatabaseException(implode("\n", $errors)); + } + return (bool) $this->result; } From 344562ab1b8b3337ea5c19e8fbfcc9258452229a Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 13:07:54 +0900 Subject: [PATCH 037/970] feat: SQLSRV: include all error information in exception messages --- system/Database/SQLSRV/Connection.php | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/system/Database/SQLSRV/Connection.php b/system/Database/SQLSRV/Connection.php index 7d8e2b2975f1..06d1f169d924 100755 --- a/system/Database/SQLSRV/Connection.php +++ b/system/Database/SQLSRV/Connection.php @@ -137,13 +137,24 @@ public function connect(bool $persistent = false) return $this->connID; } + throw new DatabaseException($this->getAllErrorMessages()); + } + + /** + * For exception message + * + * @internal + */ + public function getAllErrorMessages(): string + { $errors = []; - foreach (sqlsrv_errors(SQLSRV_ERR_ERRORS) as $error) { - $errors[] = preg_replace('/(\[.+\]\[.+\](?:\[.+\])?)(.+)/', '$2', $error['message']); + foreach (sqlsrv_errors() as $error) { + $errors[] = $error['message'] + . ' SQLSTATE: ' . $error['SQLSTATE'] . ', code: ' . $error['code']; } - throw new DatabaseException(implode("\n", $errors)); + return implode("\n", $errors); } /** From 47b023a62ba7604817146732e0efb307d3f88aff Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 13:09:15 +0900 Subject: [PATCH 038/970] refactor: use $this->db->getAllErrorMessages() --- system/Database/SQLSRV/PreparedQuery.php | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/system/Database/SQLSRV/PreparedQuery.php b/system/Database/SQLSRV/PreparedQuery.php index 7af30621125a..2e1de3076699 100755 --- a/system/Database/SQLSRV/PreparedQuery.php +++ b/system/Database/SQLSRV/PreparedQuery.php @@ -35,6 +35,18 @@ class PreparedQuery extends BasePreparedQuery */ protected $result; + /** + * A reference to the db connection to use. + * + * @var Connection + */ + protected $db; + + public function __construct(Connection $db) + { + parent::__construct($db); + } + /** * Prepares the query against the database, and saves the connection * info necessary to execute the query later. @@ -84,13 +96,7 @@ public function _execute(array $data): bool $this->result = sqlsrv_execute($this->statement); if ($this->result === false && $this->db->DBDebug) { - $errors = []; - - foreach (sqlsrv_errors() as $error) { - $errors[] = $error['message'] . ' SQLSTATE: ' . $error['SQLSTATE'] . ', code: ' . $error['code']; - } - - throw new DatabaseException(implode("\n", $errors)); + throw new DatabaseException($this->db->getAllErrorMessages()); } return (bool) $this->result; From 1f18ed955c38470a0df506f5431031e9716dbb40 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 13:10:00 +0900 Subject: [PATCH 039/970] fix: throws DatabaseException in SQLSRV prepare() --- system/Database/SQLSRV/PreparedQuery.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/system/Database/SQLSRV/PreparedQuery.php b/system/Database/SQLSRV/PreparedQuery.php index 2e1de3076699..8f62069b3309 100755 --- a/system/Database/SQLSRV/PreparedQuery.php +++ b/system/Database/SQLSRV/PreparedQuery.php @@ -71,6 +71,10 @@ public function _prepare(string $sql, array $options = []) $this->statement = sqlsrv_prepare($this->db->connID, $sql, $parameters); if (! $this->statement) { + if ($this->db->DBDebug) { + throw new DatabaseException($this->db->getAllErrorMessages()); + } + $info = $this->db->error(); $this->errorCode = $info['code']; $this->errorString = $info['message']; From 3d9d725bed61fc445bcd3f06408dca5df4aae2ef Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 21 Jun 2022 15:42:07 +0900 Subject: [PATCH 040/970] fix: throws DatabaseException in MySQL/OCI8/Postgre/SQLite3 prepare() --- system/Database/MySQLi/PreparedQuery.php | 5 +++++ system/Database/OCI8/PreparedQuery.php | 5 +++++ system/Database/Postgre/PreparedQuery.php | 5 +++++ system/Database/SQLite3/PreparedQuery.php | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/system/Database/MySQLi/PreparedQuery.php b/system/Database/MySQLi/PreparedQuery.php index cd351f2c51fa..43efb4841809 100644 --- a/system/Database/MySQLi/PreparedQuery.php +++ b/system/Database/MySQLi/PreparedQuery.php @@ -13,6 +13,7 @@ use BadMethodCallException; use CodeIgniter\Database\BasePreparedQuery; +use CodeIgniter\Database\Exceptions\DatabaseException; /** * Prepared query for MySQLi @@ -40,6 +41,10 @@ public function _prepare(string $sql, array $options = []) if (! $this->statement = $this->db->mysqli->prepare($sql)) { $this->errorCode = $this->db->mysqli->errno; $this->errorString = $this->db->mysqli->error; + + if ($this->db->DBDebug) { + throw new DatabaseException($this->errorString . ' code: ' . $this->errorCode); + } } return $this; diff --git a/system/Database/OCI8/PreparedQuery.php b/system/Database/OCI8/PreparedQuery.php index 311dacc4045f..627e12f25ba6 100644 --- a/system/Database/OCI8/PreparedQuery.php +++ b/system/Database/OCI8/PreparedQuery.php @@ -13,6 +13,7 @@ use BadMethodCallException; use CodeIgniter\Database\BasePreparedQuery; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\PreparedQueryInterface; /** @@ -50,6 +51,10 @@ public function _prepare(string $sql, array $options = []) $error = oci_error($this->db->connID); $this->errorCode = $error['code'] ?? 0; $this->errorString = $error['message'] ?? ''; + + if ($this->db->DBDebug) { + throw new DatabaseException($this->errorString . ' code: ' . $this->errorCode); + } } $this->lastInsertTableName = $this->db->parseInsertTableName($sql); diff --git a/system/Database/Postgre/PreparedQuery.php b/system/Database/Postgre/PreparedQuery.php index 890534663256..5291250aef98 100644 --- a/system/Database/Postgre/PreparedQuery.php +++ b/system/Database/Postgre/PreparedQuery.php @@ -13,6 +13,7 @@ use BadMethodCallException; use CodeIgniter\Database\BasePreparedQuery; +use CodeIgniter\Database\Exceptions\DatabaseException; use Exception; /** @@ -63,6 +64,10 @@ public function _prepare(string $sql, array $options = []) if (! $this->statement = pg_prepare($this->db->connID, $this->name, $sql)) { $this->errorCode = 0; $this->errorString = pg_last_error($this->db->connID); + + if ($this->db->DBDebug) { + throw new DatabaseException($this->errorString . ' code: ' . $this->errorCode); + } } return $this; diff --git a/system/Database/SQLite3/PreparedQuery.php b/system/Database/SQLite3/PreparedQuery.php index 7dada92b6226..d6857fe81259 100644 --- a/system/Database/SQLite3/PreparedQuery.php +++ b/system/Database/SQLite3/PreparedQuery.php @@ -13,6 +13,7 @@ use BadMethodCallException; use CodeIgniter\Database\BasePreparedQuery; +use CodeIgniter\Database\Exceptions\DatabaseException; /** * Prepared query for SQLite3 @@ -43,6 +44,10 @@ public function _prepare(string $sql, array $options = []) if (! ($this->statement = $this->db->connID->prepare($sql))) { $this->errorCode = $this->db->connID->lastErrorCode(); $this->errorString = $this->db->connID->lastErrorMsg(); + + if ($this->db->DBDebug) { + throw new DatabaseException($this->errorString . ' code: ' . $this->errorCode); + } } return $this; From 32cac8e9d17810875df14d35844390392a3a3463 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 24 Jun 2022 10:24:30 +0900 Subject: [PATCH 041/970] docs: add user guide --- user_guide_src/source/changelogs/v4.3.0.rst | 12 ++++++++++++ user_guide_src/source/installation/upgrade_430.rst | 5 +++++ 2 files changed, 17 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 62b3b203394c..4f9f9b3169bf 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -14,6 +14,18 @@ BREAKING Behavior Changes ================ + +.. _exceptions-when-database-errors-occur: + +Exceptions when Database Errors Occur +------------------------------------- + +- The exceptions thrown by the database connection classes have been changed to ``CodeIgniter\Database\Exceptions\DatabaseException``. Previously, different database drivers threw different exception classes, but these have been unified into ``DatabaseException``. +- The exceptions thrown by the ``execute()`` method of Prepared Queries have been changed to ``DatabaseException``. Previously, different database drivers might throw different exception classes or did not throw exceptions, but these have been unified into ``DatabaseException``. + +Others +------ + - The ``spark`` file has been changed due to a change in the processing of Spark commands. Enhancements diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst index 2f35abf47156..aaf11e8947fa 100644 --- a/user_guide_src/source/installation/upgrade_430.rst +++ b/user_guide_src/source/installation/upgrade_430.rst @@ -30,6 +30,11 @@ The following files received significant changes and > composer update > cp vendor/codeigniter4/framework/spark . +Breaking Changes +**************** + +- The exception classes may be changed when database errors occur. If you catch the exceptions, you must confirm that your code can catch the exceptions. See :ref:`exceptions-when-database-errors-occur` for details. + Breaking Enhancements ********************* From 567b1a1581dc3e86041f73859a4e722eea2a1339 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 24 Jun 2022 10:40:49 +0900 Subject: [PATCH 042/970] config: change the $DBDebug default value to true in BaseConnection --- system/Database/BaseConnection.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/Database/BaseConnection.php b/system/Database/BaseConnection.php index e980ba163193..f7ba9396ea0e 100644 --- a/system/Database/BaseConnection.php +++ b/system/Database/BaseConnection.php @@ -121,13 +121,11 @@ abstract class BaseConnection implements ConnectionInterface protected $pConnect = false; /** - * Debug flag - * * Whether to throw Exception or not when an error occurs. * * @var bool */ - protected $DBDebug = false; + protected $DBDebug = true; /** * Character set From 773ccb5de1255b865f4118fe58b18d51052b149f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 24 Jun 2022 10:45:48 +0900 Subject: [PATCH 043/970] refactor: replace CI_DEBUG with $this->db->DBDebug When $this->db->DBDebug is true, always throws Exceptions. --- system/Database/BaseBuilder.php | 22 +++++++++++----------- system/Database/Postgre/Builder.php | 2 +- system/Database/SQLSRV/Builder.php | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index 852708b8af2f..d2760b732e18 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -895,7 +895,7 @@ public function orHavingNotIn(?string $key = null, $values = null, ?bool $escape protected function _whereIn(?string $key = null, $values = null, bool $not = false, string $type = 'AND ', ?bool $escape = null, string $clause = 'QBWhere') { if (empty($key) || ! is_string($key)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new InvalidArgumentException(sprintf('%s() expects $key to be a non-empty string', debug_backtrace(0, 2)[1]['function'])); } @@ -903,7 +903,7 @@ protected function _whereIn(?string $key = null, $values = null, bool $not = fal } if ($values === null || (! is_array($values) && ! $this->isSubquery($values))) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); } @@ -1738,14 +1738,14 @@ public function insertBatch(?array $set = null, ?bool $escape = null, int $batch { if ($set === null) { if (empty($this->QBSet)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to update an entry.'); } return false; // @codeCoverageIgnore } } elseif (empty($set)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('insertBatch() called with no data'); } @@ -1922,7 +1922,7 @@ public function insert(?array $set = null, ?bool $escape = null) protected function validateInsert(): bool { if (empty($this->QBSet)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to insert an entry.'); } @@ -1954,7 +1954,7 @@ public function replace(?array $set = null) } if (empty($this->QBSet)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to update an entry.'); } @@ -2085,7 +2085,7 @@ protected function _update(string $table, array $values): string protected function validateUpdate(): bool { if (empty($this->QBSet)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to update an entry.'); } @@ -2105,7 +2105,7 @@ protected function validateUpdate(): bool public function updateBatch(?array $set = null, ?string $index = null, int $batchSize = 100) { if ($index === null) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must specify an index to match on for batch updates.'); } @@ -2114,14 +2114,14 @@ public function updateBatch(?array $set = null, ?string $index = null, int $batc if ($set === null) { if (empty($this->QBSet)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to update an entry.'); } return false; // @codeCoverageIgnore } } elseif (empty($set)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('updateBatch() called with no data'); } @@ -2330,7 +2330,7 @@ public function delete($where = '', ?int $limit = null, bool $resetData = true) } if (empty($this->QBWhere)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('Deletes are not allowed unless they contain a "where" or "like" clause.'); } diff --git a/system/Database/Postgre/Builder.php b/system/Database/Postgre/Builder.php index b0a94670ff18..71c8a1f2b6c3 100644 --- a/system/Database/Postgre/Builder.php +++ b/system/Database/Postgre/Builder.php @@ -146,7 +146,7 @@ public function replace(?array $set = null) } if (! $this->QBSet) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to update an entry.'); } diff --git a/system/Database/SQLSRV/Builder.php b/system/Database/SQLSRV/Builder.php index 8d0e0b419620..c8b989f923ed 100755 --- a/system/Database/SQLSRV/Builder.php +++ b/system/Database/SQLSRV/Builder.php @@ -350,7 +350,7 @@ public function replace(?array $set = null) } if (empty($this->QBSet)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('You must use the "set" method to update an entry.'); } @@ -532,7 +532,7 @@ public function delete($where = '', ?int $limit = null, bool $resetData = true) } if (empty($this->QBWhere)) { - if (CI_DEBUG) { + if ($this->db->DBDebug) { throw new DatabaseException('Deletes are not allowed unless they contain a "where" or "like" clause.'); } From f336cf8539b124c75e79784da8c5851c9cf4c0b0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 24 Jun 2022 10:46:08 +0900 Subject: [PATCH 044/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 4f9f9b3169bf..e310c8d5615b 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -41,6 +41,7 @@ Changes ******* - To be consistent in behavior regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. +- The default value of ``BaseConnection::$DBDebu`` has been changed to ``true``. - Changed the processing of Spark commands: - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. - The ``CodeIgniter::isSparked()`` method has been removed. From 9e2faf4f3349ca32f5af45b78a72d1e4d28f2e20 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 24 Jun 2022 11:32:19 +0900 Subject: [PATCH 045/970] docs: fix typo --- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index e310c8d5615b..96ce0fe18730 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -41,7 +41,7 @@ Changes ******* - To be consistent in behavior regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. -- The default value of ``BaseConnection::$DBDebu`` has been changed to ``true``. +- The default value of ``BaseConnection::$DBDebug`` has been changed to ``true``. - Changed the processing of Spark commands: - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. - The ``CodeIgniter::isSparked()`` method has been removed. From 1d711130be8b5de02d5742d23be433ba90fee891 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Jun 2022 10:45:55 +0900 Subject: [PATCH 046/970] fix: LogicException is suppressed when $DBDebug (CI_DEBUG) is true --- system/Database/BaseBuilder.php | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/system/Database/BaseBuilder.php b/system/Database/BaseBuilder.php index d2760b732e18..656e9cdaf071 100644 --- a/system/Database/BaseBuilder.php +++ b/system/Database/BaseBuilder.php @@ -895,19 +895,11 @@ public function orHavingNotIn(?string $key = null, $values = null, ?bool $escape protected function _whereIn(?string $key = null, $values = null, bool $not = false, string $type = 'AND ', ?bool $escape = null, string $clause = 'QBWhere') { if (empty($key) || ! is_string($key)) { - if ($this->db->DBDebug) { - throw new InvalidArgumentException(sprintf('%s() expects $key to be a non-empty string', debug_backtrace(0, 2)[1]['function'])); - } - - return $this; // @codeCoverageIgnore + throw new InvalidArgumentException(sprintf('%s() expects $key to be a non-empty string', debug_backtrace(0, 2)[1]['function'])); } if ($values === null || (! is_array($values) && ! $this->isSubquery($values))) { - if ($this->db->DBDebug) { - throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); - } - - return $this; // @codeCoverageIgnore + throw new InvalidArgumentException(sprintf('%s() expects $values to be of type array or closure', debug_backtrace(0, 2)[1]['function'])); } if (! is_bool($escape)) { From d57c7636d6ede74561ff519ba9c49a73b2def921 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Jun 2022 11:03:42 +0900 Subject: [PATCH 047/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 96ce0fe18730..369ac96dd5f4 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -27,6 +27,7 @@ Others ------ - The ``spark`` file has been changed due to a change in the processing of Spark commands. +- ``InvalidArgumentException`` that is a kind of ``LogicException`` in ``BaseBuilder::_whereIn()`` is not suppressed by the configuration. Previously if ``CI_DEBUG`` was true, the exception was suppressed. Enhancements ************ @@ -41,6 +42,7 @@ Changes ******* - To be consistent in behavior regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. +- ``DatabaseException`` thrown in ``BaseBuilder`` is thrown if ``$DBDebug`` is true. Previously, it is thrown if ``CI_DEBUG`` is true. - The default value of ``BaseConnection::$DBDebug`` has been changed to ``true``. - Changed the processing of Spark commands: - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. From eca175f2e6e8b700f50ec6697533241494e9fd24 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 26 Jun 2022 11:15:44 +0900 Subject: [PATCH 048/970] docs: add about DBDebug --- user_guide_src/source/changelogs/v4.3.0.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 369ac96dd5f4..1377403bfed4 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -41,9 +41,11 @@ Enhancements Changes ******* -- To be consistent in behavior regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. -- ``DatabaseException`` thrown in ``BaseBuilder`` is thrown if ``$DBDebug`` is true. Previously, it is thrown if ``CI_DEBUG`` is true. -- The default value of ``BaseConnection::$DBDebug`` has been changed to ``true``. +- DBDebug + - To be consistent in behavior regardless of environments, ``Config\Database::$default['DBDebug']`` and ``Config\Database::$tests['DBDebug']`` has been changed to ``true`` by default. With these settings, an exception is always thrown when a database error occurs. + - Now ``DatabaseException`` thrown in ``BaseBuilder`` is thrown if ``$DBDebug`` is true. Previously, it is thrown if ``CI_DEBUG`` is true. + - The default value of ``BaseConnection::$DBDebug`` has been changed to ``true``. + - With these changes, ``DBDebug`` now means whether or not to throw an exception when an error occurs. Although unrelated to debugging, the name has not been changed. - Changed the processing of Spark commands: - The ``CodeIgniter\CodeIgniter`` no longer handles Spark commands. - The ``CodeIgniter::isSparked()`` method has been removed. From 0b8072e967b5e90db3ed6bd91ae1afea3071222c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 27 Jun 2022 06:54:55 +0900 Subject: [PATCH 049/970] docs: fix wrong bool value --- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 1377403bfed4..8ace9de77261 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -27,7 +27,7 @@ Others ------ - The ``spark`` file has been changed due to a change in the processing of Spark commands. -- ``InvalidArgumentException`` that is a kind of ``LogicException`` in ``BaseBuilder::_whereIn()`` is not suppressed by the configuration. Previously if ``CI_DEBUG`` was true, the exception was suppressed. +- ``InvalidArgumentException`` that is a kind of ``LogicException`` in ``BaseBuilder::_whereIn()`` is not suppressed by the configuration. Previously if ``CI_DEBUG`` was false, the exception was suppressed. Enhancements ************ From e6c000896c53d06af98f317fa6a7e6374908f6ae Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 28 Jun 2022 11:33:20 +0900 Subject: [PATCH 050/970] feat: throw Exception if file path contains special char --- system/Autoloader/Autoloader.php | 14 ++++++++++---- tests/system/Autoloader/AutoloaderTest.php | 13 +++++++------ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 311428fe4165..6ab7804f8dd6 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -290,9 +290,9 @@ protected function includeFile(string $file) } /** - * Sanitizes a filename, replacing spaces with dashes. + * Check file path. * - * Removes special characters that are illegal in filenames on certain + * Checks special characters that are illegal in filenames on certain * operating systems and special characters requiring special escaping * to manipulate at the command line. Replaces spaces and consecutive * dashes with a single dash. Trim period, dash and underscore from beginning @@ -306,10 +306,16 @@ public function sanitizeFilename(string $filename): string // Plus the forward slash for directory separators since this might be a path. // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_278 // Modified to allow backslash and colons for on Windows machines. - $filename = preg_replace('/[^0-9\p{L}\s\/\-\_\.\:\\\\]/u', '', $filename); + $tmp = preg_replace('/[^0-9\p{L}\s\/\-\_\.\:\\\\]/u', '', $filename); // Clean up our filename edges. - return trim($filename, '.-_'); + $cleanFilename = trim($tmp, '.-_'); + + if ($filename !== $cleanFilename) { + throw new InvalidArgumentException('The file path contains special character that is not allowed: "' . $filename . '"'); + } + + return $cleanFilename; } private function loadComposerNamespaces(ClassLoader $composer): void diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index bcf91b90b679..0b33fa9ad0e3 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -16,6 +16,7 @@ use Config\Autoload; use Config\Modules; use Config\Services; +use InvalidArgumentException; use UnnamespacedClass; /** @@ -199,18 +200,18 @@ public function testloadClassNonNamespaced() public function testSanitizationSimply() { - $test = '${../path}!#/to/some/file.php_'; - $expected = '/path/to/some/file.php'; + $this->expectException(InvalidArgumentException::class); - $this->assertSame($expected, $this->loader->sanitizeFilename($test)); + $test = '${../path}!#/to/some/file.php_'; + + $this->loader->sanitizeFilename($test); } public function testSanitizationAllowUnicodeChars() { - $test = 'Ä/path/to/some/file.php_'; - $expected = 'Ä/path/to/some/file.php'; + $test = 'Ä/path/to/some/file.php'; - $this->assertSame($expected, $this->loader->sanitizeFilename($test)); + $this->assertSame($test, $this->loader->sanitizeFilename($test)); } public function testSanitizationAllowsWindowsFilepaths() From 62b20ac568ce17c6036ce7f35662e75ce87d9744 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 28 Jun 2022 15:01:53 +0900 Subject: [PATCH 051/970] feat: better exception message --- system/Autoloader/Autoloader.php | 19 ++++++++++++++++--- tests/system/Autoloader/AutoloaderTest.php | 17 ++++++++++++++++- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 6ab7804f8dd6..677c8d3a8572 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -15,6 +15,7 @@ use Config\Autoload; use Config\Modules; use InvalidArgumentException; +use RuntimeException; /** * An autoloader that uses both PSR4 autoloading, and traditional classmaps. @@ -306,13 +307,25 @@ public function sanitizeFilename(string $filename): string // Plus the forward slash for directory separators since this might be a path. // http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_278 // Modified to allow backslash and colons for on Windows machines. - $tmp = preg_replace('/[^0-9\p{L}\s\/\-\_\.\:\\\\]/u', '', $filename); + $result = preg_match_all('/[^0-9\p{L}\s\/\-_.:\\\\]/u', $filename, $matches); + + if ($result > 0) { + $chars = implode('', $matches[0]); + + throw new InvalidArgumentException( + 'The file path contains special characters "' . $chars + . '" that are not allowed: "' . $filename . '"' + ); + } + if ($result === false) { + throw new RuntimeException(preg_last_error_msg() . ' filename: "' . $filename . '"'); + } // Clean up our filename edges. - $cleanFilename = trim($tmp, '.-_'); + $cleanFilename = trim($filename, '.-_'); if ($filename !== $cleanFilename) { - throw new InvalidArgumentException('The file path contains special character that is not allowed: "' . $filename . '"'); + throw new InvalidArgumentException('The characters ".-_" are not allowed in filename edges: "' . $filename . '"'); } return $cleanFilename; diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 0b33fa9ad0e3..980f91756c5a 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -198,15 +198,30 @@ public function testloadClassNonNamespaced() $this->assertFalse($this->loader->loadClass('Modules')); } - public function testSanitizationSimply() + public function testSanitizationContailsSpecialChars() { $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'The file path contains special characters "${}!#" that are not allowed: "${../path}!#/to/some/file.php_"' + ); $test = '${../path}!#/to/some/file.php_'; $this->loader->sanitizeFilename($test); } + public function testSanitizationFilenameEdges() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'The characters ".-_" are not allowed in filename edges: "/path/to/some/file.php_"' + ); + + $test = '/path/to/some/file.php_'; + + $this->loader->sanitizeFilename($test); + } + public function testSanitizationAllowUnicodeChars() { $test = 'Ä/path/to/some/file.php'; From bbfd392db70b00a88beb8c9a1d13c56a8fc034b6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 16:00:38 +0900 Subject: [PATCH 052/970] test: add test for regex error --- tests/system/Autoloader/AutoloaderTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 980f91756c5a..215ad800a374 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -17,6 +17,7 @@ use Config\Modules; use Config\Services; use InvalidArgumentException; +use RuntimeException; use UnnamespacedClass; /** @@ -222,6 +223,16 @@ public function testSanitizationFilenameEdges() $this->loader->sanitizeFilename($test); } + public function testSanitizationRegexError() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage('Malformed UTF-8 characters, possibly incorrectly encoded filename:'); + + $test = mb_convert_encoding('クラスファイル.php', 'EUC-JP', 'UTF-8'); + + $this->loader->sanitizeFilename($test); + } + public function testSanitizationAllowUnicodeChars() { $test = 'Ä/path/to/some/file.php'; From 307e19487249e582e2eda640e2fb56ffe843de9c Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 16:46:07 +0900 Subject: [PATCH 053/970] fix: preg_last_error_msg() can be used in PHP 8.0 or later --- system/Autoloader/Autoloader.php | 8 +++++++- tests/system/Autoloader/AutoloaderTest.php | 1 - 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/system/Autoloader/Autoloader.php b/system/Autoloader/Autoloader.php index 677c8d3a8572..4178068a3e9c 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -318,7 +318,13 @@ public function sanitizeFilename(string $filename): string ); } if ($result === false) { - throw new RuntimeException(preg_last_error_msg() . ' filename: "' . $filename . '"'); + if (version_compare(PHP_VERSION, '8.0.0', '>=')) { + $message = preg_last_error_msg(); + } else { + $message = 'Regex error. error code: ' . preg_last_error(); + } + + throw new RuntimeException($message . '. filename: "' . $filename . '"'); } // Clean up our filename edges. diff --git a/tests/system/Autoloader/AutoloaderTest.php b/tests/system/Autoloader/AutoloaderTest.php index 215ad800a374..2e0224709e49 100644 --- a/tests/system/Autoloader/AutoloaderTest.php +++ b/tests/system/Autoloader/AutoloaderTest.php @@ -226,7 +226,6 @@ public function testSanitizationFilenameEdges() public function testSanitizationRegexError() { $this->expectException(RuntimeException::class); - $this->expectExceptionMessage('Malformed UTF-8 characters, possibly incorrectly encoded filename:'); $test = mb_convert_encoding('クラスファイル.php', 'EUC-JP', 'UTF-8'); From d9c4d8cc3cb66e247fb87fa0f5ac3ceb81bb86a1 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 16:54:55 +0900 Subject: [PATCH 054/970] chore: skip UnwrapFutureCompatibleIfPhpVersionRector --- rector.php | 1 + 1 file changed, 1 insertion(+) diff --git a/rector.php b/rector.php index e83bfcc18c63..82e2a9e40057 100644 --- a/rector.php +++ b/rector.php @@ -92,6 +92,7 @@ // check on constant compare UnwrapFutureCompatibleIfPhpVersionRector::class => [ __DIR__ . '/system/CodeIgniter.php', + __DIR__ . '/system/Autoloader/Autoloader.php', ], // session handlers have the gc() method with underscored parameter `$max_lifetime` From c66848f43afa4313f64170c58eff5c3bacfabcb2 Mon Sep 17 00:00:00 2001 From: MGatner Date: Mon, 27 Jun 2022 17:33:04 +0000 Subject: [PATCH 055/970] Apply config property types --- app/Config/App.php | 108 +++++++-------------------- app/Config/CURLRequest.php | 4 +- app/Config/Cache.php | 31 +++----- app/Config/ContentSecurityPolicy.php | 25 ++----- app/Config/Cookie.php | 27 ++----- app/Config/Database.php | 16 +--- app/Config/DocTypes.php | 2 +- app/Config/Email.php | 99 ++++++------------------ app/Config/Encryption.php | 16 +--- app/Config/Exceptions.php | 16 +--- app/Config/Feature.php | 4 +- app/Config/Filters.php | 16 +--- app/Config/Format.php | 6 +- app/Config/Generators.php | 2 +- app/Config/Honeypot.php | 20 ++--- app/Config/Images.php | 10 +-- app/Config/Kint.php | 20 ++--- app/Config/Logger.php | 10 +-- app/Config/Migrations.php | 12 +-- app/Config/Mimes.php | 4 +- app/Config/Pager.php | 6 +- app/Config/Paths.php | 20 ++--- app/Config/Routes.php | 6 ++ app/Config/Security.php | 33 +++----- app/Config/Toolbar.php | 18 ++--- app/Config/UserAgents.php | 8 +- app/Config/Validation.php | 4 +- 27 files changed, 157 insertions(+), 386 deletions(-) diff --git a/app/Config/App.php b/app/Config/App.php index 1a5e562ddd30..7741273bb237 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -21,10 +21,8 @@ class App extends BaseConfig * and path to your installation. However, you should always configure this * explicitly and never rely on auto-guessing, especially in production * environments. - * - * @var string */ - public $baseURL = 'http://localhost:8080/'; + public string $baseURL = 'http://localhost:8080/'; /** * -------------------------------------------------------------------------- @@ -34,10 +32,8 @@ class App extends BaseConfig * Typically this will be your index.php file, unless you've renamed it to * something else. If you are using mod_rewrite to remove the page set this * variable so that it is blank. - * - * @var string */ - public $indexPage = 'index.php'; + public string $indexPage = 'index.php'; /** * -------------------------------------------------------------------------- @@ -53,10 +49,8 @@ class App extends BaseConfig * 'PATH_INFO' Uses $_SERVER['PATH_INFO'] * * WARNING: If you set this to 'PATH_INFO', URIs will always be URL-decoded! - * - * @var string */ - public $uriProtocol = 'REQUEST_URI'; + public string $uriProtocol = 'REQUEST_URI'; /** * -------------------------------------------------------------------------- @@ -67,10 +61,8 @@ class App extends BaseConfig * is viewing the site from. It affects the language strings and other * strings (like currency markers, numbers, etc), that your program * should run under for this request. - * - * @var string */ - public $defaultLocale = 'en'; + public string $defaultLocale = 'en'; /** * -------------------------------------------------------------------------- @@ -81,10 +73,8 @@ class App extends BaseConfig * language to use based on the value of the Accept-Language header. * * If false, no automatic detection will be performed. - * - * @var bool */ - public $negotiateLocale = false; + public bool $negotiateLocale = false; /** * -------------------------------------------------------------------------- @@ -97,7 +87,7 @@ class App extends BaseConfig * * @var string[] */ - public $supportedLocales = ['en']; + public array $supportedLocales = ['en']; /** * -------------------------------------------------------------------------- @@ -106,10 +96,8 @@ class App extends BaseConfig * * The default timezone that will be used in your application to display * dates with the date helper, and can be retrieved through app_timezone() - * - * @var string */ - public $appTimezone = 'America/Chicago'; + public string $appTimezone = 'America/Chicago'; /** * -------------------------------------------------------------------------- @@ -120,10 +108,8 @@ class App extends BaseConfig * that require a character set to be provided. * * @see http://php.net/htmlspecialchars for a list of supported charsets. - * - * @var string */ - public $charset = 'UTF-8'; + public string $charset = 'UTF-8'; /** * -------------------------------------------------------------------------- @@ -134,10 +120,8 @@ class App extends BaseConfig * made via a secure connection (HTTPS). If the incoming request is not * secure, the user will be redirected to a secure version of the page * and the HTTP Strict Transport Security header will be set. - * - * @var bool */ - public $forceGlobalSecureRequests = false; + public bool $forceGlobalSecureRequests = false; /** * -------------------------------------------------------------------------- @@ -160,10 +144,8 @@ class App extends BaseConfig * -------------------------------------------------------------------------- * * The session cookie name, must contain only [0-9a-z_-] characters - * - * @var string */ - public $sessionCookieName = 'ci_session'; + public string $sessionCookieName = 'ci_session'; /** * -------------------------------------------------------------------------- @@ -172,10 +154,8 @@ class App extends BaseConfig * * The number of SECONDS you want the session to last. * Setting to 0 (zero) means expire when the browser is closed. - * - * @var int */ - public $sessionExpiration = 7200; + public int $sessionExpiration = 7200; /** * -------------------------------------------------------------------------- @@ -191,10 +171,8 @@ class App extends BaseConfig * Please read up the manual for the format with other session drivers. * * IMPORTANT: You are REQUIRED to set a valid save path! - * - * @var string */ - public $sessionSavePath = WRITEPATH . 'session'; + public string $sessionSavePath = WRITEPATH . 'session'; /** * -------------------------------------------------------------------------- @@ -205,10 +183,8 @@ class App extends BaseConfig * * WARNING: If you're using the database driver, don't forget to update * your session table's PRIMARY KEY when changing this setting. - * - * @var bool */ - public $sessionMatchIP = false; + public bool $sessionMatchIP = false; /** * -------------------------------------------------------------------------- @@ -216,10 +192,8 @@ class App extends BaseConfig * -------------------------------------------------------------------------- * * How many seconds between CI regenerating the session ID. - * - * @var int */ - public $sessionTimeToUpdate = 300; + public int $sessionTimeToUpdate = 300; /** * -------------------------------------------------------------------------- @@ -229,10 +203,8 @@ class App extends BaseConfig * 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. - * - * @var bool */ - public $sessionRegenerateDestroy = false; + public bool $sessionRegenerateDestroy = false; /** * -------------------------------------------------------------------------- @@ -241,11 +213,10 @@ class App extends BaseConfig * * Set a cookie name prefix if you need to avoid collisions. * - * @var string * * @deprecated use Config\Cookie::$prefix property instead. */ - public $cookiePrefix = ''; + public string $cookiePrefix = ''; /** * -------------------------------------------------------------------------- @@ -254,11 +225,10 @@ class App extends BaseConfig * * Set to `.your-domain.com` for site-wide cookies. * - * @var string * * @deprecated use Config\Cookie::$domain property instead. */ - public $cookieDomain = ''; + public string $cookieDomain = ''; /** * -------------------------------------------------------------------------- @@ -267,11 +237,10 @@ class App extends BaseConfig * * Typically will be a forward slash. * - * @var string * * @deprecated use Config\Cookie::$path property instead. */ - public $cookiePath = '/'; + public string $cookiePath = '/'; /** * -------------------------------------------------------------------------- @@ -280,11 +249,10 @@ class App extends BaseConfig * * Cookie will only be set if a secure HTTPS connection exists. * - * @var bool * * @deprecated use Config\Cookie::$secure property instead. */ - public $cookieSecure = false; + public bool $cookieSecure = false; /** * -------------------------------------------------------------------------- @@ -293,11 +261,10 @@ class App extends BaseConfig * * Cookie will only be accessible via HTTP(S) (no JavaScript). * - * @var bool * * @deprecated use Config\Cookie::$httponly property instead. */ - public $cookieHTTPOnly = true; + public bool $cookieHTTPOnly = true; /** * -------------------------------------------------------------------------- @@ -319,11 +286,10 @@ class App extends BaseConfig * (empty string) means default SameSite attribute set by browsers (`Lax`) * will be set on cookies. If set to `None`, `$cookieSecure` must also be set. * - * @var string|null * * @deprecated use Config\Cookie::$samesite property instead. */ - public $cookieSameSite = 'Lax'; + public ?string $cookieSameSite = 'Lax'; /** * -------------------------------------------------------------------------- @@ -353,10 +319,8 @@ class App extends BaseConfig * The token name. * * @deprecated Use `Config\Security` $tokenName property instead of using this property. - * - * @var string */ - public $CSRFTokenName = 'csrf_test_name'; + public string $CSRFTokenName = 'csrf_test_name'; /** * -------------------------------------------------------------------------- @@ -366,10 +330,8 @@ class App extends BaseConfig * The header name. * * @deprecated Use `Config\Security` $headerName property instead of using this property. - * - * @var string */ - public $CSRFHeaderName = 'X-CSRF-TOKEN'; + public string $CSRFHeaderName = 'X-CSRF-TOKEN'; /** * -------------------------------------------------------------------------- @@ -379,10 +341,8 @@ class App extends BaseConfig * The cookie name. * * @deprecated Use `Config\Security` $cookieName property instead of using this property. - * - * @var string */ - public $CSRFCookieName = 'csrf_cookie_name'; + public string $CSRFCookieName = 'csrf_cookie_name'; /** * -------------------------------------------------------------------------- @@ -392,10 +352,8 @@ class App extends BaseConfig * The number in seconds the token should expire. * * @deprecated Use `Config\Security` $expire property instead of using this property. - * - * @var int */ - public $CSRFExpire = 7200; + public int $CSRFExpire = 7200; /** * -------------------------------------------------------------------------- @@ -405,10 +363,8 @@ class App extends BaseConfig * Regenerate token on every submission? * * @deprecated Use `Config\Security` $regenerate property instead of using this property. - * - * @var bool */ - public $CSRFRegenerate = true; + public bool $CSRFRegenerate = true; /** * -------------------------------------------------------------------------- @@ -418,10 +374,8 @@ class App extends BaseConfig * Redirect to previous page with error on failure? * * @deprecated Use `Config\Security` $redirect property instead of using this property. - * - * @var bool */ - public $CSRFRedirect = true; + public bool $CSRFRedirect = true; /** * -------------------------------------------------------------------------- @@ -438,10 +392,8 @@ class App extends BaseConfig * * @see https://portswigger.net/web-security/csrf/samesite-cookies * @deprecated `Config\Cookie` $samesite property is used. - * - * @var string */ - public $CSRFSameSite = 'Lax'; + public string $CSRFSameSite = 'Lax'; /** * -------------------------------------------------------------------------- @@ -458,8 +410,6 @@ class App extends BaseConfig * * @see http://www.html5rocks.com/en/tutorials/security/content-security-policy/ * @see http://www.w3.org/TR/CSP/ - * - * @var bool */ - public $CSPEnabled = false; + public bool $CSPEnabled = false; } diff --git a/app/Config/CURLRequest.php b/app/Config/CURLRequest.php index b4c8e5c4f13c..6c3ed74aa987 100644 --- a/app/Config/CURLRequest.php +++ b/app/Config/CURLRequest.php @@ -15,8 +15,6 @@ class CURLRequest extends BaseConfig * * 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; + public bool $shareOptions = true; } diff --git a/app/Config/Cache.php b/app/Config/Cache.php index 2d1fea90c9d1..06876cd407e5 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -19,10 +19,8 @@ class Cache extends BaseConfig * * The name of the preferred handler that should be used. If for some reason * it is not available, the $backupHandler will be used in its place. - * - * @var string */ - public $handler = 'file'; + public string $handler = 'file'; /** * -------------------------------------------------------------------------- @@ -32,10 +30,8 @@ class Cache extends BaseConfig * The name of the handler that will be used in case the first one is * unreachable. Often, 'file' is used here since the filesystem is * always available, though that's not always practical for the app. - * - * @var string */ - public $backupHandler = 'dummy'; + public string $backupHandler = 'dummy'; /** * -------------------------------------------------------------------------- @@ -45,11 +41,10 @@ class Cache extends BaseConfig * The path to where cache files should be stored, if using a file-based * system. * - * @var string * * @deprecated Use the driver-specific variant under $file */ - public $storePath = WRITEPATH . 'cache/'; + public string $storePath = WRITEPATH . 'cache/'; /** * -------------------------------------------------------------------------- @@ -77,10 +72,8 @@ class Cache extends BaseConfig * * This string is added to all cache item names to help avoid collisions * if you run multiple applications with the same cache engine. - * - * @var string */ - public $prefix = ''; + public string $prefix = ''; /** * -------------------------------------------------------------------------- @@ -92,10 +85,8 @@ class Cache extends BaseConfig * WARNING: This is not used by framework handlers where 60 seconds is * hard-coded, but may be useful to projects and modules. This will replace * the hard-coded value in a future release. - * - * @var int */ - public $ttl = 60; + public int $ttl = 60; /** * -------------------------------------------------------------------------- @@ -106,10 +97,8 @@ class Cache extends BaseConfig * 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 = '{}()/\@:'; + public string $reservedCharacters = '{}()/\@:'; /** * -------------------------------------------------------------------------- @@ -120,7 +109,7 @@ class Cache extends BaseConfig * * @var array */ - public $file = [ + public array $file = [ 'storePath' => WRITEPATH . 'cache/', 'mode' => 0640, ]; @@ -136,7 +125,7 @@ class Cache extends BaseConfig * * @var array */ - public $memcached = [ + public array $memcached = [ 'host' => '127.0.0.1', 'port' => 11211, 'weight' => 1, @@ -152,7 +141,7 @@ class Cache extends BaseConfig * * @var array */ - public $redis = [ + public array $redis = [ 'host' => '127.0.0.1', 'password' => null, 'port' => 6379, @@ -170,7 +159,7 @@ class Cache extends BaseConfig * * @var array */ - public $validHandlers = [ + public array $validHandlers = [ 'dummy' => DummyHandler::class, 'file' => FileHandler::class, 'memcached' => MemcachedHandler::class, diff --git a/app/Config/ContentSecurityPolicy.php b/app/Config/ContentSecurityPolicy.php index aa18ba9f1060..6558a6a47eda 100644 --- a/app/Config/ContentSecurityPolicy.php +++ b/app/Config/ContentSecurityPolicy.php @@ -18,30 +18,23 @@ class ContentSecurityPolicy extends BaseConfig //------------------------------------------------------------------------- // Broadbrush CSP management //------------------------------------------------------------------------- - /** * Default CSP report context - * - * @var bool */ - public $reportOnly = false; + public bool $reportOnly = false; /** * Specifies a URL where a browser will send reports * when a content security policy is violated. - * - * @var string|null */ - public $reportURI; + public ?string $reportURI = null; /** * Instructs user agents to rewrite URL schemes, changing * HTTP to HTTPS. This directive is for websites with * large numbers of old URLs that need to be rewritten. - * - * @var bool */ - public $upgradeInsecureRequests = false; + public bool $upgradeInsecureRequests = false; //------------------------------------------------------------------------- // Sources allowed @@ -167,22 +160,16 @@ class ContentSecurityPolicy extends BaseConfig /** * Nonce tag for style - * - * @var string */ - public $styleNonceTag = '{csp-style-nonce}'; + public string $styleNonceTag = '{csp-style-nonce}'; /** * Nonce tag for script - * - * @var string */ - public $scriptNonceTag = '{csp-script-nonce}'; + public string $scriptNonceTag = '{csp-script-nonce}'; /** * Replace nonce tag automatically - * - * @var bool */ - public $autoNonce = true; + public bool $autoNonce = true; } diff --git a/app/Config/Cookie.php b/app/Config/Cookie.php index 8ee01c71b655..770e0f884038 100644 --- a/app/Config/Cookie.php +++ b/app/Config/Cookie.php @@ -13,10 +13,8 @@ class Cookie extends BaseConfig * -------------------------------------------------------------------------- * * Set a cookie name prefix if you need to avoid collisions. - * - * @var string */ - public $prefix = ''; + public string $prefix = ''; /** * -------------------------------------------------------------------------- @@ -37,10 +35,8 @@ class Cookie extends BaseConfig * -------------------------------------------------------------------------- * * Typically will be a forward slash. - * - * @var string */ - public $path = '/'; + public string $path = '/'; /** * -------------------------------------------------------------------------- @@ -48,10 +44,8 @@ class Cookie extends BaseConfig * -------------------------------------------------------------------------- * * Set to `.your-domain.com` for site-wide cookies. - * - * @var string */ - public $domain = ''; + public string $domain = ''; /** * -------------------------------------------------------------------------- @@ -59,10 +53,8 @@ class Cookie extends BaseConfig * -------------------------------------------------------------------------- * * Cookie will only be set if a secure HTTPS connection exists. - * - * @var bool */ - public $secure = false; + public bool $secure = false; /** * -------------------------------------------------------------------------- @@ -70,10 +62,8 @@ class Cookie extends BaseConfig * -------------------------------------------------------------------------- * * Cookie will only be accessible via HTTP(S) (no JavaScript). - * - * @var bool */ - public $httponly = true; + public bool $httponly = true; /** * -------------------------------------------------------------------------- @@ -94,10 +84,8 @@ class Cookie extends BaseConfig * Defaults to `Lax` for compatibility with modern browsers. Setting `''` * (empty string) means default SameSite attribute set by browsers (`Lax`) * will be set on cookies. If set to `None`, `$secure` must also be set. - * - * @var string */ - public $samesite = 'Lax'; + public string $samesite = 'Lax'; /** * -------------------------------------------------------------------------- @@ -110,10 +98,9 @@ class Cookie extends BaseConfig * If this is set to `true`, cookie names should be compliant of RFC 2616's * list of allowed characters. * - * @var bool * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes * @see https://tools.ietf.org/html/rfc2616#section-2.2 */ - public $raw = false; + public bool $raw = false; } diff --git a/app/Config/Database.php b/app/Config/Database.php index c6ed959b3d38..342d53ba63b7 100644 --- a/app/Config/Database.php +++ b/app/Config/Database.php @@ -12,25 +12,19 @@ class Database extends Config /** * The directory that holds the Migrations * and Seeds directories. - * - * @var string */ - public $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR; + public string $filesPath = APPPATH . 'Database' . DIRECTORY_SEPARATOR; /** * Lets you choose which connection group to * use if no other is specified. - * - * @var string */ - public $defaultGroup = 'default'; + public string $defaultGroup = 'default'; /** * The default database connection. - * - * @var array */ - public $default = [ + public array $default = [ 'DSN' => '', 'hostname' => 'localhost', 'username' => '', @@ -53,10 +47,8 @@ class Database extends Config /** * This database connection is used when * running PHPUnit database tests. - * - * @var array */ - public $tests = [ + public array $tests = [ 'DSN' => '', 'hostname' => '127.0.0.1', 'username' => '', diff --git a/app/Config/DocTypes.php b/app/Config/DocTypes.php index 6f16693686fe..60a10585c437 100755 --- a/app/Config/DocTypes.php +++ b/app/Config/DocTypes.php @@ -9,7 +9,7 @@ class DocTypes * * @var array */ - public $list = [ + public array $list = [ 'xhtml11' => '', 'xhtml1-strict' => '', 'xhtml1-trans' => '', diff --git a/app/Config/Email.php b/app/Config/Email.php index 3a42fbe68ecb..7d47308f6ff0 100644 --- a/app/Config/Email.php +++ b/app/Config/Email.php @@ -6,165 +6,114 @@ class Email extends BaseConfig { - /** - * @var string - */ - public $fromEmail; + public string $fromEmail; - /** - * @var string - */ - public $fromName; + public string $fromName; - /** - * @var string - */ - public $recipients; + public string $recipients; /** * The "user agent" - * - * @var string */ - public $userAgent = 'CodeIgniter'; + public string $userAgent = 'CodeIgniter'; /** * The mail sending protocol: mail, sendmail, smtp - * - * @var string */ - public $protocol = 'mail'; + public string $protocol = 'mail'; /** * The server path to Sendmail. - * - * @var string */ - public $mailPath = '/usr/sbin/sendmail'; + public string $mailPath = '/usr/sbin/sendmail'; /** * SMTP Server Address - * - * @var string */ - public $SMTPHost; + public string $SMTPHost; /** * SMTP Username - * - * @var string */ - public $SMTPUser; + public string $SMTPUser; /** * SMTP Password - * - * @var string */ - public $SMTPPass; + public string $SMTPPass; /** * SMTP Port - * - * @var int */ - public $SMTPPort = 25; + public int $SMTPPort = 25; /** * SMTP Timeout (in seconds) - * - * @var int */ - public $SMTPTimeout = 5; + public int $SMTPTimeout = 5; /** * Enable persistent SMTP connections - * - * @var bool */ - public $SMTPKeepAlive = false; + public bool $SMTPKeepAlive = false; /** * SMTP Encryption. Either tls or ssl - * - * @var string */ - public $SMTPCrypto = 'tls'; + public string $SMTPCrypto = 'tls'; /** * Enable word-wrap - * - * @var bool */ - public $wordWrap = true; + public bool $wordWrap = true; /** * Character count to wrap at - * - * @var int */ - public $wrapChars = 76; + public int $wrapChars = 76; /** * Type of mail, either 'text' or 'html' - * - * @var string */ - public $mailType = 'text'; + public string $mailType = 'text'; /** * Character set (utf-8, iso-8859-1, etc.) - * - * @var string */ - public $charset = 'UTF-8'; + public string $charset = 'UTF-8'; /** * Whether to validate the email address - * - * @var bool */ - public $validate = false; + public bool $validate = false; /** * Email Priority. 1 = highest. 5 = lowest. 3 = normal - * - * @var int */ - public $priority = 3; + public int $priority = 3; /** * Newline character. (Use “\r\n” to comply with RFC 822) - * - * @var string */ - public $CRLF = "\r\n"; + public string $CRLF = "\r\n"; /** * Newline character. (Use “\r\n” to comply with RFC 822) - * - * @var string */ - public $newline = "\r\n"; + public string $newline = "\r\n"; /** * Enable BCC Batch Mode. - * - * @var bool */ - public $BCCBatchMode = false; + public bool $BCCBatchMode = false; /** * Number of emails in each BCC batch - * - * @var int */ - public $BCCBatchSize = 200; + public int $BCCBatchSize = 200; /** * Enable notify message from server - * - * @var bool */ - public $DSN = false; + public bool $DSN = false; } diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php index 07b45a0bdfac..388b1fa01942 100644 --- a/app/Config/Encryption.php +++ b/app/Config/Encryption.php @@ -20,10 +20,8 @@ class Encryption extends BaseConfig * If you use the Encryption class you must set an encryption key (seed). * You need to ensure it is long enough for the cipher and mode you plan to use. * See the user guide for more info. - * - * @var string */ - public $key = ''; + public string $key = ''; /** * -------------------------------------------------------------------------- @@ -35,10 +33,8 @@ class Encryption extends BaseConfig * Available drivers: * - OpenSSL * - Sodium - * - * @var string */ - public $driver = 'OpenSSL'; + public string $driver = 'OpenSSL'; /** * -------------------------------------------------------------------------- @@ -49,10 +45,8 @@ class Encryption extends BaseConfig * before it is encrypted. This value should be greater than zero. * * See the user guide for more information on padding. - * - * @var int */ - public $blockSize = 16; + public int $blockSize = 16; /** * -------------------------------------------------------------------------- @@ -60,8 +54,6 @@ class Encryption extends BaseConfig * -------------------------------------------------------------------------- * * HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'. - * - * @var string */ - public $digest = 'SHA512'; + public string $digest = 'SHA512'; } diff --git a/app/Config/Exceptions.php b/app/Config/Exceptions.php index 7cbc78a88a3a..c695b7257660 100644 --- a/app/Config/Exceptions.php +++ b/app/Config/Exceptions.php @@ -17,10 +17,8 @@ class Exceptions extends BaseConfig * through Services::Log. * * Default: true - * - * @var bool */ - public $log = true; + public bool $log = true; /** * -------------------------------------------------------------------------- @@ -28,10 +26,8 @@ class Exceptions extends BaseConfig * -------------------------------------------------------------------------- * Any status codes here will NOT be logged if logging is turned on. * By default, only 404 (Page Not Found) exceptions are ignored. - * - * @var array */ - public $ignoreCodes = [404]; + public array $ignoreCodes = [404]; /** * -------------------------------------------------------------------------- @@ -41,10 +37,8 @@ class Exceptions extends BaseConfig * directories that hold the views used to generate errors. * * Default: APPPATH.'Views/errors' - * - * @var string */ - public $errorViewPath = APPPATH . 'Views/errors'; + public string $errorViewPath = APPPATH . 'Views/errors'; /** * -------------------------------------------------------------------------- @@ -53,8 +47,6 @@ class Exceptions extends BaseConfig * Any data that you would like to hide from the debug trace. * In order to specify 2 levels, use "/" to separate. * ex. ['server', 'setup/password', 'secret_token'] - * - * @var array */ - public $sensitiveDataInTrace = []; + public array $sensitiveDataInTrace = []; } diff --git a/app/Config/Feature.php b/app/Config/Feature.php index 4c5ec90cd3ff..0bc45c6f46c0 100644 --- a/app/Config/Feature.php +++ b/app/Config/Feature.php @@ -20,10 +20,8 @@ class Feature extends BaseConfig * - CodeIgniter\Router\Router::handle() uses: * - property $filtersInfo, instead of $filterInfo * - CodeIgniter\Router\RouteCollection::getFiltersForRoute(), instead of getFilterForRoute() - * - * @var bool */ - public $multipleFilters = false; + public bool $multipleFilters = false; /** * Use improved new auto routing instead of the default legacy version. diff --git a/app/Config/Filters.php b/app/Config/Filters.php index d0a97238b1d1..7b70c4fb3381 100644 --- a/app/Config/Filters.php +++ b/app/Config/Filters.php @@ -14,10 +14,8 @@ class Filters extends BaseConfig /** * Configures aliases for Filter classes to * make reading things nicer and simpler. - * - * @var array */ - public $aliases = [ + public array $aliases = [ 'csrf' => CSRF::class, 'toolbar' => DebugToolbar::class, 'honeypot' => Honeypot::class, @@ -28,10 +26,8 @@ class Filters extends BaseConfig /** * List of filter aliases that are always * applied before and after every request. - * - * @var array */ - public $globals = [ + public array $globals = [ 'before' => [ // 'honeypot', // 'csrf', @@ -54,10 +50,8 @@ class Filters extends BaseConfig * If you use this, you should disable auto-routing because auto-routing * permits any HTTP method to access a controller. Accessing the controller * with a method you don’t expect could bypass the filter. - * - * @var array */ - public $methods = []; + public array $methods = []; /** * List of filter aliases that should run on any @@ -65,8 +59,6 @@ class Filters extends BaseConfig * * Example: * 'isLoggedIn' => ['before' => ['account/*', 'profiles/*']] - * - * @var array */ - public $filters = []; + public array $filters = []; } diff --git a/app/Config/Format.php b/app/Config/Format.php index d89e40842c22..749da3e5fde2 100644 --- a/app/Config/Format.php +++ b/app/Config/Format.php @@ -24,7 +24,7 @@ class Format extends BaseConfig * * @var string[] */ - public $supportedResponseFormats = [ + public array $supportedResponseFormats = [ 'application/json', 'application/xml', // machine-readable XML 'text/xml', // human-readable XML @@ -41,7 +41,7 @@ class Format extends BaseConfig * * @var array */ - public $formatters = [ + public array $formatters = [ 'application/json' => JSONFormatter::class, 'application/xml' => XMLFormatter::class, 'text/xml' => XMLFormatter::class, @@ -57,7 +57,7 @@ class Format extends BaseConfig * * @var array */ - public $formatterOptions = [ + public array $formatterOptions = [ 'application/json' => JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES, 'application/xml' => 0, 'text/xml' => 0, diff --git a/app/Config/Generators.php b/app/Config/Generators.php index 11214fdc6e55..01b1ef2b2864 100644 --- a/app/Config/Generators.php +++ b/app/Config/Generators.php @@ -25,7 +25,7 @@ class Generators extends BaseConfig * * @var array */ - public $views = [ + public array $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', diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php index 42b5a0dc827e..179b01546902 100644 --- a/app/Config/Honeypot.php +++ b/app/Config/Honeypot.php @@ -8,36 +8,26 @@ class Honeypot extends BaseConfig { /** * Makes Honeypot visible or not to human - * - * @var bool */ - public $hidden = true; + public bool $hidden = true; /** * Honeypot Label Content - * - * @var string */ - public $label = 'Fill This Field'; + public string $label = 'Fill This Field'; /** * Honeypot Field Name - * - * @var string */ - public $name = 'honeypot'; + public string $name = 'honeypot'; /** * Honeypot HTML Template - * - * @var string */ - public $template = ''; + public string $template = ''; /** * Honeypot container - * - * @var string */ - public $container = '
{template}
'; + public string $container = '
{template}
'; } diff --git a/app/Config/Images.php b/app/Config/Images.php index 1c15d8151ed2..a33ddadb9a5c 100644 --- a/app/Config/Images.php +++ b/app/Config/Images.php @@ -10,25 +10,21 @@ class Images extends BaseConfig { /** * Default handler used if no other handler is specified. - * - * @var string */ - public $defaultHandler = 'gd'; + public string $defaultHandler = 'gd'; /** * The path to the image library. * Required for ImageMagick, GraphicsMagick, or NetPBM. - * - * @var string */ - public $libraryPath = '/usr/local/bin/convert'; + public string $libraryPath = '/usr/local/bin/convert'; /** * The available handler classes. * * @var array */ - public $handlers = [ + public array $handlers = [ 'gd' => GDHandler::class, 'imagick' => ImageMagickHandler::class, ]; diff --git a/app/Config/Kint.php b/app/Config/Kint.php index b1016ed57923..98c35d56da8c 100644 --- a/app/Config/Kint.php +++ b/app/Config/Kint.php @@ -24,18 +24,18 @@ class Kint extends BaseConfig */ public $plugins; - public $maxDepth = 6; - public $displayCalledFrom = true; - public $expanded = false; + public int $maxDepth = 6; + public bool $displayCalledFrom = true; + public bool $expanded = false; /* |-------------------------------------------------------------------------- | RichRenderer Settings |-------------------------------------------------------------------------- */ - public $richTheme = 'aante-light.css'; - public $richFolder = false; - public $richSort = Renderer::SORT_FULL; + public string $richTheme = 'aante-light.css'; + public bool $richFolder = false; + public int $richSort = Renderer::SORT_FULL; public $richObjectPlugins; public $richTabPlugins; @@ -44,8 +44,8 @@ class Kint extends BaseConfig | CLI Settings |-------------------------------------------------------------------------- */ - public $cliColors = true; - public $cliForceUTF8 = false; - public $cliDetectWidth = true; - public $cliMinWidth = 40; + public bool $cliColors = true; + public bool $cliForceUTF8 = false; + public bool $cliDetectWidth = true; + public int $cliMinWidth = 40; } diff --git a/app/Config/Logger.php b/app/Config/Logger.php index fe389d8a2078..5a7498fe5aa3 100644 --- a/app/Config/Logger.php +++ b/app/Config/Logger.php @@ -47,10 +47,8 @@ class Logger extends BaseConfig * * Each item that is logged has an associated date. You can use PHP date * codes to set your own date formatting - * - * @var string */ - public $dateFormat = 'Y-m-d H:i:s'; + public string $dateFormat = 'Y-m-d H:i:s'; /** * -------------------------------------------------------------------------- @@ -60,7 +58,7 @@ class Logger extends BaseConfig * The logging system supports multiple actions to be taken when something * is logged. This is done by allowing for multiple Handlers, special classes * designed to write the log to their chosen destinations, whether that is - * a file on the server, a cloud-based service, or even taking actions such + * a file on the getServer, a cloud-based service, or even taking actions such * as emailing the dev team. * * Each handler is defined by the class name used for that handler, and it @@ -74,10 +72,8 @@ class Logger extends BaseConfig * * Handlers are executed in the order defined in this array, starting with * the handler on top and continuing down. - * - * @var array */ - public $handlers = [ + public array $handlers = [ /* * -------------------------------------------------------------------- diff --git a/app/Config/Migrations.php b/app/Config/Migrations.php index 91e80b4a9074..937484ce146c 100644 --- a/app/Config/Migrations.php +++ b/app/Config/Migrations.php @@ -15,10 +15,8 @@ class Migrations extends BaseConfig * * You should enable migrations whenever you intend to do a schema migration * and disable it back when you're done. - * - * @var bool */ - public $enabled = true; + public bool $enabled = true; /** * -------------------------------------------------------------------------- @@ -30,10 +28,8 @@ class Migrations extends BaseConfig * level the system is at. It then compares the migration level in this * table to the $config['migration_version'] if they are not the same it * will migrate up. This must be set. - * - * @var string */ - public $table = 'migrations'; + public string $table = 'migrations'; /** * -------------------------------------------------------------------------- @@ -48,8 +44,6 @@ class Migrations extends BaseConfig * - YmdHis_ * - Y-m-d-His_ * - Y_m_d_His_ - * - * @var string */ - public $timestampFormat = 'Y-m-d-His_'; + public string $timestampFormat = 'Y-m-d-His_'; } diff --git a/app/Config/Mimes.php b/app/Config/Mimes.php index 884e76bc6f53..6b06c4e3a3f5 100644 --- a/app/Config/Mimes.php +++ b/app/Config/Mimes.php @@ -20,10 +20,8 @@ class Mimes { /** * Map of extensions to mime types. - * - * @var array */ - public static $mimes = [ + public static array $mimes = [ 'hqx' => [ 'application/mac-binhex40', 'application/mac-binhex', diff --git a/app/Config/Pager.php b/app/Config/Pager.php index 922575389a69..e341f4d35430 100644 --- a/app/Config/Pager.php +++ b/app/Config/Pager.php @@ -20,7 +20,7 @@ class Pager extends BaseConfig * * @var array */ - public $templates = [ + public array $templates = [ 'default_full' => 'CodeIgniter\Pager\Views\default_full', 'default_simple' => 'CodeIgniter\Pager\Views\default_simple', 'default_head' => 'CodeIgniter\Pager\Views\default_head', @@ -32,8 +32,6 @@ class Pager extends BaseConfig * -------------------------------------------------------------------------- * * The default number of results shown in a single page. - * - * @var int */ - public $perPage = 20; + public int $perPage = 20; } diff --git a/app/Config/Paths.php b/app/Config/Paths.php index 1b313a7f2a45..e419477a51ec 100644 --- a/app/Config/Paths.php +++ b/app/Config/Paths.php @@ -22,10 +22,8 @@ class Paths * * This must contain the name of your "system" folder. Include * the path if the folder is not in the same directory as this file. - * - * @var string */ - public $systemDirectory = __DIR__ . '/../../system'; + public string $systemDirectory = __DIR__ . '/../../system'; /** * --------------------------------------------------------------- @@ -38,10 +36,8 @@ class Paths * you do, use a full server path. * * @see http://codeigniter.com/user_guide/general/managing_apps.html - * - * @var string */ - public $appDirectory = __DIR__ . '/..'; + public string $appDirectory = __DIR__ . '/..'; /** * --------------------------------------------------------------- @@ -53,10 +49,8 @@ class Paths * need write permission to a single place that can be tucked away * for maximum security, keeping it out of the app and/or * system directories. - * - * @var string */ - public $writableDirectory = __DIR__ . '/../../writable'; + public string $writableDirectory = __DIR__ . '/../../writable'; /** * --------------------------------------------------------------- @@ -64,10 +58,8 @@ class Paths * --------------------------------------------------------------- * * This variable must contain the name of your "tests" directory. - * - * @var string */ - public $testsDirectory = __DIR__ . '/../../tests'; + public string $testsDirectory = __DIR__ . '/../../tests'; /** * --------------------------------------------------------------- @@ -78,8 +70,6 @@ class Paths * contains the view files used by your application. By * default this is in `app/Views`. This value * is used when no value is provided to `Services::renderer()`. - * - * @var string */ - public $viewDirectory = __DIR__ . '/../Views'; + public string $viewDirectory = __DIR__ . '/../Views'; } diff --git a/app/Config/Routes.php b/app/Config/Routes.php index 71b7a86de469..ff2ac645cb9a 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -5,6 +5,12 @@ // Create a new instance of our RouteCollection class. $routes = Services::routes(); +// Load the system's routing file first, so that the app and ENVIRONMENT +// can override as needed. +if (is_file(SYSTEMPATH . 'Config/Routes.php')) { + require SYSTEMPATH . 'Config/Routes.php'; +} + /* * -------------------------------------------------------------------- * Router Setup diff --git a/app/Config/Security.php b/app/Config/Security.php index 107bd9549dc5..22d487aaf33a 100644 --- a/app/Config/Security.php +++ b/app/Config/Security.php @@ -15,7 +15,7 @@ class Security extends BaseConfig * * @var string 'cookie' or 'session' */ - public $csrfProtection = 'cookie'; + public string $csrfProtection = 'cookie'; /** * -------------------------------------------------------------------------- @@ -23,10 +23,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Randomize the CSRF Token for added security. - * - * @var bool */ - public $tokenRandomize = false; + public bool $tokenRandomize = false; /** * -------------------------------------------------------------------------- @@ -34,10 +32,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Token name for Cross Site Request Forgery protection. - * - * @var string */ - public $tokenName = 'csrf_test_name'; + public string $tokenName = 'csrf_test_name'; /** * -------------------------------------------------------------------------- @@ -45,10 +41,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Header name for Cross Site Request Forgery protection. - * - * @var string */ - public $headerName = 'X-CSRF-TOKEN'; + public string $headerName = 'X-CSRF-TOKEN'; /** * -------------------------------------------------------------------------- @@ -56,10 +50,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Cookie name for Cross Site Request Forgery protection. - * - * @var string */ - public $cookieName = 'csrf_cookie_name'; + public string $cookieName = 'csrf_cookie_name'; /** * -------------------------------------------------------------------------- @@ -69,10 +61,8 @@ class Security extends BaseConfig * Expiration time for Cross Site Request Forgery protection cookie. * * Defaults to two hours (in seconds). - * - * @var int */ - public $expires = 7200; + public int $expires = 7200; /** * -------------------------------------------------------------------------- @@ -80,10 +70,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Regenerate CSRF Token on every submission. - * - * @var bool */ - public $regenerate = true; + public bool $regenerate = true; /** * -------------------------------------------------------------------------- @@ -91,10 +79,8 @@ class Security extends BaseConfig * -------------------------------------------------------------------------- * * Redirect to previous page with error on failure. - * - * @var bool */ - public $redirect = true; + public bool $redirect = true; /** * -------------------------------------------------------------------------- @@ -109,9 +95,8 @@ class Security extends BaseConfig * * @see https://portswigger.net/web-security/csrf/samesite-cookies * - * @var string * * @deprecated `Config\Cookie` $samesite property is used. */ - public $samesite = 'Lax'; + public string $samesite = 'Lax'; } diff --git a/app/Config/Toolbar.php b/app/Config/Toolbar.php index 7183e1336a28..1b7527c7c77a 100644 --- a/app/Config/Toolbar.php +++ b/app/Config/Toolbar.php @@ -33,7 +33,7 @@ class Toolbar extends BaseConfig * * @var string[] */ - public $collectors = [ + public array $collectors = [ Timers::class, Database::class, Logs::class, @@ -51,10 +51,8 @@ class Toolbar extends BaseConfig * * If set to false var data from the views will not be colleted. Usefull to * avoid high memory usage when there are lots of data passed to the view. - * - * @var bool */ - public $collectVarData = true; + public bool $collectVarData = true; /** * -------------------------------------------------------------------------- @@ -64,10 +62,8 @@ class Toolbar extends BaseConfig * `$maxHistory` sets a limit on the number of past requests that are stored, * helping to conserve file space used to store them. You can set it to * 0 (zero) to not have any history stored, or -1 for unlimited history. - * - * @var int */ - public $maxHistory = 20; + public int $maxHistory = 20; /** * -------------------------------------------------------------------------- @@ -76,10 +72,8 @@ class Toolbar extends BaseConfig * * The full path to the the views that are used by the toolbar. * This MUST have a trailing slash. - * - * @var string */ - public $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/'; + public string $viewsPath = SYSTEMPATH . 'Debug/Toolbar/Views/'; /** * -------------------------------------------------------------------------- @@ -92,8 +86,6 @@ class Toolbar extends BaseConfig * with hundreds of queries. * * `$maxQueries` defines the maximum amount of queries that will be stored. - * - * @var int */ - public $maxQueries = 100; + public int $maxQueries = 100; } diff --git a/app/Config/UserAgents.php b/app/Config/UserAgents.php index e1dbfa63d726..fda73748dbe8 100644 --- a/app/Config/UserAgents.php +++ b/app/Config/UserAgents.php @@ -23,7 +23,7 @@ class UserAgents extends BaseConfig * * @var array */ - public $platforms = [ + public array $platforms = [ 'windows nt 10.0' => 'Windows 10', 'windows nt 6.3' => 'Windows 8.1', 'windows nt 6.2' => 'Windows 8', @@ -78,7 +78,7 @@ class UserAgents extends BaseConfig * * @var array */ - public $browsers = [ + public array $browsers = [ 'OPR' => 'Opera', 'Flock' => 'Flock', 'Edge' => 'Spartan', @@ -119,7 +119,7 @@ class UserAgents extends BaseConfig * * @var array */ - public $mobiles = [ + public array $mobiles = [ // legacy array, old values commented out 'mobileexplorer' => 'Mobile Explorer', // 'openwave' => 'Open Wave', @@ -228,7 +228,7 @@ class UserAgents extends BaseConfig * * @var array */ - public $robots = [ + public array $robots = [ 'googlebot' => 'Googlebot', 'msnbot' => 'MSNBot', 'baiduspider' => 'Baiduspider', diff --git a/app/Config/Validation.php b/app/Config/Validation.php index a254c1850015..373615cfb16b 100644 --- a/app/Config/Validation.php +++ b/app/Config/Validation.php @@ -20,7 +20,7 @@ class Validation extends BaseConfig * * @var string[] */ - public $ruleSets = [ + public array $ruleSets = [ Rules::class, FormatRules::class, FileRules::class, @@ -33,7 +33,7 @@ class Validation extends BaseConfig * * @var array */ - public $templates = [ + public array $templates = [ 'list' => 'CodeIgniter\Validation\Views\list', 'single' => 'CodeIgniter\Validation\Views\single', ]; From 7eddfab31318a697b8140d9edbe0c324bc973de0 Mon Sep 17 00:00:00 2001 From: MGatner Date: Mon, 27 Jun 2022 17:57:08 +0000 Subject: [PATCH 056/970] Apply CS Fixer --- app/Config/App.php | 6 ------ app/Config/Cache.php | 1 - app/Config/Cookie.php | 1 - app/Config/Email.php | 2 -- app/Config/Kint.php | 10 +++++----- app/Config/Security.php | 2 -- 6 files changed, 5 insertions(+), 17 deletions(-) diff --git a/app/Config/App.php b/app/Config/App.php index 7741273bb237..47bd6c2dd4b1 100644 --- a/app/Config/App.php +++ b/app/Config/App.php @@ -213,7 +213,6 @@ class App extends BaseConfig * * Set a cookie name prefix if you need to avoid collisions. * - * * @deprecated use Config\Cookie::$prefix property instead. */ public string $cookiePrefix = ''; @@ -225,7 +224,6 @@ class App extends BaseConfig * * Set to `.your-domain.com` for site-wide cookies. * - * * @deprecated use Config\Cookie::$domain property instead. */ public string $cookieDomain = ''; @@ -237,7 +235,6 @@ class App extends BaseConfig * * Typically will be a forward slash. * - * * @deprecated use Config\Cookie::$path property instead. */ public string $cookiePath = '/'; @@ -249,7 +246,6 @@ class App extends BaseConfig * * Cookie will only be set if a secure HTTPS connection exists. * - * * @deprecated use Config\Cookie::$secure property instead. */ public bool $cookieSecure = false; @@ -261,7 +257,6 @@ class App extends BaseConfig * * Cookie will only be accessible via HTTP(S) (no JavaScript). * - * * @deprecated use Config\Cookie::$httponly property instead. */ public bool $cookieHTTPOnly = true; @@ -286,7 +281,6 @@ class App extends BaseConfig * (empty string) means default SameSite attribute set by browsers (`Lax`) * will be set on cookies. If set to `None`, `$cookieSecure` must also be set. * - * * @deprecated use Config\Cookie::$samesite property instead. */ public ?string $cookieSameSite = 'Lax'; diff --git a/app/Config/Cache.php b/app/Config/Cache.php index 06876cd407e5..828e7ba3d055 100644 --- a/app/Config/Cache.php +++ b/app/Config/Cache.php @@ -41,7 +41,6 @@ class Cache extends BaseConfig * The path to where cache files should be stored, if using a file-based * system. * - * * @deprecated Use the driver-specific variant under $file */ public string $storePath = WRITEPATH . 'cache/'; diff --git a/app/Config/Cookie.php b/app/Config/Cookie.php index 770e0f884038..440af5ee8070 100644 --- a/app/Config/Cookie.php +++ b/app/Config/Cookie.php @@ -98,7 +98,6 @@ class Cookie extends BaseConfig * If this is set to `true`, cookie names should be compliant of RFC 2616's * list of allowed characters. * - * * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#attributes * @see https://tools.ietf.org/html/rfc2616#section-2.2 */ diff --git a/app/Config/Email.php b/app/Config/Email.php index 7d47308f6ff0..729e8957f9ab 100644 --- a/app/Config/Email.php +++ b/app/Config/Email.php @@ -7,9 +7,7 @@ class Email extends BaseConfig { public string $fromEmail; - public string $fromName; - public string $recipients; /** diff --git a/app/Config/Kint.php b/app/Config/Kint.php index 98c35d56da8c..370b2f06a106 100644 --- a/app/Config/Kint.php +++ b/app/Config/Kint.php @@ -24,7 +24,7 @@ class Kint extends BaseConfig */ public $plugins; - public int $maxDepth = 6; + public int $maxDepth = 6; public bool $displayCalledFrom = true; public bool $expanded = false; @@ -33,9 +33,9 @@ class Kint extends BaseConfig | RichRenderer Settings |-------------------------------------------------------------------------- */ - public string $richTheme = 'aante-light.css'; - public bool $richFolder = false; - public int $richSort = Renderer::SORT_FULL; + public string $richTheme = 'aante-light.css'; + public bool $richFolder = false; + public int $richSort = Renderer::SORT_FULL; public $richObjectPlugins; public $richTabPlugins; @@ -47,5 +47,5 @@ class Kint extends BaseConfig public bool $cliColors = true; public bool $cliForceUTF8 = false; public bool $cliDetectWidth = true; - public int $cliMinWidth = 40; + public int $cliMinWidth = 40; } diff --git a/app/Config/Security.php b/app/Config/Security.php index 22d487aaf33a..1474404be9e4 100644 --- a/app/Config/Security.php +++ b/app/Config/Security.php @@ -94,8 +94,6 @@ class Security extends BaseConfig * Defaults to `Lax` as recommended in this link: * * @see https://portswigger.net/web-security/csrf/samesite-cookies - * - * * @deprecated `Config\Cookie` $samesite property is used. */ public string $samesite = 'Lax'; From a2310baa133a2a7624f8e726a9c09cdcaecb98ea Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 13:49:24 +0900 Subject: [PATCH 057/970] refactor: add type for properties --- phpstan-baseline.neon.dist | 165 -------------------- system/Test/Mock/MockAppConfig.php | 42 ++--- system/Test/Mock/MockCLIConfig.php | 38 ++--- system/Test/Mock/MockSecurityConfig.php | 16 +- tests/system/Config/fixtures/Encryption.php | 4 +- 5 files changed, 50 insertions(+), 215 deletions(-) diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 713e54cb0142..698fe2f56c42 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -25,21 +25,6 @@ parameters: count: 1 path: system/Autoloader/Autoloader.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 @@ -50,11 +35,6 @@ parameters: 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 @@ -80,11 +60,6 @@ parameters: 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 @@ -105,16 +80,6 @@ parameters: 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: "#^Property CodeIgniter\\\\Database\\\\BaseBuilder\\:\\:\\$db \\(CodeIgniter\\\\Database\\\\BaseConnection\\) in empty\\(\\) is not falsy\\.$#" count: 1 @@ -165,16 +130,6 @@ parameters: 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 \\$errno on bool\\|object\\|resource\\.$#" count: 1 @@ -440,26 +395,11 @@ parameters: 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: "#^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: "#^Call to an undefined method CodeIgniter\\\\View\\\\RendererInterface\\:\\:getPerformanceData\\(\\)\\.$#" count: 1 @@ -485,11 +425,6 @@ parameters: 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 @@ -500,21 +435,6 @@ parameters: 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: "#^Expression on left side of \\?\\? is not nullable\\.$#" count: 1 @@ -645,11 +565,6 @@ parameters: 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\\\\Router\\\\RouteCollectionInterface\\:\\:getDefaultNamespace\\(\\)\\.$#" count: 3 @@ -695,16 +610,6 @@ parameters: count: 1 path: system/Router/Router.php - - - message: "#^Property Config\\\\App\\:\\:\\$CSRF[a-zA-Z]+ \\([a-zA-Z]+\\) on left side of \\?\\? is not nullable\\.$#" - count: 6 - path: system/Security/Security.php - - - - message: "#^Property Config\\\\Security\\:\\:\\$[a-zA-Z]+ \\([a-zA-Z]+\\) on left side of \\?\\? is not nullable\\.$#" - count: 8 - path: system/Security/Security.php - - message: "#^Strict comparison using \\=\\=\\= between string and true will always evaluate to false\\.$#" count: 1 @@ -715,71 +620,6 @@ parameters: 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\\:\\:\\$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 @@ -845,11 +685,6 @@ parameters: count: 1 path: system/View/Parser.php - - - message: "#^Result of \\|\\| is always false\\.$#" - paths: - - system/Cache/CacheFactory.php - - message: "#^Binary operation \"/\" between string and 8 results in an error\\.$#" path: system/Encryption/Handlers/OpenSSLHandler.php diff --git a/system/Test/Mock/MockAppConfig.php b/system/Test/Mock/MockAppConfig.php index 15aff95809f0..4a714f6e05f8 100644 --- a/system/Test/Mock/MockAppConfig.php +++ b/system/Test/Mock/MockAppConfig.php @@ -15,27 +15,27 @@ 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 $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 = [ + public string $baseURL = 'http://example.com/'; + public string $uriProtocol = 'REQUEST_URI'; + public string $cookiePrefix = ''; + public string $cookieDomain = ''; + public string $cookiePath = '/'; + public bool $cookieSecure = false; + public bool $cookieHTTPOnly = false; + public ?string $cookieSameSite = 'Lax'; + public $proxyIPs = ''; + public string $CSRFTokenName = 'csrf_test_name'; + public string $CSRFHeaderName = 'X-CSRF-TOKEN'; + public string $CSRFCookieName = 'csrf_cookie_name'; + public int $CSRFExpire = 7200; + public bool $CSRFRegenerate = true; + public array $CSRFExcludeURIs = ['http://example.com']; + public bool $CSRFRedirect = false; + public string $CSRFSameSite = 'Lax'; + public bool $CSPEnabled = false; + public string $defaultLocale = 'en'; + public bool $negotiateLocale = false; + public array $supportedLocales = [ 'en', 'es', ]; diff --git a/system/Test/Mock/MockCLIConfig.php b/system/Test/Mock/MockCLIConfig.php index 6eb0dd70a8b8..4fb645cbd3c4 100644 --- a/system/Test/Mock/MockCLIConfig.php +++ b/system/Test/Mock/MockCLIConfig.php @@ -15,25 +15,25 @@ 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 $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 = [ + public string $baseURL = 'http://example.com/'; + public string $uriProtocol = 'REQUEST_URI'; + public string $cookiePrefix = ''; + public string $cookieDomain = ''; + public string $cookiePath = '/'; + public bool $cookieSecure = false; + public bool $cookieHTTPOnly = false; + public ?string $cookieSameSite = 'Lax'; + public $proxyIPs = ''; + public string $CSRFTokenName = 'csrf_test_name'; + public string $CSRFCookieName = 'csrf_cookie_name'; + public int $CSRFExpire = 7200; + public bool $CSRFRegenerate = true; + public $CSRFExcludeURIs = ['http://example.com']; + public string $CSRFSameSite = 'Lax'; + public bool $CSPEnabled = false; + public string $defaultLocale = 'en'; + public bool $negotiateLocale = false; + public array $supportedLocales = [ 'en', 'es', ]; diff --git a/system/Test/Mock/MockSecurityConfig.php b/system/Test/Mock/MockSecurityConfig.php index e01f30cdf396..001710494ed4 100644 --- a/system/Test/Mock/MockSecurityConfig.php +++ b/system/Test/Mock/MockSecurityConfig.php @@ -20,12 +20,12 @@ */ class MockSecurityConfig extends Security { - public $tokenName = 'csrf_test_name'; - public $headerName = 'X-CSRF-TOKEN'; - public $cookieName = 'csrf_cookie_name'; - public $expires = 7200; - public $regenerate = true; - public $redirect = false; - public $samesite = 'Lax'; - public $excludeURIs = ['http://example.com']; + public string $tokenName = 'csrf_test_name'; + public string $headerName = 'X-CSRF-TOKEN'; + public string $cookieName = 'csrf_cookie_name'; + public int $expires = 7200; + public bool $regenerate = true; + public bool $redirect = false; + public string $samesite = 'Lax'; + public $excludeURIs = ['http://example.com']; } diff --git a/tests/system/Config/fixtures/Encryption.php b/tests/system/Config/fixtures/Encryption.php index 7a8a00bc03fe..e4bb10eba866 100644 --- a/tests/system/Config/fixtures/Encryption.php +++ b/tests/system/Config/fixtures/Encryption.php @@ -16,8 +16,8 @@ class Encryption extends EncryptionConfig private const HEX2BIN = 'hex2bin:84cf2c0811d5daf9e1c897825a3debce91f9a33391e639f72f7a4740b30675a2'; private const BASE64 = 'base64:Psf8bUHRh1UJYG2M7e+5ec3MdjpKpzAr0twamcAvOcI='; - public $key; - public $driver = 'MCrypt'; + public string $key; + public string $driver = 'MCrypt'; public function __construct(string $prefix = 'hex2bin') { From ca9f78786fe01ddd1304c18ce2dbb1d76a673c65 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 13:50:13 +0900 Subject: [PATCH 058/970] test: fix sessionSavePath values --- tests/system/CommonFunctionsTest.php | 2 +- tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php | 2 +- tests/system/Security/SecurityCSRFSessionTest.php | 2 +- tests/system/Session/SessionTest.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/system/CommonFunctionsTest.php b/tests/system/CommonFunctionsTest.php index 5c2b6efa7f83..73cc7e38e93a 100644 --- a/tests/system/CommonFunctionsTest.php +++ b/tests/system/CommonFunctionsTest.php @@ -427,7 +427,7 @@ protected function injectSessionMock() 'sessionDriver' => FileHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, - 'sessionSavePath' => null, + 'sessionSavePath' => '', 'sessionMatchIP' => false, 'sessionTimeToUpdate' => 300, 'sessionRegenerateDestroy' => false, diff --git a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php index dca549685757..33976ede2e5e 100644 --- a/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php +++ b/tests/system/Security/SecurityCSRFSessionRandomizeTokenTest.php @@ -70,7 +70,7 @@ private function createSession($options = []): Session 'sessionDriver' => FileHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, - 'sessionSavePath' => null, + 'sessionSavePath' => '', 'sessionMatchIP' => false, 'sessionTimeToUpdate' => 300, 'sessionRegenerateDestroy' => false, diff --git a/tests/system/Security/SecurityCSRFSessionTest.php b/tests/system/Security/SecurityCSRFSessionTest.php index af7f8c21905a..e4390360e392 100644 --- a/tests/system/Security/SecurityCSRFSessionTest.php +++ b/tests/system/Security/SecurityCSRFSessionTest.php @@ -63,7 +63,7 @@ private function createSession($options = []): Session 'sessionDriver' => FileHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, - 'sessionSavePath' => null, + 'sessionSavePath' => '', 'sessionMatchIP' => false, 'sessionTimeToUpdate' => 300, 'sessionRegenerateDestroy' => false, diff --git a/tests/system/Session/SessionTest.php b/tests/system/Session/SessionTest.php index c6cf278a6073..238480997542 100644 --- a/tests/system/Session/SessionTest.php +++ b/tests/system/Session/SessionTest.php @@ -45,7 +45,7 @@ protected function getInstance($options = []) 'sessionDriver' => FileHandler::class, 'sessionCookieName' => 'ci_session', 'sessionExpiration' => 7200, - 'sessionSavePath' => null, + 'sessionSavePath' => '', 'sessionMatchIP' => false, 'sessionTimeToUpdate' => 300, 'sessionRegenerateDestroy' => false, From e6c8e93b5234260e43a3452b1cf2cfdbb9f78c69 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 14:26:52 +0900 Subject: [PATCH 059/970] refactor: update config error checking --- system/Cache/CacheFactory.php | 2 +- tests/system/Cache/CacheFactoryTest.php | 22 +--------------------- 2 files changed, 2 insertions(+), 22 deletions(-) diff --git a/system/Cache/CacheFactory.php b/system/Cache/CacheFactory.php index 380491192066..0810653b7318 100644 --- a/system/Cache/CacheFactory.php +++ b/system/Cache/CacheFactory.php @@ -42,7 +42,7 @@ class CacheFactory */ public static function getHandler(Cache $config, ?string $handler = null, ?string $backup = null) { - if (! isset($config->validHandlers) || ! is_array($config->validHandlers)) { + if (! isset($config->validHandlers) || $config->validHandlers === []) { throw CacheException::forInvalidHandlers(); } diff --git a/tests/system/Cache/CacheFactoryTest.php b/tests/system/Cache/CacheFactoryTest.php index 45bc16df58e8..f14fa646b398 100644 --- a/tests/system/Cache/CacheFactoryTest.php +++ b/tests/system/Cache/CacheFactoryTest.php @@ -54,27 +54,7 @@ public function testGetHandlerExceptionCacheInvalidHandlers() $this->expectException(CacheException::class); $this->expectExceptionMessage('Cache config must have an array of $validHandlers.'); - $this->config->validHandlers = null; - - $this->cacheFactory->getHandler($this->config); - } - - public function testGetHandlerExceptionCacheNoBackup() - { - $this->expectException(CacheException::class); - $this->expectExceptionMessage('Cache config must have a handler and backupHandler set.'); - - $this->config->backupHandler = null; - - $this->cacheFactory->getHandler($this->config); - } - - public function testGetHandlerExceptionCacheNoHandler() - { - $this->expectException(CacheException::class); - $this->expectExceptionMessage('Cache config must have a handler and backupHandler set.'); - - $this->config->handler = null; + $this->config->validHandlers = []; $this->cacheFactory->getHandler($this->config); } From 7c2fe75ac51bcb7e792f7169606a316f37df07e2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 1 Jul 2022 17:58:42 +0900 Subject: [PATCH 060/970] config: update starter/app/Config/Paths.php --- admin/starter/app/Config/Paths.php | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/admin/starter/app/Config/Paths.php b/admin/starter/app/Config/Paths.php index 3ff97302bc41..d0035fbcfb9b 100644 --- a/admin/starter/app/Config/Paths.php +++ b/admin/starter/app/Config/Paths.php @@ -22,10 +22,8 @@ class Paths * * This must contain the name of your "system" folder. Include * the path if the folder is not in the same directory as this file. - * - * @var string */ - public $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system'; + public string $systemDirectory = __DIR__ . '/../../vendor/codeigniter4/framework/system'; /** * --------------------------------------------------------------- @@ -38,10 +36,8 @@ class Paths * you do, use a full server path. * * @see http://codeigniter.com/user_guide/general/managing_apps.html - * - * @var string */ - public $appDirectory = __DIR__ . '/..'; + public string $appDirectory = __DIR__ . '/..'; /** * --------------------------------------------------------------- @@ -53,10 +49,8 @@ class Paths * need write permission to a single place that can be tucked away * for maximum security, keeping it out of the app and/or * system directories. - * - * @var string */ - public $writableDirectory = __DIR__ . '/../../writable'; + public string $writableDirectory = __DIR__ . '/../../writable'; /** * --------------------------------------------------------------- @@ -64,10 +58,8 @@ class Paths * --------------------------------------------------------------- * * This variable must contain the name of your "tests" directory. - * - * @var string */ - public $testsDirectory = __DIR__ . '/../../tests'; + public string $testsDirectory = __DIR__ . '/../../tests'; /** * --------------------------------------------------------------- @@ -78,8 +70,6 @@ class Paths * contains the view files used by your application. By * default this is in `app/Views`. This value * is used when no value is provided to `Services::renderer()`. - * - * @var string */ - public $viewDirectory = __DIR__ . '/../Views'; + public string $viewDirectory = __DIR__ . '/../Views'; } From ff0ac551ff7ecf73db7ee58b66cab0f61781a843 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Jul 2022 18:20:24 +0900 Subject: [PATCH 061/970] fix: remove mistakenly reverted lines --- app/Config/Routes.php | 6 ------ 1 file changed, 6 deletions(-) diff --git a/app/Config/Routes.php b/app/Config/Routes.php index ff2ac645cb9a..71b7a86de469 100644 --- a/app/Config/Routes.php +++ b/app/Config/Routes.php @@ -5,12 +5,6 @@ // Create a new instance of our RouteCollection class. $routes = Services::routes(); -// Load the system's routing file first, so that the app and ENVIRONMENT -// can override as needed. -if (is_file(SYSTEMPATH . 'Config/Routes.php')) { - require SYSTEMPATH . 'Config/Routes.php'; -} - /* * -------------------------------------------------------------------- * Router Setup From 6fd4d9c37894180f06b1d7b6b8b59425a98f0944 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Jul 2022 18:33:48 +0900 Subject: [PATCH 062/970] docs: add user guide --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/installation/upgrade_430.rst | 11 +++++++++++ 2 files changed, 12 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 8ace9de77261..4de1c7aba89d 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -52,6 +52,7 @@ Changes - The ``CodeIgniter\CLI\CommandRunner`` class has been removed due to a change in Spark commands processing. - The system route configuration file ``system/Config/Routes.php`` has been removed. - The route configuration file ``app/Config/Routes.php`` has been changed. Removed include of system routes configuration file. +- All union type properties in ``Config`` classes have been typed. Deprecations ************ diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst index aaf11e8947fa..88e6afac64de 100644 --- a/user_guide_src/source/installation/upgrade_430.rst +++ b/user_guide_src/source/installation/upgrade_430.rst @@ -30,6 +30,17 @@ The following files received significant changes and > composer update > cp vendor/codeigniter4/framework/spark . +Config Files +============ + +If you are using the following Mock Config classes in testing, you need to update the corresponding Config files in **app/Config**: + +- ``MockAppConfig`` (``Config\App``) +- ``MockCLIConfig`` (``Config\App``) +- ``MockSecurityConfig`` (``Config\Security``) + +Add **types** to the properties in these Config classes. You may need to fix the property values to match the property types. + Breaking Changes **************** From 89194827d05817f9b99e3ee192d4047486ca2fcb Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 2 Jul 2022 20:09:57 +0900 Subject: [PATCH 063/970] docs: not union but atomic --- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 4de1c7aba89d..f2f311c5ce89 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -52,7 +52,7 @@ Changes - The ``CodeIgniter\CLI\CommandRunner`` class has been removed due to a change in Spark commands processing. - The system route configuration file ``system/Config/Routes.php`` has been removed. - The route configuration file ``app/Config/Routes.php`` has been changed. Removed include of system routes configuration file. -- All union type properties in ``Config`` classes have been typed. +- All atomic type properties in ``Config`` classes have been typed. Deprecations ************ From cc73818029038ab667224bc5f214cc243522d6d5 Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Wed, 6 Jul 2022 07:49:47 +0200 Subject: [PATCH 064/970] Create Errors.php --- system/Language/en/Errors.php | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 system/Language/en/Errors.php diff --git a/system/Language/en/Errors.php b/system/Language/en/Errors.php new file mode 100644 index 000000000000..b6964026150d --- /dev/null +++ b/system/Language/en/Errors.php @@ -0,0 +1,25 @@ + + + + + + + <?= lang('Errors.whoops') ?> + + + + + +
+ +

+ +

+ +
+ + + + From 4fc4b12a9d7312bf6780da8829130fdea7618399 Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Wed, 6 Jul 2022 07:51:29 +0200 Subject: [PATCH 065/970] Update production.php --- app/Views/errors/html/production.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php index 9faa4a15b783..b6964026150d 100644 --- a/app/Views/errors/html/production.php +++ b/app/Views/errors/html/production.php @@ -4,7 +4,7 @@ - Whoops! + <?= lang('Errors.whoops') ?> - - - -
- -

- -

- -
- - - - + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +// Errors language settings +return [ + 'whoops' => 'Whoops!', + 'weHitASnag' => 'We seem to have hit a snag. Please try again later...', +]; From cb351810c20ca11f755a8b5b959f9bf42449902b Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Wed, 6 Jul 2022 12:15:10 +0200 Subject: [PATCH 067/970] Update production.php fix indentation --- app/Views/errors/html/production.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php index b6964026150d..2a26d767fd61 100644 --- a/app/Views/errors/html/production.php +++ b/app/Views/errors/html/production.php @@ -12,13 +12,13 @@ -
+
-

+

-

+

-
+
From ea17779800d177cad3862456cd86a593eecf0f84 Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Wed, 6 Jul 2022 12:18:08 +0200 Subject: [PATCH 068/970] Update production.php remove obsolete type="text/css" attribute --- app/Views/errors/html/production.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Views/errors/html/production.php b/app/Views/errors/html/production.php index 2a26d767fd61..2f59a8de1bc7 100644 --- a/app/Views/errors/html/production.php +++ b/app/Views/errors/html/production.php @@ -6,7 +6,7 @@ <?= lang('Errors.whoops') ?> - From ed6c368e8a4a0b94fda5cf720cc7cbc2b7dd9a45 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Fri, 1 Jul 2022 16:11:52 -0700 Subject: [PATCH 069/970] rework SQLite Connection::_getIndexData() and add/fix tests --- system/Database/SQLite3/Connection.php | 50 +++++--- tests/system/Database/Live/ForgeTest.php | 13 +- .../Database/Live/SQLite/AlterTableTest.php | 2 +- .../Database/Live/SQLite/GetIndexDataTest.php | 121 ++++++++++++++++++ 4 files changed, 160 insertions(+), 26 deletions(-) create mode 100644 tests/system/Database/Live/SQLite/GetIndexDataTest.php diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 4f9990e1b11d..159438aae7c8 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -265,34 +265,50 @@ protected function _fieldData(string $table): array */ protected function _indexData(string $table): array { - // Get indexes - // Don't use PRAGMA index_list, so we can preserve index order - $sql = "SELECT name FROM sqlite_master WHERE type='index' AND tbl_name=" . $this->escape(strtolower($table)); + $sql = "SELECT 'PRIMARY' as indexname, l.name as fieldname, 'PRIMARY' as indextype + FROM pragma_table_info(" . $this->escape(strtolower($table)) . ") as l + WHERE l.pk <> 0 + UNION ALL + SELECT sqlite_master.name as indexname, ii.name as fieldname, + CASE + WHEN ti.pk <> 0 AND sqlite_master.name LIKE 'sqlite_autoindex_%' THEN 'PRIMARY' + WHEN sqlite_master.name LIKE 'sqlite_autoindex_%' THEN 'UNIQUE' + WHEN sqlite_master.sql LIKE '% UNIQUE %' THEN 'UNIQUE' + ELSE '' + END as indextype + FROM sqlite_master + INNER JOIN pragma_index_xinfo(sqlite_master.name) ii ON ii.name IS NOT NULL + LEFT JOIN pragma_table_info(" . $this->escape(strtolower($table)) . ") ti ON ti.name = ii.name + WHERE sqlite_master.type='index' AND sqlite_master.tbl_name = " . $this->escape(strtolower($table)) . ' COLLATE NOCASE'; + if (($query = $this->query($sql)) === false) { throw new DatabaseException(lang('Database.failGetIndexData')); } $query = $query->getResultObject(); - $retVal = []; + $tempVal = []; foreach ($query as $row) { - $obj = new stdClass(); - - $obj->name = $row->name; - - // Get fields for index - $obj->fields = []; - - if (false === $fields = $this->query('PRAGMA index_info(' . $this->escape(strtolower($row->name)) . ')')) { - throw new DatabaseException(lang('Database.failGetIndexData')); + if ($row->indextype === 'PRIMARY') { + $tempVal['PRIMARY']['indextype'] = $row->indextype; + $tempVal['PRIMARY']['indexname'] = $row->indexname; + $tempVal['PRIMARY']['fields'][$row->fieldname] = $row->fieldname; + } else { + $tempVal[$row->indexname]['indextype'] = $row->indextype; + $tempVal[$row->indexname]['indexname'] = $row->indexname; + $tempVal[$row->indexname]['fields'][$row->fieldname] = $row->fieldname; } + } - $fields = $fields->getResultObject(); + $retVal = []; - foreach ($fields as $field) { - $obj->fields[] = $field->name; - } + foreach ($tempVal as $val) { + $fields = array_values($val['fields']); + $obj = new stdClass(); + $obj->name = $val['indexname']; + $obj->fields = $fields; + $obj->type = $val['indextype']; $retVal[$obj->name] = $obj; } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 2122afb36a45..2470faaee9ef 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -879,14 +879,11 @@ public function testAddFields() public function testCompositeKey() { - // SQLite3 uses auto increment different - $uniqueOrAuto = $this->db->DBDriver === 'SQLite3' ? 'unique' : 'auto_increment'; - $this->forge->addField([ 'id' => [ - 'type' => 'INTEGER', - 'constraint' => 3, - $uniqueOrAuto => true, + 'type' => 'INTEGER', + 'constraint' => 3, + 'auto_increment' => true, ], 'code' => [ 'type' => 'VARCHAR', @@ -929,8 +926,8 @@ public function testCompositeKey() $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') { - $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['PRIMARY']->name, 'PRIMARY'); + $this->assertSame($keys['PRIMARY']->fields, ['id']); $this->assertSame($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); $this->assertSame($keys['db_forge_test_1_code_company']->fields, ['code', 'company']); $this->assertSame($keys['db_forge_test_1_code_active']->name, 'db_forge_test_1_code_active'); diff --git a/tests/system/Database/Live/SQLite/AlterTableTest.php b/tests/system/Database/Live/SQLite/AlterTableTest.php index 7eb2216139e5..83ab4586c7c9 100644 --- a/tests/system/Database/Live/SQLite/AlterTableTest.php +++ b/tests/system/Database/Live/SQLite/AlterTableTest.php @@ -107,7 +107,7 @@ public function testFromTableFillsDetails() $keys = $this->getPrivateProperty($this->table, 'keys'); - $this->assertCount(3, $keys); + $this->assertCount(4, $keys); $this->assertArrayHasKey('foo_name', $keys); $this->assertSame(['fields' => ['name'], 'type' => 'index'], $keys['foo_name']); $this->assertArrayHasKey('id', $keys); diff --git a/tests/system/Database/Live/SQLite/GetIndexDataTest.php b/tests/system/Database/Live/SQLite/GetIndexDataTest.php new file mode 100644 index 000000000000..15d1e56f831f --- /dev/null +++ b/tests/system/Database/Live/SQLite/GetIndexDataTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Database\Live\SQLite; + +use CodeIgniter\Database\SQLite3\Connection; +use CodeIgniter\Database\SQLite3\Forge; +use CodeIgniter\Test\CIUnitTestCase; +use CodeIgniter\Test\DatabaseTestTrait; +use Config\Database; +use stdClass; + +/** + * @group DatabaseLive + * + * @internal + */ +final class GetIndexDataTest extends CIUnitTestCase +{ + use DatabaseTestTrait; + + /** + * In setUp() db connection is changed. So migration doesn't work + * + * @var bool + */ + protected $migrate = false; + + /** + * @var Connection + */ + protected $db; + + private Forge $forge; + + protected function setUp(): void + { + parent::setUp(); + + $config = [ + 'DBDriver' => 'SQLite3', + 'database' => 'database.db', + 'DBDebug' => true, + ]; + + $this->db = db_connect($config); + $this->forge = Database::forge($config); + } + + public function testGetIndexData() + { + $this->forge->addField([ + 'id' => ['type' => 'INTEGER', 'constraint' => 3, 'auto_increment' => true], + 'name' => ['type' => 'VARCHAR', 'constraint' => 80], + 'email' => ['type' => 'VARCHAR', 'constraint' => 100], + 'country' => ['type' => 'VARCHAR', 'constraint' => 40], + 'created_at' => ['type' => 'DATETIME', 'null' => true], + 'updated_at' => ['type' => 'DATETIME', 'null' => true], + 'deleted_at' => ['type' => 'DATETIME', 'null' => true], + ])->addKey(['id'], true)->createTable('userforeign', true); + + // INTEGER PRIMARY KEY AUTO_INCREMENT doesn't get an index by default + $this->forge->addField([ + 'id' => ['type' => 'INTEGER', 'constraint' => 3, 'auto_increment' => true], + 'userid' => ['type' => 'INTEGER', 'constraint' => 3], + 'name' => ['type' => 'VARCHAR', 'constraint' => 80], + 'email' => ['type' => 'VARCHAR', 'constraint' => 100], + 'country' => ['type' => 'VARCHAR', 'constraint' => 40], + 'created_at' => ['type' => 'DATETIME', 'null' => true], + 'updated_at' => ['type' => 'DATETIME', 'null' => true], + 'deleted_at' => ['type' => 'DATETIME', 'null' => true], + ]) + ->addKey(['id'], true)->addUniqueKey('email') + ->addKey('country') + ->addForeignKey('userid', 'userforeign', 'id') + ->addForeignKey('email', 'userforeign', 'email') + ->createTable('testuser', true); + + $expectedIndexes = []; + + $row = new stdclass(); + $row->name = 'PRIMARY'; + $row->fields = ['id']; + $row->type = 'PRIMARY'; + $expectedIndexes['PRIMARY'] = $row; + + $row = new stdclass(); + $row->name = 'testuser_email'; + $row->fields = ['email']; + $row->type = 'UNIQUE'; + $expectedIndexes['testuser_email'] = $row; + + $row = new stdclass(); + $row->name = 'testuser_country'; + $row->fields = ['country']; + $row->type = ''; + $expectedIndexes['testuser_country'] = $row; + + $indexes = $this->db->getIndexData('testuser'); + + $this->assertSame($expectedIndexes['PRIMARY']->fields, $indexes['PRIMARY']->fields); + $this->assertSame($expectedIndexes['PRIMARY']->type, $indexes['PRIMARY']->type); + + $this->assertSame($expectedIndexes['testuser_email']->fields, $indexes['testuser_email']->fields); + $this->assertSame($expectedIndexes['testuser_email']->type, $indexes['testuser_email']->type); + + $this->assertSame($expectedIndexes['testuser_country']->fields, $indexes['testuser_country']->fields); + $this->assertSame($expectedIndexes['testuser_country']->type, $indexes['testuser_country']->type); + + $this->forge->dropTable('testuser', true); + $this->forge->dropTable('userforeign', true); + } +} From 0be91e23a044e44ceb101c3dd4fca7217b9e0374 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Fri, 1 Jul 2022 16:56:37 -0700 Subject: [PATCH 070/970] removed unused code from GetIndexDataTest --- .../Database/Live/SQLite/GetIndexDataTest.php | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/tests/system/Database/Live/SQLite/GetIndexDataTest.php b/tests/system/Database/Live/SQLite/GetIndexDataTest.php index 15d1e56f831f..f9498cd0301d 100644 --- a/tests/system/Database/Live/SQLite/GetIndexDataTest.php +++ b/tests/system/Database/Live/SQLite/GetIndexDataTest.php @@ -57,16 +57,6 @@ protected function setUp(): void public function testGetIndexData() { - $this->forge->addField([ - 'id' => ['type' => 'INTEGER', 'constraint' => 3, 'auto_increment' => true], - 'name' => ['type' => 'VARCHAR', 'constraint' => 80], - 'email' => ['type' => 'VARCHAR', 'constraint' => 100], - 'country' => ['type' => 'VARCHAR', 'constraint' => 40], - 'created_at' => ['type' => 'DATETIME', 'null' => true], - 'updated_at' => ['type' => 'DATETIME', 'null' => true], - 'deleted_at' => ['type' => 'DATETIME', 'null' => true], - ])->addKey(['id'], true)->createTable('userforeign', true); - // INTEGER PRIMARY KEY AUTO_INCREMENT doesn't get an index by default $this->forge->addField([ 'id' => ['type' => 'INTEGER', 'constraint' => 3, 'auto_increment' => true], @@ -78,10 +68,9 @@ public function testGetIndexData() 'updated_at' => ['type' => 'DATETIME', 'null' => true], 'deleted_at' => ['type' => 'DATETIME', 'null' => true], ]) - ->addKey(['id'], true)->addUniqueKey('email') + ->addKey(['id'], true) + ->addUniqueKey('email') ->addKey('country') - ->addForeignKey('userid', 'userforeign', 'id') - ->addForeignKey('email', 'userforeign', 'email') ->createTable('testuser', true); $expectedIndexes = []; From b25b29dd878571d54316f2c5dcc2e16024b1c810 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Fri, 1 Jul 2022 19:52:52 -0700 Subject: [PATCH 071/970] fix --- system/Database/SQLite3/Connection.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index 159438aae7c8..c59963f7c843 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -303,11 +303,9 @@ protected function _indexData(string $table): array $retVal = []; foreach ($tempVal as $val) { - $fields = array_values($val['fields']); - $obj = new stdClass(); $obj->name = $val['indexname']; - $obj->fields = $fields; + $obj->fields = array_values($val['fields']); $obj->type = $val['indextype']; $retVal[$obj->name] = $obj; } From 9a7c4c1ef812311da9e22a84ae3e912afc777439 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Tue, 5 Jul 2022 15:50:42 -0700 Subject: [PATCH 072/970] fix alter table test and SQLite Table - deal with psudo index PRIMARY --- system/Database/SQLite3/Connection.php | 2 +- system/Database/SQLite3/Table.php | 15 +++++++++++---- tests/system/Database/Live/ForgeTest.php | 11 +++++++++++ .../Database/Live/SQLite/AlterTableTest.php | 10 +++++----- .../Database/Live/SQLite/GetIndexDataTest.php | 3 +-- 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/system/Database/SQLite3/Connection.php b/system/Database/SQLite3/Connection.php index c59963f7c843..24918cb7be97 100644 --- a/system/Database/SQLite3/Connection.php +++ b/system/Database/SQLite3/Connection.php @@ -274,7 +274,7 @@ protected function _indexData(string $table): array WHEN ti.pk <> 0 AND sqlite_master.name LIKE 'sqlite_autoindex_%' THEN 'PRIMARY' WHEN sqlite_master.name LIKE 'sqlite_autoindex_%' THEN 'UNIQUE' WHEN sqlite_master.sql LIKE '% UNIQUE %' THEN 'UNIQUE' - ELSE '' + ELSE 'INDEX' END as indextype FROM sqlite_master INNER JOIN pragma_index_xinfo(sqlite_master.name) ii ON ii.name IS NOT NULL diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 1ecb28fdf8b7..3eb5437c6a44 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -110,6 +110,13 @@ public function fromTable(string $table) $this->keys = array_merge($this->keys, $this->formatKeys($this->db->getIndexData($table))); + // if primary key index exists twice then remove psuedo index name 'primary'. + $primaryIndexes = array_filter($this->keys, static fn ($index) => $index['type'] === 'primary'); + + if (! empty($primaryIndexes) && count($primaryIndexes) > 1 && array_key_exists('primary', $this->keys)) { + unset($this->keys['primary']); + } + $this->foreignKeys = $this->db->getForeignKeyData($table); return $this; @@ -316,7 +323,7 @@ protected function formatFields($fields) ]; if ($field->primary_key) { - $this->keys[$field->name] = [ + $this->keys['primary'] = [ 'fields' => [$field->name], 'type' => 'primary', ]; @@ -343,9 +350,9 @@ protected function formatKeys($keys) $return = []; foreach ($keys as $name => $key) { - $return[$name] = [ + $return[strtolower($name)] = [ 'fields' => $key->fields, - 'type' => 'index', + 'type' => strtolower($key->type), ]; } @@ -363,7 +370,7 @@ protected function dropIndexes() } foreach ($this->keys as $name => $key) { - if ($key['type'] === 'primary' || $key['type'] === 'unique') { + if ($name === 'primary') { continue; } diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 2470faaee9ef..6eacb6ba176c 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -909,9 +909,11 @@ public function testCompositeKey() $this->assertSame($keys['PRIMARY']->name, 'PRIMARY'); $this->assertSame($keys['PRIMARY']->fields, ['id']); $this->assertSame($keys['PRIMARY']->type, 'PRIMARY'); + $this->assertSame($keys['code_company']->name, 'code_company'); $this->assertSame($keys['code_company']->fields, ['code', 'company']); $this->assertSame($keys['code_company']->type, 'INDEX'); + $this->assertSame($keys['code_active']->name, 'code_active'); $this->assertSame($keys['code_active']->fields, ['code', 'active']); $this->assertSame($keys['code_active']->type, 'UNIQUE'); @@ -919,19 +921,26 @@ public function testCompositeKey() $this->assertSame($keys['pk_db_forge_test_1']->name, 'pk_db_forge_test_1'); $this->assertSame($keys['pk_db_forge_test_1']->fields, ['id']); $this->assertSame($keys['pk_db_forge_test_1']->type, 'PRIMARY'); + $this->assertSame($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); $this->assertSame($keys['db_forge_test_1_code_company']->fields, ['code', 'company']); $this->assertSame($keys['db_forge_test_1_code_company']->type, 'INDEX'); + $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') { $this->assertSame($keys['PRIMARY']->name, 'PRIMARY'); $this->assertSame($keys['PRIMARY']->fields, ['id']); + $this->assertSame($keys['PRIMARY']->type, 'PRIMARY'); + $this->assertSame($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); $this->assertSame($keys['db_forge_test_1_code_company']->fields, ['code', 'company']); + $this->assertSame($keys['db_forge_test_1_code_company']->type, 'INDEX'); + $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 === 'SQLSRV') { $this->assertSame($keys['pk_db_forge_test_1']->name, 'pk_db_forge_test_1'); $this->assertSame($keys['pk_db_forge_test_1']->fields, ['id']); @@ -948,9 +957,11 @@ public function testCompositeKey() $this->assertSame($keys['pk_db_forge_test_1']->name, 'pk_db_forge_test_1'); $this->assertSame($keys['pk_db_forge_test_1']->fields, ['id']); $this->assertSame($keys['pk_db_forge_test_1']->type, 'PRIMARY'); + $this->assertSame($keys['db_forge_test_1_code_company']->name, 'db_forge_test_1_code_company'); $this->assertSame($keys['db_forge_test_1_code_company']->fields, ['code', 'company']); $this->assertSame($keys['db_forge_test_1_code_company']->type, 'INDEX'); + $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'); diff --git a/tests/system/Database/Live/SQLite/AlterTableTest.php b/tests/system/Database/Live/SQLite/AlterTableTest.php index 83ab4586c7c9..ce1055d04c2b 100644 --- a/tests/system/Database/Live/SQLite/AlterTableTest.php +++ b/tests/system/Database/Live/SQLite/AlterTableTest.php @@ -107,13 +107,13 @@ public function testFromTableFillsDetails() $keys = $this->getPrivateProperty($this->table, 'keys'); - $this->assertCount(4, $keys); + $this->assertCount(3, $keys); $this->assertArrayHasKey('foo_name', $keys); $this->assertSame(['fields' => ['name'], 'type' => 'index'], $keys['foo_name']); - $this->assertArrayHasKey('id', $keys); - $this->assertSame(['fields' => ['id'], 'type' => 'primary'], $keys['id']); - $this->assertArrayHasKey('id', $keys); - $this->assertSame(['fields' => ['id'], 'type' => 'primary'], $keys['id']); + $this->assertArrayHasKey('foo_email', $keys); + $this->assertSame(['fields' => ['email'], 'type' => 'unique'], $keys['foo_email']); + $this->assertArrayHasKey('primary', $keys); + $this->assertSame(['fields' => ['id'], 'type' => 'primary'], $keys['primary']); } public function testDropColumnSuccess() diff --git a/tests/system/Database/Live/SQLite/GetIndexDataTest.php b/tests/system/Database/Live/SQLite/GetIndexDataTest.php index f9498cd0301d..74074b17b823 100644 --- a/tests/system/Database/Live/SQLite/GetIndexDataTest.php +++ b/tests/system/Database/Live/SQLite/GetIndexDataTest.php @@ -90,7 +90,7 @@ public function testGetIndexData() $row = new stdclass(); $row->name = 'testuser_country'; $row->fields = ['country']; - $row->type = ''; + $row->type = 'INDEX'; $expectedIndexes['testuser_country'] = $row; $indexes = $this->db->getIndexData('testuser'); @@ -105,6 +105,5 @@ public function testGetIndexData() $this->assertSame($expectedIndexes['testuser_country']->type, $indexes['testuser_country']->type); $this->forge->dropTable('testuser', true); - $this->forge->dropTable('userforeign', true); } } From def6e1f3146d65e9ec56e3b723f3f445ee905c7b Mon Sep 17 00:00:00 2001 From: sclubricants Date: Tue, 5 Jul 2022 16:28:41 -0700 Subject: [PATCH 073/970] fix cs --- system/Database/SQLite3/Table.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 3eb5437c6a44..6c3328557578 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -369,7 +369,7 @@ protected function dropIndexes() return; } - foreach ($this->keys as $name => $key) { + foreach (array_keys($this->keys) as $name) { if ($name === 'primary') { continue; } From 60ce81d94338690ba87e85865f7827b78990af9d Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Jun 2022 15:35:33 +0900 Subject: [PATCH 074/970] feat: add class ContentReplacer --- system/Publisher/ContentReplacer.php | 87 ++++++++ .../system/Publisher/ContentReplacerTest.php | 200 ++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 system/Publisher/ContentReplacer.php create mode 100644 tests/system/Publisher/ContentReplacerTest.php diff --git a/system/Publisher/ContentReplacer.php b/system/Publisher/ContentReplacer.php new file mode 100644 index 000000000000..4c31b604c89e --- /dev/null +++ b/system/Publisher/ContentReplacer.php @@ -0,0 +1,87 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Publisher; + +class ContentReplacer +{ + /** + * Replace content + * + * @param array $replaces [search => replace] + */ + public function replace(string $content, array $replaces): string + { + return strtr($content, $replaces); + } + + /** + * Add text + * + * @param string $text Text to add. + * @param string $pattern Regexp search pattern. + * @param string $replace Regexp replacement including text to add. + * + * @return bool|string true: already updated, false: regexp error. + */ + public function add(string $content, string $text, string $pattern, string $replace) + { + $return = preg_match('/' . preg_quote($text, '/') . '/u', $content); + + if ($return === 1) { + // It has already been updated. + + return true; + } + + if ($return === false) { + // Regexp error. + + return false; + } + + return preg_replace($pattern, $replace, $content); + } + + /** + * Add line after the line with the string + * + * @param string $content Whole content. + * @param string $line Line to add. + * @param string $after String to search. + * + * @return bool|string true: already updated, false: regexp error. + */ + public function addAfter(string $content, string $line, string $after) + { + $pattern = '/(.*)(\n[^\n]*?' . preg_quote($after, '/') . '[^\n]*?\n)/su'; + $replace = '$1$2' . $line . "\n"; + + return $this->add($content, $line, $pattern, $replace); + } + + /** + * Add line before the line with the string + * + * @param string $content Whole content. + * @param string $line Line to add. + * @param string $before String to search. + * + * @return bool|string true: already updated, false: regexp error. + */ + public function addBefore(string $content, string $line, string $before) + { + $pattern = '/(\n)([^\n]*?' . preg_quote($before, '/') . ')(.*)/su'; + $replace = '$1' . $line . "\n" . '$2$3'; + + return $this->add($content, $line, $pattern, $replace); + } +} diff --git a/tests/system/Publisher/ContentReplacerTest.php b/tests/system/Publisher/ContentReplacerTest.php new file mode 100644 index 000000000000..00875c59825d --- /dev/null +++ b/tests/system/Publisher/ContentReplacerTest.php @@ -0,0 +1,200 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Publisher; + +use CodeIgniter\Test\CIUnitTestCase; + +/** + * @internal + */ +final class ContentReplacerTest extends CIUnitTestCase +{ + public function testReplace(): void + { + $replacer = new ContentReplacer(); + $content = <<<'FILE' + 'namespace Config', + "use CodeIgniter\\Config\\BaseConfig;\n" => '', + 'extends BaseConfig' => 'extends \\CodeIgniter\\Shield\\Config\\Auth', + ]; + $output = $replacer->replace($content, $replaces); + + $expected = <<<'FILE' + assertSame($expected, $output); + } + + public function testAddAddingAfter(): void + { + $replacer = new ContentReplacer(); + $content = <<<'FILE' + get('/', 'Home::index'); + + /** + * You will have access to the $routes object within that file without + * needing to reload it. + */ + + FILE; + + $text = 'service(\'auth\')->routes($routes);'; + $pattern = '/(.*)(\n' . preg_quote('$routes->', '/') . '[^\n]+?\n)/su'; + $replace = '$1$2' . "\n" . $text . "\n"; + $output = $replacer->add($content, $text, $pattern, $replace); + + $expected = <<<'FILE' + get('/', 'Home::index'); + + service('auth')->routes($routes); + + /** + * You will have access to the $routes object within that file without + * needing to reload it. + */ + + FILE; + $this->assertSame($expected, $output); + } + + public function testAddAddingBefore(): void + { + $replacer = new ContentReplacer(); + $content = <<<'FILE' + helpers = array_merge($this->helpers, [\'auth\', \'setting\']);'; + $pattern = '/(' . preg_quote('// Do Not Edit This Line', '/') . ')/u'; + $replace = $text . "\n\n " . '$1'; + $output = $replacer->add($content, $text, $pattern, $replace); + + $expected = <<<'FILE' + helpers = array_merge($this->helpers, ['auth', 'setting']); + + // Do Not Edit This Line + parent::initController($request, $response, $logger); + } + } + FILE; + $this->assertSame($expected, $output); + } + + public function testAddAfter(): void + { + $replacer = new ContentReplacer(); + $content = <<<'FILE' + $routes->get('/', 'Home::index'); + $routes->get('/login', 'Login::index'); + + FILE; + + $line = "\n" . 'service(\'auth\')->routes($routes);'; + $after = '$routes->'; + $output = $replacer->addAfter($content, $line, $after); + + $expected = <<<'FILE' + $routes->get('/', 'Home::index'); + $routes->get('/login', 'Login::index'); + + service('auth')->routes($routes); + + FILE; + $this->assertSame($expected, $output); + } + + public function testAddBefore(): void + { + $replacer = new ContentReplacer(); + $content = <<<'FILE' + helpers = array_merge($this->helpers, [\'auth\', \'setting\']);'; + $before = '// Do Not Edit This Line'; + $output = $replacer->addBefore($content, $line, $before); + + $expected = <<<'FILE' + helpers = array_merge($this->helpers, ['auth', 'setting']); + // Do Not Edit This Line + parent::initController($request, $response, $logger); + // Do Not Edit This Line + + FILE; + $this->assertSame($expected, $output); + } +} From 362a56262e46df31578a23fe43e87f39f68910f9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 16 Jun 2022 18:03:34 +0900 Subject: [PATCH 075/970] feat: add Publisher::replace(), addLineAfter(), addLineBefore() --- system/Publisher/Publisher.php | 85 +++++++++++++++- .../Publisher/PublisherContentReplaceTest.php | 97 +++++++++++++++++++ 2 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 tests/system/Publisher/PublisherContentReplaceTest.php diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 01a3c62db657..6ab147b4f8b7 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -71,6 +71,8 @@ class Publisher extends FileCollection */ private array $restrictions; + private ContentReplacer $replacer; + /** * Base path to use for the source. * @@ -157,6 +159,8 @@ public function __construct(?string $source = null, ?string $destination = null) $this->source = self::resolveDirectory($source ?? $this->source); $this->destination = self::resolveDirectory($destination ?? $this->destination); + $this->replacer = new ContentReplacer(); + // Restrictions are intentionally not injected to prevent overriding $this->restrictions = config('Publisher')->restrictions; @@ -397,12 +401,73 @@ final public function merge(bool $replace = true): bool } /** - * Copies a file with directory creation and identical file awareness. - * Intentionally allows errors. + * Replace content * - * @throws PublisherException For collisions and restriction violations + * @param array $replaces [search => replace] + * + * @return bool */ - private function safeCopyFile(string $from, string $to, bool $replace): void + public function replace(string $file, array $replaces) + { + $this->verifyAllowed($file, $file); + + $content = file_get_contents($file); + + $newContent = $this->replacer->replace($content, $replaces); + + $return = file_put_contents($file, $newContent); + + return $return !== false; + } + + /** + * Add line after the line with the string + * + * @param string $after String to search. + */ + public function addLineAfter(string $file, string $line, string $after): bool + { + $this->verifyAllowed($file, $file); + + $content = file_get_contents($file); + + $newContent = $this->replacer->addAfter($content, $line, $after); + + if (is_bool($newContent)) { + return $newContent; + } + + $return = file_put_contents($file, $newContent); + + return $return !== false; + } + + /** + * Add line before the line with the string + * + * @param string $before String to search. + */ + public function addLineBefore(string $file, string $line, string $before): bool + { + $this->verifyAllowed($file, $file); + + $content = file_get_contents($file); + + $newContent = $this->replacer->addBefore($content, $line, $before); + + if (is_bool($newContent)) { + return $newContent; + } + + $return = file_put_contents($file, $newContent); + + return $return !== false; + } + + /** + * Verify this is an allowed file for its destination. + */ + private function verifyAllowed(string $from, string $to) { // Verify this is an allowed file for its destination foreach ($this->restrictions as $directory => $pattern) { @@ -410,6 +475,18 @@ private function safeCopyFile(string $from, string $to, bool $replace): void throw PublisherException::forFileNotAllowed($from, $directory, $pattern); } } + } + + /** + * 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 + $this->verifyAllowed($from, $to); // Check for an existing file if (file_exists($to)) { diff --git a/tests/system/Publisher/PublisherContentReplaceTest.php b/tests/system/Publisher/PublisherContentReplaceTest.php new file mode 100644 index 000000000000..f265bc4c14d4 --- /dev/null +++ b/tests/system/Publisher/PublisherContentReplaceTest.php @@ -0,0 +1,97 @@ + + * + * For the full copyright and license information, please view + * the LICENSE file that was distributed with this source code. + */ + +namespace CodeIgniter\Publisher; + +use CodeIgniter\Test\CIUnitTestCase; + +/** + * @internal + */ +final class PublisherContentReplaceTest extends CIUnitTestCase +{ + private string $file; + private Publisher $publisher; + + protected function setUp(): void + { + parent::setUp(); + + $this->file = __DIR__ . '/App.php'; + copy(APPPATH . 'Config/App.php', $this->file); + + $this->publisher = new Publisher(__DIR__, __DIR__); + } + + protected function tearDown(): void + { + parent::tearDown(); + + unlink($this->file); + } + + public function testAddLineAfter() + { + $result = $this->publisher->addLineAfter( + $this->file, + ' public $myOwnConfig = 1000;', + 'public $CSPEnabled = false;' + ); + + $this->assertTrue($result); + $this->assertStringContainsString( + ' public $CSPEnabled = false; + public $myOwnConfig = 1000;', + file_get_contents($this->file) + ); + } + + public function testAddLineBefore() + { + $result = $this->publisher->addLineBefore( + $this->file, + ' public $myOwnConfig = 1000;', + 'public $CSPEnabled = false;' + ); + + $this->assertTrue($result); + $this->assertStringContainsString( + ' public $myOwnConfig = 1000; + public $CSPEnabled = false;', + file_get_contents($this->file) + ); + } + + public function testReplace() + { + $result = $this->publisher->replace( + $this->file, + [ + 'use CodeIgniter\Config\BaseConfig;' . "\n" => '', + 'class App extends BaseConfig' => 'class App extends \Some\Package\SomeConfig', + ] + ); + + $this->assertTrue($result); + $this->assertStringNotContainsString( + 'use CodeIgniter\Config\BaseConfig;', + file_get_contents($this->file) + ); + $this->assertStringContainsString( + 'class App extends \Some\Package\SomeConfig', + file_get_contents($this->file) + ); + $this->assertStringNotContainsString( + 'class App extends BaseConfig', + file_get_contents($this->file) + ); + } +} From 003e64d68d798319107be13ae69b619881ec6471 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Jun 2022 07:46:46 +0900 Subject: [PATCH 076/970] refactor: change visibility Co-authored-by: MGatner --- system/Publisher/ContentReplacer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Publisher/ContentReplacer.php b/system/Publisher/ContentReplacer.php index 4c31b604c89e..367d901a76b5 100644 --- a/system/Publisher/ContentReplacer.php +++ b/system/Publisher/ContentReplacer.php @@ -32,7 +32,7 @@ public function replace(string $content, array $replaces): string * * @return bool|string true: already updated, false: regexp error. */ - public function add(string $content, string $text, string $pattern, string $replace) + private function add(string $content, string $text, string $pattern, string $replace) { $return = preg_match('/' . preg_quote($text, '/') . '/u', $content); From 1dc06ec87b6910c7db6017d5e3a3e238f84ef021 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 19 Jun 2022 08:43:21 +0900 Subject: [PATCH 077/970] feat: change return type of ContentReplacer::add() --- system/Publisher/ContentReplacer.php | 38 ++++-- system/Publisher/Publisher.php | 24 ++-- .../system/Publisher/ContentReplacerTest.php | 118 ++++++------------ 3 files changed, 80 insertions(+), 100 deletions(-) diff --git a/system/Publisher/ContentReplacer.php b/system/Publisher/ContentReplacer.php index 367d901a76b5..05d75457ca0a 100644 --- a/system/Publisher/ContentReplacer.php +++ b/system/Publisher/ContentReplacer.php @@ -11,6 +11,9 @@ namespace CodeIgniter\Publisher; +use RuntimeException; +use stdClass; + class ContentReplacer { /** @@ -30,25 +33,38 @@ public function replace(string $content, array $replaces): string * @param string $pattern Regexp search pattern. * @param string $replace Regexp replacement including text to add. * - * @return bool|string true: already updated, false: regexp error. + * @return stdClass {updated: bool, content: string} */ - private function add(string $content, string $text, string $pattern, string $replace) + private function add(string $content, string $text, string $pattern, string $replace): stdClass { + $result = new stdClass(); + $return = preg_match('/' . preg_quote($text, '/') . '/u', $content); + if ($return === false) { + // Regexp error. + throw new RuntimeException(preg_last_error_msg()); + } + if ($return === 1) { // It has already been updated. + $result->updated = false; + $result->content = $content; - return true; + return $result; } - if ($return === false) { - // Regexp error. + $return = preg_replace($pattern, $replace, $content); - return false; + if ($return === null) { + // Regexp error. + throw new RuntimeException(preg_last_error_msg()); } - return preg_replace($pattern, $replace, $content); + $result->updated = true; + $result->content = $return; + + return $result; } /** @@ -58,9 +74,9 @@ private function add(string $content, string $text, string $pattern, string $rep * @param string $line Line to add. * @param string $after String to search. * - * @return bool|string true: already updated, false: regexp error. + * @return stdClass {updated: bool, content: string} */ - public function addAfter(string $content, string $line, string $after) + public function addAfter(string $content, string $line, string $after): stdClass { $pattern = '/(.*)(\n[^\n]*?' . preg_quote($after, '/') . '[^\n]*?\n)/su'; $replace = '$1$2' . $line . "\n"; @@ -75,9 +91,9 @@ public function addAfter(string $content, string $line, string $after) * @param string $line Line to add. * @param string $before String to search. * - * @return bool|string true: already updated, false: regexp error. + * @return stdClass {updated: bool, content: string} */ - public function addBefore(string $content, string $line, string $before) + public function addBefore(string $content, string $line, string $before): stdClass { $pattern = '/(\n)([^\n]*?' . preg_quote($before, '/') . ')(.*)/su'; $replace = '$1' . $line . "\n" . '$2$3'; diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 6ab147b4f8b7..23179da9abd2 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -431,15 +431,15 @@ public function addLineAfter(string $file, string $line, string $after): bool $content = file_get_contents($file); - $newContent = $this->replacer->addAfter($content, $line, $after); + $result = $this->replacer->addAfter($content, $line, $after); - if (is_bool($newContent)) { - return $newContent; - } + if ($result->updated) { + $return = file_put_contents($file, $result->content); - $return = file_put_contents($file, $newContent); + return $return !== false; + } - return $return !== false; + return false; } /** @@ -453,15 +453,15 @@ public function addLineBefore(string $file, string $line, string $before): bool $content = file_get_contents($file); - $newContent = $this->replacer->addBefore($content, $line, $before); + $result = $this->replacer->addBefore($content, $line, $before); - if (is_bool($newContent)) { - return $newContent; - } + if ($result->updated) { + $return = file_put_contents($file, $result->content); - $return = file_put_contents($file, $newContent); + return $return !== false; + } - return $return !== false; + return false; } /** diff --git a/tests/system/Publisher/ContentReplacerTest.php b/tests/system/Publisher/ContentReplacerTest.php index 00875c59825d..0274eb56a4a3 100644 --- a/tests/system/Publisher/ContentReplacerTest.php +++ b/tests/system/Publisher/ContentReplacerTest.php @@ -53,129 +53,92 @@ class Auth extends \CodeIgniter\Shield\Config\Auth $this->assertSame($expected, $output); } - public function testAddAddingAfter(): void + public function testAddAfter(): void { $replacer = new ContentReplacer(); $content = <<<'FILE' - get('/', 'Home::index'); - - /** - * You will have access to the $routes object within that file without - * needing to reload it. - */ + $routes->get('/login', 'Login::index'); FILE; - $text = 'service(\'auth\')->routes($routes);'; - $pattern = '/(.*)(\n' . preg_quote('$routes->', '/') . '[^\n]+?\n)/su'; - $replace = '$1$2' . "\n" . $text . "\n"; - $output = $replacer->add($content, $text, $pattern, $replace); + $line = "\n" . 'service(\'auth\')->routes($routes);'; + $after = '$routes->'; + $result = $replacer->addAfter($content, $line, $after); $expected = <<<'FILE' - get('/', 'Home::index'); + $routes->get('/login', 'Login::index'); service('auth')->routes($routes); - /** - * You will have access to the $routes object within that file without - * needing to reload it. - */ - FILE; - $this->assertSame($expected, $output); + $this->assertSame($expected, $result->content); + $this->assertTrue($result->updated); } - public function testAddAddingBefore(): void + public function testAddAfterAlreadyUpdated(): void { $replacer = new ContentReplacer(); $content = <<<'FILE' - get('/', 'Home::index'); + $routes->get('/login', 'Login::index'); - namespace App\Controllers; + service('auth')->routes($routes); - abstract class BaseController extends Controller - { - public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) - { - // Do Not Edit This Line - parent::initController($request, $response, $logger); - } - } FILE; - $text = '$this->helpers = array_merge($this->helpers, [\'auth\', \'setting\']);'; - $pattern = '/(' . preg_quote('// Do Not Edit This Line', '/') . ')/u'; - $replace = $text . "\n\n " . '$1'; - $output = $replacer->add($content, $text, $pattern, $replace); + $line = "\n" . 'service(\'auth\')->routes($routes);'; + $after = '$routes->'; + $result = $replacer->addAfter($content, $line, $after); $expected = <<<'FILE' - get('/', 'Home::index'); + $routes->get('/login', 'Login::index'); - namespace App\Controllers; + service('auth')->routes($routes); - abstract class BaseController extends Controller - { - public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger) - { - $this->helpers = array_merge($this->helpers, ['auth', 'setting']); - - // Do Not Edit This Line - parent::initController($request, $response, $logger); - } - } FILE; - $this->assertSame($expected, $output); + $this->assertSame($expected, $result->content); + $this->assertFalse($result->updated); } - public function testAddAfter(): void + public function testAddBefore(): void { $replacer = new ContentReplacer(); $content = <<<'FILE' - $routes->get('/', 'Home::index'); - $routes->get('/login', 'Login::index'); + routes($routes);'; - $after = '$routes->'; - $output = $replacer->addAfter($content, $line, $after); + $line = '$this->helpers = array_merge($this->helpers, [\'auth\', \'setting\']);'; + $before = '// Do Not Edit This Line'; + $result = $replacer->addBefore($content, $line, $before); $expected = <<<'FILE' - $routes->get('/', 'Home::index'); - $routes->get('/login', 'Login::index'); + routes($routes); + $this->helpers = array_merge($this->helpers, ['auth', 'setting']); + // Do Not Edit This Line + parent::initController($request, $response, $logger); + // Do Not Edit This Line FILE; - $this->assertSame($expected, $output); + $this->assertSame($expected, $result->content); + $this->assertTrue($result->updated); } - public function testAddBefore(): void + public function testAddBeforeAlreadyUpdated(): void { $replacer = new ContentReplacer(); $content = <<<'FILE' helpers = array_merge($this->helpers, ['auth', 'setting']); // Do Not Edit This Line parent::initController($request, $response, $logger); // Do Not Edit This Line @@ -184,7 +147,7 @@ public function testAddBefore(): void $line = '$this->helpers = array_merge($this->helpers, [\'auth\', \'setting\']);'; $before = '// Do Not Edit This Line'; - $output = $replacer->addBefore($content, $line, $before); + $result = $replacer->addBefore($content, $line, $before); $expected = <<<'FILE' assertSame($expected, $output); + $this->assertSame($expected, $result->content); + $this->assertFalse($result->updated); } } From 830d0c0003a700742778ff9118f97751a762cc6c Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 10 Jul 2022 11:35:20 +0900 Subject: [PATCH 078/970] refactor: preg_last_error_msg() requires PHP8 or later --- system/Publisher/ContentReplacer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Publisher/ContentReplacer.php b/system/Publisher/ContentReplacer.php index 05d75457ca0a..eca0c7ac55a6 100644 --- a/system/Publisher/ContentReplacer.php +++ b/system/Publisher/ContentReplacer.php @@ -43,7 +43,7 @@ private function add(string $content, string $text, string $pattern, string $rep if ($return === false) { // Regexp error. - throw new RuntimeException(preg_last_error_msg()); + throw new RuntimeException('Regex error. PCRE error code: ' . preg_last_error()); } if ($return === 1) { @@ -58,7 +58,7 @@ private function add(string $content, string $text, string $pattern, string $rep if ($return === null) { // Regexp error. - throw new RuntimeException(preg_last_error_msg()); + throw new RuntimeException('Regex error. PCRE error code: ' . preg_last_error()); } $result->updated = true; From ca91e22929040d9e7721b023cc968f2ecb44b2a3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 10 Jul 2022 11:58:26 +0900 Subject: [PATCH 079/970] test: update assertions Config\App has been changed. --- .../Publisher/PublisherContentReplaceTest.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/system/Publisher/PublisherContentReplaceTest.php b/tests/system/Publisher/PublisherContentReplaceTest.php index f265bc4c14d4..ab6748027f17 100644 --- a/tests/system/Publisher/PublisherContentReplaceTest.php +++ b/tests/system/Publisher/PublisherContentReplaceTest.php @@ -42,14 +42,14 @@ public function testAddLineAfter() { $result = $this->publisher->addLineAfter( $this->file, - ' public $myOwnConfig = 1000;', - 'public $CSPEnabled = false;' + ' public int $myOwnConfig = 1000;', + 'public bool $CSPEnabled = false;' ); $this->assertTrue($result); $this->assertStringContainsString( - ' public $CSPEnabled = false; - public $myOwnConfig = 1000;', + ' public bool $CSPEnabled = false; + public int $myOwnConfig = 1000;', file_get_contents($this->file) ); } @@ -58,14 +58,14 @@ public function testAddLineBefore() { $result = $this->publisher->addLineBefore( $this->file, - ' public $myOwnConfig = 1000;', - 'public $CSPEnabled = false;' + ' public int $myOwnConfig = 1000;', + 'public bool $CSPEnabled = false;' ); $this->assertTrue($result); $this->assertStringContainsString( - ' public $myOwnConfig = 1000; - public $CSPEnabled = false;', + ' public int $myOwnConfig = 1000; + public bool $CSPEnabled = false;', file_get_contents($this->file) ); } From 6ae1dbcca1c15a15c934183ebd7c25d3548cf604 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 11 Jul 2022 11:10:59 +0900 Subject: [PATCH 080/970] refactor: remove stdClass result object Using stdClass is not good practice. --- system/Publisher/ContentReplacer.php | 25 +++++----------- system/Publisher/Publisher.php | 8 ++--- .../system/Publisher/ContentReplacerTest.php | 30 +++---------------- 3 files changed, 16 insertions(+), 47 deletions(-) diff --git a/system/Publisher/ContentReplacer.php b/system/Publisher/ContentReplacer.php index eca0c7ac55a6..2372e850b080 100644 --- a/system/Publisher/ContentReplacer.php +++ b/system/Publisher/ContentReplacer.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Publisher; use RuntimeException; -use stdClass; class ContentReplacer { @@ -33,12 +32,10 @@ public function replace(string $content, array $replaces): string * @param string $pattern Regexp search pattern. * @param string $replace Regexp replacement including text to add. * - * @return stdClass {updated: bool, content: string} + * @return string|null Updated content, or null if not updated. */ - private function add(string $content, string $text, string $pattern, string $replace): stdClass + private function add(string $content, string $text, string $pattern, string $replace): ?string { - $result = new stdClass(); - $return = preg_match('/' . preg_quote($text, '/') . '/u', $content); if ($return === false) { @@ -48,10 +45,7 @@ private function add(string $content, string $text, string $pattern, string $rep if ($return === 1) { // It has already been updated. - $result->updated = false; - $result->content = $content; - - return $result; + return null; } $return = preg_replace($pattern, $replace, $content); @@ -61,10 +55,7 @@ private function add(string $content, string $text, string $pattern, string $rep throw new RuntimeException('Regex error. PCRE error code: ' . preg_last_error()); } - $result->updated = true; - $result->content = $return; - - return $result; + return $return; } /** @@ -74,9 +65,9 @@ private function add(string $content, string $text, string $pattern, string $rep * @param string $line Line to add. * @param string $after String to search. * - * @return stdClass {updated: bool, content: string} + * @return string|null Updated content, or null if not updated. */ - public function addAfter(string $content, string $line, string $after): stdClass + public function addAfter(string $content, string $line, string $after): ?string { $pattern = '/(.*)(\n[^\n]*?' . preg_quote($after, '/') . '[^\n]*?\n)/su'; $replace = '$1$2' . $line . "\n"; @@ -91,9 +82,9 @@ public function addAfter(string $content, string $line, string $after): stdClass * @param string $line Line to add. * @param string $before String to search. * - * @return stdClass {updated: bool, content: string} + * @return string|null Updated content, or null if not updated. */ - public function addBefore(string $content, string $line, string $before): stdClass + public function addBefore(string $content, string $line, string $before): ?string { $pattern = '/(\n)([^\n]*?' . preg_quote($before, '/') . ')(.*)/su'; $replace = '$1' . $line . "\n" . '$2$3'; diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 23179da9abd2..920650fe9351 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -433,8 +433,8 @@ public function addLineAfter(string $file, string $line, string $after): bool $result = $this->replacer->addAfter($content, $line, $after); - if ($result->updated) { - $return = file_put_contents($file, $result->content); + if ($result !== null) { + $return = file_put_contents($file, $result); return $return !== false; } @@ -455,8 +455,8 @@ public function addLineBefore(string $file, string $line, string $before): bool $result = $this->replacer->addBefore($content, $line, $before); - if ($result->updated) { - $return = file_put_contents($file, $result->content); + if ($result !== null) { + $return = file_put_contents($file, $result); return $return !== false; } diff --git a/tests/system/Publisher/ContentReplacerTest.php b/tests/system/Publisher/ContentReplacerTest.php index 0274eb56a4a3..dbfc6d80109b 100644 --- a/tests/system/Publisher/ContentReplacerTest.php +++ b/tests/system/Publisher/ContentReplacerTest.php @@ -73,8 +73,7 @@ public function testAddAfter(): void service('auth')->routes($routes); FILE; - $this->assertSame($expected, $result->content); - $this->assertTrue($result->updated); + $this->assertSame($expected, $result); } public function testAddAfterAlreadyUpdated(): void @@ -91,16 +90,7 @@ public function testAddAfterAlreadyUpdated(): void $line = "\n" . 'service(\'auth\')->routes($routes);'; $after = '$routes->'; $result = $replacer->addAfter($content, $line, $after); - - $expected = <<<'FILE' - $routes->get('/', 'Home::index'); - $routes->get('/login', 'Login::index'); - - service('auth')->routes($routes); - - FILE; - $this->assertSame($expected, $result->content); - $this->assertFalse($result->updated); + $this->assertNull($result); } public function testAddBefore(): void @@ -128,8 +118,7 @@ public function testAddBefore(): void // Do Not Edit This Line FILE; - $this->assertSame($expected, $result->content); - $this->assertTrue($result->updated); + $this->assertSame($expected, $result); } public function testAddBeforeAlreadyUpdated(): void @@ -148,17 +137,6 @@ public function testAddBeforeAlreadyUpdated(): void $line = '$this->helpers = array_merge($this->helpers, [\'auth\', \'setting\']);'; $before = '// Do Not Edit This Line'; $result = $replacer->addBefore($content, $line, $before); - - $expected = <<<'FILE' - helpers = array_merge($this->helpers, ['auth', 'setting']); - // Do Not Edit This Line - parent::initController($request, $response, $logger); - // Do Not Edit This Line - - FILE; - $this->assertSame($expected, $result->content); - $this->assertFalse($result->updated); + $this->assertNull($result); } } From 615400147b5e8cbc38d43446d6eceea7ad0937cc Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 11 Jul 2022 11:28:33 +0900 Subject: [PATCH 081/970] docs: add doc comment --- system/Publisher/ContentReplacer.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/system/Publisher/ContentReplacer.php b/system/Publisher/ContentReplacer.php index 2372e850b080..76cef11336f1 100644 --- a/system/Publisher/ContentReplacer.php +++ b/system/Publisher/ContentReplacer.php @@ -13,6 +13,9 @@ use RuntimeException; +/** + * Replace Text Content + */ class ContentReplacer { /** From 2258c955e004aca1a3c03c196f7ed59605828c4b Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Jul 2022 17:06:55 +0900 Subject: [PATCH 082/970] refactor: add return type --- system/Publisher/Publisher.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/Publisher/Publisher.php b/system/Publisher/Publisher.php index 920650fe9351..502d3670ff12 100644 --- a/system/Publisher/Publisher.php +++ b/system/Publisher/Publisher.php @@ -404,10 +404,8 @@ final public function merge(bool $replace = true): bool * Replace content * * @param array $replaces [search => replace] - * - * @return bool */ - public function replace(string $file, array $replaces) + public function replace(string $file, array $replaces): bool { $this->verifyAllowed($file, $file); From 7c028b718270c3fde17f9ea0b84be0b6f626a9e6 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Jul 2022 17:07:44 +0900 Subject: [PATCH 083/970] docs: fix existing sample code --- user_guide_src/source/libraries/publisher/010.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/libraries/publisher/010.php b/user_guide_src/source/libraries/publisher/010.php index 652322fd0bcb..61b75287e51f 100644 --- a/user_guide_src/source/libraries/publisher/010.php +++ b/user_guide_src/source/libraries/publisher/010.php @@ -15,9 +15,9 @@ class AuthPublish extends BaseCommand public function run(array $params) { // Use the Autoloader to figure out the module path - $source = service('autoloader')->getNamespace('Math\\Auth'); + $source = service('autoloader')->getNamespace('Math\\Auth')[0]; - $publisher = new Publisher($source, APPATH); + $publisher = new Publisher($source, APPPATH); try { // Add only the desired components From a4f5e8c69834d09b408ed4b9febcd21fbcb98e75 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Jul 2022 17:21:13 +0900 Subject: [PATCH 084/970] docs: add replace(), addLineAfter(), addLineBefore() --- user_guide_src/source/libraries/publisher.rst | 24 +++++++++++++++++++ .../source/libraries/publisher/013.php | 16 +++++++++++++ .../source/libraries/publisher/014.php | 14 +++++++++++ .../source/libraries/publisher/015.php | 14 +++++++++++ 4 files changed, 68 insertions(+) create mode 100644 user_guide_src/source/libraries/publisher/013.php create mode 100644 user_guide_src/source/libraries/publisher/014.php create mode 100644 user_guide_src/source/libraries/publisher/015.php diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 5c437c3715e8..9da4e6c9eb9d 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -264,3 +264,27 @@ affect other files in the destination. Returns success or failure, use ``getPubl Example: .. literalinclude:: publisher/012.php + +Modifying Files +=============== + +replace(string $file, array $replaces): bool +-------------------------------------------- + +Replaces the ``$file`` contents. The second parameter ``$replaces`` array specifies the search strings as keys and the replacements as values. + +.. literalinclude:: publisher/013.php + +addLineAfter(string $file, string $line, string $after): bool +------------------------------------------------------------- + +Adds ``$line`` after a line with specific string ``$after``. + +.. literalinclude:: publisher/014.php + +addLineBefore(string $file, string $line, string $after): bool +-------------------------------------------------------------- + +Adds ``$line`` before a line with specific string ``$after``. + +.. literalinclude:: publisher/015.php diff --git a/user_guide_src/source/libraries/publisher/013.php b/user_guide_src/source/libraries/publisher/013.php new file mode 100644 index 000000000000..a48935497f5e --- /dev/null +++ b/user_guide_src/source/libraries/publisher/013.php @@ -0,0 +1,16 @@ +getNamespace('CodeIgniter\\Shield')[0]; +$publisher = new Publisher($source, APPPATH); + +$file = APPPATH . 'Config/Auth.php'; + +$publisher->replace( + $file, + [ + 'use CodeIgniter\Config\BaseConfig;' . "\n" => '', + 'class App extends BaseConfig' => 'class App extends \Some\Package\SomeConfig', + ] +); diff --git a/user_guide_src/source/libraries/publisher/014.php b/user_guide_src/source/libraries/publisher/014.php new file mode 100644 index 000000000000..06acbe1313cb --- /dev/null +++ b/user_guide_src/source/libraries/publisher/014.php @@ -0,0 +1,14 @@ +getNamespace('CodeIgniter\\Shield')[0]; +$publisher = new Publisher($source, APPPATH); + +$file = APPPATH . 'Config/App.php'; + +$publisher->addLineAfter( + $file, + ' public int $myOwnConfig = 1000;', // Adds this line + 'public bool $CSPEnabled = false;' // After this line +); diff --git a/user_guide_src/source/libraries/publisher/015.php b/user_guide_src/source/libraries/publisher/015.php new file mode 100644 index 000000000000..28cb609d4d0b --- /dev/null +++ b/user_guide_src/source/libraries/publisher/015.php @@ -0,0 +1,14 @@ +getNamespace('CodeIgniter\\Shield')[0]; +$publisher = new Publisher($source, APPPATH); + +$file = APPPATH . 'Config/App.php'; + +$publisher->addLineBefore( + $file, + ' public int $myOwnConfig = 1000;', // Add this line + 'public bool $CSPEnabled = false;' // Before this line +); From d9ea9da28679cbc340739956060a06456cb95027 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 12 Jul 2022 17:30:10 +0900 Subject: [PATCH 085/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/libraries/publisher.rst | 2 ++ 2 files changed, 3 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index f2f311c5ce89..e753fc93ef13 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -36,6 +36,7 @@ Enhancements - Added before and after events to ``BaseModel::insertBatch()`` and ``BaseModel::updateBatch()`` methods. See :ref:`model-events-callbacks`. - Added ``Model::allowEmptyInserts()`` method to insert empty data. See :ref:`Using CodeIgniter's Model ` - Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization ` +- Added methods ``replace()``, ``addLineAfter()`` and ``addLineBefore()`` to modify files in Publisher. See :ref:`Publisher ` for details. - The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. Changes diff --git a/user_guide_src/source/libraries/publisher.rst b/user_guide_src/source/libraries/publisher.rst index 9da4e6c9eb9d..630eac44b3ad 100644 --- a/user_guide_src/source/libraries/publisher.rst +++ b/user_guide_src/source/libraries/publisher.rst @@ -265,6 +265,8 @@ Example: .. literalinclude:: publisher/012.php +.. _publisher-modifying-files: + Modifying Files =============== From 01689104f8934a168bfd14dd786154b10e7911dd Mon Sep 17 00:00:00 2001 From: sclubricants Date: Tue, 12 Jul 2022 13:46:59 -0700 Subject: [PATCH 086/970] Added change log and source guide notes --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/database/metadata.rst | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index f2f311c5ce89..1730eb026d63 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -37,6 +37,7 @@ Enhancements - Added ``Model::allowEmptyInserts()`` method to insert empty data. See :ref:`Using CodeIgniter's Model ` - Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization ` - The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. +- Added a psuedo index named 'PRIMARY' for SQLite `AUTOINCREMENT` column. SQLite treats these in a special way which was excluding them from being retrieved by calling ``BaseConnection::getIndexData()``. Changes ******* diff --git a/user_guide_src/source/database/metadata.rst b/user_guide_src/source/database/metadata.rst index 458f70004102..8e3c71458d90 100644 --- a/user_guide_src/source/database/metadata.rst +++ b/user_guide_src/source/database/metadata.rst @@ -121,6 +121,10 @@ The key types may be unique to the database you are using. For instance, MySQL will return one of primary, fulltext, spatial, index or unique for each key associated with a table. +SQLite3 includes a psuedo index named 'PRIMARY'. `AUTOINCREMENT` columns are treated +in special way and wouldn't otherwise be returned. A drop command on this index will +cause an error. + $db->getForeignKeyData() ------------------------ From 741461c7aa8650a5583a79aabaac9429c2c23a05 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Wed, 13 Jul 2022 10:21:57 -0700 Subject: [PATCH 087/970] Update user_guide_src/source/changelogs/v4.3.0.rst Co-authored-by: kenjis --- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 1730eb026d63..dd8fb8b0c8f1 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -37,7 +37,7 @@ Enhancements - Added ``Model::allowEmptyInserts()`` method to insert empty data. See :ref:`Using CodeIgniter's Model ` - Added ``$routes->useSupportedLocalesOnly(true)`` so that the Router returns 404 Not Found if the locale in the URL is not supported in ``Config\App::$supportedLocales``. See :ref:`Localization ` - The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. -- Added a psuedo index named 'PRIMARY' for SQLite `AUTOINCREMENT` column. SQLite treats these in a special way which was excluding them from being retrieved by calling ``BaseConnection::getIndexData()``. +- SQLite ``BaseConnection::getIndexData()`` now can return pseudo index named ``PRIMARY`` for `AUTOINCREMENT` column, and each returned index data has ``type`` property. Changes ******* From 97c89e13bd6d64f7e4b7c48034abb37990efddc2 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Wed, 13 Jul 2022 10:22:07 -0700 Subject: [PATCH 088/970] Update user_guide_src/source/database/metadata.rst Co-authored-by: kenjis --- user_guide_src/source/database/metadata.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/user_guide_src/source/database/metadata.rst b/user_guide_src/source/database/metadata.rst index 8e3c71458d90..ed864afaf801 100644 --- a/user_guide_src/source/database/metadata.rst +++ b/user_guide_src/source/database/metadata.rst @@ -121,9 +121,7 @@ The key types may be unique to the database you are using. For instance, MySQL will return one of primary, fulltext, spatial, index or unique for each key associated with a table. -SQLite3 includes a psuedo index named 'PRIMARY'. `AUTOINCREMENT` columns are treated -in special way and wouldn't otherwise be returned. A drop command on this index will -cause an error. +SQLite3 returns a pseudo index named ``PRIMARY``. But it is a special index, and you can't use it in your SQL commands. $db->getForeignKeyData() ------------------------ From 8a2c1e9badcf0932734169942888b548eb55a54e Mon Sep 17 00:00:00 2001 From: sclubricants Date: Fri, 8 Jul 2022 16:21:03 -0700 Subject: [PATCH 089/970] test user table ->addUniqueKey('email')->addKey('country') --- .../Migrations/20160428212500_Create_test_tables.php | 2 +- tests/system/Database/Live/UpdateTest.php | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php index e802dcedc9be..ac489ecbb57b 100644 --- a/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php +++ b/tests/_support/Database/Migrations/20160428212500_Create_test_tables.php @@ -26,7 +26,7 @@ public function up() 'created_at' => ['type' => 'DATETIME', 'null' => true], 'updated_at' => ['type' => 'DATETIME', 'null' => true], 'deleted_at' => ['type' => 'DATETIME', 'null' => true], - ])->addKey('id', true)->createTable('user', true); + ])->addKey('id', true)->addUniqueKey('email')->addKey('country')->createTable('user', true); // Job Table $this->forge->addField([ diff --git a/tests/system/Database/Live/UpdateTest.php b/tests/system/Database/Live/UpdateTest.php index d69db467cdc2..49e9446deb0d 100644 --- a/tests/system/Database/Live/UpdateTest.php +++ b/tests/system/Database/Live/UpdateTest.php @@ -51,8 +51,15 @@ public function testUpdateSetsAllWithoutWhereAndLimit() ->get() ->getResult(); - $this->assertSame('Bobby', $result[0]->name); - $this->assertSame('Ahmadinejad', $result[1]->name); + // this is really a bad test - indexes and other things can affect sort order + if ($this->db->DBDriver === 'SQLSRV') { + $this->assertSame('Derek Jones', $result[0]->name); + $this->assertSame('Bobby', $result[1]->name); + } else { + $this->assertSame('Bobby', $result[0]->name); + $this->assertSame('Ahmadinejad', $result[1]->name); + } + $this->assertSame('Richard A Causey', $result[2]->name); $this->assertSame('Chris Martin', $result[3]->name); } catch (DatabaseException $e) { From 0cf7fd3259be32f5b1209fefaa3b7f65825a6c55 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Fri, 8 Jul 2022 16:45:13 -0700 Subject: [PATCH 090/970] fix insertModelTest unique constraint error --- tests/system/Models/InsertModelTest.php | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/tests/system/Models/InsertModelTest.php b/tests/system/Models/InsertModelTest.php index 7cf1ceb87dde..77b7de0bf646 100644 --- a/tests/system/Models/InsertModelTest.php +++ b/tests/system/Models/InsertModelTest.php @@ -185,16 +185,24 @@ public function testInsertBatchNewEntityWithDateTime(): void ]; }; + $entityTwo = clone $entity; + $this->createModel(UserModel::class); - $entity->name = 'Mark'; - $entity->email = 'mark@example.com'; + $entity->name = 'Mark One'; + $entity->email = 'markone@example.com'; $entity->country = 'India'; $entity->deleted = 0; $entity->created_at = new Time('now'); + $entityTwo->name = 'Mark Two'; + $entityTwo->email = 'marktwo@example.com'; + $entityTwo->country = 'India'; + $entityTwo->deleted = 0; + $entityTwo->created_at = $entity->created_at; + $this->setPrivateProperty($this->model, 'useTimestamps', true); - $this->assertSame(2, $this->model->insertBatch([$entity, $entity])); + $this->assertSame(2, $this->model->insertBatch([$entity, $entityTwo])); } public function testInsertArrayWithNoDataException(): void From dcfc17e804081e43870a0e9c66df1caa0e0aae0f Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 16 Jul 2022 10:54:21 +0900 Subject: [PATCH 091/970] fix: spark routes does not show routes at all --- system/Commands/Utilities/Routes.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index c8fc46bf3876..c62e11df6d3f 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -75,7 +75,10 @@ class Routes extends BaseCommand */ public function run(array $params) { - $collection = Services::routes(true); + $routes = Services::routes(true); + require APPPATH . 'Config/Routes.php'; + + $collection = $routes; $methods = [ 'get', 'head', From 9469097132b825abd6fa1e734cec8b797c79b1bd Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 11:28:48 +0900 Subject: [PATCH 092/970] feat: add spark filter:check command --- system/Commands/Utilities/FilterCheck.php | 127 ++++++++++++++++++++++ tests/system/Commands/FilterCheckTest.php | 60 ++++++++++ 2 files changed, 187 insertions(+) create mode 100644 system/Commands/Utilities/FilterCheck.php create mode 100644 tests/system/Commands/FilterCheckTest.php diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php new file mode 100644 index 000000000000..9f991b4e424c --- /dev/null +++ b/system/Commands/Utilities/FilterCheck.php @@ -0,0 +1,127 @@ + + * + * 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\Commands\Utilities\Routes\FilterCollector; +use Config\Services; + +/** + * Check filters for a route. + */ +class FilterCheck 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 = 'filter:check'; + + /** + * the Command's short description + * + * @var string + */ + protected $description = 'Check filters for a route.'; + + /** + * the Command's usage + * + * @var string + */ + protected $usage = 'filter:check '; + + /** + * the Command's Arguments + * + * @var array + */ + protected $arguments = [ + 'method' => 'The HTTP method. get, post, put, etc.', + 'route' => 'The route (URI path) to check filtes.', + ]; + + /** + * the Command's Options + * + * @var array + */ + protected $options = []; + + /** + * @return int exit code + */ + public function run(array $params) + { + if (count($params) !== 2) { + CLI::error('You must specify a HTTP verb and a route.', 'light_gray', 'red'); + CLI::write(' Usage: ' . $this->usage); + CLI::write('Example: filter:check get /'); + CLI::write(' filter:check put products/1'); + + return EXIT_ERROR; + } + + $method = strtolower($params[0]); + $route = $params[1]; + + // Load Routes + $routes = Services::routes(); + require APPPATH . 'Config/Routes.php'; + $routes->getRoutes('*'); // Triggers discovery + + $filterCollector = new FilterCollector(); + + $filters = $filterCollector->get($method, $route); + + // PageNotFoundException + if ($filters['before'] === ['']) { + CLI::error( + "Can't find a route: " . + CLI::color( + '"' . strtoupper($method) . ' ' . $route . '"', + 'black' + ), + ); + + return EXIT_ERROR; + } + + $tbody[] = [ + strtoupper($method), + $route, + implode(' ', $filters['before']), + implode(' ', $filters['after']), + ]; + + $thead = [ + 'Method', + 'Route', + 'Before Filters', + 'After Filters', + ]; + + CLI::table($tbody, $thead); + + return EXIT_SUCCESS; + } +} diff --git a/tests/system/Commands/FilterCheckTest.php b/tests/system/Commands/FilterCheckTest.php new file mode 100644 index 000000000000..8e08a67bf40b --- /dev/null +++ b/tests/system/Commands/FilterCheckTest.php @@ -0,0 +1,60 @@ + + * + * 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\StreamFilterTrait; + +/** + * @internal + */ +final class FilterCheckTest extends CIUnitTestCase +{ + use StreamFilterTrait; + + protected function setUp(): void + { + $this->resetServices(); + parent::setUp(); + } + + protected function tearDown(): void + { + $this->resetServices(); + parent::tearDown(); + } + + protected function getBuffer() + { + return $this->getStreamFilterBuffer(); + } + + public function testFilterCheckDefinedRoute() + { + command('filter:check get /'); + + $this->assertStringContainsString( + '|GET|/||toolbar|', + str_replace(' ', '', $this->getBuffer()) + ); + } + + public function testFilterCheckInvalidRoute() + { + command('filter:check put product/123'); + + $this->assertStringContainsString( + 'Can\'t find a route: "PUT product/123"', + str_replace(["\033[0m", "\033[0;31m", "\033[0;30m"], '', $this->getBuffer()) + ); + } +} From cb3b9f792cccf760996bd0440494ad5b4b414823 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 13:54:41 +0900 Subject: [PATCH 093/970] docs: add user guide --- user_guide_src/source/changelogs/v4.2.0.rst | 2 +- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/incoming/filters.rst | 25 +++++++++++++++++++-- user_guide_src/source/incoming/routing.rst | 4 ++-- 4 files changed, 27 insertions(+), 5 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.2.0.rst b/user_guide_src/source/changelogs/v4.2.0.rst index 2270c38e3f1b..adb81d77ab6d 100644 --- a/user_guide_src/source/changelogs/v4.2.0.rst +++ b/user_guide_src/source/changelogs/v4.2.0.rst @@ -113,7 +113,7 @@ Commands - ``spark db:table my_table --limit-rows 50 --limit-field-value 20 --desc`` - Or you can see metadata like the column type, max length of a table. - ``spark db:table my_table --metadata`` -- The ``spark routes`` command now shows closure routes, auto routes, and filters. See :ref:`URI Routing `. +- The ``spark routes`` command now shows closure routes, auto routes, and filters. See :ref:`URI Routing `. Others ====== diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 3f8385767308..c511bd2b5683 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -39,6 +39,7 @@ Enhancements - Added methods ``replace()``, ``addLineAfter()`` and ``addLineBefore()`` to modify files in Publisher. See :ref:`Publisher ` for details. - The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. - SQLite ``BaseConnection::getIndexData()`` now can return pseudo index named ``PRIMARY`` for `AUTOINCREMENT` column, and each returned index data has ``type`` property. +- Added ``spark filter:check`` command to check the filters for a route. See :ref:`Controller Filters ` for the details. Changes ******* diff --git a/user_guide_src/source/incoming/filters.rst b/user_guide_src/source/incoming/filters.rst index 7fdbef70d3be..482b58d480ce 100644 --- a/user_guide_src/source/incoming/filters.rst +++ b/user_guide_src/source/incoming/filters.rst @@ -150,8 +150,29 @@ In this example, the array ``['dual', 'noreturn']`` will be passed in ``$argumen Confirming Filters ****************** -You can see the routes and filters by the ``spark routes`` command. -See :ref:`URI Routing `. +CodeIgniter has the following :doc:`command ` to check the filters for a route. + +.. _spark-filter-check: + +filter:check +============ + +Check the filters for the route ``/`` with **GET** method:: + + > php spark filter:check get / + +The output is like the following: + +.. code-block:: none + + +--------+-------+----------------+---------------+ + | Method | Route | Before Filters | After Filters | + +--------+-------+----------------+---------------+ + | GET | / | | toolbar | + +--------+-------+----------------+---------------+ + +You can also see the routes and filters by the ``spark routes`` command. +See :ref:`URI Routing `. **************** Provided Filters diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 10b9946c20fe..03d6ee8625cc 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -713,7 +713,7 @@ Confirming Routes CodeIgniter has the following :doc:`command ` to display all routes. -.. _spark-routes: +.. _routing-spark-routes: routes ====== @@ -756,4 +756,4 @@ The *Method* will be like ``GET(auto)``. ``/..`` in the *Route* column indicates .. 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. If you want to check filters for a route, you can use :ref:`spark filter:check ` command. From 30a45fa842414817242a5f5a6354ad06174dafb0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Jul 2022 09:50:33 +0900 Subject: [PATCH 094/970] fix: parameter checking --- system/Commands/Utilities/FilterCheck.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index 9f991b4e424c..0731f28a30b3 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -72,7 +72,7 @@ class FilterCheck extends BaseCommand */ public function run(array $params) { - if (count($params) !== 2) { + if (! isset($params[0], $params[1])) { CLI::error('You must specify a HTTP verb and a route.', 'light_gray', 'red'); CLI::write(' Usage: ' . $this->usage); CLI::write('Example: filter:check get /'); From a3178b22f6c5d307662666f8bcf73fb53e5c6176 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Jul 2022 09:52:13 +0900 Subject: [PATCH 095/970] fix: output color --- system/Commands/Utilities/FilterCheck.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index 0731f28a30b3..7469ce1444c2 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -73,7 +73,7 @@ class FilterCheck extends BaseCommand public function run(array $params) { if (! isset($params[0], $params[1])) { - CLI::error('You must specify a HTTP verb and a route.', 'light_gray', 'red'); + CLI::error('You must specify a HTTP verb and a route.'); CLI::write(' Usage: ' . $this->usage); CLI::write('Example: filter:check get /'); CLI::write(' filter:check put products/1'); @@ -99,7 +99,8 @@ public function run(array $params) "Can't find a route: " . CLI::color( '"' . strtoupper($method) . ' ' . $route . '"', - 'black' + 'black', + 'light_gray' ), ); From 724f9c758e0b30b30f9a4d9ce9825980932b1527 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Jul 2022 10:31:47 +0900 Subject: [PATCH 096/970] test: fix test case --- tests/system/Commands/FilterCheckTest.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/system/Commands/FilterCheckTest.php b/tests/system/Commands/FilterCheckTest.php index 8e08a67bf40b..d5bd14e5f534 100644 --- a/tests/system/Commands/FilterCheckTest.php +++ b/tests/system/Commands/FilterCheckTest.php @@ -54,7 +54,11 @@ public function testFilterCheckInvalidRoute() $this->assertStringContainsString( 'Can\'t find a route: "PUT product/123"', - str_replace(["\033[0m", "\033[0;31m", "\033[0;30m"], '', $this->getBuffer()) + str_replace( + ["\033[0m", "\033[1;31m", "\033[0;30m", "\033[47m"], + '', + $this->getBuffer() + ) ); } } From fa8c0f794d8d82d83560d3849fe8c86db7671ace Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 19 Jul 2022 15:54:46 +0900 Subject: [PATCH 097/970] feat: add compatibility with CI3 Encryption --- app/Config/Encryption.php | 24 +++++++ phpstan-baseline.neon.dist | 4 -- system/Encryption/Handlers/OpenSSLHandler.php | 64 ++++++++++++++++--- tests/system/Encryption/EncryptionTest.php | 17 +++++ 4 files changed, 95 insertions(+), 14 deletions(-) diff --git a/app/Config/Encryption.php b/app/Config/Encryption.php index 388b1fa01942..e37b4e2a14ec 100644 --- a/app/Config/Encryption.php +++ b/app/Config/Encryption.php @@ -56,4 +56,28 @@ class Encryption extends BaseConfig * HMAC digest to use, e.g. 'SHA512' or 'SHA256'. Default value is 'SHA512'. */ public string $digest = 'SHA512'; + + /** + * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded. + * This setting is only used by OpenSSLHandler. + * + * Set to false for CI3 Encryption compatibility. + */ + public bool $rawData = true; + + /** + * Encryption key info. + * This setting is only used by OpenSSLHandler. + * + * Set to 'encryption' for CI3 Encryption compatibility. + */ + public string $encryptKeyInfo = ''; + + /** + * Authentication key info. + * This setting is only used by OpenSSLHandler. + * + * Set to 'authentication' for CI3 Encryption compatibility. + */ + public string $authKeyInfo = ''; } diff --git a/phpstan-baseline.neon.dist b/phpstan-baseline.neon.dist index 1de32c6e210e..629b312f1488 100644 --- a/phpstan-baseline.neon.dist +++ b/phpstan-baseline.neon.dist @@ -684,7 +684,3 @@ parameters: message: "#^Property Config\\\\View\\:\\:\\$plugins \\(array\\) on left side of \\?\\? is not nullable\\.$#" count: 1 path: system/View/Parser.php - - - - message: "#^Binary operation \"/\" between string and 8 results in an error\\.$#" - path: system/Encryption/Handlers/OpenSSLHandler.php diff --git a/system/Encryption/Handlers/OpenSSLHandler.php b/system/Encryption/Handlers/OpenSSLHandler.php index dac36dc71dc7..8324b36718ea 100644 --- a/system/Encryption/Handlers/OpenSSLHandler.php +++ b/system/Encryption/Handlers/OpenSSLHandler.php @@ -25,6 +25,18 @@ class OpenSSLHandler extends BaseHandler */ protected $digest = 'SHA512'; + /** + * List of supported HMAC algorithms + * + * @var array [name => digest size] + */ + protected array $digestSize = [ + 'SHA224' => 28, + 'SHA256' => 32, + 'SHA384' => 48, + 'SHA512' => 64, + ]; + /** * Cipher to use * @@ -39,6 +51,27 @@ class OpenSSLHandler extends BaseHandler */ protected $key = ''; + /** + * Whether the cipher-text should be raw. If set to false, then it will be base64 encoded. + */ + protected bool $rawData = true; + + /** + * Encryption key info. + * This setting is only used by OpenSSLHandler. + * + * Set to 'encryption' for CI3 Encryption compatibility. + */ + public string $encryptKeyInfo = ''; + + /** + * Authentication key info. + * This setting is only used by OpenSSLHandler. + * + * Set to 'authentication' for CI3 Encryption compatibility. + */ + public string $authKeyInfo = ''; + /** * {@inheritDoc} */ @@ -54,20 +87,23 @@ public function encrypt($data, $params = null) } // derive a secret key - $secret = \hash_hkdf($this->digest, $this->key); + $encryptKey = \hash_hkdf($this->digest, $this->key, 0, $this->encryptKeyInfo); // basic encryption $iv = ($ivSize = \openssl_cipher_iv_length($this->cipher)) ? \openssl_random_pseudo_bytes($ivSize) : null; - $data = \openssl_encrypt($data, $this->cipher, $secret, OPENSSL_RAW_DATA, $iv); + $data = \openssl_encrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, $iv); if ($data === false) { throw EncryptionException::forEncryptionFailed(); } - $result = $iv . $data; + $result = $this->rawData ? $iv . $data : base64_encode($iv . $data); + + // derive a secret key + $authKey = \hash_hkdf($this->digest, $this->key, 0, $this->authKeyInfo); - $hmacKey = \hash_hmac($this->digest, $result, $secret, true); + $hmacKey = \hash_hmac($this->digest, $result, $authKey, $this->rawData); return $hmacKey . $result; } @@ -87,17 +123,22 @@ public function decrypt($data, $params = null) } // derive a secret key - $secret = \hash_hkdf($this->digest, $this->key); + $authKey = \hash_hkdf($this->digest, $this->key, 0, $this->authKeyInfo); + + $hmacLength = $this->rawData + ? $this->digestSize[$this->digest] + : $this->digestSize[$this->digest] * 2; - $hmacLength = self::substr($this->digest, 3) / 8; - $hmacKey = self::substr($data, 0, $hmacLength); - $data = self::substr($data, $hmacLength); - $hmacCalc = \hash_hmac($this->digest, $data, $secret, true); + $hmacKey = self::substr($data, 0, $hmacLength); + $data = self::substr($data, $hmacLength); + $hmacCalc = \hash_hmac($this->digest, $data, $authKey, $this->rawData); if (! hash_equals($hmacKey, $hmacCalc)) { throw EncryptionException::forAuthenticationFailed(); } + $data = $this->rawData ? $data : base64_decode($data, true); + if ($ivSize = \openssl_cipher_iv_length($this->cipher)) { $iv = self::substr($data, 0, $ivSize); $data = self::substr($data, $ivSize); @@ -105,6 +146,9 @@ public function decrypt($data, $params = null) $iv = null; } - return \openssl_decrypt($data, $this->cipher, $secret, OPENSSL_RAW_DATA, $iv); + // derive a secret key + $encryptKey = \hash_hkdf($this->digest, $this->key, 0, $this->encryptKeyInfo); + + return \openssl_decrypt($data, $this->cipher, $encryptKey, OPENSSL_RAW_DATA, $iv); } } diff --git a/tests/system/Encryption/EncryptionTest.php b/tests/system/Encryption/EncryptionTest.php index 95a69d35f0b9..f935210136c9 100644 --- a/tests/system/Encryption/EncryptionTest.php +++ b/tests/system/Encryption/EncryptionTest.php @@ -148,4 +148,21 @@ public function testMagicGetMissing() { $this->assertNull($this->encryption->bogus); } + + public function testDecryptEncryptedDataByCI3() + { + $config = new EncryptionConfig(); + $config->driver = 'OpenSSL'; + $config->key = hex2bin('64c70b0b8d45b80b9eba60b8b3c8a34d0193223d20fea46f8644b848bf7ce67f'); + $config->rawData = false; + $config->encryptKeyInfo = 'encryption'; + $config->authKeyInfo = 'authentication'; + $encrypter = Services::encrypter($config, false); + + $encrypted = 'f5eeb3f056b2dc5e8119b4a5f5ba793d724b9ca2d1ca23ab89bc72e51863f8da233a83ccb48d5daf3d6905d61f357877aaad32c8bc7a7c5e48f3268d2ba362b9UTw2A7U4CB9vb+6izrDzJHAdz1hAutIt2Ex2C2FqamJAXc8Z8RQor9UvaWy2'; + $decrypted = $encrypter->decrypt($encrypted); + + $expected = 'This is a plain-text message.'; + $this->assertSame($expected, $decrypted); + } } From 96cf2ea3ec7ff0819fe2767acddcb31cd938c685 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 10:59:05 +0900 Subject: [PATCH 098/970] docs: fix title underlines --- .../source/installation/upgrade_encryption.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index a4d8a74ce659..8191f8e6eacf 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -6,29 +6,31 @@ Upgrade Encryption :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. 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 = service('encrypter');`` and change the methods for encryption and decrypting like in the following code example. Code Example -============ +************ CodeIgniter Version 3.x ------------------------- +======================= .. literalinclude:: upgrade_encryption/ci3sample/001.php CodeIgniter Version 4.x ------------------------ +======================= .. literalinclude:: upgrade_encryption/001.php From b006c2b61c36b4106feb1a7fcc05f66e6c0bf157 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 10:59:40 +0900 Subject: [PATCH 099/970] docs: add user guide --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + .../installation/upgrade_encryption.rst | 3 +- .../source/libraries/encryption.rst | 29 ++++++++++++++----- .../source/libraries/encryption/013.php | 14 +++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 user_guide_src/source/libraries/encryption/013.php diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index c511bd2b5683..9c62bb05c150 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -40,6 +40,7 @@ Enhancements - The call handler for Spark commands from the ``CodeIgniter\CodeIgniter`` class has been extracted. This will reduce the cost of console calls. - SQLite ``BaseConnection::getIndexData()`` now can return pseudo index named ``PRIMARY`` for `AUTOINCREMENT` column, and each returned index data has ``type`` property. - Added ``spark filter:check`` command to check the filters for a route. See :ref:`Controller Filters ` for the details. +- Now **Encryption** can decrypt data encrypted with CI3's Encryption. See :ref:`encryption-compatible-with-ci3`. Changes ******* diff --git a/user_guide_src/source/installation/upgrade_encryption.rst b/user_guide_src/source/installation/upgrade_encryption.rst index 8191f8e6eacf..247c546582ea 100644 --- a/user_guide_src/source/installation/upgrade_encryption.rst +++ b/user_guide_src/source/installation/upgrade_encryption.rst @@ -20,7 +20,8 @@ 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 = service('encrypter');`` and change the methods for encryption and decrypting like in the following code example. +2. If you need to decrypt data encrypted with CI3's Encryption, configure settings to maintain compatibility. See :ref:`encryption-compatible-with-ci3`. +3. 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/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index f707bcc0be7c..b77863152167 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -61,14 +61,17 @@ Configuring the Library The example above uses the configuration settings found in **app/Config/Encryption.php**. -========== ==================================================== -Option Possible values (default in parentheses) -========== ==================================================== -key Encryption key starter -driver Preferred handler, e.g., OpenSSL or Sodium (``OpenSSL``) -blockSize Padding length in bytes for SodiumHandler (``16``) -digest Message digest algorithm (``SHA512``) -========== ==================================================== +============== ======================================================== +Option Possible values (default in parentheses) +============== ======================================================== +key Encryption key starter +driver Preferred handler, e.g., OpenSSL or Sodium (``OpenSSL``) +blockSize Padding length in bytes for SodiumHandler (``16``) +digest Message digest algorithm (``SHA512``) +encryptKeyInfo Encryption key info (``''``). This is only used by OpenSSLHandler. +authKeyInfo Authentication key info (``''``). This is only used by OpenSSLHandler. +rawData Whether the cipher-text should be raw (``true``). This is only used by OpenSSLHandler. +============== ======================================================== 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 @@ -76,6 +79,16 @@ an instance of the ``Config\Encryption`` class. .. literalinclude:: encryption/003.php +.. _encryption-compatible-with-ci3: + +Configuration to Maintain Compatibility with CI3 +------------------------------------------------ + +Since v4.3.0, you can decrypt data encrypted with CI3's Encryption. +If you need to decrypt such data, use the following settings to maintain compatibility. + +.. literalinclude:: encryption/013.php + Default Behavior ================ diff --git a/user_guide_src/source/libraries/encryption/013.php b/user_guide_src/source/libraries/encryption/013.php new file mode 100644 index 000000000000..badfb04fdcc8 --- /dev/null +++ b/user_guide_src/source/libraries/encryption/013.php @@ -0,0 +1,14 @@ +driver = 'OpenSSL'; +// Your CI3's encryption_key +$config->key = hex2bin('64c70b0b8d45b80b9eba60b8b3c8a34d0193223d20fea46f8644b848bf7ce67f'); +$config->rawData = false; +$config->encryptKeyInfo = 'encryption'; +$config->authKeyInfo = 'authentication'; + +$encrypter = Services::encrypter($config, false); From 435451babb6a66166d4f1fad697634796cb528a5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 17:30:34 +0900 Subject: [PATCH 100/970] docs: add Supported HMAC Authentication Algorithms From CI3 docs. --- .../source/libraries/encryption.rst | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index b77863152167..25db2f0c2cb5 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -89,6 +89,30 @@ If you need to decrypt such data, use the following settings to maintain compati .. literalinclude:: encryption/013.php +Supported HMAC Authentication Algorithms +---------------------------------------- + +For HMAC message authentication, the Encryption library supports +usage of the SHA-2 family of algorithms: + +=========== ==================== ============================ +Algorithm Raw length (bytes) Hex-encoded length (bytes) +=========== ==================== ============================ +sha512 64 128 +sha384 48 96 +sha256 32 64 +sha224 28 56 +=========== ==================== ============================ + +The reason for not including other popular algorithms, such as +MD5 or SHA1 is that they are no longer considered secure enough +and as such, we don't want to encourage their usage. +If you absolutely need to use them, it is easy to do so via PHP's +native `hash_hmac() `_ function. + +Stronger algorithms of course will be added in the future as they +appear and become widely available. + Default Behavior ================ From d323c0eb8c0f890ff15b80b9e7ff4c1ccc660fcb Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 17:31:18 +0900 Subject: [PATCH 101/970] docs: change TOC depth to 3 --- user_guide_src/source/libraries/encryption.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 25db2f0c2cb5..3cab1d65567f 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -32,7 +32,7 @@ A more comprehensive package like `Halite ` .. contents:: :local: - :depth: 2 + :depth: 3 .. _usage: From a65fc7dce132aa0f838869dce4d25a1c25013126 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 21 Jul 2022 17:32:54 +0900 Subject: [PATCH 102/970] docs: make algorithm upper case --- user_guide_src/source/libraries/encryption.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/encryption.rst b/user_guide_src/source/libraries/encryption.rst index 3cab1d65567f..1e90da575393 100644 --- a/user_guide_src/source/libraries/encryption.rst +++ b/user_guide_src/source/libraries/encryption.rst @@ -98,10 +98,10 @@ usage of the SHA-2 family of algorithms: =========== ==================== ============================ Algorithm Raw length (bytes) Hex-encoded length (bytes) =========== ==================== ============================ -sha512 64 128 -sha384 48 96 -sha256 32 64 -sha224 28 56 +SHA512 64 128 +SHA384 48 96 +SHA256 32 64 +SHA224 28 56 =========== ==================== ============================ The reason for not including other popular algorithms, such as From 23fe28de29a972265a11cf1de309231bffe4bb27 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 22 Jul 2022 10:15:02 +0900 Subject: [PATCH 103/970] test: add test to decrypt data encrypted by CI v4.2.0. --- tests/system/Encryption/EncryptionTest.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/system/Encryption/EncryptionTest.php b/tests/system/Encryption/EncryptionTest.php index f935210136c9..202772ad4bdc 100644 --- a/tests/system/Encryption/EncryptionTest.php +++ b/tests/system/Encryption/EncryptionTest.php @@ -165,4 +165,18 @@ public function testDecryptEncryptedDataByCI3() $expected = 'This is a plain-text message.'; $this->assertSame($expected, $decrypted); } + + public function testDecryptEncryptedDataByCI42() + { + $config = new EncryptionConfig(); + $config->key = hex2bin('64c70b0b8d45b80b9eba60b8b3c8a34d0193223d20fea46f8644b848bf7ce67f'); + $encrypter = Services::encrypter($config, false); + + // Encrypted message by CI v4.2.0. + $encrypted = base64_decode('UB9PC3QfQIoLY5+/GU8BUQnfhEcCml6i4Sve6k0f8r6Id6IzlbkvMhfWf5E2lBH5+OTWuv5MUoTBQWv9Pd46ua07QsqS6/vHaW3rCg6cpLM/8d2IZE/VO+uXeaU6XHO5mJ8ehGKg96JITvKjxA==', true); + $decrypted = $encrypter->decrypt($encrypted); + + $expected = 'This is a plain-text message.'; + $this->assertSame($expected, $decrypted); + } } From baa8ed58a75e3a97587105d6d2e482021e3192f0 Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Sat, 23 Jul 2022 15:06:34 +0200 Subject: [PATCH 104/970] add language strings to error_404.php --- app/Views/errors/html/error_404.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php index f81717fdd0f5..952010c0367a 100644 --- a/app/Views/errors/html/error_404.php +++ b/app/Views/errors/html/error_404.php @@ -2,7 +2,7 @@ - 404 Page Not Found + <?= lang('Errors.404pageNotFound') ?> -
-

+
-

+

+ +

From d398c18735ef991db6b71ad7530368cfc0ab6c50 Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Sat, 23 Jul 2022 15:36:53 +0200 Subject: [PATCH 107/970] do not show error message twice before this PR it shows: 404 - Page Not Found Page Not Found because $messages is always set (as I have seen) After PR: 404 Page Not Found --- app/Views/errors/html/error_404.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php index bd8380c630dd..3176f1eef567 100644 --- a/app/Views/errors/html/error_404.php +++ b/app/Views/errors/html/error_404.php @@ -11,7 +11,7 @@

-

+

404

From 652ca943503556f64ac4b004f63a0fb0ff558b0d Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Tue, 26 Jul 2022 14:51:43 +0200 Subject: [PATCH 108/970] remove unnessesary type tag Per HTML5 spec, typically there is no need to specify a type when including CSS and JavaScript files as text/css and text/javascript are their respective defaults. --- app/Views/errors/html/error_exception.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Views/errors/html/error_exception.php b/app/Views/errors/html/error_exception.php index 77e963b2920a..8387f0adb06f 100644 --- a/app/Views/errors/html/error_exception.php +++ b/app/Views/errors/html/error_exception.php @@ -6,11 +6,11 @@ <?= esc($title) ?> - - From bbf9daa4f4b9e87428bea9e16c41940fd3f4018e Mon Sep 17 00:00:00 2001 From: Rival Arya Date: Wed, 27 Jul 2022 15:54:28 +0700 Subject: [PATCH 109/970] - make method promptByMultipleKey() in class CLI - make a test for the method - write the method in user guide --- system/CLI/CLI.php | 87 +++++++++++++++++++ tests/system/CLI/CLITest.php | 15 ++++ user_guide_src/source/cli/cli_library.rst | 9 ++ user_guide_src/source/cli/cli_library/023.php | 17 ++++ 4 files changed, 128 insertions(+) create mode 100644 user_guide_src/source/cli/cli_library/023.php diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 7a5030314948..158d3c07a5dc 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -301,6 +301,93 @@ public static function promptByKey($text, array $options, $validation = null): s return static::prompt(PHP_EOL . array_shift($text), array_keys($options), $validation); } + /** + * * This method is the same as promptByKey(), but this method supports multiple value. + * + * @param 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 + * + * @return array The selected key and value of $options + * + */ + public static function promptByMultipleKey($text, array $options) + { + if (is_string($text)) { + $text = [$text]; + } elseif (!is_array($text)) { + throw new InvalidArgumentException('$text can only be string'); + } + + if (is_array($options) && $options) { + $opts = $options; + $extraOutputDefault = static::color('0', 'green'); + + unset($opts[0]); + + if (empty($opts)) { + $extraOutput = $extraOutputDefault; + } else { + $optsKey = []; + foreach (array_keys($opts) as $key) { + $optsKey[] = $key; + } + $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']'; + } + + $default = 0; + } else { + throw new InvalidArgumentException('$options can only be array'); + } + + if ($line = array_shift($text)) { + CLI::newLine(); + 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)); + } + static::fwrite(STDOUT, (trim(strval(intval($text))) ? ' ' : '') . $extraOutput . ': '); + $input = trim(static::input()) ?: $default; + + // search alphabetic character + // return the prompt again if it is true because the key of $options is number + if (preg_match_all('/[a-zA-Z]/i', trim($input))) { + static::error('Please select correctly'); + return $input = static::promptByMultipleKey($line, $options); + } + + // separate input by comma and convert all to an int[] + $inputToArray = array_map(fn ($value) => intval($value), explode(',', $input)); + + // find max from key of $options + $maxOptions = array_key_last($options); + // find max from input + $maxInput = max($inputToArray); + // if max from $options less than max from input + // it is mean user tried to access null value in $options + if ($maxOptions < $maxInput) { + static::error('Please select correctly'); + return $input = static::promptByMultipleKey($line, $options); + } + + $input = []; + foreach ($options as $key => $description) { + foreach ($inputToArray as $inputKey) { + if ($key === $inputKey) { + $input[$key] = $description; + } + } + } + + return $input; + } + /** * Validate one prompt "field" at a time * diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index da4524ae47a8..37acba9b0258 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -525,4 +525,19 @@ public function testStrlen() $this->assertSame(7, CLI::strlen(CLI::color('success', 'green'))); $this->assertSame(0, CLI::strlen(null)); } + + public function testPromptByMultipleKey() + { + $options = ['one', 'two', 'three']; + CLI::promptByMultipleKey('Is this a question?', $options); + + $expected = '' . PHP_EOL . 'Is this a question?' . PHP_EOL; + foreach ($options as $key => $description) { + $name = str_pad(' [' . $key . '] ', 7, ' '); + $expected .= '' . CLI::color($name, 'green') . CLI::wrap($description, 125, 7) . PHP_EOL; + } + $expected .= '[' . CLI::color('0', 'green') . ', 1, 2]: '; + + $this->assertSame($expected, $this->getStreamFilterBuffer()); + } } diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 29bc6b252f88..66ba890c8a3c 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -66,6 +66,15 @@ 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. +promptByMultipleKey() +============= + +This method is the same as ``promptByKey()``, but it supports multiple value. + +.. literalinclude:: cli_library/023.php + +.. important:: The method ``promptByMultipleKey()``, unlike ``promptByKey()``, does not support named keys or validation. + Providing Feedback ****************** diff --git a/user_guide_src/source/cli/cli_library/023.php b/user_guide_src/source/cli/cli_library/023.php new file mode 100644 index 000000000000..e44edba36755 --- /dev/null +++ b/user_guide_src/source/cli/cli_library/023.php @@ -0,0 +1,17 @@ + "Playing game", + * [2] => "Badminton" + * ] + */ From f7ffeccd22e7f03ac405a1e4c3624a88cb64a58c Mon Sep 17 00:00:00 2001 From: Rival Arya Date: Wed, 27 Jul 2022 17:44:36 +0700 Subject: [PATCH 110/970] - add the method in docs upgrading v4.3.0 - fix title urderline in user guide --- user_guide_src/source/changelogs/v4.3.0.rst | 6 ++++++ user_guide_src/source/cli/cli_library.rst | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 9c62bb05c150..0dccc2ca83c0 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -32,6 +32,12 @@ Others Enhancements ************ +CLI +=== +- Added methods ``CLI::promptByMultipleKey()`` to support multiple value in input, unlike ``promptByKey()``. See :ref:`prompt-by-multiple-key` for details. + +Others +====== - Added the ``StreamFilterTrait`` to make it easier to work with capturing data from STDOUT and STDERR streams. See :ref:`testing-overview-stream-filters`. - Added before and after events to ``BaseModel::insertBatch()`` and ``BaseModel::updateBatch()`` methods. See :ref:`model-events-callbacks`. - Added ``Model::allowEmptyInserts()`` method to insert empty data. See :ref:`Using CodeIgniter's Model ` diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 66ba890c8a3c..6d0466883fe8 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -66,8 +66,10 @@ 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. +.. _prompt-by-multiple-key: + promptByMultipleKey() -============= +===================== This method is the same as ``promptByKey()``, but it supports multiple value. From 45834977793d64a80907b5d513e1096df3161d9c Mon Sep 17 00:00:00 2001 From: Rival Arya Date: Wed, 27 Jul 2022 18:01:03 +0700 Subject: [PATCH 111/970] run CS-fix --- system/CLI/CLI.php | 19 +++++++++++-------- tests/system/CLI/CLITest.php | 1 + user_guide_src/source/cli/cli_library/023.php | 2 +- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 158d3c07a5dc..de97fa431b54 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -304,18 +304,17 @@ public static function promptByKey($text, array $options, $validation = null): s /** * * This method is the same as promptByKey(), but this method supports multiple value. * - * @param 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 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 * * @return array The selected key and value of $options - * */ public static function promptByMultipleKey($text, array $options) { if (is_string($text)) { $text = [$text]; - } elseif (!is_array($text)) { + } elseif (! is_array($text)) { throw new InvalidArgumentException('$text can only be string'); } @@ -329,10 +328,11 @@ public static function promptByMultipleKey($text, array $options) $extraOutput = $extraOutputDefault; } else { $optsKey = []; + foreach (array_keys($opts) as $key) { $optsKey[] = $key; } - $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']'; + $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']'; } $default = 0; @@ -352,18 +352,19 @@ public static function promptByMultipleKey($text, array $options) $name = str_pad(' [' . $key . '] ', $keyMaxLength + 4, ' '); CLI::write(CLI::color($name, 'green') . CLI::wrap($description, 125, $keyMaxLength + 4)); } - static::fwrite(STDOUT, (trim(strval(intval($text))) ? ' ' : '') . $extraOutput . ': '); + static::fwrite(STDOUT, (trim((string) ((int) $text)) ? ' ' : '') . $extraOutput . ': '); $input = trim(static::input()) ?: $default; // search alphabetic character // return the prompt again if it is true because the key of $options is number if (preg_match_all('/[a-zA-Z]/i', trim($input))) { static::error('Please select correctly'); + return $input = static::promptByMultipleKey($line, $options); } // separate input by comma and convert all to an int[] - $inputToArray = array_map(fn ($value) => intval($value), explode(',', $input)); + $inputToArray = array_map(static fn ($value) => (int) $value, explode(',', $input)); // find max from key of $options $maxOptions = array_key_last($options); @@ -373,10 +374,12 @@ public static function promptByMultipleKey($text, array $options) // it is mean user tried to access null value in $options if ($maxOptions < $maxInput) { static::error('Please select correctly'); + return $input = static::promptByMultipleKey($line, $options); } $input = []; + foreach ($options as $key => $description) { foreach ($inputToArray as $inputKey) { if ($key === $inputKey) { diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 37acba9b0258..160091f4ec94 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -532,6 +532,7 @@ public function testPromptByMultipleKey() CLI::promptByMultipleKey('Is this a question?', $options); $expected = '' . PHP_EOL . 'Is this a question?' . PHP_EOL; + foreach ($options as $key => $description) { $name = str_pad(' [' . $key . '] ', 7, ' '); $expected .= '' . CLI::color($name, 'green') . CLI::wrap($description, 125, 7) . PHP_EOL; diff --git a/user_guide_src/source/cli/cli_library/023.php b/user_guide_src/source/cli/cli_library/023.php index e44edba36755..1d4a06437494 100644 --- a/user_guide_src/source/cli/cli_library/023.php +++ b/user_guide_src/source/cli/cli_library/023.php @@ -8,7 +8,7 @@ * [2] Badminton * * [0, 1, 2]: - * + * * if your answer is '0,2', the return is the key and the value of the options : * [ * [0] => "Playing game", From dbf3962cc98f8b0cf90cff328e3c2996f291da74 Mon Sep 17 00:00:00 2001 From: Rival Arya Date: Thu, 28 Jul 2022 18:22:54 +0700 Subject: [PATCH 112/970] resolve grammar(?) --- system/CLI/CLI.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index de97fa431b54..80969b75a81e 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -302,7 +302,7 @@ public static function promptByKey($text, array $options, $validation = null): s } /** - * * This method is the same as promptByKey(), but this method supports multiple value. + * * This method is the same as promptByKey(), but this method supports multiple keys, separated by commas. * * @param 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 @@ -310,7 +310,7 @@ public static function promptByKey($text, array $options, $validation = null): s * * @return array The selected key and value of $options */ - public static function promptByMultipleKey($text, array $options) + public static function promptByMultipleKeys($text, array $options) { if (is_string($text)) { $text = [$text]; @@ -360,7 +360,7 @@ public static function promptByMultipleKey($text, array $options) if (preg_match_all('/[a-zA-Z]/i', trim($input))) { static::error('Please select correctly'); - return $input = static::promptByMultipleKey($line, $options); + return $input = static::promptByMultipleKeys($line, $options); } // separate input by comma and convert all to an int[] @@ -375,7 +375,7 @@ public static function promptByMultipleKey($text, array $options) if ($maxOptions < $maxInput) { static::error('Please select correctly'); - return $input = static::promptByMultipleKey($line, $options); + return $input = static::promptByMultipleKeys($line, $options); } $input = []; From 60f878dcc30f4cc19b553aff627368aa2f73d378 Mon Sep 17 00:00:00 2001 From: Rival Arya Date: Thu, 28 Jul 2022 19:48:53 +0700 Subject: [PATCH 113/970] change method name in unit test --- tests/system/CLI/CLITest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 160091f4ec94..7478ce18f2bc 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -526,10 +526,10 @@ public function testStrlen() $this->assertSame(0, CLI::strlen(null)); } - public function testPromptByMultipleKey() + public function testPromptByMultipleKeys() { $options = ['one', 'two', 'three']; - CLI::promptByMultipleKey('Is this a question?', $options); + CLI::promptByMultipleKeys('Is this a question?', $options); $expected = '' . PHP_EOL . 'Is this a question?' . PHP_EOL; From 01a58d6500ce428646394f3d477ce7628d0d339a Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 24 Jul 2022 11:15:05 +0900 Subject: [PATCH 114/970] refactor: loading Config/Routes.php --- system/CodeIgniter.php | 3 ++- system/Commands/Utilities/FilterCheck.php | 3 +-- system/Commands/Utilities/Routes.php | 4 ++-- system/Router/RouteCollection.php | 18 ++++++++++++++++++ system/Test/FeatureTestCase.php | 8 ++------ system/Test/FeatureTestTrait.php | 8 ++------ system/Test/FilterTestTrait.php | 4 ++-- system/Test/bootstrap.php | 9 ++------- 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index fd59c1417ff3..fb6885a37d25 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -730,7 +730,8 @@ public function displayPerformanceMetrics(string $output): string protected function tryToRouteIt(?RouteCollectionInterface $routes = null) { if ($routes === null) { - require APPPATH . 'Config/Routes.php'; + $routes = Services::routes(); + $routes->loadRoutes(); } // $routes is defined in Config/Routes.php diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index 7469ce1444c2..ecf2a65fc673 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -86,8 +86,7 @@ public function run(array $params) // Load Routes $routes = Services::routes(); - require APPPATH . 'Config/Routes.php'; - $routes->getRoutes('*'); // Triggers discovery + $routes->loadRoutes(); $filterCollector = new FilterCollector(); diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index c62e11df6d3f..95f8def6d8b1 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -75,8 +75,8 @@ class Routes extends BaseCommand */ public function run(array $params) { - $routes = Services::routes(true); - require APPPATH . 'Config/Routes.php'; + $routes = Services::routes(); + $routes->loadRoutes(); $collection = $routes; $methods = [ diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index ffc6ea95b2c5..63e5b5423de8 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1393,6 +1393,7 @@ public function resetRoutes() } $this->prioritizeDetected = false; + $this->didDiscover = false; } /** @@ -1490,4 +1491,21 @@ public function shouldUseSupportedLocalesOnly(): bool { return $this->useSupportedLocalesOnly; } + + /** + * Loads main routes file and discover routes. + * + * Loads only once unless reset. + */ + public function loadRoutes(string $routesFile = APPPATH . 'Config/Routes.php'): void + { + if ($this->didDiscover) { + return; + } + + $routes = $this; + require $routesFile; + + $this->discoverRoutes(); + } } diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index dc0c65b4a8b7..d47eb73046e4 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -176,12 +176,8 @@ public function call(string $method, string $path, ?array $params = null) // Initialize the RouteCollection if (! $routes = $this->routes) { - require APPPATH . 'Config/Routes.php'; - - /** - * @var RouteCollection $routes - */ - $routes->getRoutes('*'); + $routes = Services::routes(); + $routes->loadRoutes(); } $routes->setHTTPVerb($method); diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index 790de784e237..59bca1a5adc6 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -166,12 +166,8 @@ public function call(string $method, string $path, ?array $params = null) // Initialize the RouteCollection if (! $routes = $this->routes) { - require APPPATH . 'Config/Routes.php'; - - /** - * @var RouteCollection $routes - */ - $routes->getRoutes('*'); + $routes = Services::routes(); + $routes->loadRoutes(); } $routes->setHTTPVerb($method); diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 1407a67b0a64..4a60a6e91f16 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -104,9 +104,9 @@ protected function setUpFilterTestTrait(): void if ($this->collection === null) { // Load the RouteCollection from Config to gather App route info // (creates $routes using the Service as a starting point) - require APPPATH . 'Config/Routes.php'; + $routes = Services::routes(); + $routes->loadRoutes(); - $routes->getRoutes('*'); // Triggers discovery $this->collection = $routes; } diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index 6b0068f04670..976f21dc4895 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -10,7 +10,6 @@ */ use CodeIgniter\Config\DotEnv; -use CodeIgniter\Router\RouteCollection; use Config\Autoload; use Config\Modules; use Config\Paths; @@ -93,9 +92,5 @@ // Always load the URL helper, it should be used in most of apps. helper('url'); -require_once APPPATH . 'Config/Routes.php'; - -/** - * @var RouteCollection $routes - */ -$routes->getRoutes('*'); +$routes = Services::routes(); +$routes->loadRoutes(); From 125deacd2eb672e39aa73b1642056d52a6f1fe30 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 24 Jul 2022 20:22:41 +0900 Subject: [PATCH 115/970] refactor: now you can write Services::routes()->loadRoutes() --- system/CodeIgniter.php | 3 +-- system/Commands/Utilities/FilterCheck.php | 3 +-- system/Commands/Utilities/Routes.php | 5 +---- system/Router/RouteCollection.php | 8 ++++++-- system/Test/FeatureTestCase.php | 3 +-- system/Test/FeatureTestTrait.php | 3 +-- system/Test/FilterTestTrait.php | 7 +------ system/Test/bootstrap.php | 3 +-- 8 files changed, 13 insertions(+), 22 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index fb6885a37d25..36a9dabc1d07 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -730,8 +730,7 @@ public function displayPerformanceMetrics(string $output): string protected function tryToRouteIt(?RouteCollectionInterface $routes = null) { if ($routes === null) { - $routes = Services::routes(); - $routes->loadRoutes(); + $routes = Services::routes()->loadRoutes(); } // $routes is defined in Config/Routes.php diff --git a/system/Commands/Utilities/FilterCheck.php b/system/Commands/Utilities/FilterCheck.php index ecf2a65fc673..15f66e97a8a7 100644 --- a/system/Commands/Utilities/FilterCheck.php +++ b/system/Commands/Utilities/FilterCheck.php @@ -85,8 +85,7 @@ public function run(array $params) $route = $params[1]; // Load Routes - $routes = Services::routes(); - $routes->loadRoutes(); + Services::routes()->loadRoutes(); $filterCollector = new FilterCollector(); diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index 95f8def6d8b1..8f8b5188e570 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -75,10 +75,7 @@ class Routes extends BaseCommand */ public function run(array $params) { - $routes = Services::routes(); - $routes->loadRoutes(); - - $collection = $routes; + $collection = Services::routes()->loadRoutes(); $methods = [ 'get', 'head', diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index 63e5b5423de8..fc97bbc5cb50 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -1496,16 +1496,20 @@ public function shouldUseSupportedLocalesOnly(): bool * Loads main routes file and discover routes. * * Loads only once unless reset. + * + * @return $this */ - public function loadRoutes(string $routesFile = APPPATH . 'Config/Routes.php'): void + public function loadRoutes(string $routesFile = APPPATH . 'Config/Routes.php') { if ($this->didDiscover) { - return; + return $this; } $routes = $this; require $routesFile; $this->discoverRoutes(); + + return $this; } } diff --git a/system/Test/FeatureTestCase.php b/system/Test/FeatureTestCase.php index d47eb73046e4..bf79d69d3c51 100644 --- a/system/Test/FeatureTestCase.php +++ b/system/Test/FeatureTestCase.php @@ -176,8 +176,7 @@ public function call(string $method, string $path, ?array $params = null) // Initialize the RouteCollection if (! $routes = $this->routes) { - $routes = Services::routes(); - $routes->loadRoutes(); + $routes = Services::routes()->loadRoutes(); } $routes->setHTTPVerb($method); diff --git a/system/Test/FeatureTestTrait.php b/system/Test/FeatureTestTrait.php index 59bca1a5adc6..e61c53001b85 100644 --- a/system/Test/FeatureTestTrait.php +++ b/system/Test/FeatureTestTrait.php @@ -166,8 +166,7 @@ public function call(string $method, string $path, ?array $params = null) // Initialize the RouteCollection if (! $routes = $this->routes) { - $routes = Services::routes(); - $routes->loadRoutes(); + $routes = Services::routes()->loadRoutes(); } $routes->setHTTPVerb($method); diff --git a/system/Test/FilterTestTrait.php b/system/Test/FilterTestTrait.php index 4a60a6e91f16..465648f4f6b3 100644 --- a/system/Test/FilterTestTrait.php +++ b/system/Test/FilterTestTrait.php @@ -102,12 +102,7 @@ protected function setUpFilterTestTrait(): void $this->filters ??= new Filters($this->filtersConfig, $this->request, $this->response); if ($this->collection === null) { - // Load the RouteCollection from Config to gather App route info - // (creates $routes using the Service as a starting point) - $routes = Services::routes(); - $routes->loadRoutes(); - - $this->collection = $routes; + $this->collection = Services::routes()->loadRoutes(); } $this->doneFilterSetUp = true; diff --git a/system/Test/bootstrap.php b/system/Test/bootstrap.php index 976f21dc4895..5eeaae6071ab 100644 --- a/system/Test/bootstrap.php +++ b/system/Test/bootstrap.php @@ -92,5 +92,4 @@ // Always load the URL helper, it should be used in most of apps. helper('url'); -$routes = Services::routes(); -$routes->loadRoutes(); +Services::routes()->loadRoutes(); From 4288efe22046a6ef81b51a5767e03e45dc4795d3 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 24 Jul 2022 20:27:28 +0900 Subject: [PATCH 116/970] refactor: change the method order loadRoutes() and discoverRoutes() are initialization. --- system/Router/RouteCollection.php | 112 +++++++++++++++--------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/system/Router/RouteCollection.php b/system/Router/RouteCollection.php index fc97bbc5cb50..34989d54a171 100644 --- a/system/Router/RouteCollection.php +++ b/system/Router/RouteCollection.php @@ -239,6 +239,62 @@ public function __construct(FileLocator $locator, Modules $moduleConfig) $this->httpHost = Services::request()->getServer('HTTP_HOST'); } + /** + * Loads main routes file and discover routes. + * + * Loads only once unless reset. + * + * @return $this + */ + public function loadRoutes(string $routesFile = APPPATH . 'Config/Routes.php') + { + if ($this->didDiscover) { + return $this; + } + + $routes = $this; + require $routesFile; + + $this->discoverRoutes(); + + return $this; + } + + /** + * Will attempt to discover any additional routes, either through + * the local PSR4 namespaces, or through selected Composer packages. + */ + protected function discoverRoutes() + { + if ($this->didDiscover) { + return; + } + + // We need this var in local scope + // so route files can access it. + $routes = $this; + + 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 (in_array($file, $excludes, true)) { + continue; + } + + include $file; + } + } + + $this->didDiscover = true; + } + /** * Registers a new constraint with the system. Constraints are used * by the routes as placeholders for regular expressions to make defining @@ -362,41 +418,6 @@ public function get404Override() return $this->override404; } - /** - * Will attempt to discover any additional routes, either through - * the local PSR4 namespaces, or through selected Composer packages. - */ - protected function discoverRoutes() - { - if ($this->didDiscover) { - return; - } - - // We need this var in local scope - // so route files can access it. - $routes = $this; - - 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 (in_array($file, $excludes, true)) { - continue; - } - - include $file; - } - } - - $this->didDiscover = true; - } - /** * Sets the default constraint to be used in the system. Typically * for use with the 'resource' method. @@ -1491,25 +1512,4 @@ public function shouldUseSupportedLocalesOnly(): bool { return $this->useSupportedLocalesOnly; } - - /** - * Loads main routes file and discover routes. - * - * Loads only once unless reset. - * - * @return $this - */ - public function loadRoutes(string $routesFile = APPPATH . 'Config/Routes.php') - { - if ($this->didDiscover) { - return $this; - } - - $routes = $this; - require $routesFile; - - $this->discoverRoutes(); - - return $this; - } } From 04cbdf1e811e00cd78dbdb4abbb666b0d191a8a0 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 29 Jul 2022 19:50:59 +0900 Subject: [PATCH 117/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 9c62bb05c150..959f9baaf5f0 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -28,6 +28,7 @@ Others - The ``spark`` file has been changed due to a change in the processing of Spark commands. - ``InvalidArgumentException`` that is a kind of ``LogicException`` in ``BaseBuilder::_whereIn()`` is not suppressed by the configuration. Previously if ``CI_DEBUG`` was false, the exception was suppressed. +- ``RouteCollection::resetRoutes()`` resets Auto-Discovery of Routes. Previously once discovered, RouteCollection never discover Routes files again even if ``RouteCollection::resetRoutes()`` is called. Enhancements ************ From c07de8eabb8c3a0c604ce0252e715a6f5a426d8b Mon Sep 17 00:00:00 2001 From: Rival Arya Date: Fri, 29 Jul 2022 17:58:38 +0700 Subject: [PATCH 118/970] - refactor code - delete unit test for promptByMultipleKeys because #6076 - change method name in docs and changelog --- system/CLI/CLI.php | 106 +++++++++--------- tests/system/CLI/CLITest.php | 15 --- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- user_guide_src/source/cli/cli_library.rst | 4 +- user_guide_src/source/cli/cli_library/023.php | 2 +- 5 files changed, 58 insertions(+), 71 deletions(-) diff --git a/system/CLI/CLI.php b/system/CLI/CLI.php index 80969b75a81e..7a67f4998d6b 100644 --- a/system/CLI/CLI.php +++ b/system/CLI/CLI.php @@ -282,21 +282,13 @@ public static function promptByKey($text, array $options, $validation = null): s throw new InvalidArgumentException('$text can only be of type string|array'); } - if (! $options) { - throw new InvalidArgumentException('No options to select from were provided'); - } + CLI::isZeroOptions($options); 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)); - } + CLI::printKeysAndValues($options); return static::prompt(PHP_EOL . array_shift($text), array_keys($options), $validation); } @@ -308,59 +300,38 @@ public static function promptByKey($text, array $options, $validation = null): s * 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 * - * @return array The selected key and value of $options + * @return array The selected key(s) and value(s) of $options */ public static function promptByMultipleKeys($text, array $options) { - if (is_string($text)) { - $text = [$text]; - } elseif (! is_array($text)) { - throw new InvalidArgumentException('$text can only be string'); - } - - if (is_array($options) && $options) { - $opts = $options; - $extraOutputDefault = static::color('0', 'green'); + CLI::isZeroOptions($options); - unset($opts[0]); - - if (empty($opts)) { - $extraOutput = $extraOutputDefault; - } else { - $optsKey = []; - - foreach (array_keys($opts) as $key) { - $optsKey[] = $key; - } - $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']'; - } + $extraOutputDefault = static::color('0', 'green'); + $opts = $options; + unset($opts[0]); - $default = 0; + if (empty($opts)) { + $extraOutput = $extraOutputDefault; } else { - throw new InvalidArgumentException('$options can only be array'); - } - - if ($line = array_shift($text)) { - CLI::newLine(); - CLI::write($line); + $optsKey = []; + foreach (array_keys($opts) as $key) { + $optsKey[] = $key; + } + $extraOutput = '[' . $extraOutputDefault . ', ' . implode(', ', $optsKey) . ']'; } - // +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)); - } + CLI::newLine(); + CLI::write($text); + CLI::printKeysAndValues($options); static::fwrite(STDOUT, (trim((string) ((int) $text)) ? ' ' : '') . $extraOutput . ': '); - $input = trim(static::input()) ?: $default; + $input = trim(static::input()) ?: 0; // 0 is default - // search alphabetic character + // search alphabetic character in $input // return the prompt again if it is true because the key of $options is number if (preg_match_all('/[a-zA-Z]/i', trim($input))) { static::error('Please select correctly'); - return $input = static::promptByMultipleKeys($line, $options); + return static::promptByMultipleKeys($text, $options); } // separate input by comma and convert all to an int[] @@ -369,17 +340,16 @@ public static function promptByMultipleKeys($text, array $options) // find max from key of $options $maxOptions = array_key_last($options); // find max from input - $maxInput = max($inputToArray); + $maxInput = max($inputToArray); // if max from $options less than max from input // it is mean user tried to access null value in $options if ($maxOptions < $maxInput) { static::error('Please select correctly'); - return $input = static::promptByMultipleKeys($line, $options); + return static::promptByMultipleKeys($text, $options); } $input = []; - foreach ($options as $key => $description) { foreach ($inputToArray as $inputKey) { if ($key === $inputKey) { @@ -391,6 +361,38 @@ public static function promptByMultipleKeys($text, array $options) return $input; } + //-------------------------------------------------------------------- + // Utility for promptBy... + //-------------------------------------------------------------------- + + /** + * Validation for $options in promptByKey() and promptByMultipleKeys(). Return an error if $options is an empty array. + */ + private static function isZeroOptions(array $options) : void + { + if(!$options){ + throw new InvalidArgumentException('No options to select from were provided'); + } + } + + /** + * Print each key and value one by one + */ + private static function printKeysAndValues(array $options) : void + { + // +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)); + } + } + + //-------------------------------------------------------------------- + // End Utility for promptBy... + //-------------------------------------------------------------------- + /** * Validate one prompt "field" at a time * diff --git a/tests/system/CLI/CLITest.php b/tests/system/CLI/CLITest.php index 7478ce18f2bc..e2b6857c5053 100644 --- a/tests/system/CLI/CLITest.php +++ b/tests/system/CLI/CLITest.php @@ -526,19 +526,4 @@ public function testStrlen() $this->assertSame(0, CLI::strlen(null)); } - public function testPromptByMultipleKeys() - { - $options = ['one', 'two', 'three']; - CLI::promptByMultipleKeys('Is this a question?', $options); - - $expected = '' . PHP_EOL . 'Is this a question?' . PHP_EOL; - - foreach ($options as $key => $description) { - $name = str_pad(' [' . $key . '] ', 7, ' '); - $expected .= '' . CLI::color($name, 'green') . CLI::wrap($description, 125, 7) . PHP_EOL; - } - $expected .= '[' . CLI::color('0', 'green') . ', 1, 2]: '; - - $this->assertSame($expected, $this->getStreamFilterBuffer()); - } } diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 0dccc2ca83c0..fe6d688af1ae 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -34,7 +34,7 @@ Enhancements CLI === -- Added methods ``CLI::promptByMultipleKey()`` to support multiple value in input, unlike ``promptByKey()``. See :ref:`prompt-by-multiple-key` for details. +- Added methods ``CLI::promptByMultipleKeys()`` to support multiple value in input, unlike ``promptByKey()``. See :ref:`prompt-by-multiple-keys` for details. Others ====== diff --git a/user_guide_src/source/cli/cli_library.rst b/user_guide_src/source/cli/cli_library.rst index 6d0466883fe8..b68d412e4dac 100644 --- a/user_guide_src/source/cli/cli_library.rst +++ b/user_guide_src/source/cli/cli_library.rst @@ -66,9 +66,9 @@ 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. -.. _prompt-by-multiple-key: +.. _prompt-by-multiple-keys: -promptByMultipleKey() +promptByMultipleKeys() ===================== This method is the same as ``promptByKey()``, but it supports multiple value. diff --git a/user_guide_src/source/cli/cli_library/023.php b/user_guide_src/source/cli/cli_library/023.php index 1d4a06437494..44a80fe4881e 100644 --- a/user_guide_src/source/cli/cli_library/023.php +++ b/user_guide_src/source/cli/cli_library/023.php @@ -1,6 +1,6 @@ Date: Sat, 30 Jul 2022 13:06:07 +0200 Subject: [PATCH 119/970] Undo style changes, translation only. --- app/Views/errors/html/error_404.php | 69 ++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php index 3176f1eef567..fc4bdf055629 100644 --- a/app/Views/errors/html/error_404.php +++ b/app/Views/errors/html/error_404.php @@ -5,15 +5,74 @@ <?= lang('Errors.404pageNotFound') ?> -

+
+

404

-

404

- -

+

From bf7c6bc5736927e8060db99991a252493b2119a9 Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 19:08:14 +0200 Subject: [PATCH 120/970] Add Timer method record for callables --- system/Common.php | 12 +++- system/Debug/Timer.php | 18 ++++++ tests/system/Debug/TimerTest.php | 95 ++++++++++++++++++++++++++++++++ 3 files changed, 122 insertions(+), 3 deletions(-) diff --git a/system/Common.php b/system/Common.php index 962483bb68b2..6880a570664b 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1076,12 +1076,14 @@ function stringify_attributes($attributes, bool $js = false): string if (! function_exists('timer')) { /** * A convenience method for working with the timer. - * If no parameter is passed, it will return the timer instance, - * otherwise will start or stop the timer intelligently. + * If no parameter is passed, it will return the timer instance. + * If callable is passed, it measures time of callable and + * returns its return value if any. + * Otherwise will start or stop the timer intelligently. * * @return mixed|Timer */ - function timer(?string $name = null) + function timer(?string $name = null, ?callable $callable) { $timer = Services::timer(); @@ -1089,6 +1091,10 @@ function timer(?string $name = null) return $timer; } + if (! is_null($callable)) { + return $timer->record($name, $callable); + } + if ($timer->has($name)) { return $timer->stop($name); } diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php index 9ca51d1c9b08..a576eb9586e4 100644 --- a/system/Debug/Timer.php +++ b/system/Debug/Timer.php @@ -126,4 +126,22 @@ public function has(string $name): bool { return array_key_exists(strtolower($name), $this->timers); } + + /** + * Executes callable and measures its time. + * Returns its return value if any. + * + * @param string $name The name of the timer + * @param callable $callable callable to be executed + * + * @return mixed|null + */ + public function record(string $name, callable $callable) + { + $this->start($name); + $returnValue = call_user_func($callable); + $this->stop($name); + + return $returnValue; + } } diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index fdd09829d9ff..f3ca047bf4b9 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -121,4 +121,99 @@ public function testReturnsNullGettingElapsedTimeOfNonTimer() $this->assertNull($timer->getElapsedTime('test1')); } + + /** + * @timeLimit 1.5 + */ + public function testRecordFunctionNoReturn() + { + $timer = new Timer(); + $returnValue = $timer->record('longjohn', function() { sleep(1); }); + + $this->assertGreaterThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); + $this->assertNull($returnValue); + } + + /** + * @timeLimit 1.5 + */ + public function testRecordFunctionWithReturn() + { + $timer = new Timer(); + $returnValue = $timer->record('longjohn', function() { sleep(1); return 'test'; }); + + $this->assertGreaterThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); + $this->assertSame('test', $returnValue); + } + + public function testRecordArrowFunction() + { + $timer = new Timer(); + $returnValue = $timer->record('longjohn', fn() => strlen('CI4') ); + + $this->assertLessThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); + $this->assertSame(3, $returnValue); + } + + public function testRecordThrowsException() + { + $this->expectException('RuntimeException'); + + $timer = new Timer(); + $timer->record('ex', function() { throw new RuntimeException(); }); + } + + public function testRecordThrowsErrorOnCallableWithParams() + { + $this->expectException('Error'); + + $timer = new Timer(); + $timer->record('error', 'strlen'); + } + + public function testCommonNoNameExpectTimer() + { + $returnValue = timer(); + + $this->assertInstanceOf(Timer::class, $returnValue); + } + + public function testCommonWithNameExpectTimer() + { + $returnValue = timer('test'); + + $this->assertInstanceOf(Timer::class, $returnValue); + $this->assertTrue($returnValue->has('test')); + } + + public function testCommonNoNameCallableExpectTimer() + { + $returnValue = timer(null, fn() => strlen('CI4') ); + + $this->assertInstanceOf(Timer::class, $returnValue); + } + + /** + * @timeLimit 1.5 + */ + public function testCommonCallableExpectNoReturn() + { + $returnValue = timer('common', function() { sleep(1); } ); + + $this->assertNotInstanceOf(Timer::class, $returnValue); + $this->assertNull($returnValue); + $this->assertGreaterThanOrEqual(1.0, timer()->getElapsedTime('common')); + } + + /** + * @timeLimit 1.5 + */ + public function testCommonCallableExpectWithReturn() + { + $returnValue = timer('common', function() { sleep(1); return strlen('CI4'); } ); + + $this->assertNotInstanceOf(Timer::class, $returnValue); + $this->assertSame(3, $returnValue); + $this->assertGreaterThanOrEqual(1.0, timer()->getElapsedTime('common')); + } } From ba1cc5cdf0ce507d99a34f06b2159fe83d414973 Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 19:16:56 +0200 Subject: [PATCH 121/970] Code fixes --- system/Common.php | 2 +- tests/system/Debug/TimerTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/system/Common.php b/system/Common.php index 6880a570664b..8af9122e846f 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1083,7 +1083,7 @@ function stringify_attributes($attributes, bool $js = false): string * * @return mixed|Timer */ - function timer(?string $name = null, ?callable $callable) + function timer(?string $name = null, ?callable $callable = null) { $timer = Services::timer(); diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index f3ca047bf4b9..402348797a6c 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -160,7 +160,7 @@ public function testRecordThrowsException() $this->expectException('RuntimeException'); $timer = new Timer(); - $timer->record('ex', function() { throw new RuntimeException(); }); + $timer->record('ex', function() { throw new \RuntimeException(); }); } public function testRecordThrowsErrorOnCallableWithParams() From 22194d0620ec05c4d599fd79420a8d102fa3ea45 Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 19:19:01 +0200 Subject: [PATCH 122/970] Changelogs and user guide --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/testing/benchmark.rst | 14 ++++++++++++++ user_guide_src/source/testing/benchmark/010.php | 11 +++++++++++ user_guide_src/source/testing/benchmark/011.php | 13 +++++++++++++ user_guide_src/source/testing/benchmark/012.php | 13 +++++++++++++ 5 files changed, 52 insertions(+) create mode 100644 user_guide_src/source/testing/benchmark/010.php create mode 100644 user_guide_src/source/testing/benchmark/011.php create mode 100644 user_guide_src/source/testing/benchmark/012.php diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 9c62bb05c150..2f250c389f38 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -41,6 +41,7 @@ Enhancements - SQLite ``BaseConnection::getIndexData()`` now can return pseudo index named ``PRIMARY`` for `AUTOINCREMENT` column, and each returned index data has ``type`` property. - Added ``spark filter:check`` command to check the filters for a route. See :ref:`Controller Filters ` for the details. - Now **Encryption** can decrypt data encrypted with CI3's Encryption. See :ref:`encryption-compatible-with-ci3`. +- Added method ``Timer::record`` to measure performance in a callable. Also enhanced common function ``timer()`` to accept optional callable. Changes ******* diff --git a/user_guide_src/source/testing/benchmark.rst b/user_guide_src/source/testing/benchmark.rst index fb92eb19dfec..072021a2afb3 100644 --- a/user_guide_src/source/testing/benchmark.rst +++ b/user_guide_src/source/testing/benchmark.rst @@ -38,6 +38,20 @@ and stop timers: .. literalinclude:: benchmark/003.php +If you use very small code blocks to benchmark, you can also use the ``record()`` method. It accepts +a no-parameter callable and measures its execution time. Methods ``start()`` and ``stop()`` will be called +automatically around the function call. + +.. literalinclude:: benchmark/010.php + +You can also return the callable's return value for further processing. + +.. literalinclude:: benchmark/011.php + +The same functionality is also available when passing callable to ``timer()`` as second parameter. + +.. literalinclude:: benchmark/012.php + Viewing Your Benchmark Points ============================= diff --git a/user_guide_src/source/testing/benchmark/010.php b/user_guide_src/source/testing/benchmark/010.php new file mode 100644 index 000000000000..ae958b1c1471 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/010.php @@ -0,0 +1,11 @@ +record('slow_function', function() { slow_function('...'); }); + +/* + * Same as: + * + * $benchmark->start('slow_function'); + * slow_function('...'); + * $benchmark->stop('slow_function'); +*/ \ No newline at end of file diff --git a/user_guide_src/source/testing/benchmark/011.php b/user_guide_src/source/testing/benchmark/011.php new file mode 100644 index 000000000000..5e09cd4d98b5 --- /dev/null +++ b/user_guide_src/source/testing/benchmark/011.php @@ -0,0 +1,13 @@ +record('string length', fn() => strlen('CI4') ); + +/* + * $length = 3 + * + * Same as: + * + * $benchmark->start('string length'); + * $length = strlen('CI4'); + * $benchmark->stop('string length'); +*/ \ No newline at end of file diff --git a/user_guide_src/source/testing/benchmark/012.php b/user_guide_src/source/testing/benchmark/012.php new file mode 100644 index 000000000000..b4b942ab3d6d --- /dev/null +++ b/user_guide_src/source/testing/benchmark/012.php @@ -0,0 +1,13 @@ + strlen('CI4') ); + +/* + * $length = 3 + * + * Same as: + * + * timer('string length'); + * $length = strlen('CI4'); + * timer('string length'); +*/ \ No newline at end of file From 3dbcc7fdc5a81953fc5655333f5c25b4c1f77126 Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 19:27:06 +0200 Subject: [PATCH 123/970] CS-Fixer changes --- system/Common.php | 2 +- system/Debug/Timer.php | 10 +++++----- tests/system/Debug/TimerTest.php | 25 +++++++++++++++---------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/system/Common.php b/system/Common.php index 8af9122e846f..2215da3f7679 100644 --- a/system/Common.php +++ b/system/Common.php @@ -1091,7 +1091,7 @@ function timer(?string $name = null, ?callable $callable = null) return $timer; } - if (! is_null($callable)) { + if (null !== $callable) { return $timer->record($name, $callable); } diff --git a/system/Debug/Timer.php b/system/Debug/Timer.php index a576eb9586e4..1e34a708e98a 100644 --- a/system/Debug/Timer.php +++ b/system/Debug/Timer.php @@ -130,16 +130,16 @@ public function has(string $name): bool /** * Executes callable and measures its time. * Returns its return value if any. - * - * @param string $name The name of the timer - * @param callable $callable callable to be executed - * + * + * @param string $name The name of the timer + * @param callable $callable callable to be executed + * * @return mixed|null */ public function record(string $name, callable $callable) { $this->start($name); - $returnValue = call_user_func($callable); + $returnValue = $callable(); $this->stop($name); return $returnValue; diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index 402348797a6c..5e0ffbd5c7b2 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Debug; use CodeIgniter\Test\CIUnitTestCase; +use RuntimeException; /** * @internal @@ -127,8 +128,8 @@ public function testReturnsNullGettingElapsedTimeOfNonTimer() */ public function testRecordFunctionNoReturn() { - $timer = new Timer(); - $returnValue = $timer->record('longjohn', function() { sleep(1); }); + $timer = new Timer(); + $returnValue = $timer->record('longjohn', static function () { sleep(1); }); $this->assertGreaterThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); $this->assertNull($returnValue); @@ -139,8 +140,10 @@ public function testRecordFunctionNoReturn() */ public function testRecordFunctionWithReturn() { - $timer = new Timer(); - $returnValue = $timer->record('longjohn', function() { sleep(1); return 'test'; }); + $timer = new Timer(); + $returnValue = $timer->record('longjohn', static function () { sleep(1); + +return 'test'; }); $this->assertGreaterThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); $this->assertSame('test', $returnValue); @@ -148,8 +151,8 @@ public function testRecordFunctionWithReturn() public function testRecordArrowFunction() { - $timer = new Timer(); - $returnValue = $timer->record('longjohn', fn() => strlen('CI4') ); + $timer = new Timer(); + $returnValue = $timer->record('longjohn', static fn () => strlen('CI4')); $this->assertLessThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); $this->assertSame(3, $returnValue); @@ -160,7 +163,7 @@ public function testRecordThrowsException() $this->expectException('RuntimeException'); $timer = new Timer(); - $timer->record('ex', function() { throw new \RuntimeException(); }); + $timer->record('ex', static function () { throw new RuntimeException(); }); } public function testRecordThrowsErrorOnCallableWithParams() @@ -188,7 +191,7 @@ public function testCommonWithNameExpectTimer() public function testCommonNoNameCallableExpectTimer() { - $returnValue = timer(null, fn() => strlen('CI4') ); + $returnValue = timer(null, static fn () => strlen('CI4')); $this->assertInstanceOf(Timer::class, $returnValue); } @@ -198,7 +201,7 @@ public function testCommonNoNameCallableExpectTimer() */ public function testCommonCallableExpectNoReturn() { - $returnValue = timer('common', function() { sleep(1); } ); + $returnValue = timer('common', static function () { sleep(1); }); $this->assertNotInstanceOf(Timer::class, $returnValue); $this->assertNull($returnValue); @@ -210,7 +213,9 @@ public function testCommonCallableExpectNoReturn() */ public function testCommonCallableExpectWithReturn() { - $returnValue = timer('common', function() { sleep(1); return strlen('CI4'); } ); + $returnValue = timer('common', static function () { sleep(1); + +return strlen('CI4'); }); $this->assertNotInstanceOf(Timer::class, $returnValue); $this->assertSame(3, $returnValue); From 838995bd9ffc86b10c3d7f164b1632ec44dedfed Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 19:48:52 +0200 Subject: [PATCH 124/970] Fixed CS-Fixer style issues --- tests/system/Debug/TimerTest.php | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index 5e0ffbd5c7b2..62ed83b74fb3 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -141,9 +141,10 @@ public function testRecordFunctionNoReturn() public function testRecordFunctionWithReturn() { $timer = new Timer(); - $returnValue = $timer->record('longjohn', static function () { sleep(1); - -return 'test'; }); + $returnValue = $timer->record('longjohn', static function () { + sleep(1); + return 'test'; + }); $this->assertGreaterThanOrEqual(1.0, $timer->getElapsedTime('longjohn')); $this->assertSame('test', $returnValue); @@ -213,9 +214,10 @@ public function testCommonCallableExpectNoReturn() */ public function testCommonCallableExpectWithReturn() { - $returnValue = timer('common', static function () { sleep(1); - -return strlen('CI4'); }); + $returnValue = timer('common', static function () { + sleep(1); + return strlen('CI4'); + }); $this->assertNotInstanceOf(Timer::class, $returnValue); $this->assertSame(3, $returnValue); From a47411b01626dd9bbf6ade87fa6189dbfecceafe Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 20:21:23 +0200 Subject: [PATCH 125/970] Unit test fixes for v7, added more new lines --- tests/system/Debug/TimerTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index 62ed83b74fb3..d6a1cbe3b5e9 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -143,6 +143,7 @@ public function testRecordFunctionWithReturn() $timer = new Timer(); $returnValue = $timer->record('longjohn', static function () { sleep(1); + return 'test'; }); @@ -169,7 +170,7 @@ public function testRecordThrowsException() public function testRecordThrowsErrorOnCallableWithParams() { - $this->expectException('Error'); + $this->expectException('Throwable'); $timer = new Timer(); $timer->record('error', 'strlen'); @@ -216,6 +217,7 @@ public function testCommonCallableExpectWithReturn() { $returnValue = timer('common', static function () { sleep(1); + return strlen('CI4'); }); From 9603cea4f9c7909f1f41afdc192a95653340701e Mon Sep 17 00:00:00 2001 From: Christian Rumpf Date: Sun, 31 Jul 2022 21:21:32 +0200 Subject: [PATCH 126/970] Further CS-Fixer changes --- tests/system/Debug/TimerTest.php | 5 +++-- user_guide_src/source/testing/benchmark/010.php | 4 ++-- user_guide_src/source/testing/benchmark/011.php | 6 +++--- user_guide_src/source/testing/benchmark/012.php | 6 +++--- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/system/Debug/TimerTest.php b/tests/system/Debug/TimerTest.php index d6a1cbe3b5e9..580432b0ee96 100644 --- a/tests/system/Debug/TimerTest.php +++ b/tests/system/Debug/TimerTest.php @@ -13,6 +13,7 @@ use CodeIgniter\Test\CIUnitTestCase; use RuntimeException; +use Throwable; /** * @internal @@ -162,7 +163,7 @@ public function testRecordArrowFunction() public function testRecordThrowsException() { - $this->expectException('RuntimeException'); + $this->expectException(RuntimeException::class); $timer = new Timer(); $timer->record('ex', static function () { throw new RuntimeException(); }); @@ -170,7 +171,7 @@ public function testRecordThrowsException() public function testRecordThrowsErrorOnCallableWithParams() { - $this->expectException('Throwable'); + $this->expectException(Throwable::class); $timer = new Timer(); $timer->record('error', 'strlen'); diff --git a/user_guide_src/source/testing/benchmark/010.php b/user_guide_src/source/testing/benchmark/010.php index ae958b1c1471..76a5405b7129 100644 --- a/user_guide_src/source/testing/benchmark/010.php +++ b/user_guide_src/source/testing/benchmark/010.php @@ -1,10 +1,10 @@ record('slow_function', function() { slow_function('...'); }); +$benchmark->record('slow_function', static function () { slow_function('...'); }); /* * Same as: - * + * * $benchmark->start('slow_function'); * slow_function('...'); * $benchmark->stop('slow_function'); diff --git a/user_guide_src/source/testing/benchmark/011.php b/user_guide_src/source/testing/benchmark/011.php index 5e09cd4d98b5..bc12efafa3a4 100644 --- a/user_guide_src/source/testing/benchmark/011.php +++ b/user_guide_src/source/testing/benchmark/011.php @@ -1,12 +1,12 @@ record('string length', fn() => strlen('CI4') ); +$length = $benchmark->record('string length', static fn () => strlen('CI4')); /* * $length = 3 - * + * * Same as: - * + * * $benchmark->start('string length'); * $length = strlen('CI4'); * $benchmark->stop('string length'); diff --git a/user_guide_src/source/testing/benchmark/012.php b/user_guide_src/source/testing/benchmark/012.php index b4b942ab3d6d..2a964324df88 100644 --- a/user_guide_src/source/testing/benchmark/012.php +++ b/user_guide_src/source/testing/benchmark/012.php @@ -1,12 +1,12 @@ strlen('CI4') ); +$length = timer('string length', static fn () => strlen('CI4')); /* * $length = 3 - * + * * Same as: - * + * * timer('string length'); * $length = strlen('CI4'); * timer('string length'); From ab52365fde07bd61a1afb29fcc88f0bcd6756c47 Mon Sep 17 00:00:00 2001 From: kenjis Date: Sat, 16 Jul 2022 10:36:53 +0900 Subject: [PATCH 127/970] feat: spark routes shows route name --- system/Commands/Utilities/Routes.php | 10 ++++- .../Utilities/Routes/AutoRouteCollector.php | 1 + .../AutoRouterImproved/AutoRouteCollector.php | 1 + tests/system/Commands/RoutesTest.php | 45 +++++++++++++++++-- 4 files changed, 53 insertions(+), 4 deletions(-) diff --git a/system/Commands/Utilities/Routes.php b/system/Commands/Utilities/Routes.php index 8f8b5188e570..bf91729cb273 100644 --- a/system/Commands/Utilities/Routes.php +++ b/system/Commands/Utilities/Routes.php @@ -101,10 +101,17 @@ public function run(array $params) $sampleUri = $uriGenerator->get($route); $filters = $filterCollector->get($method, $sampleUri); + if ($handler instanceof Closure) { + $handler = '(Closure)'; + } + + $routeName = $collection->getRoutesOptions($route)['as'] ?? '»'; + $tbody[] = [ strtoupper($method), $route, - is_string($handler) ? $handler : '(Closure)', + $routeName, + $handler, implode(' ', array_map('class_basename', $filters['before'])), implode(' ', array_map('class_basename', $filters['after'])), ]; @@ -149,6 +156,7 @@ public function run(array $params) $thead = [ 'Method', 'Route', + 'Name', 'Handler', 'Before Filters', 'After Filters', diff --git a/system/Commands/Utilities/Routes/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouteCollector.php index 30c8eecfee9d..a2fa46c497e9 100644 --- a/system/Commands/Utilities/Routes/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouteCollector.php @@ -56,6 +56,7 @@ public function get(): array $tbody[] = [ 'auto', $item['route'], + '', $item['handler'], ]; } diff --git a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php index e7597014f899..f2de8e4b4a6d 100644 --- a/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php +++ b/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollector.php @@ -85,6 +85,7 @@ public function get(): array $tbody[] = [ strtoupper($item['method']) . '(auto)', $item['route'] . $item['route_params'], + '', $item['handler'], $item['before'], $item['after'], diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index c761a1eb2eb0..f38957e1eadf 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -39,6 +39,11 @@ protected function getBuffer() return $this->getStreamFilterBuffer(); } + private function getBufferWithoutSpaces(): string + { + return str_replace(' ', '', $this->getBuffer()); + } + public function testRoutesCommand() { command('routes'); @@ -49,7 +54,7 @@ public function testRoutesCommand() $this->assertStringContainsString('\\TestController::index', $this->getBuffer()); } - public function testRoutesCommandRouteFilterAndAutoRoute() + public function testRoutesCommandRouteFilterAndAutoRouteLegacy() { $routes = Services::routes(); $routes->setDefaultNamespace('App\Controllers'); @@ -60,8 +65,42 @@ public function testRoutesCommandRouteFilterAndAutoRoute() command('routes'); $this->assertStringContainsString( - '|auto|/|\App\Controllers\Home::index||toolbar|', - str_replace(' ', '', $this->getBuffer()) + '|auto|/||\App\Controllers\Home::index||toolbar|', + $this->getBufferWithoutSpaces() + ); + } + + public function testRoutesCommandRouteFilterAndAutoRouteImproved() + { + $routes = Services::routes(); + $routes->resetRoutes(); + $routes->loadRoutes(); + $routes->setAutoRoute(true); + config('Feature')->autoRoutesImproved = true; + $namespace = 'Tests\Support\Controllers'; + $routes->setDefaultNamespace($namespace); + + command('routes'); + + $this->assertStringContainsString( + '|GET|/|»|\App\Controllers\Home::index||toolbar|', + $this->getBufferWithoutSpaces() + ); + $this->assertStringContainsString( + '|GET|closure|»|(Closure)||toolbar|', + $this->getBufferWithoutSpaces() + ); + $this->assertStringContainsString( + '|GET|testing|testing-index|\App\Controllers\TestController::index||toolbar|', + $this->getBufferWithoutSpaces() + ); + $this->assertStringContainsString( + '|GET(auto)|newautorouting||\Tests\Support\Controllers\Newautorouting::getIndex||toolbar|', + $this->getBufferWithoutSpaces() + ); + $this->assertStringContainsString( + '|POST(auto)|newautorouting/save/../..[/..]||\Tests\Support\Controllers\Newautorouting::postSave||toolbar|', + $this->getBufferWithoutSpaces() ); } } From c978338cae8a50b64ce9c5c675a02cd862e19b81 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:12:07 +0900 Subject: [PATCH 128/970] test: improve tests --- tests/system/Commands/RoutesTest.php | 135 +++++++++++++++++++-------- 1 file changed, 94 insertions(+), 41 deletions(-) diff --git a/tests/system/Commands/RoutesTest.php b/tests/system/Commands/RoutesTest.php index f38957e1eadf..e262e5ca7c69 100644 --- a/tests/system/Commands/RoutesTest.php +++ b/tests/system/Commands/RoutesTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Commands; +use CodeIgniter\Router\RouteCollection; use CodeIgniter\Test\CIUnitTestCase; use CodeIgniter\Test\StreamFilterTrait; use Config\Services; @@ -39,68 +40,120 @@ protected function getBuffer() return $this->getStreamFilterBuffer(); } - private function getBufferWithoutSpaces(): string + private function getCleanRoutes(): RouteCollection { - return str_replace(' ', '', $this->getBuffer()); + $routes = Services::routes(); + $routes->resetRoutes(); + $routes->loadRoutes(); + + return $routes; } public function testRoutesCommand() { + $this->getCleanRoutes(); + command('routes'); - $this->assertStringContainsString('| (Closure)', $this->getBuffer()); - $this->assertStringContainsString('| Route', $this->getBuffer()); - $this->assertStringContainsString('| testing', $this->getBuffer()); - $this->assertStringContainsString('\\TestController::index', $this->getBuffer()); + $expected = <<<'EOL' + +---------+---------+---------------+----------------------------------------+----------------+---------------+ + | Method | Route | Name | Handler | Before Filters | After Filters | + +---------+---------+---------------+----------------------------------------+----------------+---------------+ + | GET | / | » | \App\Controllers\Home::index | | toolbar | + | GET | closure | » | (Closure) | | toolbar | + | GET | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | HEAD | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | POST | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | PUT | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | DELETE | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | OPTIONS | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | TRACE | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | CONNECT | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | CLI | testing | testing-index | \App\Controllers\TestController::index | | | + +---------+---------+---------------+----------------------------------------+----------------+---------------+ + EOL; + $this->assertStringContainsString($expected, $this->getBuffer()); } - public function testRoutesCommandRouteFilterAndAutoRouteLegacy() + public function testRoutesCommandAutoRouteImproved() { - $routes = Services::routes(); - $routes->setDefaultNamespace('App\Controllers'); - $routes->resetRoutes(); - $routes->get('/', 'Home::index', ['filter' => 'csrf']); + $routes = $this->getCleanRoutes(); + $routes->setAutoRoute(true); + config('Feature')->autoRoutesImproved = true; + $namespace = 'Tests\Support\Controllers'; + $routes->setDefaultNamespace($namespace); command('routes'); - $this->assertStringContainsString( - '|auto|/||\App\Controllers\Home::index||toolbar|', - $this->getBufferWithoutSpaces() - ); + $expected = <<<'EOL' + +------------+--------------------------------+---------------+-----------------------------------------------------+----------------+---------------+ + | Method | Route | Name | Handler | Before Filters | After Filters | + +------------+--------------------------------+---------------+-----------------------------------------------------+----------------+---------------+ + | GET | / | » | \App\Controllers\Home::index | | toolbar | + | GET | closure | » | (Closure) | | toolbar | + | GET | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | HEAD | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | POST | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | PUT | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | DELETE | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | OPTIONS | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | TRACE | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | CONNECT | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | CLI | testing | testing-index | \App\Controllers\TestController::index | | | + | GET(auto) | newautorouting | | \Tests\Support\Controllers\Newautorouting::getIndex | | toolbar | + | POST(auto) | newautorouting/save/../..[/..] | | \Tests\Support\Controllers\Newautorouting::postSave | | toolbar | + +------------+--------------------------------+---------------+-----------------------------------------------------+----------------+---------------+ + EOL; + $this->assertStringContainsString($expected, $this->getBuffer()); } - public function testRoutesCommandRouteFilterAndAutoRouteImproved() + public function testRoutesCommandRouteLegacy() { - $routes = Services::routes(); - $routes->resetRoutes(); - $routes->loadRoutes(); + $routes = $this->getCleanRoutes(); + $routes->setAutoRoute(true); - config('Feature')->autoRoutesImproved = true; - $namespace = 'Tests\Support\Controllers'; + $namespace = 'Tests\Support\Controllers'; $routes->setDefaultNamespace($namespace); command('routes'); - $this->assertStringContainsString( - '|GET|/|»|\App\Controllers\Home::index||toolbar|', - $this->getBufferWithoutSpaces() - ); - $this->assertStringContainsString( - '|GET|closure|»|(Closure)||toolbar|', - $this->getBufferWithoutSpaces() - ); - $this->assertStringContainsString( - '|GET|testing|testing-index|\App\Controllers\TestController::index||toolbar|', - $this->getBufferWithoutSpaces() - ); - $this->assertStringContainsString( - '|GET(auto)|newautorouting||\Tests\Support\Controllers\Newautorouting::getIndex||toolbar|', - $this->getBufferWithoutSpaces() - ); - $this->assertStringContainsString( - '|POST(auto)|newautorouting/save/../..[/..]||\Tests\Support\Controllers\Newautorouting::postSave||toolbar|', - $this->getBufferWithoutSpaces() - ); + $expected = <<<'EOL' + +---------+-------------------------------+---------------+-----------------------------------------------------+----------------+---------------+ + | Method | Route | Name | Handler | Before Filters | After Filters | + +---------+-------------------------------+---------------+-----------------------------------------------------+----------------+---------------+ + | GET | / | » | \App\Controllers\Home::index | | toolbar | + | GET | closure | » | (Closure) | | toolbar | + | GET | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | HEAD | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | POST | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | PUT | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | DELETE | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | OPTIONS | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | TRACE | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | CONNECT | testing | testing-index | \App\Controllers\TestController::index | | toolbar | + | CLI | testing | testing-index | \App\Controllers\TestController::index | | | + | auto | hello | | \Tests\Support\Controllers\Hello::index | | toolbar | + | auto | hello/index[/...] | | \Tests\Support\Controllers\Hello::index | | toolbar | + | auto | newautorouting/getIndex[/...] | | \Tests\Support\Controllers\Newautorouting::getIndex | | toolbar | + | auto | newautorouting/postSave[/...] | | \Tests\Support\Controllers\Newautorouting::postSave | | toolbar | + | auto | popcorn | | \Tests\Support\Controllers\Popcorn::index | | toolbar | + | auto | popcorn/index[/...] | | \Tests\Support\Controllers\Popcorn::index | | toolbar | + | auto | popcorn/pop[/...] | | \Tests\Support\Controllers\Popcorn::pop | | toolbar | + | auto | popcorn/popper[/...] | | \Tests\Support\Controllers\Popcorn::popper | | toolbar | + | auto | popcorn/weasel[/...] | | \Tests\Support\Controllers\Popcorn::weasel | | toolbar | + | auto | popcorn/oops[/...] | | \Tests\Support\Controllers\Popcorn::oops | | toolbar | + | auto | popcorn/goaway[/...] | | \Tests\Support\Controllers\Popcorn::goaway | | toolbar | + | auto | popcorn/index3[/...] | | \Tests\Support\Controllers\Popcorn::index3 | | toolbar | + | auto | popcorn/canyon[/...] | | \Tests\Support\Controllers\Popcorn::canyon | | toolbar | + | auto | popcorn/cat[/...] | | \Tests\Support\Controllers\Popcorn::cat | | toolbar | + | auto | popcorn/json[/...] | | \Tests\Support\Controllers\Popcorn::json | | toolbar | + | auto | popcorn/xml[/...] | | \Tests\Support\Controllers\Popcorn::xml | | toolbar | + | auto | popcorn/toindex[/...] | | \Tests\Support\Controllers\Popcorn::toindex | | toolbar | + | auto | popcorn/echoJson[/...] | | \Tests\Support\Controllers\Popcorn::echoJson | | toolbar | + | auto | remap[/...] | | \Tests\Support\Controllers\Remap::_remap | | toolbar | + +---------+-------------------------------+---------------+-----------------------------------------------------+----------------+---------------+ + EOL; + $this->assertStringContainsString($expected, $this->getBuffer()); } } From 30e2bd45e7fc7ef2e4dae1b634f31d308e48c49c Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:30:45 +0900 Subject: [PATCH 129/970] docs: update spark routes --- user_guide_src/source/incoming/routing.rst | 57 +++++++++++++--------- 1 file changed, 35 insertions(+), 22 deletions(-) diff --git a/user_guide_src/source/incoming/routing.rst b/user_guide_src/source/incoming/routing.rst index 03d6ee8625cc..f7d431f207dd 100644 --- a/user_guide_src/source/incoming/routing.rst +++ b/user_guide_src/source/incoming/routing.rst @@ -711,7 +711,7 @@ In this example, if the user were to visit **example.com/products**, and a ``Pro Confirming Routes ***************** -CodeIgniter has the following :doc:`command ` to display all routes. +CodeIgniter has the following :doc:`command ` to display all routes. .. _routing-spark-routes: @@ -726,34 +726,47 @@ The output is like the following: .. code-block:: none - +--------+------------------+------------------------------------------+----------------+-----------------------+ - | Method | Route | Handler | Before Filters | After Filters | - +--------+------------------+------------------------------------------+----------------+-----------------------+ - | GET | / | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | - | GET | feed | (Closure) | invalidchars | secureheaders toolbar | - | auto | / | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | - | auto | home | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | - | auto | home/index[/...] | \App\Controllers\Home::index | invalidchars | secureheaders toolbar | - +--------+------------------+------------------------------------------+----------------+-----------------------+ + +---------+---------+---------------+-------------------------------+----------------+---------------+ + | Method | Route | Name | Handler | Before Filters | After Filters | + +---------+---------+---------------+-------------------------------+----------------+---------------+ + | GET | / | » | \App\Controllers\Home::index | | toolbar | + | GET | feed | » | (Closure) | | toolbar | + +---------+---------+---------------+-------------------------------+----------------+---------------+ -The *Method* column shows the HTTP method that the route is listening for. ``auto`` means that the route is discovered by Auto Routing (Legacy), so it is not defined in **app/Config/Routes.php**. +The *Method* column shows the HTTP method that the route is listening for. -The *Route* column shows the URI path to match. The route of a defined route is expressed as a regular expression. -But ``[/...]`` in the route of an auto route is indicates any number of segments. +The *Route* column shows the route (URI path) to match. The route of a defined route is expressed as a regular expression. + +The *Name* column shows the route name. ``»`` indicates the name is the same as the route. + +.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. If you want to check filters for a route, you can use :ref:`spark filter:check ` command. When you use Auto Routing (Improved), the output is like the following: .. code-block:: none - +-----------+-------------------------+------------------------------------------+----------------+---------------+ - | Method | Route | Handler | Before Filters | After Filters | - +-----------+-------------------------+------------------------------------------+----------------+---------------+ - | GET(auto) | product/list/../..[/..] | \App\Controllers\Product::getList | | toolbar | - +-----------+-------------------------+------------------------------------------+----------------+---------------+ + +-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+ + | Method | Route | Name | Handler | Before Filters | After Filters | + +-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+ + | GET(auto) | product/list/../..[/..] | | \App\Controllers\Product::getList | | toolbar | + +-----------+-------------------------+---------------+-----------------------------------+----------------+---------------+ -The *Method* will be like ``GET(auto)``. ``/..`` in the *Route* column indicates one segment. -``[/..]`` indicates it is optional. +The *Method* will be like ``GET(auto)``. -.. 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``. +``/..`` in the *Route* column indicates one segment. ``[/..]`` indicates it is optional. -.. important:: The system is not perfect. If you use Custom Placeholders, *Filters* might not be correct. If you want to check filters for a route, you can use :ref:`spark filter:check ` command. +When you use Auto Routing (Legacy), the output is like the following: + +.. code-block:: none + + +--------+--------------------+---------------+-----------------------------------+----------------+---------------+ + | Method | Route | Name | Handler | Before Filters | After Filters | + +--------+--------------------+---------------+-----------------------------------+----------------+---------------+ + | auto | product/list[/...] | | \App\Controllers\Product::getList | | toolbar | + +--------+--------------------+---------------+-----------------------------------+----------------+---------------+ + +The *Method* will be ``auto``. + +``[/...]`` in the *Route* column indicates any number of segments. + +.. note:: When auto-routing is enabled, if you have the route ``home``, it can be also accessd by ``Home``, or maybe by ``hOme``, ``hoMe``, ``HOME``, etc. But the command shows only ``home``. From 49e1b6dd3a1920b8728451a79b8b7e30785ebef2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:31:28 +0900 Subject: [PATCH 130/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 959f9baaf5f0..3a429f6bc36b 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -42,6 +42,7 @@ Enhancements - SQLite ``BaseConnection::getIndexData()`` now can return pseudo index named ``PRIMARY`` for `AUTOINCREMENT` column, and each returned index data has ``type`` property. - Added ``spark filter:check`` command to check the filters for a route. See :ref:`Controller Filters ` for the details. - Now **Encryption** can decrypt data encrypted with CI3's Encryption. See :ref:`encryption-compatible-with-ci3`. +- Now ``spark routes`` command shows route names. See :ref:`URI Routing `. Changes ******* From 655baeea2438bf79a9bc9b7a63f19635665e3c5f Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:36:25 +0900 Subject: [PATCH 131/970] test: remove unnecessary array keys --- .../Routes/AutoRouteCollectorTest.php | 114 +++++++++--------- 1 file changed, 57 insertions(+), 57 deletions(-) diff --git a/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php b/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php index 12e82eef93af..54ec9831e30a 100644 --- a/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php +++ b/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php @@ -31,97 +31,97 @@ public function testGet() $expected = [ [ - 0 => 'auto', - 1 => 'hello', - 2 => '\\Tests\\Support\\Controllers\\Hello::index', + 'auto', + 'hello', + '\\Tests\\Support\\Controllers\\Hello::index', ], [ - 0 => 'auto', - 1 => 'hello/index[/...]', - 2 => '\\Tests\\Support\\Controllers\\Hello::index', + 'auto', + 'hello/index[/...]', + '\\Tests\\Support\\Controllers\\Hello::index', ], [ - 0 => 'auto', - 1 => 'newautorouting/getIndex[/...]', - 2 => '\Tests\Support\Controllers\Newautorouting::getIndex', + 'auto', + 'newautorouting/getIndex[/...]', + '\Tests\Support\Controllers\Newautorouting::getIndex', ], [ - 0 => 'auto', - 1 => 'newautorouting/postSave[/...]', - 2 => '\Tests\Support\Controllers\Newautorouting::postSave', + 'auto', + 'newautorouting/postSave[/...]', + '\Tests\Support\Controllers\Newautorouting::postSave', ], [ - 0 => 'auto', - 1 => 'popcorn', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::index', + 'auto', + 'popcorn', + '\\Tests\\Support\\Controllers\\Popcorn::index', ], [ - 0 => 'auto', - 1 => 'popcorn/index[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::index', + 'auto', + 'popcorn/index[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::index', ], [ - 0 => 'auto', - 1 => 'popcorn/pop[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::pop', + 'auto', + 'popcorn/pop[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::pop', ], [ - 0 => 'auto', - 1 => 'popcorn/popper[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::popper', + 'auto', + 'popcorn/popper[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::popper', ], [ - 0 => 'auto', - 1 => 'popcorn/weasel[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::weasel', + 'auto', + 'popcorn/weasel[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::weasel', ], [ - 0 => 'auto', - 1 => 'popcorn/oops[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::oops', + 'auto', + 'popcorn/oops[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::oops', ], [ - 0 => 'auto', - 1 => 'popcorn/goaway[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::goaway', + 'auto', + 'popcorn/goaway[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::goaway', ], [ - 0 => 'auto', - 1 => 'popcorn/index3[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::index3', + 'auto', + 'popcorn/index3[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::index3', ], [ - 0 => 'auto', - 1 => 'popcorn/canyon[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::canyon', + 'auto', + 'popcorn/canyon[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::canyon', ], [ - 0 => 'auto', - 1 => 'popcorn/cat[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::cat', + 'auto', + 'popcorn/cat[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::cat', ], [ - 0 => 'auto', - 1 => 'popcorn/json[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::json', + 'auto', + 'popcorn/json[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::json', ], [ - 0 => 'auto', - 1 => 'popcorn/xml[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::xml', + 'auto', + 'popcorn/xml[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::xml', ], [ - 0 => 'auto', - 1 => 'popcorn/toindex[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::toindex', + 'auto', + 'popcorn/toindex[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::toindex', ], [ - 0 => 'auto', - 1 => 'popcorn/echoJson[/...]', - 2 => '\\Tests\\Support\\Controllers\\Popcorn::echoJson', + 'auto', + 'popcorn/echoJson[/...]', + '\\Tests\\Support\\Controllers\\Popcorn::echoJson', ], [ - 0 => 'auto', - 1 => 'remap[/...]', - 2 => '\\Tests\\Support\\Controllers\\Remap::_remap', + 'auto', + 'remap[/...]', + '\\Tests\\Support\\Controllers\\Remap::_remap', ], ]; $this->assertSame($expected, $routes); From 545f4970099f4fe6aafb9c847dca4eabdf215bfb Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:39:45 +0900 Subject: [PATCH 132/970] test: update test expectations --- .../Routes/AutoRouteCollectorTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php b/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php index 54ec9831e30a..8f1f2185d047 100644 --- a/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php +++ b/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php @@ -33,94 +33,113 @@ public function testGet() [ 'auto', 'hello', + '', '\\Tests\\Support\\Controllers\\Hello::index', ], [ 'auto', 'hello/index[/...]', + '', '\\Tests\\Support\\Controllers\\Hello::index', ], [ 'auto', 'newautorouting/getIndex[/...]', + '', '\Tests\Support\Controllers\Newautorouting::getIndex', ], [ 'auto', 'newautorouting/postSave[/...]', + '', '\Tests\Support\Controllers\Newautorouting::postSave', ], [ 'auto', 'popcorn', + '', '\\Tests\\Support\\Controllers\\Popcorn::index', ], [ 'auto', 'popcorn/index[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::index', ], [ 'auto', 'popcorn/pop[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::pop', ], [ 'auto', 'popcorn/popper[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::popper', ], [ 'auto', 'popcorn/weasel[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::weasel', ], [ 'auto', 'popcorn/oops[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::oops', ], [ 'auto', 'popcorn/goaway[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::goaway', ], [ 'auto', 'popcorn/index3[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::index3', ], [ 'auto', 'popcorn/canyon[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::canyon', ], [ 'auto', 'popcorn/cat[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::cat', ], [ 'auto', 'popcorn/json[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::json', ], [ 'auto', 'popcorn/xml[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::xml', ], [ 'auto', 'popcorn/toindex[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::toindex', ], [ 'auto', 'popcorn/echoJson[/...]', + '', '\\Tests\\Support\\Controllers\\Popcorn::echoJson', ], [ 'auto', 'remap[/...]', + '', '\\Tests\\Support\\Controllers\\Remap::_remap', ], ]; From c2b490dc60749bcc882129e9897b760714d0e39b Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:40:11 +0900 Subject: [PATCH 133/970] style: break lines --- .../Commands/Utilities/Routes/AutoRouteCollectorTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php b/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php index 8f1f2185d047..7733fb6f6cf3 100644 --- a/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php +++ b/tests/system/Commands/Utilities/Routes/AutoRouteCollectorTest.php @@ -89,12 +89,14 @@ public function testGet() 'popcorn/oops[/...]', '', '\\Tests\\Support\\Controllers\\Popcorn::oops', - ], [ + ], + [ 'auto', 'popcorn/goaway[/...]', '', '\\Tests\\Support\\Controllers\\Popcorn::goaway', - ], [ + ], + [ 'auto', 'popcorn/index3[/...]', '', From 48953df9f4b4dce99694c830595d5bb2d16f2ccb Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:42:29 +0900 Subject: [PATCH 134/970] test: remove unnecessary array keys --- .../AutoRouteCollectorTest.php | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php b/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php index 0f368925d57f..8e47466bf56e 100644 --- a/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php +++ b/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php @@ -59,18 +59,18 @@ public function testGetFilterMatches() $expected = [ 0 => [ - 0 => 'GET(auto)', - 1 => 'newautorouting', - 2 => '\\Tests\\Support\\Controllers\\Newautorouting::getIndex', - 3 => '', - 4 => 'toolbar', + 'GET(auto)', + 'newautorouting', + '\\Tests\\Support\\Controllers\\Newautorouting::getIndex', + '', + 'toolbar', ], 1 => [ - 0 => 'POST(auto)', - 1 => 'newautorouting/save/../..[/..]', - 2 => '\\Tests\\Support\\Controllers\\Newautorouting::postSave', - 3 => 'honeypot', - 4 => 'toolbar', + 'POST(auto)', + 'newautorouting/save/../..[/..]', + '\\Tests\\Support\\Controllers\\Newautorouting::postSave', + 'honeypot', + 'toolbar', ], ]; $this->assertSame($expected, $routes); @@ -85,18 +85,18 @@ public function testGetFilterDoesNotMatch() $expected = [ 0 => [ - 0 => 'GET(auto)', - 1 => 'newautorouting', - 2 => '\\Tests\\Support\\Controllers\\Newautorouting::getIndex', - 3 => '', - 4 => 'toolbar', + 'GET(auto)', + 'newautorouting', + '\\Tests\\Support\\Controllers\\Newautorouting::getIndex', + '', + 'toolbar', ], 1 => [ - 0 => 'POST(auto)', - 1 => 'newautorouting/save/../..[/..]', - 2 => '\\Tests\\Support\\Controllers\\Newautorouting::postSave', - 3 => '', - 4 => 'toolbar', + 'POST(auto)', + 'newautorouting/save/../..[/..]', + '\\Tests\\Support\\Controllers\\Newautorouting::postSave', + '', + 'toolbar', ], ]; $this->assertSame($expected, $routes); From 8300dcee16cd36a0871a4a7b04a69f3f4d8c5310 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 1 Aug 2022 13:43:30 +0900 Subject: [PATCH 135/970] test: update test expectations --- .../Routes/AutoRouterImproved/AutoRouteCollectorTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php b/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php index 8e47466bf56e..823646875812 100644 --- a/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php +++ b/tests/system/Commands/Utilities/Routes/AutoRouterImproved/AutoRouteCollectorTest.php @@ -61,6 +61,7 @@ public function testGetFilterMatches() 0 => [ 'GET(auto)', 'newautorouting', + '', '\\Tests\\Support\\Controllers\\Newautorouting::getIndex', '', 'toolbar', @@ -68,6 +69,7 @@ public function testGetFilterMatches() 1 => [ 'POST(auto)', 'newautorouting/save/../..[/..]', + '', '\\Tests\\Support\\Controllers\\Newautorouting::postSave', 'honeypot', 'toolbar', @@ -87,6 +89,7 @@ public function testGetFilterDoesNotMatch() 0 => [ 'GET(auto)', 'newautorouting', + '', '\\Tests\\Support\\Controllers\\Newautorouting::getIndex', '', 'toolbar', @@ -94,6 +97,7 @@ public function testGetFilterDoesNotMatch() 1 => [ 'POST(auto)', 'newautorouting/save/../..[/..]', + '', '\\Tests\\Support\\Controllers\\Newautorouting::postSave', '', 'toolbar', From 6636a3e9744858224ed676786c2fd80e22901e54 Mon Sep 17 00:00:00 2001 From: Stefan Bauer Date: Mon, 1 Aug 2022 14:06:28 +0200 Subject: [PATCH 136/970] camelCase language vars --- app/Views/errors/html/error_404.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Views/errors/html/error_404.php b/app/Views/errors/html/error_404.php index fc4bdf055629..2b2bca046eb6 100644 --- a/app/Views/errors/html/error_404.php +++ b/app/Views/errors/html/error_404.php @@ -2,7 +2,7 @@ - <?= lang('Errors.404pageNotFound') ?> + <?= lang('Errors.pageNotFound') ?> ') + 8); $script = PHP_EOL - . '' - . '' + . '' . '' . $kintScript . PHP_EOL; diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php index 0e73076f0e02..aae7fc6a81a1 100644 --- a/system/Debug/Toolbar/Views/toolbar.tpl.php +++ b/system/Debug/Toolbar/Views/toolbar.tpl.php @@ -22,7 +22,7 @@ -

diff --git a/system/Helpers/html_helper.php b/system/Helpers/html_helper.php index 11491f76910d..31c9525bdf08 100755 --- a/system/Helpers/html_helper.php +++ b/system/Helpers/html_helper.php @@ -214,7 +214,7 @@ function script_tag($src = '', bool $indexPage = false): string } } - return $script . 'type="text/javascript">'; + return rtrim($script) . '>'; } } diff --git a/system/Helpers/url_helper.php b/system/Helpers/url_helper.php index 94f430a44b67..906716f0b240 100644 --- a/system/Helpers/url_helper.php +++ b/system/Helpers/url_helper.php @@ -371,7 +371,7 @@ function safe_mailto(string $email, string $title = '', $attributes = ''): strin // improve obfuscation by eliminating newlines & whitespace $cspNonce = csp_script_nonce(); $cspNonce = $cspNonce ? ' ' . $cspNonce : $cspNonce; - $output = ''; + $expected = ''; $this->assertSame($expected, script_tag($target)); } public function testScriptTagWithoutProtocol() { $target = 'js/mystyles.js'; - $expected = ''; + $expected = ''; $this->assertSame($expected, script_tag($target)); } public function testScriptTagWithIndexpage() { $target = 'js/mystyles.js'; - $expected = ''; + $expected = ''; $this->assertSame($expected, script_tag($target, true)); } public function testScriptTagWithSrc() { $target = ['src' => 'http://site.com/js/mystyles.js']; - $expected = ''; + $expected = ''; $this->assertSame($expected, script_tag($target)); } public function testScriptTagWithSrcWithoutProtocol() { $target = ['src' => 'js/mystyles.js']; - $expected = ''; + $expected = ''; $this->assertSame($expected, script_tag($target)); } public function testScriptTagWithSrcAndAttributes() { $target = ['src' => 'js/mystyles.js', 'charset' => 'UTF-8', 'defer' => '', 'async' => null]; - $expected = ''; + $expected = ''; $this->assertSame($expected, script_tag($target)); } @@ -299,7 +299,7 @@ public function testScriptTagWithCsp() */ public function testScriptTagWithoutAnyArg() { - $expected = ''; + $expected = ''; $this->assertSame($expected, script_tag()); } diff --git a/tests/system/Helpers/URLHelper/MiscUrlTest.php b/tests/system/Helpers/URLHelper/MiscUrlTest.php index b213f6413e97..66282e304c93 100644 --- a/tests/system/Helpers/URLHelper/MiscUrlTest.php +++ b/tests/system/Helpers/URLHelper/MiscUrlTest.php @@ -439,18 +439,18 @@ public function safeMailtoPatterns() { return [ 'page01' => [ - "", + "", 'me@my-site.com', 'Click Here to Contact Me', ], 'page02' => [ - "", + "", 'me@my-site.com', 'Contact Me', ['title' => 'Mail me'], ], 'page03' => [ - "", + "", 'me@my-site.com', ], ]; @@ -542,7 +542,7 @@ public function autolinkEmails() ], 'test02' => [ 'This is my noreply@codeigniter.com test', - "This is my test", + "This is my test", ], 'test03' => [ '
www.google.com', @@ -562,11 +562,11 @@ public function autolinkEmails() ], 'test07' => [ 'Visit example.com or email foo@bar.com', - "Visit example.com or email ", + "Visit example.com or email ", ], 'test08' => [ 'Visit www.example.com or email foo@bar.com', - "Visit www.example.com or email ", + "Visit www.example.com or email ", ], ]; } @@ -591,7 +591,7 @@ public function autolinkBoth() ], 'test02' => [ 'This is my noreply@codeigniter.com test', - "This is my test", + "This is my test", ], 'test03' => [ '
www.google.com', @@ -611,11 +611,11 @@ public function autolinkBoth() ], 'test07' => [ 'Visit example.com or email foo@bar.com', - "Visit example.com or email ", + "Visit example.com or email ", ], 'test08' => [ 'Visit www.example.com or email foo@bar.com', - "Visit www.example.com or email ", + "Visit www.example.com or email ", ], ]; } From d0e48fbfdb5e9c3c72a06e8ef7feab49b0f07631 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 5 Oct 2022 12:10:38 +0900 Subject: [PATCH 439/970] docs: update user guide --- user_guide_src/source/changelogs/v4.3.0.rst | 1 + user_guide_src/source/helpers/html_helper/010.php | 2 +- user_guide_src/source/helpers/html_helper/011.php | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 85e04e06a322..1b28541bba4f 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -46,6 +46,7 @@ Others - ``CITestStreamFilter::$buffer = ''`` no longer causes the filter to be registered to listen for streams. Now there is a ``CITestStreamFilter::registration()`` method for this. See :ref:`upgrade-430-stream-filter` for details. - The data structure returned by :ref:`BaseConnection::getForeignKeyData() ` has been changed. +- :php:func:`script_tag()` and :php:func:`safe_mailto()` no longer output ``type="text/javascript"`` in `` +// diff --git a/user_guide_src/source/helpers/html_helper/011.php b/user_guide_src/source/helpers/html_helper/011.php index f47bb7053770..586621f9c207 100644 --- a/user_guide_src/source/helpers/html_helper/011.php +++ b/user_guide_src/source/helpers/html_helper/011.php @@ -3,4 +3,4 @@ $script = ['src' => 'js/printer.js', 'defer' => null]; echo script_tag($script); -// +// From 2b0973d82c2c0383db264c97580d68ba6de23a90 Mon Sep 17 00:00:00 2001 From: kenjis Date: Thu, 6 Oct 2022 19:01:02 +0900 Subject: [PATCH 440/970] fix: error when Config\Modules::$composerPackages is missing --- 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 367a0194a126..ad4de0329d66 100644 --- a/system/Autoloader/Autoloader.php +++ b/system/Autoloader/Autoloader.php @@ -139,7 +139,8 @@ private function loadComposerInfo(Modules $modules): void // Should we load through Composer's namespaces, also? if ($modules->discoverInComposer) { - $this->loadComposerNamespaces($composer, $modules->composerPackages); + // @phpstan-ignore-next-line + $this->loadComposerNamespaces($composer, $modules->composerPackages ?? []); } unset($composer); From f4641f6d9de19129427d2c5a17107a72f7d8f1c4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 09:50:20 +0900 Subject: [PATCH 441/970] feat: add missing Response::getCSP() method and use it --- system/Debug/Toolbar.php | 4 ++-- system/HTTP/ResponseTrait.php | 7 +++++++ tests/system/HTTP/ContentSecurityPolicyTest.php | 4 ++-- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 4b3ac0124fc6..a9ad94b31a77 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -163,8 +163,8 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques $data['config'] = Config::display(); - if ($response->CSP !== null) { - $response->CSP->addImageSrc('data:'); + if ($response->getCSP() !== null) { + $response->getCSP()->addImageSrc('data:'); } return json_encode($data); diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index b58fcdae8e53..efa7c52b1a80 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -48,6 +48,8 @@ trait ResponseTrait * Content security policy handler * * @var ContentSecurityPolicy + * + * @TODO Will be protected. Use `getCSP()` instead. */ public $CSP; @@ -795,4 +797,9 @@ public function download(string $filename = '', $data = '', bool $setMime = fals return $response; } + + public function getCSP(): ContentSecurityPolicy + { + return $this->CSP; + } } diff --git a/tests/system/HTTP/ContentSecurityPolicyTest.php b/tests/system/HTTP/ContentSecurityPolicyTest.php index 19d720d9f49b..608a6eb1aeee 100644 --- a/tests/system/HTTP/ContentSecurityPolicyTest.php +++ b/tests/system/HTTP/ContentSecurityPolicyTest.php @@ -40,7 +40,7 @@ protected function prepare(bool $CSPEnabled = true) $config->CSPEnabled = $CSPEnabled; $this->response = new Response($config); $this->response->pretend(false); - $this->csp = $this->response->CSP; + $this->csp = $this->response->getCSP(); } protected function work(string $parm = 'Hello') @@ -635,7 +635,7 @@ public function testCSPDisabled() { $this->prepare(false); $this->work(); - $this->response->CSP->addStyleSrc('https://example.com'); + $this->response->getCSP()->addStyleSrc('https://example.com'); $this->assertHeaderNotEmitted('content-security-policy', true); } From 8cdd561a9cfe85330672fb738ff7a39212d9530d Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:05:37 +0900 Subject: [PATCH 442/970] fix: add missing getCSP() in ResponseInterface --- system/HTTP/ResponseInterface.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index f6b00a5044db..7e38d1edeb5b 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -382,4 +382,13 @@ public function redirect(string $uri, string $method = 'auto', ?int $code = null * @return DownloadResponse|null */ public function download(string $filename = '', $data = '', bool $setMime = false); + + // -------------------------------------------------------------------- + // CSP Methods + // -------------------------------------------------------------------- + + /** + * Get Content Security Policy handler. + */ + public function getCSP(): ContentSecurityPolicy; } From 77fd44b44585db255a6a0c1fe9243ee6e2051087 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:08:19 +0900 Subject: [PATCH 443/970] docs: remove duplicate "response" --- system/HTTP/ResponseInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index 7e38d1edeb5b..76c98094643b 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -135,7 +135,7 @@ public function getStatusCode(): int; public function setStatusCode(int $code, string $reason = ''); /** - * Gets the response response phrase associated with the status code. + * Gets the response phrase associated with the status code. * * @see http://tools.ietf.org/html/rfc7231#section-6 * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml From 508782e770ce0e281eb0468357194454bafeef48 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:09:39 +0900 Subject: [PATCH 444/970] fix: add missing getReasonPhrase() and getCookieStore() in ResponseInterface --- system/HTTP/ResponseInterface.php | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index 76c98094643b..346f2dd802f0 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -12,6 +12,7 @@ namespace CodeIgniter\HTTP; use CodeIgniter\Cookie\Cookie; +use CodeIgniter\Cookie\CookieStore; use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\Pager\PagerInterface; use DateTime; @@ -144,6 +145,22 @@ public function setStatusCode(int $code, string $reason = ''); */ public function getReason(): string; + /** + * Gets the response reason phrase associated with the status code. + * + * Because a reason phrase is not a required element in a response + * status line, the reason phrase value MAY be null. Implementations MAY + * choose to return the default RFC 7231 recommended reason phrase (or those + * listed in the IANA HTTP Status Code Registry) for the response's + * status code. + * + * @see http://tools.ietf.org/html/rfc7231#section-6 + * @see http://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml + * + * @return string Reason phrase; must return an empty string if none present. + */ + public function getReasonPhrase(); + // -------------------------------------------------------------------- // Convenience Methods // -------------------------------------------------------------------- @@ -353,6 +370,13 @@ public function deleteCookie(string $name = '', string $domain = '', string $pat */ public function getCookies(); + /** + * Returns the `CookieStore` instance. + * + * @return CookieStore + */ + public function getCookieStore(); + // -------------------------------------------------------------------- // Response Methods // -------------------------------------------------------------------- From 680945dc7fc3e4d3e331c1d5f2a558df5f9c1ccb Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:18:40 +0900 Subject: [PATCH 445/970] fix: incorrect declared types --- system/API/ResponseTrait.php | 4 +--- system/Common.php | 2 +- system/Config/Services.php | 2 +- system/Debug/Exceptions.php | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/system/API/ResponseTrait.php b/system/API/ResponseTrait.php index 93dd976eaefb..cc302a9de91d 100644 --- a/system/API/ResponseTrait.php +++ b/system/API/ResponseTrait.php @@ -282,10 +282,8 @@ protected function failTooManyRequests(string $description = 'Too Many Requests' * @param string $description The error message to show the user. * @param string|null $code A custom, API-specific, error code. * @param string $message A custom "reason" message to return. - * - * @return Response The value of the Response's send() method. */ - protected function failServerError(string $description = 'Internal Server Error', ?string $code = null, string $message = ''): Response + protected function failServerError(string $description = 'Internal Server Error', ?string $code = null, string $message = ''): ResponseInterface { return $this->fail($description, $this->codes['server_error'], $code, $message); } diff --git a/system/Common.php b/system/Common.php index 306afaa744de..631aa14488c0 100644 --- a/system/Common.php +++ b/system/Common.php @@ -900,7 +900,7 @@ function request() /** * Returns the shared Response. */ - function response(): Response + function response(): ResponseInterface { return Services::response(); } diff --git a/system/Config/Services.php b/system/Config/Services.php index 08d1a354bc4e..edfe13113457 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -253,7 +253,7 @@ public static function encrypter(?EncryptionConfig $config = null, $getShared = public static function exceptions( ?ExceptionsConfig $config = null, ?IncomingRequest $request = null, - ?Response $response = null, + ?ResponseInterface $response = null, bool $getShared = true ) { if ($getShared) { diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 01eca101d887..01609788bd0f 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -70,7 +70,7 @@ class Exceptions /** * @param CLIRequest|IncomingRequest $request */ - public function __construct(ExceptionsConfig $config, $request, Response $response) + public function __construct(ExceptionsConfig $config, $request, ResponseInterface $response) { $this->ob_level = ob_get_level(); $this->viewPath = rtrim($config->errorViewPath, '\\/ ') . DIRECTORY_SEPARATOR; From 180b67c3b2749b376c94c12215467efafae45d86 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:19:27 +0900 Subject: [PATCH 446/970] docs: fix incorrect @throws --- system/HTTP/ResponseInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/ResponseInterface.php b/system/HTTP/ResponseInterface.php index 346f2dd802f0..878d1488c25d 100644 --- a/system/HTTP/ResponseInterface.php +++ b/system/HTTP/ResponseInterface.php @@ -131,7 +131,7 @@ public function getStatusCode(): int; * * @return $this * - * @throws InvalidArgumentException For invalid status code arguments. + * @throws HTTPException For invalid status code arguments. */ public function setStatusCode(int $code, string $reason = ''); From a39efce8569c2c225b681af927397716efecdd9e Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:21:30 +0900 Subject: [PATCH 447/970] docs: fix @return --- system/HTTP/ResponseTrait.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index efa7c52b1a80..cec378cb2a6b 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -175,7 +175,7 @@ public function setStatusCode(int $code, string $reason = '') /** * Sets the date header * - * @return Response + * @return $this */ public function setDate(DateTime $date) { @@ -191,7 +191,7 @@ public function setDate(DateTime $date) * * @see http://tools.ietf.org/html/rfc5988 * - * @return Response + * @return $this * * @todo Recommend moving to Pager */ @@ -222,7 +222,7 @@ public function setLink(PagerInterface $pager) * Sets the Content Type header for this response with the mime type * and, optionally, the charset. * - * @return Response + * @return $this */ public function setContentType(string $mime, string $charset = 'UTF-8') { @@ -336,7 +336,7 @@ protected function formatBody($body, string $format) * Sets the appropriate headers to ensure this response * is not cached by the browsers. * - * @return Response + * @return $this * * @todo Recommend researching these directives, might need: 'private', 'no-transform', 'no-store', 'must-revalidate' * @@ -374,7 +374,7 @@ public function noCache() * - proxy-revalidate * - no-transform * - * @return Response + * @return $this */ public function setCache(array $options = []) { @@ -411,7 +411,7 @@ public function setCache(array $options = []) * * @param DateTime|string $date * - * @return Response + * @return $this */ public function setLastModified($date) { @@ -454,7 +454,7 @@ public function send() /** * Sends the headers of this HTTP response to the browser. * - * @return Response + * @return $this */ public function sendHeaders() { @@ -483,7 +483,7 @@ public function sendHeaders() /** * Sends the Body of the message to the browser. * - * @return Response + * @return $this */ public function sendBody() { From c2657f6a45a745a332ff917bb0ee9baff191c77a Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:22:05 +0900 Subject: [PATCH 448/970] docs: replace Response with ResponseInterface in doc comments --- system/API/ResponseTrait.php | 29 ++++++++++++++------------- system/Config/BaseService.php | 5 ++--- system/Config/Services.php | 2 +- system/Debug/Exceptions.php | 4 ++-- system/Debug/Toolbar.php | 3 --- system/HTTP/ContentSecurityPolicy.php | 6 +----- system/RESTful/ResourceController.php | 16 +++++++-------- 7 files changed, 29 insertions(+), 36 deletions(-) diff --git a/system/API/ResponseTrait.php b/system/API/ResponseTrait.php index cc302a9de91d..d623bc942df3 100644 --- a/system/API/ResponseTrait.php +++ b/system/API/ResponseTrait.php @@ -14,6 +14,7 @@ use CodeIgniter\Format\FormatterInterface; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; use Config\Services; /** @@ -85,7 +86,7 @@ trait ResponseTrait * * @param array|string|null $data * - * @return Response + * @return ResponseInterface */ protected function respond($data = null, ?int $status = null, string $message = '') { @@ -119,7 +120,7 @@ protected function respond($data = null, ?int $status = null, string $message = * @param int $status HTTP status code * @param string|null $code Custom, API-specific, error code * - * @return Response + * @return ResponseInterface */ protected function fail($messages, int $status = 400, ?string $code = null, string $customMessage = '') { @@ -145,7 +146,7 @@ protected function fail($messages, int $status = 400, ?string $code = null, stri * * @param array|string|null $data * - * @return Response + * @return ResponseInterface */ protected function respondCreated($data = null, string $message = '') { @@ -157,7 +158,7 @@ protected function respondCreated($data = null, string $message = '') * * @param array|string|null $data * - * @return Response + * @return ResponseInterface */ protected function respondDeleted($data = null, string $message = '') { @@ -169,7 +170,7 @@ protected function respondDeleted($data = null, string $message = '') * * @param array|string|null $data * - * @return Response + * @return ResponseInterface */ protected function respondUpdated($data = null, string $message = '') { @@ -180,7 +181,7 @@ protected function respondUpdated($data = null, string $message = '') * Used after a command has been successfully executed but there is no * meaningful reply to send back to the client. * - * @return Response + * @return ResponseInterface */ protected function respondNoContent(string $message = 'No Content') { @@ -192,7 +193,7 @@ protected function respondNoContent(string $message = 'No Content') * or had bad authorization credentials. User is encouraged to try again * with the proper information. * - * @return Response + * @return ResponseInterface */ protected function failUnauthorized(string $description = 'Unauthorized', ?string $code = null, string $message = '') { @@ -203,7 +204,7 @@ protected function failUnauthorized(string $description = 'Unauthorized', ?strin * Used when access is always denied to this resource and no amount * of trying again will help. * - * @return Response + * @return ResponseInterface */ protected function failForbidden(string $description = 'Forbidden', ?string $code = null, string $message = '') { @@ -213,7 +214,7 @@ protected function failForbidden(string $description = 'Forbidden', ?string $cod /** * Used when a specified resource cannot be found. * - * @return Response + * @return ResponseInterface */ protected function failNotFound(string $description = 'Not Found', ?string $code = null, string $message = '') { @@ -223,7 +224,7 @@ protected function failNotFound(string $description = 'Not Found', ?string $code /** * Used when the data provided by the client cannot be validated. * - * @return Response + * @return ResponseInterface * * @deprecated Use failValidationErrors instead */ @@ -237,7 +238,7 @@ protected function failValidationError(string $description = 'Bad Request', ?str * * @param string|string[] $errors * - * @return Response + * @return ResponseInterface */ protected function failValidationErrors($errors, ?string $code = null, string $message = '') { @@ -247,7 +248,7 @@ protected function failValidationErrors($errors, ?string $code = null, string $m /** * Use when trying to create a new resource and it already exists. * - * @return Response + * @return ResponseInterface */ protected function failResourceExists(string $description = 'Conflict', ?string $code = null, string $message = '') { @@ -259,7 +260,7 @@ protected function failResourceExists(string $description = 'Conflict', ?string * Not Found, because here we know the data previously existed, but is now gone, * where Not Found means we simply cannot find any information about it. * - * @return Response + * @return ResponseInterface */ protected function failResourceGone(string $description = 'Gone', ?string $code = null, string $message = '') { @@ -269,7 +270,7 @@ protected function failResourceGone(string $description = 'Gone', ?string $code /** * Used when the user has made too many requests for the resource recently. * - * @return Response + * @return ResponseInterface */ protected function failTooManyRequests(string $description = 'Too Many Requests', ?string $code = null, string $message = '') { diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index a240246d3c5c..98cb19fde9e7 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -35,7 +35,6 @@ use CodeIgniter\HTTP\RedirectResponse; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\RequestInterface; -use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\URI; use CodeIgniter\Images\Handlers\BaseHandler; @@ -101,7 +100,7 @@ * @method static CURLRequest curlrequest($options = [], ResponseInterface $response = null, App $config = null, $getShared = true) * @method static Email email($config = null, $getShared = true) * @method static EncrypterInterface encrypter(Encryption $config = null, $getShared = false) - * @method static Exceptions exceptions(ConfigExceptions $config = null, IncomingRequest $request = null, Response $response = null, $getShared = true) + * @method static Exceptions exceptions(ConfigExceptions $config = null, IncomingRequest $request = null, ResponseInterface $response = null, $getShared = true) * @method static Filters filters(ConfigFilters $config = null, $getShared = true) * @method static Format format(ConfigFormat $config = null, $getShared = true) * @method static Honeypot honeypot(ConfigHoneyPot $config = null, $getShared = true) @@ -117,7 +116,7 @@ * @method static RedirectResponse redirectresponse(App $config = null, $getShared = true) * @method static View renderer($viewPath = null, ConfigView $config = null, $getShared = true) * @method static IncomingRequest|CLIRequest request(App $config = null, $getShared = true) - * @method static Response response(App $config = null, $getShared = true) + * @method static ResponseInterface response(App $config = null, $getShared = true) * @method static Router router(RouteCollectionInterface $routes = null, Request $request = null, $getShared = true) * @method static RouteCollection routes($getShared = true) * @method static Security security(App $config = null, $getShared = true) diff --git a/system/Config/Services.php b/system/Config/Services.php index edfe13113457..aa2be0219b71 100644 --- a/system/Config/Services.php +++ b/system/Config/Services.php @@ -546,7 +546,7 @@ public static function incomingrequest(?App $config = null, bool $getShared = tr /** * The Response class models an HTTP response. * - * @return Response + * @return ResponseInterface */ public static function response(?App $config = null, bool $getShared = true) { diff --git a/system/Debug/Exceptions.php b/system/Debug/Exceptions.php index 01609788bd0f..1e976fc6be1a 100644 --- a/system/Debug/Exceptions.php +++ b/system/Debug/Exceptions.php @@ -18,7 +18,7 @@ use CodeIgniter\HTTP\CLIRequest; use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; use Config\Exceptions as ExceptionsConfig; use Config\Paths; use ErrorException; @@ -63,7 +63,7 @@ class Exceptions /** * The outgoing response. * - * @var Response + * @var ResponseInterface */ protected $response; diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index a9ad94b31a77..2d459227ca6e 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -20,7 +20,6 @@ use CodeIgniter\HTTP\DownloadResponse; use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\RequestInterface; -use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface; use Config\Services; use Config\Toolbar as ToolbarConfig; @@ -71,7 +70,6 @@ public function __construct(ToolbarConfig $config) * * @param float $startTime App start time * @param IncomingRequest $request - * @param Response $response * * @return string JSON encoded data */ @@ -355,7 +353,6 @@ public function prepare(?RequestInterface $request = null, ?ResponseInterface $r { /** * @var IncomingRequest|null $request - * @var Response|null $response */ if (CI_DEBUG && ! is_cli()) { $app = Services::codeigniter(); diff --git a/system/HTTP/ContentSecurityPolicy.php b/system/HTTP/ContentSecurityPolicy.php index 4f912a8ea011..3cc9b03a58db 100644 --- a/system/HTTP/ContentSecurityPolicy.php +++ b/system/HTTP/ContentSecurityPolicy.php @@ -690,11 +690,7 @@ protected function generateNonces(ResponseInterface $response) */ protected function buildHeaders(ResponseInterface $response) { - /** - * Ensure both headers are available and arrays... - * - * @var Response $response - */ + // Ensure both headers are available and arrays... $response->setHeader('Content-Security-Policy', []); $response->setHeader('Content-Security-Policy-Report-Only', []); diff --git a/system/RESTful/ResourceController.php b/system/RESTful/ResourceController.php index 42bf93831e85..93a16d0dff98 100644 --- a/system/RESTful/ResourceController.php +++ b/system/RESTful/ResourceController.php @@ -12,7 +12,7 @@ namespace CodeIgniter\RESTful; use CodeIgniter\API\ResponseTrait; -use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; /** * An extendable controller to provide a RESTful API for a resource. @@ -24,7 +24,7 @@ class ResourceController extends BaseResource /** * Return an array of resource objects, themselves in array format * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function index() { @@ -36,7 +36,7 @@ public function index() * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function show($id = null) { @@ -46,7 +46,7 @@ public function show($id = null) /** * Return a new resource object, with default properties * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function new() { @@ -56,7 +56,7 @@ public function new() /** * Create a new resource object, from "posted" parameters * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function create() { @@ -68,7 +68,7 @@ public function create() * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function edit($id = null) { @@ -80,7 +80,7 @@ public function edit($id = null) * * @param string|null|int$id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function update($id = null) { @@ -92,7 +92,7 @@ public function update($id = null) * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function delete($id = null) { From 7379b67b2670f2ef1a17c82ad7e6f2110773b302 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:45:10 +0900 Subject: [PATCH 449/970] docs: replace Response with ResponseInterface in doc comments --- system/API/ResponseTrait.php | 5 ++--- system/HTTP/CURLRequest.php | 2 -- system/RESTful/ResourcePresenter.php | 18 +++++++++--------- system/Security/Security.php | 2 -- system/Session/Session.php | 2 -- 5 files changed, 11 insertions(+), 18 deletions(-) diff --git a/system/API/ResponseTrait.php b/system/API/ResponseTrait.php index d623bc942df3..450c24288cea 100644 --- a/system/API/ResponseTrait.php +++ b/system/API/ResponseTrait.php @@ -13,7 +13,6 @@ use CodeIgniter\Format\FormatterInterface; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\Response; use CodeIgniter\HTTP\ResponseInterface; use Config\Services; @@ -22,8 +21,8 @@ * consistent HTTP responses under a variety of common * situations when working as an API. * - * @property IncomingRequest $request - * @property Response $response + * @property IncomingRequest $request + * @property ResponseInterface $response */ trait ResponseTrait { diff --git a/system/HTTP/CURLRequest.php b/system/HTTP/CURLRequest.php index 2ecf69cc0242..217899863aa7 100644 --- a/system/HTTP/CURLRequest.php +++ b/system/HTTP/CURLRequest.php @@ -96,8 +96,6 @@ class CURLRequest extends Request * - baseURI * - timeout * - any other request options to use as defaults. - * - * @param ResponseInterface $response */ public function __construct(App $config, URI $uri, ?ResponseInterface $response = null, array $options = []) { diff --git a/system/RESTful/ResourcePresenter.php b/system/RESTful/ResourcePresenter.php index 3b832a2412be..5aedb28d4ad8 100644 --- a/system/RESTful/ResourcePresenter.php +++ b/system/RESTful/ResourcePresenter.php @@ -11,7 +11,7 @@ namespace CodeIgniter\RESTful; -use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; /** * An extendable controller to help provide a UI for a resource. @@ -21,7 +21,7 @@ class ResourcePresenter extends BaseResource /** * Present a view of resource objects * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function index() { @@ -33,7 +33,7 @@ public function index() * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function show($id = null) { @@ -43,7 +43,7 @@ public function show($id = null) /** * Present a view to present a new single resource object * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function new() { @@ -54,7 +54,7 @@ public function new() * Process the creation/insertion of a new resource object. * This should be a POST. * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function create() { @@ -66,7 +66,7 @@ public function create() * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function edit($id = null) { @@ -79,7 +79,7 @@ public function edit($id = null) * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function update($id = null) { @@ -91,7 +91,7 @@ public function update($id = null) * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function remove($id = null) { @@ -103,7 +103,7 @@ public function remove($id = null) * * @param int|string|null $id * - * @return Response|string|void + * @return ResponseInterface|string|void */ public function delete($id = null) { diff --git a/system/Security/Security.php b/system/Security/Security.php index bc24c0605e30..ba70e3ec24f0 100644 --- a/system/Security/Security.php +++ b/system/Security/Security.php @@ -15,7 +15,6 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Request; use CodeIgniter\HTTP\RequestInterface; -use CodeIgniter\HTTP\Response; use CodeIgniter\Security\Exceptions\SecurityException; use CodeIgniter\Session\Session; use Config\App; @@ -571,7 +570,6 @@ private function saveHashInCookie(): void ] ); - /** @var Response $response */ $response = Services::response(); $response->setCookie($this->cookie); } diff --git a/system/Session/Session.php b/system/Session/Session.php index f864a09b6f19..1ac80e40f02f 100644 --- a/system/Session/Session.php +++ b/system/Session/Session.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Session; use CodeIgniter\Cookie\Cookie; -use CodeIgniter\HTTP\Response; use Config\App; use Config\Cookie as CookieConfig; use Config\Services; @@ -930,7 +929,6 @@ protected function setCookie() $expiration = $this->sessionExpiration === 0 ? 0 : time() + $this->sessionExpiration; $this->cookie = $this->cookie->withValue(session_id())->withExpires($expiration); - /** @var Response $response */ $response = Services::response(); $response->setCookie($this->cookie); } From cf74c952b072ccd618eeb042761f911030ffb9e4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:46:03 +0900 Subject: [PATCH 450/970] fix: use ResponseInterface instead of Response in ControllerTestTrait --- system/Test/ControllerTestTrait.php | 8 ++++---- system/Test/ControllerTester.php | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/system/Test/ControllerTestTrait.php b/system/Test/ControllerTestTrait.php index 6a784eb8c7e9..27ccb5cfcbec 100644 --- a/system/Test/ControllerTestTrait.php +++ b/system/Test/ControllerTestTrait.php @@ -14,7 +14,7 @@ use CodeIgniter\Controller; use CodeIgniter\HTTP\Exceptions\HTTPException; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\URI; use Config\App; use Config\Services; @@ -55,7 +55,7 @@ trait ControllerTestTrait /** * Response. * - * @var Response + * @var ResponseInterface */ protected $response; @@ -177,7 +177,7 @@ public function execute(string $method, ...$params) } // If the controller did not return a response then start one - if (! $response instanceof Response) { + if (! $response instanceof ResponseInterface) { $response = $this->response; } @@ -244,7 +244,7 @@ public function withRequest($request) /** * Set controller's response, with method chaining. * - * @param mixed $response + * @param ResponseInterface $response * * @return $this */ diff --git a/system/Test/ControllerTester.php b/system/Test/ControllerTester.php index 67b5e01e782e..a4b41a94c308 100644 --- a/system/Test/ControllerTester.php +++ b/system/Test/ControllerTester.php @@ -13,7 +13,7 @@ use CodeIgniter\Controller; use CodeIgniter\HTTP\IncomingRequest; -use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; use CodeIgniter\HTTP\URI; use Config\App; use Config\Services; @@ -58,7 +58,7 @@ trait ControllerTester /** * Response. * - * @var Response + * @var ResponseInterface */ protected $response; @@ -182,7 +182,7 @@ public function execute(string $method, ...$params) $output = ob_get_clean(); // If the controller returned a response, use it - if (isset($response) && $response instanceof Response) { + if (isset($response) && $response instanceof ResponseInterface) { $result->setResponse($response); } From 22d4d6070ab59958c84460cf3182e3f11d31cc9f Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 10:58:33 +0900 Subject: [PATCH 451/970] docs: add @deprecated to Response::$CSP It will be protected. --- system/HTTP/ResponseTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/HTTP/ResponseTrait.php b/system/HTTP/ResponseTrait.php index cec378cb2a6b..7ba699262869 100644 --- a/system/HTTP/ResponseTrait.php +++ b/system/HTTP/ResponseTrait.php @@ -49,7 +49,7 @@ trait ResponseTrait * * @var ContentSecurityPolicy * - * @TODO Will be protected. Use `getCSP()` instead. + * @deprecated Will be protected. Use `getCSP()` instead. */ public $CSP; From d9e59193d772e0d77f78be0d704b8d2d7a6ecc1b Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 23 Sep 2022 11:05:41 +0900 Subject: [PATCH 452/970] refactor: run rector --- system/Debug/Toolbar.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/Debug/Toolbar.php b/system/Debug/Toolbar.php index 2d459227ca6e..49ccc340f18c 100644 --- a/system/Debug/Toolbar.php +++ b/system/Debug/Toolbar.php @@ -161,9 +161,7 @@ public function run(float $startTime, float $totalTime, RequestInterface $reques $data['config'] = Config::display(); - if ($response->getCSP() !== null) { - $response->getCSP()->addImageSrc('data:'); - } + $response->getCSP()->addImageSrc('data:'); return json_encode($data); } From 81cb93acc0f4904443b22d8cc819b30745c4dfaa Mon Sep 17 00:00:00 2001 From: kenjis Date: Sun, 9 Oct 2022 08:42:48 +0900 Subject: [PATCH 453/970] docs: add changelog --- user_guide_src/source/changelogs/v4.3.0.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 1b28541bba4f..ec93e937445b 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -55,6 +55,7 @@ Interface Changes - Added missing ``getBody()``, ``hasHeader()`` and ``getHeaderLine()`` method in ``MessageInterface``. - Now ``ResponseInterface`` extends ``MessageInterface``. +- Added missing ``ResponseInterface::getCSP()`` (and ``Response::getCSP()``), ``ResponseInterface::getReasonPhrase()`` and ``ResponseInterface::getCookieStore()`` methods. Method Signature Changes ======================== @@ -96,6 +97,10 @@ Others - ``BaseBuilder::_updateBatch()`` - The second parameter ``$values`` has changed to ``$keys``. - The third parameter ``$index`` has changed to ``$values``. The parameter type also has changed to ``array``. +- The return type of ``API\ResponseTrait::failServerError()`` has been changed to ``ResponseInterface``. +- The following methods have been changed to accept ``ResponseInterface`` as a parameter instead of ``Response``. + - ``Debug\Exceptions::__construct()`` + - ``Services::exceptions()`` Enhancements ************ @@ -186,6 +191,7 @@ Deprecations - ``RouteCollection::localizeRoute()`` is deprecated. - ``RouteCollection::fillRouteParams()`` is deprecated. Use ``RouteCollection::buildReverseRoute()`` instead. - ``BaseBuilder::setUpdateBatch()`` and ``BaseBuilder::setInsertBatch()`` are deprecated. Use ``BaseBuilder::setData()`` instead. +- The public property ``Response::$CSP`` is deprecated. It will be protected. Use ``Response::getCSP()`` instead. Bugs Fixed ********** From e51c0d7b74c59095fddccdb5a874d41435d3d2e2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 10 Oct 2022 07:02:32 +0900 Subject: [PATCH 454/970] feat: add method to disable controller filters --- system/CodeIgniter.php | 88 ++++++++++++++++++++------------ tests/system/CodeIgniterTest.php | 27 ++++++++++ 2 files changed, 81 insertions(+), 34 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 902c98a8f069..2e5207ff3664 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -152,6 +152,11 @@ class CodeIgniter */ protected ?string $context = null; + /** + * Whether to enable Control Filters. + */ + protected bool $enableFilters = true; + /** * Constructor. */ @@ -399,6 +404,14 @@ private function isWeb(): bool return $this->context === 'web'; } + /** + * Disables Controller Filters. + */ + public function disableFilters(): void + { + $this->enableFilters = false; + } + /** * Handles the main request logic and fires the controller. * @@ -413,35 +426,37 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache $uri = $this->determinePath(); - // Start up the filters - $filters = Services::filters(); - - // If any filters were specified within the routes file, - // we need to ensure it's active for the current request - if ($routeFilter !== null) { - $multipleFiltersEnabled = config('Feature')->multipleFilters ?? false; - if ($multipleFiltersEnabled) { - $filters->enableFilters($routeFilter, 'before'); - $filters->enableFilters($routeFilter, 'after'); - } else { - // for backward compatibility - $filters->enableFilter($routeFilter, 'before'); - $filters->enableFilter($routeFilter, 'after'); + if ($this->enableFilters) { + // Start up the filters + $filters = Services::filters(); + + // If any filters were specified within the routes file, + // we need to ensure it's active for the current request + if ($routeFilter !== null) { + $multipleFiltersEnabled = config('Feature')->multipleFilters ?? false; + if ($multipleFiltersEnabled) { + $filters->enableFilters($routeFilter, 'before'); + $filters->enableFilters($routeFilter, 'after'); + } else { + // for backward compatibility + $filters->enableFilter($routeFilter, 'before'); + $filters->enableFilter($routeFilter, 'after'); + } } - } - // Run "before" filters - $this->benchmark->start('before_filters'); - $possibleResponse = $filters->run($uri, 'before'); - $this->benchmark->stop('before_filters'); + // 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) { - return $returnResponse ? $possibleResponse : $possibleResponse->send(); - } + // If a ResponseInterface instance is returned then send it back to the client and stop + if ($possibleResponse instanceof ResponseInterface) { + return $returnResponse ? $possibleResponse : $possibleResponse->send(); + } - if ($possibleResponse instanceof Request) { - $this->request = $possibleResponse; + if ($possibleResponse instanceof Request) { + $this->request = $possibleResponse; + } } $returned = $this->startController(); @@ -468,20 +483,25 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache // so it can be used with the output. $this->gatherOutput($cacheConfig, $returned); - $filters->setResponse($this->response); + if ($this->enableFilters) { + $filters = Services::filters(); + $filters->setResponse($this->response); - // After filter debug toolbar requires 'total_execution'. - $this->totalTime = $this->benchmark->getElapsedTime('total_execution'); + // After filter debug toolbar requires 'total_execution'. + $this->totalTime = $this->benchmark->getElapsedTime('total_execution'); - // Run "after" filters - $this->benchmark->start('after_filters'); - $response = $filters->run($uri, 'after'); - $this->benchmark->stop('after_filters'); + // Run "after" filters + $this->benchmark->start('after_filters'); + $response = $filters->run($uri, 'after'); + $this->benchmark->stop('after_filters'); - if ($response instanceof ResponseInterface) { - $this->response = $response; + if ($response instanceof ResponseInterface) { + $this->response = $response; + } } + $response ??= $this->response; + // Skip unnecessary processing for special Responses. if (! $response instanceof DownloadResponse && ! $response instanceof RedirectResponse) { // Cache it without the performance metrics replaced diff --git a/tests/system/CodeIgniterTest.php b/tests/system/CodeIgniterTest.php index ca95d403d6d5..418b79f14af7 100644 --- a/tests/system/CodeIgniterTest.php +++ b/tests/system/CodeIgniterTest.php @@ -245,6 +245,33 @@ public function testControllersRunFilterByClassName() $this->resetServices(); } + public function testDisableControllerFilters() + { + $_SERVER['argv'] = ['index.php', 'pages/about']; + $_SERVER['argc'] = 2; + + $_SERVER['REQUEST_URI'] = '/pages/about'; + + // Inject mock router. + $routes = Services::routes(); + $routes->add( + 'pages/about', + static fn () => Services::incomingrequest()->getBody(), + ['filter' => Customfilter::class] + ); + $router = Services::router($routes, Services::incomingrequest()); + Services::injectMock('router', $router); + + ob_start(); + $this->codeigniter->disableFilters(); + $this->codeigniter->run(); + $output = ob_get_clean(); + + $this->assertStringContainsString('', $output); + + $this->resetServices(); + } + public function testResponseConfigEmpty() { $_SERVER['argv'] = ['index.php', '/']; From 21669f3e5bfd6ed8210835fd5b69973bec3d3be9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 10 Oct 2022 07:42:57 +0900 Subject: [PATCH 455/970] refactor: use $this->response instead of $response --- system/CodeIgniter.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 2e5207ff3664..f4b319d9a1a4 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -500,10 +500,8 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache } } - $response ??= $this->response; - // Skip unnecessary processing for special Responses. - if (! $response instanceof DownloadResponse && ! $response instanceof RedirectResponse) { + if (! $this->response instanceof DownloadResponse && ! $this->response instanceof RedirectResponse) { // Cache it without the performance metrics replaced // so that we can have live speed updates along the way. // Must be run after filters to preserve the Response headers. From badbd2242fbf4bade491384202bd68ec2ae0c9a7 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 10 Oct 2022 07:43:54 +0900 Subject: [PATCH 456/970] style: break long line --- system/CodeIgniter.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index f4b319d9a1a4..4fcba3c7e0e7 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -501,7 +501,10 @@ protected function handleRequest(?RouteCollectionInterface $routes, Cache $cache } // Skip unnecessary processing for special Responses. - if (! $this->response instanceof DownloadResponse && ! $this->response instanceof RedirectResponse) { + if ( + ! $this->response instanceof DownloadResponse + && ! $this->response instanceof RedirectResponse + ) { // Cache it without the performance metrics replaced // so that we can have live speed updates along the way. // Must be run after filters to preserve the Response headers. From ed70083a88030bc56537825f6d1e49cea8a129d5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Mon, 10 Oct 2022 09:23:55 +0900 Subject: [PATCH 457/970] docs: deprecated CodeIgniter::$path and CodeIgniter::setPath() --- system/CodeIgniter.php | 8 ++++++-- user_guide_src/source/changelogs/v4.3.0.rst | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/system/CodeIgniter.php b/system/CodeIgniter.php index 902c98a8f069..6bf5b5046c72 100644 --- a/system/CodeIgniter.php +++ b/system/CodeIgniter.php @@ -130,6 +130,8 @@ class CodeIgniter * Request path to use. * * @var string + * + * @deprecated No longer used. */ protected $path; @@ -789,7 +791,7 @@ protected function tryToRouteIt(?RouteCollectionInterface $routes = null) /** * Determines the path to use for us to try to route to, based - * on user input (setPath), or the CLI/IncomingRequest path. + * on the CLI/IncomingRequest path. * * @return string */ @@ -806,9 +808,11 @@ protected function determinePath() * Allows the request path to be set from outside the class, * instead of relying on CLIRequest or IncomingRequest for the path. * - * This is primarily used by the Console. + * This is not used now. * * @return $this + * + * @deprecated No longer used. */ public function setPath(string $path) { diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index ec93e937445b..09146748cb21 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -192,6 +192,7 @@ Deprecations - ``RouteCollection::fillRouteParams()`` is deprecated. Use ``RouteCollection::buildReverseRoute()`` instead. - ``BaseBuilder::setUpdateBatch()`` and ``BaseBuilder::setInsertBatch()`` are deprecated. Use ``BaseBuilder::setData()`` instead. - The public property ``Response::$CSP`` is deprecated. It will be protected. Use ``Response::getCSP()`` instead. +- ``CodeIgniter::$path`` and ``CodeIgniter::setPath()`` are deprecated. No longer used. Bugs Fixed ********** From da9a6ba2a1ca6d5ec7ccd8bc8e2e3bbb032efaea Mon Sep 17 00:00:00 2001 From: sclubricants Date: Fri, 16 Sep 2022 16:01:05 -0700 Subject: [PATCH 458/970] Add ability to set key names for primary, key, and unique key Mysql and Sqlite Forgot to commit this in smaller steps.. --- system/Database/Forge.php | 124 +++++++++++++++-------- system/Database/MySQLi/Forge.php | 30 +++--- system/Database/SQLite3/Forge.php | 39 +------ tests/system/Database/Live/ForgeTest.php | 2 + 4 files changed, 100 insertions(+), 95 deletions(-) diff --git a/system/Database/Forge.php b/system/Database/Forge.php index eabed06ed6ec..282f01f26ec2 100644 --- a/system/Database/Forge.php +++ b/system/Database/Forge.php @@ -39,7 +39,7 @@ class Forge /** * List of keys. * - * @var array + * @phpstan-var array{}|list */ protected $keys = []; @@ -51,9 +51,9 @@ class Forge protected $uniqueKeys = []; /** - * List of primary keys. + * Primary keys. * - * @var array + * @phpstan-var array{}|array{fields: string[], keyName: string} */ protected $primaryKeys = []; @@ -309,14 +309,12 @@ public function dropDatabase(string $dbName): bool * * @return Forge */ - public function addKey($key, bool $primary = false, bool $unique = false) + public function addKey($key, bool $primary = false, bool $unique = false, string $keyName = '') { if ($primary) { - foreach ((array) $key as $one) { - $this->primaryKeys[] = $one; - } + $this->primaryKeys = ['fields' => (array) $key, 'keyName' => $keyName]; } else { - $this->keys[] = $key; + $this->keys[] = ['fields' => (array) $key, 'keyName' => $keyName]; if ($unique) { $this->uniqueKeys[] = count($this->keys) - 1; @@ -333,9 +331,9 @@ public function addKey($key, bool $primary = false, bool $unique = false) * * @return Forge */ - public function addPrimaryKey($key) + public function addPrimaryKey($key, string $keyName = '') { - return $this->addKey($key, true); + return $this->addKey($key, true, false, $keyName); } /** @@ -345,9 +343,9 @@ public function addPrimaryKey($key) * * @return Forge */ - public function addUniqueKey($key) + public function addUniqueKey($key, string $keyName = '') { - return $this->addKey($key, false, true); + return $this->addKey($key, false, true, $keyName); } /** @@ -404,11 +402,9 @@ public function addField($field) * @param string|string[] $fieldName * @param string|string[] $tableField * - * @return Forge - * * @throws DatabaseException */ - public function addForeignKey($fieldName = '', string $tableName = '', $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = '') + public function addForeignKey($fieldName = '', string $tableName = '', $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = ''): Forge { $fieldName = (array) $fieldName; $tableField = (array) $tableField; @@ -441,17 +437,27 @@ public function addForeignKey($fieldName = '', string $tableName = '', $tableFie /** * Drop Key * - * @return bool - * * @throws DatabaseException */ - public function dropKey(string $table, string $keyName) + public function dropKey(string $table, string $keyName, bool $prefixKeyName = true): bool { - $sql = sprintf( - $this->dropIndexStr, - $this->db->escapeIdentifiers($this->db->DBPrefix . $keyName), - $this->db->escapeIdentifiers($this->db->DBPrefix . $table), - ); + $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName); + $table = $this->db->escapeIdentifiers($this->db->DBPrefix . $table); + $dropKeyAsConstraint = $this->dropKeyAsConstraint($table, $keyName); + + if ($dropKeyAsConstraint === true) { + $sql = sprintf( + $this->dropConstraintStr, + $table, + $keyName, + ); + } else { + $sql = sprintf( + $this->dropIndexStr, + $keyName, + $table, + ); + } if ($sql === '') { if ($this->db->DBDebug) { @@ -464,15 +470,37 @@ public function dropKey(string $table, string $keyName) return $this->db->query($sql); } + /** + * Checks if if key needs to be dropped as a constraint. + */ + protected function dropKeyAsConstraint(string $table, string $constraintName): bool + { + $sql = $this->_dropKeyAsConstraint($table, $constraintName); + + if ($sql === '') { + return false; + } + + return $this->db->query($sql)->getResultArray() !== []; + } + + /** + * Constructs sql to check if key is a constraint. + */ + protected function _dropKeyAsConstraint(string $table, string $constraintName): string + { + return ''; + } + /** * Drop Primary Key */ - public function dropPrimaryKey(string $table): bool + public function dropPrimaryKey(string $table, string $keyName = ''): bool { $sql = sprintf( 'ALTER TABLE %s DROP CONSTRAINT %s', $this->db->escapeIdentifiers($this->db->DBPrefix . $table), - $this->db->escapeIdentifiers('pk_' . $this->db->DBPrefix . $table), + ($keyName === '') ? $this->db->escapeIdentifiers('pk_' . $this->db->DBPrefix . $table) : $this->db->escapeIdentifiers($keyName), ); return $this->db->query($sql); @@ -1016,15 +1044,19 @@ protected function _processPrimaryKeys(string $table): string { $sql = ''; - for ($i = 0, $c = count($this->primaryKeys); $i < $c; $i++) { - if (! isset($this->fields[$this->primaryKeys[$i]])) { - unset($this->primaryKeys[$i]); + if (isset($this->primaryKeys['fields'])) { + for ($i = 0, $c = count($this->primaryKeys['fields']); $i < $c; $i++) { + if (! isset($this->fields[$this->primaryKeys['fields'][$i]])) { + unset($this->primaryKeys['fields'][$i]); + } } } - if ($this->primaryKeys !== []) { - $sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers('pk_' . $table) - . ' PRIMARY KEY(' . implode(', ', $this->db->escapeIdentifiers($this->primaryKeys)) . ')'; + if (isset($this->primaryKeys['fields']) && $this->primaryKeys['fields'] !== []) { + $sql .= ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers(($this->primaryKeys['keyName'] === '' ? + 'pk_' . $table : + $this->primaryKeys['keyName'])) + . ' PRIMARY KEY(' . implode(', ', $this->db->escapeIdentifiers($this->primaryKeys['fields'])) . ')'; } return $sql; @@ -1035,29 +1067,37 @@ 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]); + for ($i2 = 0, $c2 = count($this->keys[$i]['fields']); $i2 < $c2; $i2++) { + if (! isset($this->fields[$this->keys[$i]['fields'][$i2]])) { + unset($this->keys[$i]['fields'][$i2]); } } - if (count($this->keys[$i]) <= 0) { + if (count($this->keys[$i]['fields']) <= 0) { continue; } + $keyName = $this->db->escapeIdentifiers(($this->keys[$i]['keyName'] === '') ? + $table . '_' . implode('_', $this->keys[$i]['fields']) : + $this->keys[$i]['keyName']); + if (in_array($i, $this->uniqueKeys, true)) { - $sqls[] = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) - . ' ADD CONSTRAINT ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) - . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ')'; + if ($this->db->DBDriver === 'SQLite3') { + $sqls[] = 'CREATE UNIQUE INDEX ' . $keyName + . ' ON ' . $this->db->escapeIdentifiers($table) + . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; + } else { + $sqls[] = 'ALTER TABLE ' . $this->db->escapeIdentifiers($table) + . ' ADD CONSTRAINT ' . $keyName + . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; + } continue; } - $sqls[] = 'CREATE INDEX ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) + $sqls[] = 'CREATE INDEX ' . $keyName . ' ON ' . $this->db->escapeIdentifiers($table) - . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ')'; + . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; } return $sqls; diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index 12aab402d647..6adcbeb9ce64 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -192,28 +192,28 @@ protected function _processIndexes(string $table): string $sql = ''; 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++) { - if (! isset($this->fields[$this->keys[$i][$i2]])) { - unset($this->keys[$i][$i2]); + if (isset($this->keys[$i]['fields'])) { + for ($i2 = 0, $c2 = count($this->keys[$i]['fields']); $i2 < $c2; $i2++) { + if (! isset($this->fields[$this->keys[$i]['fields'][$i2]])) { + unset($this->keys[$i]['fields'][$i2]); continue; } } - } elseif (! isset($this->fields[$this->keys[$i]])) { - unset($this->keys[$i]); - - continue; } - if (! is_array($this->keys[$i])) { - $this->keys[$i] = [$this->keys[$i]]; + if (! is_array($this->keys[$i]['fields'])) { + $this->keys[$i]['fields'] = [$this->keys[$i]['fields']]; } $unique = in_array($i, $this->uniqueKeys, true) ? 'UNIQUE ' : ''; - $sql .= ",\n\t{$unique}KEY " . $this->db->escapeIdentifiers(implode('_', $this->keys[$i])) - . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ')'; + $keyName = $this->db->escapeIdentifiers(($this->keys[$i]['keyName'] === '') ? + implode('_', $this->keys[$i]['fields']) : + $this->keys[$i]['keyName']); + + $sql .= ",\n\t{$unique}KEY " . $keyName + . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ')'; } $this->keys = []; @@ -223,10 +223,8 @@ protected function _processIndexes(string $table): string /** * Drop Key - * - * @return bool */ - public function dropKey(string $table, string $keyName) + public function dropKey(string $table, string $keyName, bool $prefixKeyName = true): bool { $sql = sprintf( $this->dropIndexStr, @@ -240,7 +238,7 @@ public function dropKey(string $table, string $keyName) /** * Drop Primary Key */ - public function dropPrimaryKey(string $table): bool + public function dropPrimaryKey(string $table, string $keyName = ''): bool { $sql = sprintf( 'ALTER TABLE %s DROP PRIMARY KEY', diff --git a/system/Database/SQLite3/Forge.php b/system/Database/SQLite3/Forge.php index 5538777f610b..0de70960fc0a 100644 --- a/system/Database/SQLite3/Forge.php +++ b/system/Database/SQLite3/Forge.php @@ -156,41 +156,6 @@ protected function _processColumn(array $field): string . $field['default']; } - /** - * Process indexes - */ - protected function _processIndexes(string $table): array - { - $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[] = 'CREATE UNIQUE INDEX ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) - . ' ON ' . $this->db->escapeIdentifiers($table) - . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; - - continue; - } - - $sqls[] = 'CREATE INDEX ' . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) - . ' ON ' . $this->db->escapeIdentifiers($table) - . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; - } - - return $sqls; - } - /** * Field attribute TYPE * @@ -254,7 +219,7 @@ public function dropForeignKey(string $table, string $foreignName): bool /** * Drop Primary Key */ - public function dropPrimaryKey(string $table): bool + public function dropPrimaryKey(string $table, string $keyName = ''): bool { $sqlTable = new Table($this->db, $this); @@ -263,7 +228,7 @@ public function dropPrimaryKey(string $table): bool ->run(); } - public function addForeignKey($fieldName = '', string $tableName = '', $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = '') + public function addForeignKey($fieldName = '', string $tableName = '', $tableField = '', string $onUpdate = '', string $onDelete = '', string $fkName = ''): BaseForge { if ($fkName === '') { return parent::addForeignKey($fieldName, $tableName, $tableField, $onUpdate, $onDelete, $fkName); diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index 978550939b09..cc709c0fe5df 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1047,6 +1047,8 @@ public function testAddFields() public function testCompositeKey() { + $this->forge->dropTable('forge_test_1', true); + $this->forge->addField([ 'id' => [ 'type' => 'INTEGER', From e53c0eb92e770846b37d5e0180a86b65acb72336 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 11:44:33 -0700 Subject: [PATCH 459/970] Add index name to sqlsrv --- system/Database/MySQLi/Forge.php | 2 ++ system/Database/SQLSRV/Forge.php | 38 ++++++++++++++++++------------- system/Database/SQLite3/Forge.php | 2 ++ 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index 6adcbeb9ce64..b3069f2b4cb7 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -237,6 +237,8 @@ public function dropKey(string $table, string $keyName, bool $prefixKeyName = tr /** * Drop Primary Key + * + * @param mixed $keyName */ public function dropPrimaryKey(string $table, string $keyName = ''): bool { diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index e9625018cb00..b1b54e02c207 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -250,31 +250,35 @@ protected function _processIndexes(string $table) $sqls = []; for ($i = 0, $c = count($this->keys); $i < $c; $i++) { - $this->keys[$i] = (array) $this->keys[$i]; + $this->keys[$i]['fields'] = (array) $this->keys[$i]['fields']; - for ($i2 = 0, $c2 = count($this->keys[$i]); $i2 < $c2; $i2++) { - if (! isset($this->fields[$this->keys[$i][$i2]])) { - unset($this->keys[$i][$i2]); + for ($i2 = 0, $c2 = count($this->keys[$i]['fields']); $i2 < $c2; $i2++) { + if (! isset($this->fields[$this->keys[$i]['fields'][$i2]])) { + unset($this->keys[$i]['fields'][$i2]); } } - if (count($this->keys[$i]) <= 0) { + if (count($this->keys[$i]['fields']) <= 0) { continue; } + $keyName = ($this->keys[$i]['keyName'] === '') ? + $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i]['fields'])) : + $this->db->escapeIdentifiers($this->keys[$i]['keyName']); + 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])) . ');'; + . ' ADD CONSTRAINT ' . $keyName + . ' UNIQUE (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ');'; continue; } $sqls[] = 'CREATE INDEX ' - . $this->db->escapeIdentifiers($table . '_' . implode('_', $this->keys[$i])) + . $keyName . ' ON ' . $this->db->escapeIdentifiers($this->db->schema) . '.' . $this->db->escapeIdentifiers($table) - . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i])) . ');'; + . ' (' . implode(', ', $this->db->escapeIdentifiers($this->keys[$i]['fields'])) . ');'; } return $sqls; @@ -300,15 +304,17 @@ protected function _processColumn(array $field): string */ protected function _processPrimaryKeys(string $table): string { - for ($i = 0, $c = count($this->primaryKeys); $i < $c; $i++) { - if (! isset($this->fields[$this->primaryKeys[$i]])) { - unset($this->primaryKeys[$i]); + if (isset($this->primaryKeys['fields'])) { + for ($i = 0, $c = count($this->primaryKeys['fields']); $i < $c; $i++) { + if (! isset($this->fields[$this->primaryKeys['fields'][$i]])) { + unset($this->primaryKeys['fields'][$i]); + } } - } - if ($this->primaryKeys !== []) { - $sql = ",\n\tCONSTRAINT " . $this->db->escapeIdentifiers('pk_' . $table) - . ' PRIMARY KEY(' . implode(', ', $this->db->escapeIdentifiers($this->primaryKeys)) . ')'; + if ($this->primaryKeys['fields'] !== []) { + $sql = ",\n\tCONSTRAINT " . ($this->primaryKeys['keyName'] === '' ? $this->db->escapeIdentifiers('pk_' . $table) : $this->primaryKeys['keyName']) + . ' PRIMARY KEY(' . implode(', ', $this->db->escapeIdentifiers($this->primaryKeys['fields'])) . ')'; + } } return $sql ?? ''; diff --git a/system/Database/SQLite3/Forge.php b/system/Database/SQLite3/Forge.php index 0de70960fc0a..0098bc250cf7 100644 --- a/system/Database/SQLite3/Forge.php +++ b/system/Database/SQLite3/Forge.php @@ -218,6 +218,8 @@ public function dropForeignKey(string $table, string $foreignName): bool /** * Drop Primary Key + * + * @param mixed $keyName */ public function dropPrimaryKey(string $table, string $keyName = ''): bool { From 63a969ef137615ae195c4879588b12af434bcefe Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 12:27:09 -0700 Subject: [PATCH 460/970] Add index name to OCI8 --- system/Database/OCI8/Forge.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/system/Database/OCI8/Forge.php b/system/Database/OCI8/Forge.php index 8acbd246c063..5c9b549fe2bc 100644 --- a/system/Database/OCI8/Forge.php +++ b/system/Database/OCI8/Forge.php @@ -186,7 +186,7 @@ protected function _processColumn(array $field): string . ' IN ' . $field['length'] . ')'; $field['length'] = '(' . max(array_map('mb_strlen', explode("','", mb_substr($field['length'], 2, -2)))) . ')' . $constraint; - } elseif (count($this->primaryKeys) === 1 && $field['name'] === $this->primaryKeys[0]) { + } elseif (isset($this->primaryKeys['fields']) && count($this->primaryKeys['fields']) === 1 && $field['name'] === $this->primaryKeys['fields'][0]) { $field['unique'] = ''; } From 3ad29908b91e3be9c88cdeac6a5c933502e7f862 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 14:19:57 -0700 Subject: [PATCH 461/970] Created dropKey() methohd for OCI8 Some keys such as unique indexes are created as constraints. This looks to see if there is a constraint by the index name. If there is then we will drop constraint else we drop index. --- system/Database/OCI8/Forge.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/system/Database/OCI8/Forge.php b/system/Database/OCI8/Forge.php index 5c9b549fe2bc..15cb77f6b54a 100644 --- a/system/Database/OCI8/Forge.php +++ b/system/Database/OCI8/Forge.php @@ -279,4 +279,14 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade) return $sql; } + + /** + * Constructs sql to check if key is a constraint. + */ + protected function _dropKeyAsConstraint(string $table, string $constraintName): string + { + return "SELECT constraint_name FROM all_constraints WHERE table_name = '" + . trim($table, '"') . "' AND index_name = '" + . trim($constraintName, '"') . "'"; + } } From 6d8648f6231645b66027c72950bd55b2da2bdec0 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 14:43:57 -0700 Subject: [PATCH 462/970] Add prefixKeyName to mysql dropKey() --- system/Database/MySQLi/Forge.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/system/Database/MySQLi/Forge.php b/system/Database/MySQLi/Forge.php index b3069f2b4cb7..6adcbeb9ce64 100644 --- a/system/Database/MySQLi/Forge.php +++ b/system/Database/MySQLi/Forge.php @@ -237,8 +237,6 @@ public function dropKey(string $table, string $keyName, bool $prefixKeyName = tr /** * Drop Primary Key - * - * @param mixed $keyName */ public function dropPrimaryKey(string $table, string $keyName = ''): bool { From d47d1ebbf63c2092618e0c934da7e3d5e0e9cfb0 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 15:28:02 -0700 Subject: [PATCH 463/970] Add dropKey() to postgres Same as oracle - this looks up if key is a constraint --- system/Database/Postgre/Forge.php | 52 +++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index 6791da6169fa..cb757acebc6e 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -190,4 +190,56 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str return $sql; } + + /** + * Drop Key + * + * @param mixed $prefixKeyName + * + * @return bool + * + * @throws DatabaseException + */ + public function dropKey(string $table, string $keyName, bool $prefixKeyName = true) + { + $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName); + + // check if key is a constraint + $sql = "SELECT con.conname + FROM pg_catalog.pg_constraint con + INNER JOIN pg_catalog.pg_class rel + ON rel.oid = con.conrelid + INNER JOIN pg_catalog.pg_namespace nsp + ON nsp.oid = connamespace + WHERE nsp.nspname = '{$this->db->schema}' + AND rel.relname = '" . $this->db->DBPrefix . $table . "' + AND con.conname = '" . trim($keyName, '"') . "'"; + + $constraint = $this->db->query($sql)->getResultArray(); + + $sql = sprintf( + $this->dropIndexStr, + $keyName, + $this->db->escapeIdentifiers($this->db->DBPrefix . $table), + ); + + if (count($constraint) !== 0) { + $sqlString = $this->dropConstraintStr; + $sql = sprintf( + $this->dropConstraintStr, + $this->db->escapeIdentifiers($this->db->DBPrefix . $table), + $keyName, + ); + } + + if ($sql === '') { + if ($this->db->DBDebug) { + throw new DatabaseException('This feature is not available for the database you are using.'); + } + + return false; + } + + return $this->db->query($sql); + } } From b34c15110f3d0880ce9da5194828da67905c8d40 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 15:55:26 -0700 Subject: [PATCH 464/970] Fix SQLite Table class to use index names --- system/Database/SQLite3/Table.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/system/Database/SQLite3/Table.php b/system/Database/SQLite3/Table.php index 2c142086a1d5..e1e0d8aad6e6 100644 --- a/system/Database/SQLite3/Table.php +++ b/system/Database/SQLite3/Table.php @@ -261,18 +261,18 @@ protected function createTable() // Unique/Index keys if (is_array($this->keys)) { - foreach ($this->keys as $key) { + foreach ($this->keys as $i => $key) { switch ($key['type']) { case 'primary': $this->forge->addPrimaryKey($key['fields']); break; case 'unique': - $this->forge->addUniqueKey($key['fields']); + $this->forge->addUniqueKey($key['fields'], $i); break; case 'index': - $this->forge->addKey($key['fields']); + $this->forge->addKey($key['fields'], false, false, $i); break; } } From 83382bb001e263c97509fe2d24b4900305381c45 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 16:09:36 -0700 Subject: [PATCH 465/970] Add dropKey() to SQLSRV Have to lookup if key is constraint. --- system/Database/SQLSRV/Forge.php | 46 ++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index b1b54e02c207..8b34eaabd038 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -391,4 +391,50 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str return $sql; } + + /** + * Drop Key + * + * @param mixed $prefixKeyName + * + * @return bool + * + * @throws DatabaseException + */ + public function dropKey(string $table, string $keyName, bool $prefixKeyName = true) + { + $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName); + + // check if key is a constraint + $sql = "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS + WHERE TABLE_NAME= '" . $this->db->DBPrefix . $table . "' + AND CONSTRAINT_NAME = '" . trim($keyName, '"') . "'"; + + $constraint = $this->db->query($sql)->getResultArray(); + + $sql = sprintf( + $this->dropIndexStr, + $keyName, + $this->db->escapeIdentifiers($this->db->DBPrefix . $table), + ); + + if (count($constraint) !== 0) { + $sqlString = $this->dropConstraintStr; + $sql = sprintf( + $this->dropConstraintStr, + $this->db->escapeIdentifiers($this->db->DBPrefix . $table), + $keyName, + ); + } + + if ($sql === '') { + if ($this->db->DBDebug) { + throw new DatabaseException('This feature is not available for the database you are using.'); + } + + return false; + } + + return $this->db->query($sql); + } } From a3faf8fea3a61166053a6587b6bbc57fef129824 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 16:29:05 -0700 Subject: [PATCH 466/970] Add test This test adding custom names but also test removing them by custom names. --- tests/system/Database/Live/ForgeTest.php | 64 ++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/tests/system/Database/Live/ForgeTest.php b/tests/system/Database/Live/ForgeTest.php index cc709c0fe5df..1346cfa1e1e0 100644 --- a/tests/system/Database/Live/ForgeTest.php +++ b/tests/system/Database/Live/ForgeTest.php @@ -1140,6 +1140,70 @@ public function testCompositeKey() $this->forge->dropTable('forge_test_1', true); } + public function testSetKeyNames() + { + $this->forge->dropTable('forge_test_1', true); + + $this->forge->addField([ + 'id' => [ + 'type' => 'INTEGER', + 'constraint' => 3, + 'auto_increment' => true, + ], + 'code' => [ + 'type' => 'VARCHAR', + 'constraint' => 40, + ], + 'company' => [ + 'type' => 'VARCHAR', + 'constraint' => 40, + ], + 'active' => [ + 'type' => 'INTEGER', + 'constraint' => 1, + ], + ]); + + $pk = 'my_custom_pk'; + $index = 'my_custom_index'; + $uniqueIndex = 'my_custom_unique_index'; + + if ($this->db->DBDriver === 'MySQLi' || $this->db->DBDriver === 'SQLite3') { + $pk = 'PRIMARY'; + } + + $this->forge->addPrimaryKey('id', $pk); + $this->forge->addKey(['code', 'company'], false, false, $index); + $this->forge->addUniqueKey(['code', 'active'], $uniqueIndex); + $this->forge->createTable('forge_test_1', true); + + $keys = $this->db->getIndexData('forge_test_1'); + + // mysql must redefine auto increment which can only exist on a key + if ($this->db->DBDriver === 'MySQLi') { + $id = [ + 'id' => [ + 'name' => 'id', + 'type' => 'INTEGER', + 'constraint' => 3, + ], + ]; + $this->forge->modifyColumn('forge_test_1', $id); + } + + $this->assertSame($keys[$pk]->name, $pk); + $this->assertSame($keys[$index]->name, $index); + $this->assertSame($keys[$uniqueIndex]->name, $uniqueIndex); + + $this->forge->dropPrimaryKey('forge_test_1', $pk); + $this->forge->dropKey('forge_test_1', $index, false); + $this->forge->dropKey('forge_test_1', $uniqueIndex, false); + + $this->assertCount(0, $this->db->getIndexData('forge_test_1')); + + $this->forge->dropTable('forge_test_1', true); + } + public function testDropColumn() { $this->forge->dropTable('forge_test_two', true); From 9eff2f1a91e668f46a58194653e47a32c512a801 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 17:46:53 -0700 Subject: [PATCH 467/970] Fix phpstan --- system/Database/Postgre/Forge.php | 24 ++++++++++++++++++------ system/Database/SQLSRV/Forge.php | 8 +++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index cb757acebc6e..bcad20d5fcf7 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -11,6 +11,8 @@ namespace CodeIgniter\Database\Postgre; +use CodeIgniter\Database\BaseConnection; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Forge as BaseForge; /** @@ -65,6 +67,19 @@ class Forge extends BaseForge */ protected $null = 'NULL'; + /** + * @var Connection + */ + protected $db; + + /** + * Constructor. + */ + public function __construct(BaseConnection $db) + { + parent::__construct($db); + } + /** * CREATE TABLE attributes * @@ -194,8 +209,6 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str /** * Drop Key * - * @param mixed $prefixKeyName - * * @return bool * * @throws DatabaseException @@ -214,7 +227,7 @@ public function dropKey(string $table, string $keyName, bool $prefixKeyName = tr WHERE nsp.nspname = '{$this->db->schema}' AND rel.relname = '" . $this->db->DBPrefix . $table . "' AND con.conname = '" . trim($keyName, '"') . "'"; - + $constraint = $this->db->query($sql)->getResultArray(); $sql = sprintf( @@ -223,9 +236,8 @@ public function dropKey(string $table, string $keyName, bool $prefixKeyName = tr $this->db->escapeIdentifiers($this->db->DBPrefix . $table), ); - if (count($constraint) !== 0) { - $sqlString = $this->dropConstraintStr; - $sql = sprintf( + if ($constraint !== []) { + $sql = sprintf( $this->dropConstraintStr, $this->db->escapeIdentifiers($this->db->DBPrefix . $table), $keyName, diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index 8b34eaabd038..a75eff49f90f 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -12,6 +12,7 @@ namespace CodeIgniter\Database\SQLSRV; use CodeIgniter\Database\BaseConnection; +use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Forge as BaseForge; /** @@ -395,8 +396,6 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str /** * Drop Key * - * @param mixed $prefixKeyName - * * @return bool * * @throws DatabaseException @@ -418,9 +417,8 @@ public function dropKey(string $table, string $keyName, bool $prefixKeyName = tr $this->db->escapeIdentifiers($this->db->DBPrefix . $table), ); - if (count($constraint) !== 0) { - $sqlString = $this->dropConstraintStr; - $sql = sprintf( + if ($constraint !== []) { + $sql = sprintf( $this->dropConstraintStr, $this->db->escapeIdentifiers($this->db->DBPrefix . $table), $keyName, From 3907420c0716fb03bb4c0c061abcd7679105e04d Mon Sep 17 00:00:00 2001 From: sclubricants Date: Sun, 18 Sep 2022 17:54:45 -0700 Subject: [PATCH 468/970] Fix rector --- system/Database/Postgre/Forge.php | 9 --------- 1 file changed, 9 deletions(-) diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index bcad20d5fcf7..f2257fca620b 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -11,7 +11,6 @@ namespace CodeIgniter\Database\Postgre; -use CodeIgniter\Database\BaseConnection; use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Forge as BaseForge; @@ -72,14 +71,6 @@ class Forge extends BaseForge */ protected $db; - /** - * Constructor. - */ - public function __construct(BaseConnection $db) - { - parent::__construct($db); - } - /** * CREATE TABLE attributes * From 5c51465533c263f367f25c8dfcc051eeaeafad0f Mon Sep 17 00:00:00 2001 From: sclubricants Date: Mon, 19 Sep 2022 14:38:12 -0700 Subject: [PATCH 469/970] Refactor dropKey() Get rid of CPD error --- system/Database/Postgre/Forge.php | 44 ++++--------------------------- system/Database/SQLSRV/Forge.php | 44 ++++--------------------------- 2 files changed, 10 insertions(+), 78 deletions(-) diff --git a/system/Database/Postgre/Forge.php b/system/Database/Postgre/Forge.php index f2257fca620b..662fbe666595 100644 --- a/system/Database/Postgre/Forge.php +++ b/system/Database/Postgre/Forge.php @@ -11,7 +11,6 @@ namespace CodeIgniter\Database\Postgre; -use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Forge as BaseForge; /** @@ -198,51 +197,18 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str } /** - * Drop Key - * - * @return bool - * - * @throws DatabaseException + * Constructs sql to check if key is a constraint. */ - public function dropKey(string $table, string $keyName, bool $prefixKeyName = true) + protected function _dropKeyAsConstraint(string $table, string $constraintName): string { - $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName); - - // check if key is a constraint - $sql = "SELECT con.conname + return "SELECT con.conname FROM pg_catalog.pg_constraint con INNER JOIN pg_catalog.pg_class rel ON rel.oid = con.conrelid INNER JOIN pg_catalog.pg_namespace nsp ON nsp.oid = connamespace WHERE nsp.nspname = '{$this->db->schema}' - AND rel.relname = '" . $this->db->DBPrefix . $table . "' - AND con.conname = '" . trim($keyName, '"') . "'"; - - $constraint = $this->db->query($sql)->getResultArray(); - - $sql = sprintf( - $this->dropIndexStr, - $keyName, - $this->db->escapeIdentifiers($this->db->DBPrefix . $table), - ); - - if ($constraint !== []) { - $sql = sprintf( - $this->dropConstraintStr, - $this->db->escapeIdentifiers($this->db->DBPrefix . $table), - $keyName, - ); - } - - if ($sql === '') { - if ($this->db->DBDebug) { - throw new DatabaseException('This feature is not available for the database you are using.'); - } - - return false; - } - - return $this->db->query($sql); + AND rel.relname = '" . trim($table, '"') . "' + AND con.conname = '" . trim($constraintName, '"') . "'"; } } diff --git a/system/Database/SQLSRV/Forge.php b/system/Database/SQLSRV/Forge.php index a75eff49f90f..f6079ad3363b 100755 --- a/system/Database/SQLSRV/Forge.php +++ b/system/Database/SQLSRV/Forge.php @@ -12,7 +12,6 @@ namespace CodeIgniter\Database\SQLSRV; use CodeIgniter\Database\BaseConnection; -use CodeIgniter\Database\Exceptions\DatabaseException; use CodeIgniter\Database\Forge as BaseForge; /** @@ -394,45 +393,12 @@ protected function _dropTable(string $table, bool $ifExists, bool $cascade): str } /** - * Drop Key - * - * @return bool - * - * @throws DatabaseException + * Constructs sql to check if key is a constraint. */ - public function dropKey(string $table, string $keyName, bool $prefixKeyName = true) + protected function _dropKeyAsConstraint(string $table, string $constraintName): string { - $keyName = $this->db->escapeIdentifiers(($prefixKeyName === true ? $this->db->DBPrefix : '') . $keyName); - - // check if key is a constraint - $sql = "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS - WHERE TABLE_NAME= '" . $this->db->DBPrefix . $table . "' - AND CONSTRAINT_NAME = '" . trim($keyName, '"') . "'"; - - $constraint = $this->db->query($sql)->getResultArray(); - - $sql = sprintf( - $this->dropIndexStr, - $keyName, - $this->db->escapeIdentifiers($this->db->DBPrefix . $table), - ); - - if ($constraint !== []) { - $sql = sprintf( - $this->dropConstraintStr, - $this->db->escapeIdentifiers($this->db->DBPrefix . $table), - $keyName, - ); - } - - if ($sql === '') { - if ($this->db->DBDebug) { - throw new DatabaseException('This feature is not available for the database you are using.'); - } - - return false; - } - - return $this->db->query($sql); + return "SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS + WHERE TABLE_NAME= '" . trim($table, '"') . "' + AND CONSTRAINT_NAME = '" . trim($constraintName, '"') . "'"; } } From f6fb1689659929ade8d949009f63e101f53c61e7 Mon Sep 17 00:00:00 2001 From: sclubricants Date: Mon, 19 Sep 2022 15:53:19 -0700 Subject: [PATCH 470/970] Added documentation --- user_guide_src/source/changelogs/v4.3.0.rst | 12 ++++---- user_guide_src/source/dbmgmt/forge.rst | 33 +++++++++++++++++---- user_guide_src/source/dbmgmt/forge/010.php | 8 ++--- user_guide_src/source/dbmgmt/forge/020.php | 5 ++-- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 09146748cb21..ade238a16437 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -46,7 +46,6 @@ Others - ``CITestStreamFilter::$buffer = ''`` no longer causes the filter to be registered to listen for streams. Now there is a ``CITestStreamFilter::registration()`` method for this. See :ref:`upgrade-430-stream-filter` for details. - The data structure returned by :ref:`BaseConnection::getForeignKeyData() ` has been changed. -- :php:func:`script_tag()` and :php:func:`safe_mailto()` no longer output ``type="text/javascript"`` in ``' . '' - . '' + . '' . $kintScript . PHP_EOL; diff --git a/system/Debug/Toolbar/Views/toolbar.tpl.php b/system/Debug/Toolbar/Views/toolbar.tpl.php index aae7fc6a81a1..7c0d5336a5d4 100644 --- a/system/Debug/Toolbar/Views/toolbar.tpl.php +++ b/system/Debug/Toolbar/Views/toolbar.tpl.php @@ -18,7 +18,7 @@ * @var \CodeIgniter\View\Parser $parser */ ?> - @@ -264,7 +264,7 @@ setData($config)->render('_config.tpl') ?>
-'; + $body = str_ireplace('', $style . '', $body); + } + $response->setBody($body); } From 87a677efd950d9cce7902254de9d21c18820d722 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:28:01 +0900 Subject: [PATCH 957/970] docs: fix section level --- user_guide_src/source/libraries/honeypot.rst | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index cdaa4eb1eb52..4b49e4c85b19 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -1,6 +1,6 @@ -===================== +############## Honeypot Class -===================== +############## The Honeypot Class makes it possible to determine when a Bot makes a request to a CodeIgniter4 application, if it's enabled in ``Application\Config\Filters.php`` file. This is done by attaching form fields to any form, @@ -11,8 +11,9 @@ assumed the request is coming from a Bot, and you can throw a ``HoneypotExceptio :local: :depth: 2 +***************** 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: @@ -23,8 +24,9 @@ A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``. If it is not suitable, make your own at ``app/Filters/Honeypot.php``, and modify the ``$aliases`` in the configuration appropriately. +******************** Customizing Honeypot -===================== +******************** Honeypot can be customized. The fields below can be set either in **app/Config/Honeypot.php** or in **.env**. From 53380f4ba830e98096dc9dc9585617db17bf43fb Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:28:48 +0900 Subject: [PATCH 958/970] docs: fix text decoration --- user_guide_src/source/libraries/honeypot.rst | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index 4b49e4c85b19..643c7044282d 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -3,7 +3,7 @@ Honeypot Class ############## The Honeypot Class makes it possible to determine when a Bot makes a request to a CodeIgniter4 application, -if it's enabled in ``Application\Config\Filters.php`` file. This is done by attaching form fields to any form, +if it's enabled in **app\Config\Filters.php** file. This is done by attaching form fields to any form, and this form field is hidden from a human but accessible to a Bot. When data is entered into the field, it's assumed the request is coming from a Bot, and you can throw a ``HoneypotException``. @@ -20,8 +20,8 @@ from the ``$globals`` array, like: .. literalinclude:: honeypot/001.php -A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``. -If it is not suitable, make your own at ``app/Filters/Honeypot.php``, +A sample Honeypot filter is bundled, as **system/Filters/Honeypot.php**. +If it is not suitable, make your own at **app/Filters/Honeypot.php**, and modify the ``$aliases`` in the configuration appropriately. ******************** @@ -31,7 +31,7 @@ Customizing Honeypot Honeypot can be customized. The fields below can be set either in **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' -* ``name`` - name of the HTML form field used for the template; default is 'honeypot' -* ``template`` - form field template used for the honeypot; default is '' +* ``$hidden`` - ``true`` or ``false`` to control visibility of the honeypot field; default is ``true`` +* ``$label`` - HTML label for the honeypot field, default is ``'Fill This Field'`` +* ``$name`` - name of the HTML form field used for the template; default is ``'honeypot'`` +* ``$template`` - form field template used for the honeypot; default is ``''`` From 0c25173cb119c20d2752600ea4f55c3f1432efab Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:38:51 +0900 Subject: [PATCH 959/970] docs: update sample Config file --- user_guide_src/source/libraries/honeypot/001.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php index f0dbf7e64d57..573010145976 100644 --- a/user_guide_src/source/libraries/honeypot/001.php +++ b/user_guide_src/source/libraries/honeypot/001.php @@ -6,14 +6,18 @@ class Filters extends BaseConfig { + // ... + public $globals = [ 'before' => [ 'honeypot', // 'csrf', + // 'invalidchars', ], 'after' => [ 'toolbar', 'honeypot', + // 'secureheaders', ], ]; From 184dd467955453c4f92006889c83f4cdeceb8c74 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 14:34:01 +0900 Subject: [PATCH 960/970] docs: add config items --- user_guide_src/source/libraries/honeypot.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst index 643c7044282d..e034e0dc08db 100644 --- a/user_guide_src/source/libraries/honeypot.rst +++ b/user_guide_src/source/libraries/honeypot.rst @@ -35,3 +35,6 @@ Honeypot can be customized. The fields below can be set either in * ``$label`` - HTML label for the honeypot field, default is ``'Fill This Field'`` * ``$name`` - name of the HTML form field used for the template; default is ``'honeypot'`` * ``$template`` - form field template used for the honeypot; default is ``''`` +* ``$container`` - container tag for the template; default is ``'
{template}
'``. + If you enables CSP, you can remove ``style="display:none"``. +* ``$containerId`` - [Since v4.3.0] this setting is used only when you enables CSP. You can change the id attribute for the container tag; default is ``'hpc'`` From ee49833c035cc36c2e076bdbc630de75c711afc9 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:15:29 +0900 Subject: [PATCH 961/970] docs: add changelog and upgrading guide --- user_guide_src/source/changelogs/v4.3.0.rst | 2 ++ user_guide_src/source/installation/upgrade_430.rst | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 7fdb8038d6d4..4ea3b567cf68 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -291,6 +291,7 @@ The following items are affected: - Typography class: Creation of ``br`` tag - View Parser: The ``nl2br`` filter +- Honeypot: ``input`` tag - Form helper - HTML helper - Common Functions @@ -364,3 +365,4 @@ Bugs Fixed - Fixed a bug when all types of ``Prepared Queries`` were returning a ``Result`` object instead of a bool value for write-type queries. - Fixed a bug with variable filtering in JSON requests using with ``IncomingRequest::getVar()`` or ``IncomingRequest::getJsonVar()`` methods. - Fixed a bug when variable type may be changed when using a specified index with ``IncomingRequest::getVar()`` or ``IncomingRequest::getJsonVar()`` methods. +- Fixed a bug that Honeypot field appears when CSP is enabled. See also :ref:`upgrade-430-honeypot-and-csp`. diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst index 5d7192822c31..04f44a03f4b4 100644 --- a/user_guide_src/source/installation/upgrade_430.rst +++ b/user_guide_src/source/installation/upgrade_430.rst @@ -216,6 +216,16 @@ Database - The ``Model::update()`` method now raises a ``DatabaseException`` if it generates an SQL statement without a WHERE clause. If you need to update all records in a table, use Query Builder instead. E.g., ``$model->builder()->update($data)``. +.. _upgrade-430-honeypot-and-csp: + +Honeypot and CSP +================ + +When CSP is enabled, id attribute ``id="hpc"`` will be injected into the container tag +for the Honeypot field to hide the field. If the id is already used in your views, you need to change it +with ``Config\Honeypot::$containerId``. +And you can remove ``style="display:none"`` in ``Config\Honeypot::$container``. + Others ====== @@ -260,6 +270,10 @@ Config - app/Config/Exceptions.php - Two additional public properties were added: ``$logDeprecations`` and ``$deprecationLogLevel``. See See :ref:`logging_deprecation_warnings` for details. +- app/Config/Honeypot.php + - The new property ``$containerId`` is added to set id attribute value for the container tag + when CSP is enabled. + - The ``input`` tag in the property ``$template`` value has been changed to HTML5 compatible. - app/Config/Logger.php - The property ``$threshold`` has been changed to ``9`` in other than ``production`` environment. From 221b9ac1df24a045b3140035eadf3cccbb73f6f4 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:18:44 +0900 Subject: [PATCH 962/970] test: use aliasing with use operator --- tests/system/Honeypot/HoneypotTest.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 5b9c0c0073d8..7a6f2341dd1c 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -18,6 +18,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; use CodeIgniter\Test\CIUnitTestCase; +use Config\Honeypot as HoneypotConfig; /** * @backupGlobals enabled @@ -28,7 +29,7 @@ */ final class HoneypotTest extends CIUnitTestCase { - private \Config\Honeypot $config; + private HoneypotConfig $config; private Honeypot $honeypot; /** @@ -41,7 +42,7 @@ final class HoneypotTest extends CIUnitTestCase protected function setUp(): void { parent::setUp(); - $this->config = new \Config\Honeypot(); + $this->config = new HoneypotConfig(); $this->honeypot = new Honeypot($this->config); unset($_POST[$this->config->name]); @@ -147,7 +148,7 @@ public function testHoneypotFilterAfter() public function testEmptyConfigContainer() { - $config = new \Config\Honeypot(); + $config = new HoneypotConfig(); $config->container = ''; $honeypot = new Honeypot($config); @@ -159,7 +160,7 @@ public function testEmptyConfigContainer() public function testNoTemplateConfigContainer() { - $config = new \Config\Honeypot(); + $config = new HoneypotConfig(); $config->container = '
'; $honeypot = new Honeypot($config); From 3c339cd045c027ced37002cac7b43056c24153d2 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:20:42 +0900 Subject: [PATCH 963/970] test: update expected --- tests/system/Honeypot/HoneypotTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 7a6f2341dd1c..167d41e080d3 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -67,13 +67,13 @@ public function testAttachHoneypotAndContainer() { $this->response->setBody('
'); $this->honeypot->attachHoneypot($this->response); - $expected = '
'; + $expected = '
'; $this->assertSame($expected, $this->response->getBody()); $this->config->container = ''; $this->response->setBody('
'); $this->honeypot->attachHoneypot($this->response); - $expected = '
'; + $expected = '
'; $this->assertSame($expected, $this->response->getBody()); } From 4643580f5b9c821b6337feba499c2abf7fdde609 Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 27 Dec 2022 15:48:52 +0900 Subject: [PATCH 964/970] test: add test --- tests/system/Honeypot/HoneypotTest.php | 27 ++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php index 167d41e080d3..b87ce3fe3c48 100644 --- a/tests/system/Honeypot/HoneypotTest.php +++ b/tests/system/Honeypot/HoneypotTest.php @@ -11,6 +11,7 @@ namespace CodeIgniter\Honeypot; +use CodeIgniter\Config\Factories; use CodeIgniter\Config\Services; use CodeIgniter\Filters\Filters; use CodeIgniter\Honeypot\Exceptions\HoneypotException; @@ -18,6 +19,7 @@ use CodeIgniter\HTTP\IncomingRequest; use CodeIgniter\HTTP\Response; use CodeIgniter\Test\CIUnitTestCase; +use Config\App; use Config\Honeypot as HoneypotConfig; /** @@ -42,14 +44,16 @@ final class HoneypotTest extends CIUnitTestCase protected function setUp(): void { parent::setUp(); + $this->config = new HoneypotConfig(); $this->honeypot = new Honeypot($this->config); unset($_POST[$this->config->name]); $_SERVER['REQUEST_METHOD'] = 'POST'; $_POST[$this->config->name] = 'hey'; - $this->request = Services::request(null, false); - $this->response = Services::response(); + + $this->request = Services::request(null, false); + $this->response = Services::response(); } public function testAttachHoneypot() @@ -77,6 +81,25 @@ public function testAttachHoneypotAndContainer() $this->assertSame($expected, $this->response->getBody()); } + public function testAttachHoneypotAndContainerWithCSP() + { + $this->resetServices(); + + $config = new App(); + $config->CSPEnabled = true; + Factories::injectMock('config', 'App', $config); + $this->response = Services::response($config, false); + + $this->config = new HoneypotConfig(); + $this->honeypot = new Honeypot($this->config); + + $this->response->setBody('
'); + $this->honeypot->attachHoneypot($this->response); + + $regex = '!
!u'; + $this->assertMatchesRegularExpression($regex, $this->response->getBody()); + } + public function testHasntContent() { unset($_POST[$this->config->name]); From 4a1d91e956f86dfe650764966a598420adbdc361 Mon Sep 17 00:00:00 2001 From: kenjis Date: Wed, 28 Dec 2022 09:10:59 +0900 Subject: [PATCH 965/970] docs: fix typo Co-authored-by: MGatner --- app/Config/Honeypot.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php index 019b48acf9de..67ebcb0ee74c 100644 --- a/app/Config/Honeypot.php +++ b/app/Config/Honeypot.php @@ -29,7 +29,7 @@ class Honeypot extends BaseConfig /** * Honeypot container * - * If you enables CSP, you can remove `style="display:none"`. + * If you enabled CSP, you can remove `style="display:none"`. */ public string $container = '
{template}
'; From f0700a53569fc93323c8ffedb9223dc2db5a6cb4 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 28 Dec 2022 10:53:46 +0700 Subject: [PATCH 966/970] [Rector] Enable skipped RemoveUselessReturnTagRector `RemoveUselessReturnTagRector` already cover `@return true` --- rector.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/rector.php b/rector.php index 81ad3df5006b..bdaf1165bddb 100644 --- a/rector.php +++ b/rector.php @@ -29,7 +29,6 @@ use Rector\CodingStyle\Rector\FuncCall\CountArrayToEmptyArrayComparisonRector; use Rector\Config\RectorConfig; use Rector\DeadCode\Rector\ClassMethod\RemoveUnusedPrivateMethodRector; -use Rector\DeadCode\Rector\ClassMethod\RemoveUselessReturnTagRector; use Rector\DeadCode\Rector\If_\UnwrapFutureCompatibleIfPhpVersionRector; use Rector\DeadCode\Rector\MethodCall\RemoveEmptyMethodCallRector; use Rector\EarlyReturn\Rector\Foreach_\ChangeNestedForeachIfsToEarlyContinueRector; @@ -116,12 +115,7 @@ // @TODO remove if https://github.com/rectorphp/rector-phpunit/issues/86 is fixed GetMockBuilderGetMockToCreateMockRector::class => [ __DIR__ . '/tests/system/Email/EmailTest.php', - ], - - // rector mistakenly removes `@return true` - RemoveUselessReturnTagRector::class => [ - __DIR__ . '/system/Debug/Exceptions.php', - ], + ] ]); // auto import fully qualified class names From 4b78a2ea0a8a617cce4a507f1087081ee70757c5 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Wed, 28 Dec 2022 10:58:51 +0700 Subject: [PATCH 967/970] add trailing comma --- rector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rector.php b/rector.php index bdaf1165bddb..d53f9af118eb 100644 --- a/rector.php +++ b/rector.php @@ -115,7 +115,7 @@ // @TODO remove if https://github.com/rectorphp/rector-phpunit/issues/86 is fixed GetMockBuilderGetMockToCreateMockRector::class => [ __DIR__ . '/tests/system/Email/EmailTest.php', - ] + ], ]); // auto import fully qualified class names From 7558424fa2e6d8fd7c6bd41b130cfb271c8f81a5 Mon Sep 17 00:00:00 2001 From: kenjis Date: Fri, 6 Jan 2023 09:46:23 +0900 Subject: [PATCH 968/970] chore: update Kint to 5.0.2 --- system/ThirdParty/Kint/Parser/XmlPlugin.php | 5 --- system/ThirdParty/Kint/Zval/BlobValue.php | 9 ++++- .../SplFileInfoRepresentation.php | 37 +++++++++++-------- system/ThirdParty/Kint/init.php | 6 ++- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- 5 files changed, 35 insertions(+), 24 deletions(-) diff --git a/system/ThirdParty/Kint/Parser/XmlPlugin.php b/system/ThirdParty/Kint/Parser/XmlPlugin.php index 4e5671fb7273..a5a31abd4361 100644 --- a/system/ThirdParty/Kint/Parser/XmlPlugin.php +++ b/system/ThirdParty/Kint/Parser/XmlPlugin.php @@ -113,11 +113,6 @@ protected static function xmlToSimpleXML(string $var, ?string $parent_path): ?ar /** * Get the DOMDocument info. * - * The documentation of DOMDocument::loadXML() states that while you can - * call it statically, it will give an E_STRICT warning. On my system it - * actually gives an E_DEPRECATED warning, but it works so we'll just add - * an error-silencing '@' to the access path. - * * If it errors loading then we wouldn't have gotten this far in the first place. * * @psalm-param non-empty-string $var The XML string diff --git a/system/ThirdParty/Kint/Zval/BlobValue.php b/system/ThirdParty/Kint/Zval/BlobValue.php index cfee55e60ac8..ff5a6a24cfc9 100644 --- a/system/ThirdParty/Kint/Zval/BlobValue.php +++ b/system/ThirdParty/Kint/Zval/BlobValue.php @@ -74,8 +74,11 @@ class BlobValue extends Value * windows-125x and iso-8859-x which have practically undetectable * differences because they use every single byte available. * - * This is *NOT* reliable and should not be trusted implicitly. As - * with char_encodings, the order of the charsets is significant. + * This is *NOT* reliable and should not be trusted implicitly. Since it + * works by triggering and suppressing conversion warnings, your error + * handler may complain. + * + * As with char_encodings, the order of the charsets is significant. * * This depends on the iconv extension */ @@ -182,6 +185,8 @@ public static function detectEncoding(string $string) if (\function_exists('iconv')) { foreach (self::$legacy_encodings as $encoding) { + // Iconv detection works by triggering + // "Detected an illegal character in input string" warnings if (@\iconv($encoding, $encoding, $string) === $string) { return $encoding; } diff --git a/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php b/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php index 607877e5aee8..44980d7e359a 100644 --- a/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php +++ b/system/ThirdParty/Kint/Zval/Representation/SplFileInfoRepresentation.php @@ -28,6 +28,7 @@ namespace Kint\Zval\Representation; use Kint\Utils; +use RuntimeException; use SplFileInfo; class SplFileInfoRepresentation extends Representation @@ -53,24 +54,30 @@ public function __construct(SplFileInfo $fileInfo) { parent::__construct('SplFileInfo'); - if ($fileInfo->getRealPath()) { - $this->realpath = $fileInfo->getRealPath(); - $this->perms = $fileInfo->getPerms(); - $this->size = $fileInfo->getSize(); - $this->owner = $fileInfo->getOwner(); - $this->group = $fileInfo->getGroup(); - $this->ctime = $fileInfo->getCTime(); - $this->mtime = $fileInfo->getMTime(); - } - $this->path = $fileInfo->getPathname(); - $this->is_dir = $fileInfo->isDir(); - $this->is_file = $fileInfo->isFile(); - $this->is_link = $fileInfo->isLink(); + try { + if ($fileInfo->getRealPath()) { + $this->perms = $fileInfo->getPerms(); + $this->size = $fileInfo->getSize(); + $this->owner = $fileInfo->getOwner(); + $this->group = $fileInfo->getGroup(); + $this->ctime = $fileInfo->getCTime(); + $this->mtime = $fileInfo->getMTime(); + $this->realpath = $fileInfo->getRealPath(); + } + + $this->is_dir = $fileInfo->isDir(); + $this->is_file = $fileInfo->isFile(); + $this->is_link = $fileInfo->isLink(); - if ($this->is_link) { - $this->linktarget = $fileInfo->getLinkTarget(); + if ($this->is_link) { + $this->linktarget = $fileInfo->getLinkTarget(); + } + } catch (RuntimeException $e) { + if (false === \strpos($e->getMessage(), ' open_basedir ')) { + throw $e; + } } switch ($this->perms & 0xF000) { diff --git a/system/ThirdParty/Kint/init.php b/system/ThirdParty/Kint/init.php index 4c3a22bb500b..7605415b6e6e 100644 --- a/system/ThirdParty/Kint/init.php +++ b/system/ThirdParty/Kint/init.php @@ -53,8 +53,12 @@ if (isset($_SERVER['DOCUMENT_ROOT'])) { Kint::$app_root_dirs = [ $_SERVER['DOCUMENT_ROOT'] => '', - \realpath($_SERVER['DOCUMENT_ROOT']) => '', ]; + + // Suppressed for unreadable document roots (related to open_basedir) + if (false !== @\realpath($_SERVER['DOCUMENT_ROOT'])) { + Kint::$app_root_dirs[\realpath($_SERVER['DOCUMENT_ROOT'])] = ''; + } } Utils::composerSkipFlags(); diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst index 4ea3b567cf68..2fe99ab82722 100644 --- a/user_guide_src/source/changelogs/v4.3.0.rst +++ b/user_guide_src/source/changelogs/v4.3.0.rst @@ -322,7 +322,7 @@ Others - **Validation:** Added Closure validation rule. See :ref:`validation-using-closure-rule` for details. - **Config:** Now you can specify Composer packages to auto-discover manually. See :ref:`Code Modules `. - **Config:** Added ``Config\Session`` class to handle session configuration. -- **Debug:** Kint has been updated to 5.0.1. +- **Debug:** Kint has been updated to 5.0.2. - **Request:** Added new ``$request->getRawInputVar()`` method to return a specified variable from raw stream. See :ref:`Retrieving Raw data `. - **Request:** Added new ``$request->is()`` method to query the request type. See :ref:`Determining Request Type `. From d01d5bece0cdc45ec62218bde72e01cdfe5943eb Mon Sep 17 00:00:00 2001 From: kenjis Date: Tue, 10 Jan 2023 11:14:21 +0900 Subject: [PATCH 969/970] Prep for 4.3.0 release --- CHANGELOG.md | 110 ++++++++++++++++++ system/CodeIgniter.php | 2 +- user_guide_src/source/changelogs/v4.3.0.rst | 2 +- user_guide_src/source/conf.py | 4 +- .../source/installation/upgrade_430.rst | 52 ++++++++- 5 files changed, 160 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7837363ab950..60e6e3b4ed00 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,115 @@ # Changelog +## [v4.3.0](https://github.com/codeigniter4/CodeIgniter4/tree/v4.3.0) (2023-01-10) +[Full Changelog](https://github.com/codeigniter4/CodeIgniter4/compare/v4.2.12...v4.3.0) + +### Breaking Changes + +* fix: throws DatabaseException in DB connections by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6163 +* config: DB Error always throws Exception CI_DBUG by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6183 +* Config Property Types by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6214 +* refactor: loading app/Config/routes.php by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6293 +* fix: exceptionHandler may return invalid HTTP status code by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6228 +* feat: add Form helpers for Validation Errors by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6384 +* fix: ValidationInterface by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6253 +* [Reverted] Make Unique Index Name Unique by @sclubricants in https://github.com/codeigniter4/CodeIgniter4/pull/6516 +* fix: types in database classes by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6527 +* fix: ResponseInterface (1) by @kenjis in https://github.com/codeigniter4/CodeIgniter4/pull/6556 +* Improve BaseConnection::getForeignKeyData() and Forge::addForeignKey() by @sclubricants in https://github.com/codeigniter4/CodeIgniter4/pull/6468 +* Refactor BaseBuilder *Batch() Methods by @sclubricants in https://github.com/codeigniter4/CodeIgniter4/pull/6536 +* refactor: remove `type="text/javascript"` in