- Add comprehensive health check system with multiple endpoints - Add Prometheus metrics endpoint - Add production logging configurations (5 strategies) - Add complete deployment documentation suite: * QUICKSTART.md - 30-minute deployment guide * DEPLOYMENT_CHECKLIST.md - Printable verification checklist * DEPLOYMENT_WORKFLOW.md - Complete deployment lifecycle * PRODUCTION_DEPLOYMENT.md - Comprehensive technical reference * production-logging.md - Logging configuration guide * ANSIBLE_DEPLOYMENT.md - Infrastructure as Code automation * README.md - Navigation hub * DEPLOYMENT_SUMMARY.md - Executive summary - Add deployment scripts and automation - Add DEPLOYMENT_PLAN.md - Concrete plan for immediate deployment - Update README with production-ready features All production infrastructure is now complete and ready for deployment.
265 lines
7.1 KiB
PHP
265 lines
7.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Application\LiveComponents\Chart;
|
|
|
|
use App\Application\LiveComponents\LiveComponentState;
|
|
|
|
/**
|
|
* Type-safe state for ChartComponent
|
|
*
|
|
* Provides compile-time type safety for real-time chart visualization.
|
|
* All properties are readonly and immutable - transformations return new instances.
|
|
*/
|
|
final readonly class ChartState implements LiveComponentState
|
|
{
|
|
public function __construct(
|
|
public string $chartType = 'line',
|
|
public array $chartData = [],
|
|
public string $dataRange = '24h',
|
|
public int $lastUpdate = 0,
|
|
public bool $autoRefresh = true,
|
|
public int $refreshInterval = 5000,
|
|
public float $executionTimeMs = 0,
|
|
public int $dataPointsCount = 0,
|
|
public string $dataSource = 'demo'
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Create from ComponentData (Framework → Domain conversion)
|
|
*/
|
|
public static function fromArray(array $data): self
|
|
{
|
|
return new self(
|
|
chartType: (string) ($data['chart_type'] ?? 'line'),
|
|
chartData: ($data['chart_data'] ?? []),
|
|
dataRange: (string) ($data['data_range'] ?? '24h'),
|
|
lastUpdate: (int) ($data['last_update'] ?? 0),
|
|
autoRefresh: (bool) ($data['auto_refresh'] ?? true),
|
|
refreshInterval: (int) ($data['refresh_interval'] ?? 5000),
|
|
executionTimeMs: (float) ($data['execution_time_ms'] ?? 0),
|
|
dataPointsCount: (int) ($data['data_points_count'] ?? 0),
|
|
dataSource: (string) ($data['data_source'] ?? 'demo')
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Create empty state with defaults
|
|
*/
|
|
public static function empty(): self
|
|
{
|
|
return new self();
|
|
}
|
|
|
|
/**
|
|
* Convert to ComponentData (Domain → Framework conversion)
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'chart_type' => $this->chartType,
|
|
'chart_data' => $this->chartData,
|
|
'data_range' => $this->dataRange,
|
|
'last_update' => $this->lastUpdate,
|
|
'auto_refresh' => $this->autoRefresh,
|
|
'refresh_interval' => $this->refreshInterval,
|
|
'execution_time_ms' => $this->executionTimeMs,
|
|
'data_points_count' => $this->dataPointsCount,
|
|
'data_source' => $this->dataSource,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Update chart with refreshed data
|
|
*/
|
|
public function withRefreshedData(array $chartData, float $executionTimeMs): self
|
|
{
|
|
return new self(
|
|
chartType: $this->chartType,
|
|
chartData: $chartData,
|
|
dataRange: $this->dataRange,
|
|
lastUpdate: time(),
|
|
autoRefresh: $this->autoRefresh,
|
|
refreshInterval: $this->refreshInterval,
|
|
executionTimeMs: $executionTimeMs,
|
|
dataPointsCount: $this->calculateDataPointsCount($chartData),
|
|
dataSource: $this->dataSource
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Change chart type
|
|
*/
|
|
public function withChartType(string $chartType, array $chartData): self
|
|
{
|
|
return new self(
|
|
chartType: $chartType,
|
|
chartData: $chartData,
|
|
dataRange: $this->dataRange,
|
|
lastUpdate: time(),
|
|
autoRefresh: $this->autoRefresh,
|
|
refreshInterval: $this->refreshInterval,
|
|
executionTimeMs: 0,
|
|
dataPointsCount: $this->calculateDataPointsCount($chartData),
|
|
dataSource: $this->dataSource
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Change data range
|
|
*/
|
|
public function withDataRange(string $dataRange, array $chartData): self
|
|
{
|
|
return new self(
|
|
chartType: $this->chartType,
|
|
chartData: $chartData,
|
|
dataRange: $dataRange,
|
|
lastUpdate: time(),
|
|
autoRefresh: $this->autoRefresh,
|
|
refreshInterval: $this->refreshInterval,
|
|
executionTimeMs: 0,
|
|
dataPointsCount: $this->calculateDataPointsCount($chartData),
|
|
dataSource: $this->dataSource
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Toggle auto-refresh
|
|
*/
|
|
public function withToggledAutoRefresh(): self
|
|
{
|
|
return new self(
|
|
chartType: $this->chartType,
|
|
chartData: $this->chartData,
|
|
dataRange: $this->dataRange,
|
|
lastUpdate: $this->lastUpdate,
|
|
autoRefresh: ! $this->autoRefresh,
|
|
refreshInterval: $this->refreshInterval,
|
|
executionTimeMs: $this->executionTimeMs,
|
|
dataPointsCount: $this->dataPointsCount,
|
|
dataSource: $this->dataSource
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Calculate data points count from chart data
|
|
*/
|
|
private function calculateDataPointsCount(array $chartData): int
|
|
{
|
|
if (empty($chartData)) {
|
|
return 0;
|
|
}
|
|
|
|
return count($chartData['labels'] ?? []);
|
|
}
|
|
|
|
/**
|
|
* Check if has chart data
|
|
*/
|
|
public function hasChartData(): bool
|
|
{
|
|
return ! empty($this->chartData);
|
|
}
|
|
|
|
/**
|
|
* Get chart data as JSON
|
|
*/
|
|
public function getChartDataJson(): string
|
|
{
|
|
return ! empty($this->chartData) ? json_encode($this->chartData) : '{}';
|
|
}
|
|
|
|
/**
|
|
* Format last update timestamp
|
|
*/
|
|
public function getFormattedLastUpdate(): string
|
|
{
|
|
if ($this->lastUpdate === 0) {
|
|
return 'Noch nicht aktualisiert';
|
|
}
|
|
|
|
$diff = time() - $this->lastUpdate;
|
|
|
|
if ($diff < 60) {
|
|
return 'Gerade eben';
|
|
}
|
|
|
|
if ($diff < 3600) {
|
|
$minutes = floor($diff / 60);
|
|
|
|
return "Vor {$minutes} Minute" . ($minutes > 1 ? 'n' : '');
|
|
}
|
|
|
|
if ($diff < 86400) {
|
|
$hours = floor($diff / 3600);
|
|
|
|
return "Vor {$hours} Stunde" . ($hours > 1 ? 'n' : '');
|
|
}
|
|
|
|
return date('d.m.Y H:i', $this->lastUpdate);
|
|
}
|
|
|
|
/**
|
|
* Get auto-refresh status text
|
|
*/
|
|
public function getAutoRefreshText(): string
|
|
{
|
|
return $this->autoRefresh ? 'Auto-Refresh aktiv' : 'Auto-Refresh pausiert';
|
|
}
|
|
|
|
/**
|
|
* Get auto-refresh button text
|
|
*/
|
|
public function getAutoRefreshButtonText(): string
|
|
{
|
|
return $this->autoRefresh ? 'Pausieren' : 'Starten';
|
|
}
|
|
|
|
/**
|
|
* Get auto-refresh button CSS class
|
|
*/
|
|
public function getAutoRefreshButtonClass(): string
|
|
{
|
|
return $this->autoRefresh ? 'btn-warning' : 'btn-success';
|
|
}
|
|
|
|
/**
|
|
* Get data points text
|
|
*/
|
|
public function getDataPointsText(): string
|
|
{
|
|
if ($this->dataPointsCount === 0) {
|
|
return 'Keine Datenpunkte';
|
|
}
|
|
|
|
return $this->dataPointsCount === 1 ? '1 Datenpunkt' : "{$this->dataPointsCount} Datenpunkte";
|
|
}
|
|
|
|
/**
|
|
* Check if should show refresh button
|
|
*/
|
|
public function shouldShowRefreshButton(): bool
|
|
{
|
|
return ! $this->autoRefresh;
|
|
}
|
|
|
|
/**
|
|
* Check if should show performance metrics
|
|
*/
|
|
public function shouldShowPerformanceMetrics(): bool
|
|
{
|
|
return $this->executionTimeMs > 0;
|
|
}
|
|
|
|
/**
|
|
* Get chart container CSS class
|
|
*/
|
|
public function getChartContainerClass(): string
|
|
{
|
|
return 'chart-container chart-type-' . $this->chartType;
|
|
}
|
|
|
|
}
|