- 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.
231 lines
6.7 KiB
PHP
231 lines
6.7 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Framework\View\Components;
|
|
|
|
use App\Framework\View\ValueObjects\HtmlAttributes;
|
|
use App\Framework\View\ValueObjects\HtmlElement;
|
|
use App\Framework\View\ValueObjects\HtmlTag;
|
|
use App\Framework\View\ValueObjects\StandardHtmlElement;
|
|
use App\Framework\View\ValueObjects\TagName;
|
|
|
|
final readonly class FormSelect implements HtmlElement
|
|
{
|
|
public HtmlTag $tag;
|
|
|
|
public HtmlAttributes $attributes;
|
|
|
|
public string $content;
|
|
|
|
/**
|
|
* @param array<string, string> $options Key-value pairs for options
|
|
*/
|
|
public function __construct(
|
|
public string $name,
|
|
public array $options,
|
|
public ?string $selected = null,
|
|
public ?string $label = null,
|
|
public ?string $id = null,
|
|
public ?string $placeholder = null,
|
|
public bool $required = false,
|
|
public bool $disabled = false,
|
|
public bool $multiple = false,
|
|
public ?string $errorMessage = null,
|
|
public HtmlAttributes $additionalAttributes = new HtmlAttributes()
|
|
) {
|
|
$this->tag = new HtmlTag(TagName::DIV);
|
|
$this->attributes = HtmlAttributes::empty()->withClass('form-group');
|
|
$this->content = $this->buildContent();
|
|
}
|
|
|
|
public static function create(
|
|
string $name,
|
|
array $options,
|
|
?string $label = null
|
|
): self {
|
|
return new self(name: $name, options: $options, label: $label);
|
|
}
|
|
|
|
public function withSelected(string $selected): self
|
|
{
|
|
return new self(
|
|
name: $this->name,
|
|
options: $this->options,
|
|
selected: $selected,
|
|
label: $this->label,
|
|
id: $this->id,
|
|
placeholder: $this->placeholder,
|
|
required: $this->required,
|
|
disabled: $this->disabled,
|
|
multiple: $this->multiple,
|
|
errorMessage: $this->errorMessage,
|
|
additionalAttributes: $this->additionalAttributes
|
|
);
|
|
}
|
|
|
|
public function withRequired(bool $required = true): self
|
|
{
|
|
return new self(
|
|
name: $this->name,
|
|
options: $this->options,
|
|
selected: $this->selected,
|
|
label: $this->label,
|
|
id: $this->id,
|
|
placeholder: $this->placeholder,
|
|
required: $required,
|
|
disabled: $this->disabled,
|
|
multiple: $this->multiple,
|
|
errorMessage: $this->errorMessage,
|
|
additionalAttributes: $this->additionalAttributes
|
|
);
|
|
}
|
|
|
|
public function withMultiple(bool $multiple = true): self
|
|
{
|
|
return new self(
|
|
name: $this->name,
|
|
options: $this->options,
|
|
selected: $this->selected,
|
|
label: $this->label,
|
|
id: $this->id,
|
|
placeholder: $this->placeholder,
|
|
required: $this->required,
|
|
disabled: $this->disabled,
|
|
multiple: $multiple,
|
|
errorMessage: $this->errorMessage,
|
|
additionalAttributes: $this->additionalAttributes
|
|
);
|
|
}
|
|
|
|
public function withError(string $errorMessage): self
|
|
{
|
|
return new self(
|
|
name: $this->name,
|
|
options: $this->options,
|
|
selected: $this->selected,
|
|
label: $this->label,
|
|
id: $this->id,
|
|
placeholder: $this->placeholder,
|
|
required: $this->required,
|
|
disabled: $this->disabled,
|
|
multiple: $this->multiple,
|
|
errorMessage: $errorMessage,
|
|
additionalAttributes: $this->additionalAttributes
|
|
);
|
|
}
|
|
|
|
private function buildContent(): string
|
|
{
|
|
$selectId = $this->id ?? "select-{$this->name}";
|
|
|
|
$attributes = HtmlAttributes::empty()
|
|
->withName($this->name)
|
|
->withId($selectId)
|
|
->withClass('form-select');
|
|
|
|
if ($this->required) {
|
|
$attributes = $attributes->withRequired();
|
|
}
|
|
|
|
if ($this->disabled) {
|
|
$attributes = $attributes->withDisabled();
|
|
}
|
|
|
|
if ($this->multiple) {
|
|
$attributes = $attributes->with('multiple', 'multiple');
|
|
}
|
|
|
|
if ($this->errorMessage !== null) {
|
|
$attributes = $attributes
|
|
->withClass('form-select--error')
|
|
->with('aria-invalid', 'true')
|
|
->with('aria-describedby', "{$selectId}-error");
|
|
}
|
|
|
|
// Merge additional attributes
|
|
foreach ($this->additionalAttributes->attributes as $name => $value) {
|
|
$attributes = $attributes->with($name, $value);
|
|
}
|
|
|
|
// Build options
|
|
$optionElements = [];
|
|
|
|
if ($this->placeholder !== null) {
|
|
$optionElements[] = StandardHtmlElement::create(
|
|
TagName::OPTION,
|
|
HtmlAttributes::empty()
|
|
->withValue('')
|
|
->withDisabled()
|
|
->withSelected(),
|
|
$this->placeholder
|
|
);
|
|
}
|
|
|
|
foreach ($this->options as $value => $text) {
|
|
$optionAttrs = HtmlAttributes::empty()->withValue($value);
|
|
|
|
if ($this->selected !== null && $value === $this->selected) {
|
|
$optionAttrs = $optionAttrs->withSelected();
|
|
}
|
|
|
|
$optionElements[] = StandardHtmlElement::create(
|
|
TagName::OPTION,
|
|
$optionAttrs,
|
|
$text
|
|
);
|
|
}
|
|
|
|
$selectContent = implode('', array_map('strval', $optionElements));
|
|
|
|
$elements = [];
|
|
|
|
// Label
|
|
if ($this->label !== null) {
|
|
$labelAttrs = HtmlAttributes::empty()
|
|
->withClass('form-label')
|
|
->with('for', $selectId);
|
|
|
|
if ($this->required) {
|
|
$labelAttrs = $labelAttrs->withClass('form-label--required');
|
|
}
|
|
|
|
$elements[] = StandardHtmlElement::create(
|
|
TagName::LABEL,
|
|
$labelAttrs,
|
|
$this->label
|
|
);
|
|
}
|
|
|
|
// Select
|
|
$elements[] = StandardHtmlElement::create(
|
|
TagName::SELECT,
|
|
$attributes,
|
|
$selectContent
|
|
);
|
|
|
|
// Error message
|
|
if ($this->errorMessage !== null) {
|
|
$elements[] = StandardHtmlElement::create(
|
|
TagName::SPAN,
|
|
HtmlAttributes::empty()
|
|
->withClass('form-error')
|
|
->withId("{$selectId}-error")
|
|
->with('role', 'alert'),
|
|
$this->errorMessage
|
|
);
|
|
}
|
|
|
|
return implode('', array_map('strval', $elements));
|
|
}
|
|
|
|
public function __toString(): string
|
|
{
|
|
return (string) StandardHtmlElement::create(
|
|
$this->tag->name,
|
|
$this->attributes,
|
|
$this->content
|
|
);
|
|
}
|
|
}
|