From b0b819fefd94d5a7601756f4372663d8c2aba34c Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 8 Sep 2026 00:52:15 +0700 Subject: [PATCH] refactor: make `BaseService` and `BaseCollector` abstract --- .php-cs-fixer.dist.php | 1 + structarmed.php | 64 +++++++++++-------- system/Config/BaseService.php | 2 +- .../Toolbar/Collectors/BaseCollector.php | 2 +- user_guide_src/source/changelogs/v4.8.0.rst | 2 + 5 files changed, 41 insertions(+), 30 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index ad6ffacb8f0c..f8952a74da94 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -33,6 +33,7 @@ __DIR__ . '/.php-cs-fixer.user-guide.php', __DIR__ . '/preload.php', __DIR__ . '/rector.php', + __DIR__ . '/structarmed.php', __DIR__ . '/spark', ]); diff --git a/structarmed.php b/structarmed.php index 75e4b52e1d5b..700b31b1a0db 100644 --- a/structarmed.php +++ b/structarmed.php @@ -10,37 +10,41 @@ * For the full copyright and license information, please view * the LICENSE file that was distributed with this source code. */ -use Boundwize\StructArmed\Rule\Rules\Function_\MustHaveReturnTypeFunctionRule; + +use Boundwize\StructArmed\Architecture; +use Boundwize\StructArmed\Preset\Preset; use Boundwize\StructArmed\Preset\Presets\CodeQualityPreset; +use Boundwize\StructArmed\Preset\Presets\Psr4Preset; +use Boundwize\StructArmed\Rule\Rules\Class_\ExtendedClassMustBeAbstractOrInstantiatedRule; +use Boundwize\StructArmed\Rule\Rules\Function_\MustHaveReturnTypeFunctionRule; use CodeIgniter\Cache\ResponseCache; +use CodeIgniter\Config\BaseConfig; +use CodeIgniter\Database\BaseResult; +use CodeIgniter\Database\Config; +use CodeIgniter\DataCaster\DataCaster; +use CodeIgniter\DataConverter\DataConverter; +use CodeIgniter\Entity\Cast\CastInterface; +use CodeIgniter\Entity\Cast\URICast; +use CodeIgniter\Entity\Entity; +use CodeIgniter\Entity\Exceptions\CastException; use CodeIgniter\HTTP\CLIRequest; +use CodeIgniter\HTTP\DownloadResponse; use CodeIgniter\HTTP\Header; use CodeIgniter\HTTP\IncomingRequest; +use CodeIgniter\HTTP\RedirectResponse; +use CodeIgniter\HTTP\Response; +use CodeIgniter\HTTP\ResponseInterface; +use CodeIgniter\HTTP\ResponseTrait; use CodeIgniter\HTTP\SSEResponse; use CodeIgniter\HTTP\StreamResponse; -use CodeIgniter\HTTP\ResponseInterface; -use CodeIgniter\DataCaster\DataCaster; -use CodeIgniter\Entity\Cast\CastInterface; -use CodeIgniter\Entity\Exceptions\CastException; -use CodeIgniter\DataConverter\DataConverter; -use CodeIgniter\Entity\Entity; -use CodeIgniter\Entity\Cast\URICast; use CodeIgniter\HTTP\URI; use CodeIgniter\Log\Handlers\ChromeLoggerHandler; -use CodeIgniter\Security\CheckPhpIni; -use CodeIgniter\View\Table; -use CodeIgniter\Database\BaseResult; -use CodeIgniter\View\Plugins; -use CodeIgniter\HTTP\ResponseTrait; use CodeIgniter\Pager\PagerInterface; -use CodeIgniter\HTTP\Response; -use CodeIgniter\HTTP\RedirectResponse; -use CodeIgniter\HTTP\DownloadResponse; +use CodeIgniter\Security\CheckPhpIni; use CodeIgniter\Validation\Validation; +use CodeIgniter\View\Plugins; use CodeIgniter\View\RendererInterface; -use Boundwize\StructArmed\Architecture; -use Boundwize\StructArmed\Preset\Preset; -use Boundwize\StructArmed\Preset\Presets\Psr4Preset; +use CodeIgniter\View\Table; return Architecture::define() ->skip([ @@ -58,6 +62,9 @@ ->layer('Helpers', __DIR__ . '/system/Helpers') ->rule('helpers.functions_must_have_return_type', new MustHaveReturnTypeFunctionRule('Helpers')) + ->layerPattern('BaseClasses', '/^CodeIgniter\\\\.*Base.*$/') + ->rule('base_classes.must_be_abstract', new ExtendedClassMustBeAbstractOrInstantiatedRule('BaseClasses')) + // Resolve CodeIgniter layers from class names because several layers share directories. ->layerPattern('API', '/^CodeIgniter\\\\API\\\\.*$/') ->layerPattern('Cache', '/^CodeIgniter\\\\Cache\\\\.*$/') @@ -115,13 +122,13 @@ 'Pager' => ['URI', 'View'], 'Publisher' => ['Files', 'URI'], // +API = API + its allowed layers; +Controller = Controller + its allowed layers - 'RESTful' => ['+API', '+Controller'], - 'Router' => ['HTTP', 'I18n'], - 'Security' => ['Cookie', 'HTTP', 'I18n', 'Session'], - 'Session' => ['Cookie', 'Database', 'HTTP', 'I18n'], - 'Throttle' => ['Cache', 'I18n'], - 'Validation' => ['Database', 'HTTP', 'Helpers', 'I18n', 'Input'], - 'View' => ['Cache'], + 'RESTful' => ['+API', '+Controller'], + 'Router' => ['HTTP', 'I18n'], + 'Security' => ['Cookie', 'HTTP', 'I18n', 'Session'], + 'Session' => ['Cookie', 'Database', 'HTTP', 'I18n'], + 'Throttle' => ['Cache', 'I18n'], + 'Validation' => ['Database', 'HTTP', 'Helpers', 'I18n', 'Input'], + 'View' => ['Cache'], ]) ->skipPathsForRuleset(['*test*']) // Skip violations for class-specific dependencies. @@ -135,7 +142,7 @@ CastInterface::class, CastException::class, ]) - ->skipClassViolation(\CodeIgniter\DataCaster\Exceptions\CastException::class, [ + ->skipClassViolation(CodeIgniter\DataCaster\Exceptions\CastException::class, [ CastException::class, ]) ->skipClassViolation(DataConverter::class, [ @@ -165,4 +172,5 @@ ->skipClassViolation(DownloadResponse::class, [PagerInterface::class]) ->skipClassViolation(SSEResponse::class, [PagerInterface::class]) ->skipClassViolation(StreamResponse::class, [PagerInterface::class]) - ->skipClassViolation(Validation::class, [RendererInterface::class]); + ->skipClassViolation(Validation::class, [RendererInterface::class]) + ->skipClassViolation(Config::class, [BaseConfig::class]); diff --git a/system/Config/BaseService.php b/system/Config/BaseService.php index 600edb7a0a3f..91133cdf705b 100644 --- a/system/Config/BaseService.php +++ b/system/Config/BaseService.php @@ -149,7 +149,7 @@ * @method static ValidationInterface validation(ConfigValidation $config = null, $getShared = true) * @method static Cell viewcell($getShared = true) */ -class BaseService +abstract class BaseService { /** * Cache for instance of any services that diff --git a/system/Debug/Toolbar/Collectors/BaseCollector.php b/system/Debug/Toolbar/Collectors/BaseCollector.php index 89415377be46..ab873a04c969 100644 --- a/system/Debug/Toolbar/Collectors/BaseCollector.php +++ b/system/Debug/Toolbar/Collectors/BaseCollector.php @@ -16,7 +16,7 @@ /** * Base Toolbar collector */ -class BaseCollector +abstract class BaseCollector { /** * Whether this collector has data that can diff --git a/user_guide_src/source/changelogs/v4.8.0.rst b/user_guide_src/source/changelogs/v4.8.0.rst index d296985cca1d..4d5e181c09fd 100644 --- a/user_guide_src/source/changelogs/v4.8.0.rst +++ b/user_guide_src/source/changelogs/v4.8.0.rst @@ -41,7 +41,9 @@ Behavior Changes - **Commands:** The ``db:table`` output was reworded: the data and metadata column headers are now capitalized (e.g. ``Id``, ``Created_at``), the connection summary headers read ``Hostname``, ``Database``, ``Username``, ``DB Driver``, ``DB Prefix``, and ``Port``, and the section titles changed (e.g. ``Data of "users" table:``). Scripts that grep the previous output will need updating. - **Commands:** The ``worker:uninstall`` command now returns ``EXIT_SUCCESS`` (previously ``EXIT_ERROR``) when the user declines the interactive confirmation prompt, since user-initiated cancellation is not a failure. In non-interactive mode without ``--force`` it now aborts with ``EXIT_ERROR`` instead of prompting, and the redundant ``Uninstalling FrankenPHP Worker Mode`` header was dropped. Scripts that branch on the previous exit code or wording will need updating. - **Commands:** The ``phpini:check`` command's invalid-argument error now prints only ``You must specify a correct argument.``. The usage example and the argument listing moved to ``phpini:check --help``, where the argument is now named ``section``. Scripts that grep the previous output will need updating. +- **Config:** ``CodeIgniter\Config\BaseService`` is now ``abstract``. It is intended to be extended (as ``Config\Services`` does) and accessed statically; code that instantiated it directly with ``new BaseService()`` will now throw an ``Error``. - **Database:** The Postgre driver's ``$db->error()['code']`` previously always returned ``''``. It now returns the 5-character SQLSTATE string for query and transaction failures (e.g., ``'42P01'``), or ``'08006'`` for connection-level failures. Code that relied on ``$db->error()['code'] === ''`` will need updating. +- **Debug:** ``CodeIgniter\Debug\Toolbar\Collectors\BaseCollector`` is now ``abstract``. Custom toolbar collectors must extend it; code that instantiated it directly with ``new BaseCollector()`` will now throw an ``Error``. - **Filters:** HTTP method matching for method-based filters is now case-sensitive. The keys in ``Config\Filters::$methods`` must exactly match the request method (e.g., ``GET``, ``POST``). Lowercase method names (e.g., ``post``) will no longer match. - **HTTP:** Routes defined with ``$routes->add()`` now also match HTTP ``QUERY`` requests. If the route has CSRF protection, remember that CSRF verification does not protect safe methods such as ``GET`` and ``QUERY``.