feat(wpmc S2): make Plugin::boot() idempotent

Add private \$booted flag; guard skips all re-registration on subsequent
calls. TDD: RED (3x boot -> expectAdded->once() fails) then GREEN.
Drop deprecated setAccessible() call (no-op since PHP 8.1).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Vladimir Bryzgalov
2026-05-12 18:01:43 +05:00
parent bc16851b71
commit 38bb7dae55
2 changed files with 40 additions and 0 deletions
+6
View File
@@ -6,6 +6,7 @@ namespace WPMultiCity;
final class Plugin final class Plugin
{ {
private static ?Plugin $instance = null; private static ?Plugin $instance = null;
private bool $booted = false;
public static function instance(): Plugin public static function instance(): Plugin
{ {
@@ -36,6 +37,11 @@ final class Plugin
public function boot(): void public function boot(): void
{ {
if ($this->booted) {
return;
}
$this->booted = true;
if (!$this->dependencies_satisfied()) { if (!$this->dependencies_satisfied()) {
add_action('admin_notices', [$this, 'render_dependency_notice']); add_action('admin_notices', [$this, 'render_dependency_notice']);
return; return;
+34
View File
@@ -29,4 +29,38 @@ final class PluginBootTest extends TestCase
'boot() must register FieldGroup on acf/init' 'boot() must register FieldGroup on acf/init'
); );
} }
public function test_boot_is_idempotent_when_called_multiple_times(): void
{
if (!class_exists('ACF', false)) {
eval('class ACF {}');
}
// Reset the singleton's boot flag so this test is independent of
// whatever previous tests did to the static instance. (We will add
// the flag in GREEN.)
$plugin = Plugin::instance();
$reflection = new \ReflectionClass($plugin);
if ($reflection->hasProperty('booted')) {
$prop = $reflection->getProperty('booted');
$prop->setValue($plugin, false);
}
\Brain\Monkey\Actions\expectAdded('init')
->with([\WPMultiCity\Taxonomy::class, 'do_register'])
->once();
\Brain\Monkey\Actions\expectAdded('init')
->with([\WPMultiCity\PostType::class, 'do_register'])
->once();
\Brain\Monkey\Actions\expectAdded('acf/init')
->with([\WPMultiCity\FieldGroup::class, 'do_register'])
->once();
$plugin->boot();
$plugin->boot();
$plugin->boot();
// Mockery verifies ->once() in tearDown.
self::assertTrue(true);
}
} }