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:
2026-04-14 08:23:04 +02:00
parent 143d887a5c
commit b1a907b79c
10 changed files with 604 additions and 24 deletions

View File

@@ -3,6 +3,7 @@
namespace MintyPHP\Service\Auth;
use MintyPHP\App\Module\ModuleEventDispatcher;
use MintyPHP\App\Module\ModuleEvents;
use MintyPHP\Auth;
use MintyPHP\Http\SessionStoreInterface;
use MintyPHP\Repository\User\UserReadRepositoryInterface;
@@ -132,7 +133,7 @@ class AuthService
'actor_tenant_id' => $this->currentTenantIdFromSession(),
]);
$this->eventDispatcher?->dispatch('user.login', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_LOGIN, [
'user_id' => $userId,
'provider' => 'local',
]);
@@ -226,7 +227,7 @@ class AuthService
'metadata' => ['provider' => $loginProvider],
]);
$this->eventDispatcher?->dispatch('user.login', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_LOGIN, [
'user_id' => $userId,
'provider' => $loginProvider,
]);
@@ -290,7 +291,7 @@ class AuthService
$actorUserId = (int) ($this->sessionUser()['id'] ?? 0);
$actorTenantId = $this->currentTenantIdFromSession();
$this->eventDispatcher?->dispatch('user.logout', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_LOGOUT, [
'user_id' => $actorUserId,
]);

View File

@@ -3,6 +3,7 @@
namespace MintyPHP\Service\Scheduler;
use MintyPHP\App\Module\ModuleEventDispatcher;
use MintyPHP\App\Module\ModuleEvents;
use MintyPHP\Domain\Taxonomy\ScheduledJobRunStatus;
use MintyPHP\Domain\Taxonomy\ScheduledJobTriggerType;
use MintyPHP\Domain\Taxonomy\SchedulerRuntimeResult;
@@ -423,7 +424,7 @@ class SchedulerRunService
}
try {
$this->eventDispatcher->dispatch('scheduler.job_failed', [
$this->eventDispatcher->dispatch(ModuleEvents::SCHEDULER_JOB_FAILED, [
'job_id' => (int) ($job['id'] ?? 0),
'job_key' => (string) ($job['job_key'] ?? ''),
'label' => (string) ($job['label'] ?? ''),

View File

@@ -3,6 +3,7 @@
namespace MintyPHP\Service\User;
use MintyPHP\App\Module\ModuleEventDispatcher;
use MintyPHP\App\Module\ModuleEvents;
use MintyPHP\I18n;
use MintyPHP\Repository\Support\DatabaseSessionRepository;
use MintyPHP\Repository\User\UserListQueryRepositoryInterface;
@@ -118,7 +119,7 @@ class UserAccountService
'target_uuid' => (string) ($user['uuid'] ?? ''),
]);
$this->eventDispatcher?->dispatch('user.deleted', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_DELETED, [
'user_id' => $userId,
'uuid' => (string) ($user['uuid'] ?? ''),
'actor_user_id' => $currentUserId,
@@ -191,7 +192,7 @@ class UserAccountService
]);
foreach ($deletedUsers as $deletedUser) {
$this->eventDispatcher?->dispatch('user.deleted', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_DELETED, [
'user_id' => (int) $deletedUser['id'],
'uuid' => (string) $deletedUser['uuid'],
'actor_user_id' => $currentUserId,
@@ -336,7 +337,7 @@ class UserAccountService
],
]);
$this->eventDispatcher?->dispatch('user.created', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_CREATED, [
'user_id' => $userId,
'uuid' => is_string($uuid) ? $uuid : '',
'actor_user_id' => $currentUserId,
@@ -467,7 +468,7 @@ class UserAccountService
$tenantIds = $this->extractTenantIdsFromAssignments(
$this->safeAssignmentsForUser($userId)
);
$eventType = ((int) $form['active'] === 1) ? 'user.activated' : 'user.deactivated';
$eventType = ((int) $form['active'] === 1) ? ModuleEvents::USER_ACTIVATED : ModuleEvents::USER_DEACTIVATED;
$this->eventDispatcher?->dispatch($eventType, [
'user_id' => $userId,
'uuid' => (string) ($existing['uuid'] ?? ''),
@@ -521,7 +522,7 @@ class UserAccountService
$tenantIds = $this->extractTenantIdsFromAssignments(
$this->safeAssignmentsForUser($userId)
);
$this->eventDispatcher?->dispatch($active ? 'user.activated' : 'user.deactivated', [
$this->eventDispatcher?->dispatch($active ? ModuleEvents::USER_ACTIVATED : ModuleEvents::USER_DEACTIVATED, [
'user_id' => $userId,
'uuid' => (string) ($user['uuid'] ?? ''),
'display_name' => trim((string) ($user['display_name'] ?? '')),
@@ -587,7 +588,7 @@ class UserAccountService
$tenantIds = $this->extractTenantIdsFromAssignments(
$this->safeAssignmentsForUser($targetUserId)
);
$this->eventDispatcher?->dispatch($active ? 'user.activated' : 'user.deactivated', [
$this->eventDispatcher?->dispatch($active ? ModuleEvents::USER_ACTIVATED : ModuleEvents::USER_DEACTIVATED, [
'user_id' => $targetUserId,
'uuid' => (string) ($user['uuid'] ?? ''),
'display_name' => trim((string) ($user['display_name'] ?? '')),
@@ -801,7 +802,7 @@ class UserAccountService
return;
}
$this->eventDispatcher?->dispatch('user.assignment_changed', [
$this->eventDispatcher?->dispatch(ModuleEvents::USER_ASSIGNMENT_CHANGED, [
'user_id' => $userId,
'uuid' => (string) ($user['uuid'] ?? ''),
'display_name' => trim((string) ($user['display_name'] ?? '')),