feat: CI/CD pipeline setup complete - Ansible playbooks updated, secrets configured, workflow ready
This commit is contained in:
177
src/Framework/LiveComponents/Polling/PollableClosureRegistry.php
Normal file
177
src/Framework/LiveComponents/Polling/PollableClosureRegistry.php
Normal file
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\LiveComponents\Polling;
|
||||
|
||||
use App\Framework\LiveComponents\ValueObjects\ComponentId;
|
||||
|
||||
/**
|
||||
* Registry for tracking PollableClosure instances in templates.
|
||||
*
|
||||
* Maintains a mapping of PollIds to their pollable closure registrations
|
||||
* for automatic JavaScript generation and endpoint registration.
|
||||
*/
|
||||
final class PollableClosureRegistry
|
||||
{
|
||||
/** @var array<string, PollableClosureRegistration> */
|
||||
private array $registrations = [];
|
||||
|
||||
/**
|
||||
* Register a pollable closure.
|
||||
*
|
||||
* @param string $templateKey Template variable key (e.g., 'notifications')
|
||||
* @param PollableClosure $closure The pollable closure
|
||||
* @param ComponentId|null $componentId Optional component ID for scoping
|
||||
* @return PollableClosureRegistration
|
||||
*/
|
||||
public function register(
|
||||
string $templateKey,
|
||||
PollableClosure $closure,
|
||||
?ComponentId $componentId = null
|
||||
): PollableClosureRegistration {
|
||||
$pollId = $this->generatePollId($templateKey, $componentId);
|
||||
|
||||
$registration = new PollableClosureRegistration(
|
||||
pollId: $pollId,
|
||||
closure: $closure,
|
||||
templateKey: $templateKey,
|
||||
componentId: $componentId
|
||||
);
|
||||
|
||||
$this->registrations[$pollId->value] = $registration;
|
||||
|
||||
return $registration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a registration by poll ID.
|
||||
*/
|
||||
public function get(PollId $pollId): ?PollableClosureRegistration
|
||||
{
|
||||
return $this->registrations[$pollId->value] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a poll ID exists.
|
||||
*/
|
||||
public function has(PollId $pollId): bool
|
||||
{
|
||||
return isset($this->registrations[$pollId->value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered closures.
|
||||
*
|
||||
* @return array<PollableClosureRegistration>
|
||||
*/
|
||||
public function getAll(): array
|
||||
{
|
||||
return array_values($this->registrations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all enabled registrations.
|
||||
*
|
||||
* @return array<PollableClosureRegistration>
|
||||
*/
|
||||
public function getEnabled(): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
$this->registrations,
|
||||
fn(PollableClosureRegistration $reg) => $reg->shouldPoll()
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get registrations for specific component.
|
||||
*
|
||||
* @return array<PollableClosureRegistration>
|
||||
*/
|
||||
public function getForComponent(ComponentId $componentId): array
|
||||
{
|
||||
return array_values(array_filter(
|
||||
$this->registrations,
|
||||
fn(PollableClosureRegistration $reg) => $reg->isForComponent($componentId)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a closure by poll ID.
|
||||
*
|
||||
* @throws \RuntimeException if poll ID not found or closure throws
|
||||
*/
|
||||
public function execute(PollId $pollId): mixed
|
||||
{
|
||||
$registration = $this->get($pollId);
|
||||
|
||||
if ($registration === null) {
|
||||
throw new \RuntimeException("Poll ID '{$pollId}' not found");
|
||||
}
|
||||
|
||||
try {
|
||||
return $registration->execute();
|
||||
} catch (\Throwable $e) {
|
||||
throw new \RuntimeException(
|
||||
"Failed to execute pollable closure '{$pollId}': {$e->getMessage()}",
|
||||
previous: $e
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a closure.
|
||||
*/
|
||||
public function unregister(PollId $pollId): void
|
||||
{
|
||||
unset($this->registrations[$pollId->value]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all registered closures.
|
||||
*/
|
||||
public function clear(): void
|
||||
{
|
||||
$this->registrations = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of registered closures.
|
||||
*/
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->registrations);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unique poll ID.
|
||||
*/
|
||||
private function generatePollId(string $templateKey, ?ComponentId $componentId): PollId
|
||||
{
|
||||
if ($componentId !== null) {
|
||||
return PollId::forClosure($templateKey, $componentId->toString());
|
||||
}
|
||||
|
||||
return PollId::forClosure($templateKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get polling metadata for JavaScript generation.
|
||||
*
|
||||
* @return array<string, array{template_key: string, interval: int, event: ?string, endpoint: string, component_id: ?string}>
|
||||
*/
|
||||
public function getPollingMetadata(): array
|
||||
{
|
||||
$metadata = [];
|
||||
|
||||
foreach ($this->registrations as $pollIdString => $registration) {
|
||||
if (!$registration->shouldPoll()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$metadata[$pollIdString] = $registration->getMetadata();
|
||||
}
|
||||
|
||||
return $metadata;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user