Skip to content

Commit 2d8b3bd

Browse files
authored
Merge pull request #9073 from kenjis/check-for-duplicate-registrar-discovery
fix: add check for duplicate Registrar Auto-Discovery runs
2 parents 10ba2eb + eb53f86 commit 2d8b3bd

File tree

4 files changed

+89
-1
lines changed

4 files changed

+89
-1
lines changed

system/Config/BaseConfig.php

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace CodeIgniter\Config;
1313

14+
use CodeIgniter\Exceptions\ConfigException;
1415
use CodeIgniter\Exceptions\RuntimeException;
1516
use Config\Encryption;
1617
use Config\Modules;
@@ -45,12 +46,22 @@ class BaseConfig
4546
public static bool $override = true;
4647

4748
/**
48-
* Has module discovery happened yet?
49+
* Has module discovery completed?
4950
*
5051
* @var bool
5152
*/
5253
protected static $didDiscovery = false;
5354

55+
/**
56+
* Is module discovery running or not?
57+
*/
58+
protected static bool $discovering = false;
59+
60+
/**
61+
* The processing Registrar file for error message.
62+
*/
63+
protected static string $registrarFile = '';
64+
5465
/**
5566
* The modules configuration.
5667
*
@@ -230,10 +241,24 @@ protected function registerProperties()
230241
}
231242

232243
if (! static::$didDiscovery) {
244+
// Discovery must be completed before the first instantiation of any Config class.
245+
if (static::$discovering) {
246+
throw new ConfigException(
247+
'During Auto-Discovery of Registrars,'
248+
. ' "' . static::class . '" executes Auto-Discovery again.'
249+
. ' "' . clean_path(static::$registrarFile) . '" seems to have bad code.'
250+
);
251+
}
252+
253+
static::$discovering = true;
254+
233255
$locator = service('locator');
234256
$registrarsFiles = $locator->search('Config/Registrar.php');
235257

236258
foreach ($registrarsFiles as $file) {
259+
// Saves the file for error message.
260+
static::$registrarFile = $file;
261+
237262
$className = $locator->findQualifiedNameFromPath($file);
238263

239264
if ($className === false) {
@@ -244,6 +269,7 @@ protected function registerProperties()
244269
}
245270

246271
static::$didDiscovery = true;
272+
static::$discovering = false;
247273
}
248274

249275
$shortName = (new ReflectionClass($this))->getShortName();

user_guide_src/source/changelogs/v4.6.0.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,13 @@ The ``Filters`` class has been changed to allow multiple runs of the same filter
5050
with different arguments in before or after. See
5151
:ref:`Upgrading Guide <upgrade-460-filters-changes>` for details.
5252

53+
Registrars
54+
----------
55+
56+
Added check to prevent Auto-Discovery of Registrars from running twice. If it is
57+
executed twice, an exception will be thrown. See
58+
:ref:`upgrade-460-registrars-with-dirty-hack`.
59+
5360
.. _v460-interface-changes:
5461

5562
Interface Changes

user_guide_src/source/installation/upgrade_460.rst

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,28 @@ See :ref:`ChangeLog <v460-behavior-changes-exceptions>` for details.
2929

3030
If you have code that catches these exceptions, change the exception classes.
3131

32+
.. _upgrade-460-registrars-with-dirty-hack:
33+
34+
Registrars with Dirty Hack
35+
==========================
36+
37+
To prevent Auto-Discovery of :ref:`registrars` from running twice, when a registrar
38+
class is loaded or instantiated, if it instantiates a Config class (which extends
39+
``CodeIgniter\Config\BaseConfig``), ``ConfigException`` will be raised.
40+
41+
This is because if Auto-Discovery of Registrars is performed twice, duplicate
42+
values may be added to properties of Config classes.
43+
44+
All registrar classes (**Config/Registrar.php** in all namespaces) must be modified
45+
so that they do not instantiate any Config class when loaded or instantiated.
46+
47+
If the packages/modules you are using provide such registrar classes, the registrar
48+
classes in the packages/modules need to be fixed.
49+
50+
The following is an example of code that will no longer work:
51+
52+
.. literalinclude:: upgrade_460/001.php
53+
3254
Interface Changes
3355
=================
3456

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace CodeIgniter\Shield\Config;
4+
5+
use Config\App;
6+
7+
class Registrar
8+
{
9+
public function __construct()
10+
{
11+
$config = new App(); // Bad. When this class is instantiated, Config\App will be instantiated.
12+
13+
// Does something.
14+
}
15+
16+
public static function Pager(): array
17+
{
18+
return [
19+
'templates' => [
20+
'module_pager' => 'MyModule\Views\Pager',
21+
],
22+
];
23+
}
24+
25+
public static function hack(): void
26+
{
27+
$config = config('Cache');
28+
29+
// Does something.
30+
}
31+
}
32+
33+
Registrar::hack(); // Bad. When this class is loaded, Config\Cache will be instantiated.

0 commit comments

Comments
 (0)