- 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.
286 lines
6.5 KiB
PHP
286 lines
6.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Svg\Builder;
|
|
|
|
use App\Framework\Core\ValueObjects\Dimensions;
|
|
use App\Framework\Filesystem\FileStorage;
|
|
use App\Framework\Svg\Elements\CircleElement;
|
|
use App\Framework\Svg\Elements\GroupElement;
|
|
use App\Framework\Svg\Elements\LineElement;
|
|
use App\Framework\Svg\Elements\RectElement;
|
|
use App\Framework\Svg\Elements\SvgElement;
|
|
use App\Framework\Svg\Elements\TextElement;
|
|
use App\Framework\Svg\ValueObjects\Geometry\Position;
|
|
use App\Framework\Svg\ValueObjects\Geometry\Radius;
|
|
use App\Framework\Svg\ValueObjects\Geometry\ViewBox;
|
|
use App\Framework\Svg\ValueObjects\Styling\Fill;
|
|
use App\Framework\Svg\ValueObjects\Styling\Stroke;
|
|
use App\Framework\Svg\ValueObjects\Text\TextContent;
|
|
use App\Framework\Svg\ValueObjects\Text\TextStyle;
|
|
use App\Framework\Svg\ValueObjects\Transform\Transform;
|
|
|
|
/**
|
|
* Mutable builder for creating SVG documents
|
|
* Uses fluent interface for convenient API
|
|
*/
|
|
final class SvgCanvas
|
|
{
|
|
/** @var array<SvgElement> */
|
|
private array $elements = [];
|
|
|
|
public function __construct(
|
|
private readonly Dimensions $dimensions,
|
|
private readonly ?ViewBox $viewBox = null,
|
|
private ?string $title = null,
|
|
private ?string $description = null,
|
|
private readonly ?FileStorage $fileStorage = null
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* Add rectangle to canvas
|
|
*/
|
|
public function rect(
|
|
Position $position,
|
|
Dimensions $dimensions,
|
|
Fill $fill,
|
|
?Stroke $stroke = null,
|
|
?Radius $rx = null,
|
|
?Radius $ry = null,
|
|
?Transform $transform = null,
|
|
?string $id = null,
|
|
?string $class = null
|
|
): self {
|
|
$this->elements[] = new RectElement(
|
|
$position,
|
|
$dimensions,
|
|
$fill,
|
|
$stroke,
|
|
$rx,
|
|
$ry,
|
|
$transform,
|
|
$id,
|
|
$class
|
|
);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add circle to canvas
|
|
*/
|
|
public function circle(
|
|
Position $center,
|
|
Radius $radius,
|
|
Fill $fill,
|
|
?Stroke $stroke = null,
|
|
?Transform $transform = null,
|
|
?string $id = null,
|
|
?string $class = null
|
|
): self {
|
|
$this->elements[] = new CircleElement(
|
|
$center,
|
|
$radius,
|
|
$fill,
|
|
$stroke,
|
|
$transform,
|
|
$id,
|
|
$class
|
|
);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add line to canvas
|
|
*/
|
|
public function line(
|
|
Position $start,
|
|
Position $end,
|
|
Stroke $stroke,
|
|
?Transform $transform = null,
|
|
?string $id = null,
|
|
?string $class = null
|
|
): self {
|
|
$this->elements[] = new LineElement(
|
|
$start,
|
|
$end,
|
|
$stroke,
|
|
$transform,
|
|
$id,
|
|
$class
|
|
);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add text to canvas
|
|
*/
|
|
public function text(
|
|
string $content,
|
|
Position $position,
|
|
TextStyle $style,
|
|
?Transform $transform = null,
|
|
?string $id = null,
|
|
?string $class = null
|
|
): self {
|
|
$this->elements[] = new TextElement(
|
|
new TextContent($content),
|
|
$position,
|
|
$style,
|
|
$transform,
|
|
$id,
|
|
$class
|
|
);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add group to canvas
|
|
*/
|
|
public function group(
|
|
array $children,
|
|
?Transform $transform = null,
|
|
?string $id = null,
|
|
?string $class = null
|
|
): self {
|
|
$this->elements[] = new GroupElement(
|
|
$children,
|
|
$transform,
|
|
$id,
|
|
$class
|
|
);
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Add custom element to canvas
|
|
*/
|
|
public function element(SvgElement $element): self
|
|
{
|
|
$this->elements[] = $element;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set title for accessibility
|
|
*/
|
|
public function withTitle(string $title): self
|
|
{
|
|
$this->title = $title;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Set description for accessibility
|
|
*/
|
|
public function withDescription(string $description): self
|
|
{
|
|
$this->description = $description;
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get all elements
|
|
*/
|
|
public function getElements(): array
|
|
{
|
|
return $this->elements;
|
|
}
|
|
|
|
/**
|
|
* Clear all elements
|
|
*/
|
|
public function clear(): self
|
|
{
|
|
$this->elements = [];
|
|
|
|
return $this;
|
|
}
|
|
|
|
/**
|
|
* Get element count
|
|
*/
|
|
public function count(): int
|
|
{
|
|
return count($this->elements);
|
|
}
|
|
|
|
/**
|
|
* Render complete SVG document
|
|
*/
|
|
public function toSvg(): string
|
|
{
|
|
$svgAttributes = [
|
|
'width' => (string) $this->dimensions->width,
|
|
'height' => (string) $this->dimensions->height,
|
|
'xmlns' => 'http://www.w3.org/2000/svg',
|
|
];
|
|
|
|
if ($this->viewBox !== null) {
|
|
$svgAttributes['viewBox'] = $this->viewBox->toSvgAttribute();
|
|
}
|
|
|
|
$attributeString = $this->buildAttributeString($svgAttributes);
|
|
|
|
$svg = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
|
|
$svg .= "<svg {$attributeString}>\n";
|
|
|
|
// Add accessibility elements
|
|
if ($this->title !== null) {
|
|
$svg .= " <title>" . htmlspecialchars($this->title, ENT_XML1, 'UTF-8') . "</title>\n";
|
|
}
|
|
|
|
if ($this->description !== null) {
|
|
$svg .= " <desc>" . htmlspecialchars($this->description, ENT_XML1, 'UTF-8') . "</desc>\n";
|
|
}
|
|
|
|
// Add all elements
|
|
foreach ($this->elements as $element) {
|
|
$svg .= " " . $element->toSvg() . "\n";
|
|
}
|
|
|
|
$svg .= "</svg>";
|
|
|
|
return $svg;
|
|
}
|
|
|
|
/**
|
|
* Render to inline SVG (without XML declaration)
|
|
*/
|
|
public function toInlineSvg(): string
|
|
{
|
|
$svg = $this->toSvg();
|
|
|
|
// Remove XML declaration
|
|
return preg_replace('/<\?xml[^?]*\?>\s*/', '', $svg) ?? $svg;
|
|
}
|
|
|
|
/**
|
|
* Export to file using Framework's FileStorage
|
|
*/
|
|
public function toFile(string $filepath): void
|
|
{
|
|
$storage = $this->fileStorage ?? new FileStorage();
|
|
$storage->put($filepath, $this->toSvg());
|
|
}
|
|
|
|
private function buildAttributeString(array $attributes): string
|
|
{
|
|
$parts = [];
|
|
foreach ($attributes as $key => $value) {
|
|
$parts[] = sprintf('%s="%s"', $key, htmlspecialchars((string) $value, ENT_QUOTES, 'UTF-8'));
|
|
}
|
|
|
|
return implode(' ', $parts);
|
|
}
|
|
}
|