forked from fa/breadcrumb-the-shire
feat(modules): harden module platform with event constants, validation checks, and CLI improvements
- Add ModuleEvents constants class with all 8 event strings; update dispatch call sites - ValidateCommand: check AuthorizationPolicy container registration (check 20) - ValidateCommand: warn on unknown event_listeners keys (check 21) - make:module --simple flag for minimal manifests - module:deactivate reverse-dependency warning - 12 new PHPUnit tests covering all improvements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ use MintyPHP\App\Module\Contracts\LayoutContextProvider;
|
||||
use MintyPHP\App\Module\Contracts\ModuleDeactivationHandler;
|
||||
use MintyPHP\App\Module\Contracts\SearchResourceProvider;
|
||||
use MintyPHP\App\Module\Contracts\SessionProvider;
|
||||
use MintyPHP\App\Module\ModuleEvents;
|
||||
use MintyPHP\App\Module\ModuleManifestLoader;
|
||||
use MintyPHP\Console\Command;
|
||||
use MintyPHP\Service\Access\AuthorizationPolicyInterface;
|
||||
@@ -292,9 +293,63 @@ final class ValidateCommand extends Command
|
||||
}
|
||||
}
|
||||
|
||||
// 20. AuthorizationPolicy classes referenced in ContainerRegistrar source
|
||||
$registrarSources = $this->loadRegistrarSources($moduleDir, $manifest->containerRegistrars);
|
||||
foreach ($manifest->authorizationPolicies as $policyClass) {
|
||||
if (!class_exists($policyClass)) {
|
||||
continue; // Already reported by check 9
|
||||
}
|
||||
$shortName = (new \ReflectionClass($policyClass))->getShortName();
|
||||
$found = false;
|
||||
foreach ($registrarSources as $source) {
|
||||
if (str_contains($source, $shortName)) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!$found) {
|
||||
$warnings[] = "AuthorizationPolicy '{$shortName}' is not referenced in any ContainerRegistrar — may not be registered in the container";
|
||||
}
|
||||
}
|
||||
|
||||
// 21. Event listener keys reference known events
|
||||
$knownEvents = ModuleEvents::all();
|
||||
foreach ($manifest->eventListeners as $eventName => $handlers) {
|
||||
if (!in_array($eventName, $knownEvents, true)) {
|
||||
$warnings[] = "Event listener subscribes to unknown event '{$eventName}' — not defined in ModuleEvents";
|
||||
}
|
||||
}
|
||||
|
||||
return [$errors, $warnings];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<class-string> $registrarClasses
|
||||
* @return list<string> Source code of each registrar file
|
||||
*/
|
||||
private function loadRegistrarSources(string $moduleDir, array $registrarClasses): array
|
||||
{
|
||||
$sources = [];
|
||||
foreach ($registrarClasses as $class) {
|
||||
if (!class_exists($class)) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
$refClass = new \ReflectionClass($class);
|
||||
$file = $refClass->getFileName();
|
||||
if ($file !== false && is_file($file)) {
|
||||
$content = file_get_contents($file);
|
||||
if ($content !== false) {
|
||||
$sources[] = $content;
|
||||
}
|
||||
}
|
||||
} catch (\ReflectionException) {
|
||||
// Skip unresolvable classes
|
||||
}
|
||||
}
|
||||
return $sources;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<string> &$errors
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user