- 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.
201 lines
4.9 KiB
PHP
201 lines
4.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\Core\ValueObjects;
|
|
|
|
use App\Framework\Exception\ErrorCode;
|
|
use App\Framework\Exception\FrameworkException;
|
|
|
|
/**
|
|
* Value Object representing dimensions (width and height)
|
|
* Can be used for images, videos, HTML elements, etc.
|
|
*/
|
|
final readonly class Dimensions
|
|
{
|
|
public function __construct(
|
|
public int $width,
|
|
public int $height
|
|
) {
|
|
if ($width <= 0) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'Width must be greater than 0'
|
|
)->withData(['width' => $width]);
|
|
}
|
|
|
|
if ($height <= 0) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'Height must be greater than 0'
|
|
)->withData(['height' => $height]);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Create from image file
|
|
*/
|
|
public static function fromImageFile(string $filepath): self
|
|
{
|
|
$imageInfo = getimagesize($filepath);
|
|
|
|
if ($imageInfo === false) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'Could not read dimensions from image file'
|
|
)->withData(['filepath' => $filepath]);
|
|
}
|
|
|
|
return new self($imageInfo[0], $imageInfo[1]);
|
|
}
|
|
|
|
/**
|
|
* Create from array [width, height]
|
|
*/
|
|
public static function fromArray(array $data): self
|
|
{
|
|
if (count($data) !== 2) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'Dimensions array must contain exactly 2 elements [width, height]'
|
|
)->withData(['data' => $data]);
|
|
}
|
|
|
|
return new self((int) $data[0], (int) $data[1]);
|
|
}
|
|
|
|
/**
|
|
* Calculate aspect ratio
|
|
*/
|
|
public function getAspectRatio(): float
|
|
{
|
|
return $this->width / $this->height;
|
|
}
|
|
|
|
/**
|
|
* Get orientation
|
|
*/
|
|
public function getOrientation(): Orientation
|
|
{
|
|
if ($this->height > $this->width) {
|
|
return Orientation::PORTRAIT;
|
|
}
|
|
|
|
if ($this->width > $this->height) {
|
|
return Orientation::LANDSCAPE;
|
|
}
|
|
|
|
return Orientation::SQUARE;
|
|
}
|
|
|
|
/**
|
|
* Check if dimensions are portrait orientation
|
|
*/
|
|
public function isPortrait(): bool
|
|
{
|
|
return $this->getOrientation() === Orientation::PORTRAIT;
|
|
}
|
|
|
|
/**
|
|
* Check if dimensions are landscape orientation
|
|
*/
|
|
public function isLandscape(): bool
|
|
{
|
|
return $this->getOrientation() === Orientation::LANDSCAPE;
|
|
}
|
|
|
|
/**
|
|
* Check if dimensions are square
|
|
*/
|
|
public function isSquare(): bool
|
|
{
|
|
return $this->getOrientation() === Orientation::SQUARE;
|
|
}
|
|
|
|
/**
|
|
* Get total area (width * height)
|
|
*/
|
|
public function getArea(): int
|
|
{
|
|
return $this->width * $this->height;
|
|
}
|
|
|
|
/**
|
|
* Scale dimensions proportionally to fit within max dimensions
|
|
*/
|
|
public function scaleToFit(int $maxWidth, int $maxHeight): self
|
|
{
|
|
$ratio = min($maxWidth / $this->width, $maxHeight / $this->height);
|
|
|
|
if ($ratio >= 1) {
|
|
return $this; // Already fits
|
|
}
|
|
|
|
return new self(
|
|
(int) round($this->width * $ratio),
|
|
(int) round($this->height * $ratio)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Scale dimensions proportionally to fill max dimensions (may crop)
|
|
*/
|
|
public function scaleToFill(int $maxWidth, int $maxHeight): self
|
|
{
|
|
$ratio = max($maxWidth / $this->width, $maxHeight / $this->height);
|
|
|
|
return new self(
|
|
(int) round($this->width * $ratio),
|
|
(int) round($this->height * $ratio)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Scale by factor
|
|
*/
|
|
public function scaleBy(float $factor): self
|
|
{
|
|
if ($factor <= 0) {
|
|
throw FrameworkException::create(
|
|
ErrorCode::VAL_INVALID_FORMAT,
|
|
'Scale factor must be greater than 0'
|
|
)->withData(['factor' => $factor]);
|
|
}
|
|
|
|
return new self(
|
|
(int) round($this->width * $factor),
|
|
(int) round($this->height * $factor)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Check if dimensions match
|
|
*/
|
|
public function equals(self $other): bool
|
|
{
|
|
return $this->width === $other->width && $this->height === $other->height;
|
|
}
|
|
|
|
/**
|
|
* Convert to array
|
|
*/
|
|
public function toArray(): array
|
|
{
|
|
return [
|
|
'width' => $this->width,
|
|
'height' => $this->height,
|
|
'aspect_ratio' => $this->getAspectRatio(),
|
|
'orientation' => $this->getOrientation()->value,
|
|
'area' => $this->getArea(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* String representation (e.g., "1920x1080")
|
|
*/
|
|
public function __toString(): string
|
|
{
|
|
return "{$this->width}x{$this->height}";
|
|
}
|
|
}
|