Skip to content

Commit aef9e37

Browse files
authored
Merge pull request #9012 from kenjis/feat-Services-resetServicesCache
feat: add Services::resetServicesCache() to reset services cache
2 parents cb39e7e + a4563e5 commit aef9e37

File tree

8 files changed

+118
-0
lines changed

8 files changed

+118
-0
lines changed

phpstan.neon.dist

+3
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ parameters:
4242
booleansInConditions: true
4343
disallowedConstructs: true
4444
matchingInheritedMethodNames: true
45+
codeigniter:
46+
additionalServices:
47+
- AfterAutoloadModule\Config\Services

system/Config/BaseService.php

+9
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,15 @@ public static function injectMock(string $name, $mock)
388388
static::$mocks[strtolower($name)] = $mock;
389389
}
390390

391+
/**
392+
* Resets the service cache.
393+
*/
394+
public static function resetServicesCache(): void
395+
{
396+
self::$serviceNames = [];
397+
static::$discovered = false;
398+
}
399+
391400
protected static function buildServicesCache(): void
392401
{
393402
if (! static::$discovered) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace AfterAutoloadModule\Config;
15+
16+
use AfterAutoloadModule\Test;
17+
use CodeIgniter\Config\BaseService;
18+
19+
/**
20+
* Services for testing BaseService::resetServicesCache().
21+
*
22+
* This class should not be discovered by the autoloader until the test adds
23+
* this namespace to the autoloader.
24+
*/
25+
class Services extends BaseService
26+
{
27+
/**
28+
* Return a shared instance of the Test class for testing
29+
*/
30+
public static function test(bool $getShared = true): Test
31+
{
32+
if ($getShared) {
33+
return static::getSharedInstance('test');
34+
}
35+
36+
return new Test();
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/**
6+
* This file is part of CodeIgniter 4 framework.
7+
*
8+
* (c) CodeIgniter Foundation <[email protected]>
9+
*
10+
* For the full copyright and license information, please view
11+
* the LICENSE file that was distributed with this source code.
12+
*/
13+
14+
namespace AfterAutoloadModule;
15+
16+
/**
17+
* A simple class for testing BaseService::resetServicesCache().
18+
*
19+
* This class should not be discovered by the autoloader until the test adds
20+
* this namespace to the autoloader.
21+
*/
22+
class Test
23+
{
24+
}

tests/system/CommonSingleServiceTest.php

+1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ public static function provideServiceNames(): iterable
110110
'serviceExists',
111111
'reset',
112112
'resetSingle',
113+
'resetServicesCache',
113114
'injectMock',
114115
'encrypter', // Encrypter needs a starter key
115116
'session', // Headers already sent

tests/system/Config/ServicesTest.php

+24
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
namespace CodeIgniter\Config;
1515

16+
use AfterAutoloadModule\Test;
1617
use CodeIgniter\Autoloader\Autoloader;
1718
use CodeIgniter\Autoloader\FileLocator;
1819
use CodeIgniter\Database\MigrationRunner;
@@ -350,6 +351,29 @@ public function testResetSingleCaseInsensitive(): void
350351
$this->assertNotInstanceOf(MockResponse::class, $someService);
351352
}
352353

354+
#[PreserveGlobalState(false)]
355+
#[RunInSeparateProcess]
356+
public function testResetServiceCache(): void
357+
{
358+
Services::injectMock('response', new MockResponse(new App()));
359+
$response = service('response');
360+
$this->assertInstanceOf(MockResponse::class, $response);
361+
service('response')->setStatusCode(200);
362+
363+
Services::autoloader()->addNamespace(
364+
'AfterAutoloadModule',
365+
SUPPORTPATH . '_AfterAutoloadModule/'
366+
);
367+
Services::resetServicesCache();
368+
369+
$response = service('response');
370+
$this->assertInstanceOf(MockResponse::class, $response);
371+
$this->assertSame(200, $response->getStatusCode());
372+
373+
$test = service('test');
374+
$this->assertInstanceOf(Test::class, $test);
375+
}
376+
353377
public function testFilters(): void
354378
{
355379
$result = Services::filters();

user_guide_src/source/changelogs/v4.6.0.rst

+2
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,8 @@ Others
157157

158158
- **Filters:** Now you can execute a filter more than once with the different
159159
arguments in before or after.
160+
- **Services:** Added ``BaseService::resetServicesCache()`` method to reset
161+
the services cache. See :ref:`resetting-services-cache`.
160162

161163
***************
162164
Message Changes

user_guide_src/source/concepts/services.rst

+17
Original file line numberDiff line numberDiff line change
@@ -173,3 +173,20 @@ would simply use the framework's ``Config\Services`` class to grab your service:
173173
.. literalinclude:: services/012.php
174174

175175
.. note:: If multiple Services files have the same method name, the first one found will be the instance returned.
176+
177+
.. _resetting-services-cache:
178+
179+
Resetting Services Cache
180+
========================
181+
182+
.. versionadded:: 4.6.0
183+
184+
When the Services class is first called fairly early in the framework initialization
185+
process, the Services classes discovered by auto-discovery are cached in a property,
186+
and it will not be updated.
187+
188+
If modules are dynamically loaded later, and there are Services in the modules,
189+
the cache must be updated.
190+
191+
This can be done by running ``Config\Services::resetServicesCache()``. This will
192+
clear the cache, and force the service discovery again when needed.

0 commit comments

Comments
 (0)