refactor(di): add analysis components for dependency parsing and resolution

- Introduce `CodeParser` to extract dependencies from `container->get()` calls and `return new` statements.
- Add `DependencyPathAnalyzer` for recursive analysis of dependency paths with cycle detection.
- Implement `InitializerFinder` to locate initializers based on naming conventions.
- Include `InterfaceResolver` to determine interface implementations using introspection and initializers.
- Add `NamespaceResolver` for resolving class names from use statements and namespaces.
- Introduce `ReturnTypeAnalyzer` for method and closure return type analysis.
This commit is contained in:
2025-11-03 22:38:06 +01:00
parent 703d9b04fe
commit a93a086ee4
12 changed files with 1120 additions and 838 deletions

View File

@@ -2,7 +2,9 @@
declare(strict_types=1);
use App\Framework\Http\Session\SessionInterface;
use App\Framework\DateTime\SystemClock;
use App\Framework\Http\Session\Session;
use App\Framework\Http\Session\SessionId;
use App\Framework\LiveComponents\ComponentEventDispatcher;
use App\Framework\LiveComponents\Contracts\LiveComponentContract;
use App\Framework\LiveComponents\LiveComponentHandler;
@@ -10,74 +12,20 @@ use App\Framework\LiveComponents\ValueObjects\ActionParameters;
use App\Framework\LiveComponents\ValueObjects\ComponentAction;
use App\Framework\LiveComponents\ValueObjects\ComponentData;
use App\Framework\LiveComponents\ValueObjects\ComponentId;
use App\Framework\Random\SecureRandomGenerator;
use App\Framework\Security\CsrfToken;
use App\Framework\Security\CsrfTokenGenerator;
use App\Framework\View\LiveComponentRenderer;
use App\Framework\View\TemplateRenderer;
use App\Framework\View\Loading\TemplateLoader;
use App\Framework\View\TemplateProcessor;
beforeEach(function () {
// Create mock SessionInterface for CSRF testing
$this->session = new class () implements SessionInterface {
private array $tokens = [];
public function __get(string $name): mixed
{
if ($name === 'csrf') {
return new class ($this) {
public function __construct(private $session)
{
}
public function generateToken(string $formId): CsrfToken
{
$token = CsrfToken::generate();
$this->session->tokens[$formId] = $token->toString();
return $token;
}
public function validateToken(string $formId, CsrfToken $token): bool
{
return isset($this->session->tokens[$formId])
&& hash_equals($this->session->tokens[$formId], $token->toString());
}
};
}
return null;
}
public function get(string $key, mixed $default = null): mixed
{
return $default;
}
public function set(string $key, mixed $value): void
{
}
public function has(string $key): bool
{
return false;
}
public function remove(string $key): void
{
}
public function regenerate(): bool
{
return true;
}
public function destroy(): void
{
}
public function getId(): string
{
return 'test-session-id';
}
};
$this->session = Session::fromArray(
SessionId::fromString(str_repeat('a', 32)),
new SystemClock(),
new CsrfTokenGenerator(new SecureRandomGenerator()),
[]
);
$this->eventDispatcher = new ComponentEventDispatcher();
$this->handler = new LiveComponentHandler($this->eventDispatcher, $this->session);
@@ -86,7 +34,8 @@ beforeEach(function () {
describe('CSRF Token Generation', function () {
it('generates unique CSRF token for each component instance', function () {
$renderer = new LiveComponentRenderer(
$this->createMock(TemplateRenderer::class),
$this->createMock(TemplateLoader::class),
$this->createMock(TemplateProcessor::class),
$this->session
);
@@ -126,7 +75,8 @@ describe('CSRF Token Generation', function () {
it('includes CSRF token in rendered wrapper HTML', function () {
$renderer = new LiveComponentRenderer(
$this->createMock(TemplateRenderer::class),
$this->createMock(TemplateLoader::class),
$this->createMock(TemplateProcessor::class),
$this->session
);
@@ -465,7 +415,8 @@ describe('End-to-End CSRF Flow', function () {
it('completes full CSRF flow from render to action execution', function () {
// Step 1: Render component with CSRF token
$renderer = new LiveComponentRenderer(
$this->createMock(TemplateRenderer::class),
$this->createMock(TemplateLoader::class),
$this->createMock(TemplateProcessor::class),
$this->session
);