- 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.
121 lines
2.6 KiB
PHP
121 lines
2.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Svg\Charts\ValueObjects;
|
|
|
|
use App\Framework\Exception\ErrorCode;
|
|
use App\Framework\Exception\FrameworkException;
|
|
|
|
/**
|
|
* Value Object representing chart data
|
|
*/
|
|
final readonly class ChartData
|
|
{
|
|
/**
|
|
* @param array<DataPoint> $points
|
|
*/
|
|
public function __construct(
|
|
public array $points
|
|
) {
|
|
if (empty($points)) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'Chart data cannot be empty'
|
|
);
|
|
}
|
|
|
|
// Validate all points are DataPoint instances
|
|
foreach ($points as $point) {
|
|
if (!$point instanceof DataPoint) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'All chart data points must be DataPoint instances'
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create from array of values with labels
|
|
*/
|
|
public static function fromArray(array $data): self
|
|
{
|
|
$points = [];
|
|
foreach ($data as $label => $value) {
|
|
$points[] = new DataPoint((string) $label, (float) $value);
|
|
}
|
|
|
|
return new self($points);
|
|
}
|
|
|
|
/**
|
|
* Get point count
|
|
*/
|
|
public function count(): int
|
|
{
|
|
return count($this->points);
|
|
}
|
|
|
|
/**
|
|
* Get minimum value
|
|
*/
|
|
public function getMinValue(): float
|
|
{
|
|
return min(array_map(fn (DataPoint $p) => $p->value, $this->points));
|
|
}
|
|
|
|
/**
|
|
* Get maximum value
|
|
*/
|
|
public function getMaxValue(): float
|
|
{
|
|
return max(array_map(fn (DataPoint $p) => $p->value, $this->points));
|
|
}
|
|
|
|
/**
|
|
* Get sum of all values
|
|
*/
|
|
public function getSum(): float
|
|
{
|
|
return array_sum(array_map(fn (DataPoint $p) => $p->value, $this->points));
|
|
}
|
|
|
|
/**
|
|
* Get average value
|
|
*/
|
|
public function getAverage(): float
|
|
{
|
|
return $this->getSum() / $this->count();
|
|
}
|
|
|
|
/**
|
|
* Normalize values to 0-1 range
|
|
*/
|
|
public function normalize(): self
|
|
{
|
|
$min = $this->getMinValue();
|
|
$max = $this->getMaxValue();
|
|
$range = $max - $min;
|
|
|
|
if ($range === 0.0) {
|
|
return $this;
|
|
}
|
|
|
|
$normalized = array_map(
|
|
fn (DataPoint $p) => new DataPoint(
|
|
$p->label,
|
|
($p->value - $min) / $range
|
|
),
|
|
$this->points
|
|
);
|
|
|
|
return new self($normalized);
|
|
}
|
|
|
|
public function toArray(): array
|
|
{
|
|
return array_map(fn (DataPoint $p) => $p->toArray(), $this->points);
|
|
}
|
|
}
|