From 9c7231c6cab1025c0b5eeec04b2e7ae7cdcb683a Mon Sep 17 00:00:00 2001 From: Divarion_D Date: Tue, 11 Aug 2026 19:22:09 +0300 Subject: [PATCH] refactor(core): remove unused BoundaryInterface marker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit BoundaryInterface was a marker interface with no runtime consumer — nothing read getEntryPoint()/isIsolated() and, being static-less metadata, it enforced nothing. Its only implementor was MinistraModule. Removes the interface, drops `implements BoundaryInterface` plus the two orphaned methods from MinistraModule (getName/getVersion stay — they come from BaseModule/ModuleInterface), and deletes the now-empty Core/Boundary/. Test contract (InterfaceContractTest) loses the three BoundaryInterface assertions; docs (en/ru architecture + modules, .github instructions) now describe isolated subsystems like Ministra as a convention — own entry point + bootstrap — rather than a marker interface. Verified: php -l, make gates, make phpstan (No errors); InterfaceContractTest + ArchitectureTest green (33 tests, 96 assertions). --- .../architecture-rules.instructions.md | 2 +- docs/en/development/architecture.md | 2 +- docs/en/development/modules.md | 31 ++++++------- docs/ru/development/architecture.md | 2 +- docs/ru/development/modules.md | 16 ++----- src/Core/Boundary/BoundaryInterface.php | 41 ------------------ src/Modules/ministra_85a7d/MinistraModule.php | 11 +---- tests/Unit/ArchitectureTest.php | 2 +- tests/Unit/InterfaceContractTest.php | 43 ------------------- 9 files changed, 23 insertions(+), 127 deletions(-) delete mode 100644 src/Core/Boundary/BoundaryInterface.php diff --git a/.github/instructions/architecture-rules.instructions.md b/.github/instructions/architecture-rules.instructions.md index 09190fd2..e22c2918 100644 --- a/.github/instructions/architecture-rules.instructions.md +++ b/.github/instructions/architecture-rules.instructions.md @@ -18,7 +18,7 @@ Authoritative reference: `docs/en/development/architecture.md`. | `src/Public/` | Front controller, router, controllers, views, assets | | `src/Cli/` | Console commands and cron entry points | | `src/Modules/` | Optional extension layer (`{name}_{hash5}/`), loaded by `ModuleLoader` | -| `src/ministra/` | Stalker Portal — isolated subsystem (`BoundaryInterface`) | +| `src/ministra/` | Stalker Portal — isolated subsystem | ## Layer pattern Every domain context follows **Controller → Service → Repository → Database**: diff --git a/docs/en/development/architecture.md b/docs/en/development/architecture.md index 803d4209..65527753 100644 --- a/docs/en/development/architecture.md +++ b/docs/en/development/architecture.md @@ -19,7 +19,7 @@ Structured PHP monolith with a modular extension layer. | `src/Modules/` | Optional extension layer — loaded by `ModuleLoader` | | `src/Public/` | Front controller, router, controllers, views, assets | | `src/Cli/` | Console commands and cron entry points | -| `src/ministra/` | Stalker Portal — isolated subsystem (`BoundaryInterface`) | +| `src/ministra/` | Stalker Portal — isolated subsystem | --- diff --git a/docs/en/development/modules.md b/docs/en/development/modules.md index cf23d6c3..d1923d94 100644 --- a/docs/en/development/modules.md +++ b/docs/en/development/modules.md @@ -232,7 +232,7 @@ class MyModuleModule extends BaseModule { > **Tip:** a module with no routes, no navbar items, and no CLI commands only needs > `getName()`, `getVersion()`, and `boot()`. -> A `BoundaryInterface` module (isolated subsystem with its own entry point) typically +> An isolated-subsystem module (its own entry point and bootstrap, like Ministra) typically > leaves `boot()` and `registerRoutes()` inherited as no-ops. ### Method contract @@ -523,34 +523,31 @@ Under the hood: --- -## Isolated subsystems (BoundaryInterface) +## Isolated subsystems -A module that is a fully isolated subsystem with its own entry point and bootstrap -(like Ministra) implements `BoundaryInterface` alongside `ModuleInterface`: +A module can be a fully isolated subsystem with its own entry point and bootstrap +(like Ministra). This is a **convention**, not a marker interface — it stays an +ordinary `ModuleInterface`/`BaseModule` module: ```php -class MyModule implements ModuleInterface, BoundaryInterface { +class MyModule extends BaseModule { public function getName(): string { return 'my-module'; } - public function getEntryPoint(): string { - // Path relative to src/ — this file handles its own bootstrap - return 'my-module/portal.php'; - } - - public function isIsolated(): bool { - return true; + public function getVersion(): string { + return '1.0.0'; } } ``` -`BoundaryInterface` is an isolation marker. `isIsolated() = true` means the subsystem -runs through its own entry point with a separate bootstrap path. It shares infrastructure -(db, cache, config) but does **not** participate in the main `Router`, `ModuleLoader::bootAll()`, -or `NavbarRegistry`. The `boot()` and `registerRoutes()` implementations may be left as -no-ops in this case. +Isolation means the subsystem runs through its own public entry point (e.g. +`my-module/portal.php`, a path relative to `src/` that handles its own bootstrap) +with a separate bootstrap path. It shares infrastructure (db, cache, config) but +does **not** participate in the main `Router`, `ModuleLoader::bootAll()`, or +`NavbarRegistry`. The `boot()` and `registerRoutes()` implementations are typically +left as inherited no-ops. --- diff --git a/docs/ru/development/architecture.md b/docs/ru/development/architecture.md index 5a81ecc0..48d35100 100644 --- a/docs/ru/development/architecture.md +++ b/docs/ru/development/architecture.md @@ -19,7 +19,7 @@ | `src/Modules/` | Опциональный слой расширений — загружается `ModuleLoader` | | `src/Public/` | Front controller, router, controllers, views, assets | | `src/Cli/` | Консольные команды и точки входа для cron | -| `src/ministra/` | Stalker Portal — изолированная подсистема (`BoundaryInterface`) | +| `src/ministra/` | Stalker Portal — изолированная подсистема | --- diff --git a/docs/ru/development/modules.md b/docs/ru/development/modules.md index 538ef44d..8e3aec95 100644 --- a/docs/ru/development/modules.md +++ b/docs/ru/development/modules.md @@ -665,27 +665,19 @@ $manager->downloadFromPlatform(slug: 'my-module', version: '1.2.0', apiKey: $key --- -## Изолированные подсистемы (BoundaryInterface) +## Изолированные подсистемы -Если модуль является изолированной подсистемой с собственным bootstrap (как Ministra), он реализует `BoundaryInterface`: +Модуль может быть полностью изолированной подсистемой с собственной точкой входа и bootstrap (как Ministra). Это **соглашение**, а не маркер-интерфейс — он остаётся обычным модулем на `BaseModule`: ```php -class MyModule extends BaseModule implements BoundaryInterface { +class MyModule extends BaseModule { public function getName(): string { return 'my-module'; } public function getVersion(): string { return '1.0.0'; } - - public function getEntryPoint(): string { - return 'my-module/portal.php'; - } - - public function isIsolated(): bool { - return true; - } } ``` -`BoundaryInterface` — маркер изоляции. `isIsolated() = true` означает, что подсистема запускается через собственный entry point с отдельным bootstrap. +Изоляция означает, что подсистема запускается через собственную публичную точку входа (например, `my-module/portal.php`, путь относительно `src/` с отдельным bootstrap). Она делит инфраструктуру (БД, кэш, конфиг), но **не** участвует в основном `Router`, `ModuleLoader::bootAll()` и `NavbarRegistry`. --- diff --git a/src/Core/Boundary/BoundaryInterface.php b/src/Core/Boundary/BoundaryInterface.php deleted file mode 100644 index 655d5d66..00000000 --- a/src/Core/Boundary/BoundaryInterface.php +++ /dev/null @@ -1,41 +0,0 @@ - - * @copyright 2025-2026 Vateron Media - * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html - */ -interface BoundaryInterface { - - /** - * Unique boundary name (e.g. 'ministra', 'player'). - */ - public function getName(): string; - - /** - * Public entry-point path relative to src/ (e.g. 'ministra/portal.php'). - */ - public function getEntryPoint(): string; - - /** - * Whether this boundary has its own bootstrap, independent of XC_Bootstrap. - */ - public function isIsolated(): bool; -} diff --git a/src/Modules/ministra_85a7d/MinistraModule.php b/src/Modules/ministra_85a7d/MinistraModule.php index 0ef92f11..1b0beab7 100644 --- a/src/Modules/ministra_85a7d/MinistraModule.php +++ b/src/Modules/ministra_85a7d/MinistraModule.php @@ -2,7 +2,6 @@ namespace XcVm\Module\Ministra; -use XcVm\Core\Boundary\BoundaryInterface; use XcVm\Core\Module\BaseModule; /** @@ -40,7 +39,7 @@ use XcVm\Core\Module\BaseModule; * @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html */ -class MinistraModule extends BaseModule implements BoundaryInterface { +class MinistraModule extends BaseModule { public function getName(): string { return 'ministra'; @@ -49,12 +48,4 @@ class MinistraModule extends BaseModule implements BoundaryInterface { public function getVersion(): string { return '1.0.0'; } - - public function getEntryPoint(): string { - return 'ministra/portal.php'; - } - - public function isIsolated(): bool { - return true; - } } diff --git a/tests/Unit/ArchitectureTest.php b/tests/Unit/ArchitectureTest.php index 587c7780..d2acf684 100644 --- a/tests/Unit/ArchitectureTest.php +++ b/tests/Unit/ArchitectureTest.php @@ -106,7 +106,7 @@ final class ArchitectureTest extends TestCase { * Web-context module files must not use `global $db`. * * Exemptions: - * - ministra/ — BoundaryInterface subsystem with its own portal bootstrap (permanent) + * - ministra/ — isolated subsystem with its own portal bootstrap (permanent) */ public function testNoWebContextModuleUsesGlobalDb(): void { $ministraDir = $this->moduleDirBasename('ministra'); diff --git a/tests/Unit/InterfaceContractTest.php b/tests/Unit/InterfaceContractTest.php index 3fd564e5..3d4fb7db 100644 --- a/tests/Unit/InterfaceContractTest.php +++ b/tests/Unit/InterfaceContractTest.php @@ -2,7 +2,6 @@ use XcVm\Module\Ministra\MinistraModule; use XcVm\Cli\CommandRegistry; -use XcVm\Core\Boundary\BoundaryInterface; use XcVm\Core\Enum\ModuleState; use XcVm\Core\Events\ListensTo; use XcVm\Core\Events\EventDispatcher; @@ -110,30 +109,6 @@ final class InterfaceContractTest extends TestCase { $this->assertInterfaceMethod($rc, 'getStreamMiddleware', [], 'array'); } - // ── BoundaryInterface ───────────────────────────────────────── - - public function testBoundaryInterfaceHasCorrectMethods(): void { - $rc = new ReflectionClass(BoundaryInterface::class); - $this->assertTrue($rc->isInterface()); - - $this->assertInterfaceMethod($rc, 'getName', [], 'string'); - $this->assertInterfaceMethod($rc, 'getEntryPoint', [], 'string'); - $this->assertInterfaceMethod($rc, 'isIsolated', [], 'bool'); - } - - public function testBoundaryInterfaceHasExactlyThreeMethods(): void { - $rc = new ReflectionClass(BoundaryInterface::class); - $own = array_filter( - $rc->getMethods(ReflectionMethod::IS_PUBLIC), - fn(ReflectionMethod $m) => $m->getDeclaringClass()->getName() === BoundaryInterface::class - ); - $this->assertCount( - 3, - $own, - 'BoundaryInterface must have exactly 3 methods: getName, getEntryPoint, isIsolated' - ); - } - // ── MigratableInterface ─────────────────────────────────────── public function testMigratableInterfaceHasGetMigrations(): void { @@ -260,24 +235,6 @@ final class InterfaceContractTest extends TestCase { } } - // ── MinistraModule ──────────────────────────────────────────── - - public function testMinistraModuleImplementsBoundaryInterface(): void { - if (!class_exists(\XcVm\Module\Ministra\MinistraModule::class)) { - // Module directories use the `{name}_{hash5}` convention, so glob for the - // ministra dir rather than assuming a bare `Modules/ministra/` path. - $base = defined('MAIN_HOME') ? MAIN_HOME . 'Modules' : __DIR__ . '/../../src/Modules'; - $matches = glob($base . '/ministra*/MinistraModule.php'); - $file = $matches[0] ?? ($base . '/ministra/MinistraModule.php'); - require_once $file; - } - $rc = new ReflectionClass(\XcVm\Module\Ministra\MinistraModule::class); - $this->assertTrue( - $rc->implementsInterface(BoundaryInterface::class), - 'MinistraModule must implement BoundaryInterface' - ); - } - // ── ModuleState enum ────────────────────────────────────────── public function testModuleStateEnumExists(): void {