feat(Deployment): Integrate Ansible deployment via PHP deployment pipeline
- Create AnsibleDeployStage using framework's Process module for secure command execution - Integrate AnsibleDeployStage into DeploymentPipelineCommands for production deployments - Add force_deploy flag support in Ansible playbook to override stale locks - Use PHP deployment module as orchestrator (php console.php deploy:production) - Fix ErrorAggregationInitializer to use Environment class instead of $_ENV superglobal Architecture: - BuildStage → AnsibleDeployStage → HealthCheckStage for production - Process module provides timeout, error handling, and output capture - Ansible playbook supports rollback via rollback-git-based.yml - Zero-downtime deployments with health checks
This commit is contained in:
142
src/Framework/Notification/Templates/NotificationTemplate.php
Normal file
142
src/Framework/Notification/Templates/NotificationTemplate.php
Normal file
@@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Framework\Notification\Templates;
|
||||
|
||||
use App\Framework\Notification\ValueObjects\NotificationChannel;
|
||||
use App\Framework\Notification\ValueObjects\NotificationPriority;
|
||||
|
||||
/**
|
||||
* Notification Template
|
||||
*
|
||||
* Reusable template with placeholders for dynamic content
|
||||
* Supports per-channel customization and variable substitution
|
||||
*/
|
||||
final readonly class NotificationTemplate
|
||||
{
|
||||
/**
|
||||
* @param TemplateId $id Unique template identifier
|
||||
* @param string $name Template name (e.g., 'order.shipped', 'user.welcome')
|
||||
* @param string $titleTemplate Title with placeholders (e.g., 'Order {{order_id}} shipped')
|
||||
* @param string $bodyTemplate Body with placeholders
|
||||
* @param array<NotificationChannel, ChannelTemplate> $channelTemplates Per-channel customization
|
||||
* @param NotificationPriority $defaultPriority Default priority for notifications using this template
|
||||
* @param array<string> $requiredVariables Variables that must be provided when rendering
|
||||
* @param array<string, mixed> $defaultVariables Default values for optional variables
|
||||
*/
|
||||
public function __construct(
|
||||
public TemplateId $id,
|
||||
public string $name,
|
||||
public string $titleTemplate,
|
||||
public string $bodyTemplate,
|
||||
public array $channelTemplates = [],
|
||||
public NotificationPriority $defaultPriority = NotificationPriority::NORMAL,
|
||||
public array $requiredVariables = [],
|
||||
public array $defaultVariables = []
|
||||
) {
|
||||
if (empty($name)) {
|
||||
throw new \InvalidArgumentException('Template name cannot be empty');
|
||||
}
|
||||
|
||||
if (empty($titleTemplate)) {
|
||||
throw new \InvalidArgumentException('Title template cannot be empty');
|
||||
}
|
||||
|
||||
if (empty($bodyTemplate)) {
|
||||
throw new \InvalidArgumentException('Body template cannot be empty');
|
||||
}
|
||||
}
|
||||
|
||||
public static function create(
|
||||
string $name,
|
||||
string $titleTemplate,
|
||||
string $bodyTemplate
|
||||
): self {
|
||||
return new self(
|
||||
id: TemplateId::generate(),
|
||||
name: $name,
|
||||
titleTemplate: $titleTemplate,
|
||||
bodyTemplate: $bodyTemplate
|
||||
);
|
||||
}
|
||||
|
||||
public function withChannelTemplate(
|
||||
NotificationChannel $channel,
|
||||
ChannelTemplate $template
|
||||
): self {
|
||||
return new self(
|
||||
id: $this->id,
|
||||
name: $this->name,
|
||||
titleTemplate: $this->titleTemplate,
|
||||
bodyTemplate: $this->bodyTemplate,
|
||||
channelTemplates: [...$this->channelTemplates, $channel => $template],
|
||||
defaultPriority: $this->defaultPriority,
|
||||
requiredVariables: $this->requiredVariables,
|
||||
defaultVariables: $this->defaultVariables
|
||||
);
|
||||
}
|
||||
|
||||
public function withPriority(NotificationPriority $priority): self
|
||||
{
|
||||
return new self(
|
||||
id: $this->id,
|
||||
name: $this->name,
|
||||
titleTemplate: $this->titleTemplate,
|
||||
bodyTemplate: $this->bodyTemplate,
|
||||
channelTemplates: $this->channelTemplates,
|
||||
defaultPriority: $priority,
|
||||
requiredVariables: $this->requiredVariables,
|
||||
defaultVariables: $this->defaultVariables
|
||||
);
|
||||
}
|
||||
|
||||
public function withRequiredVariables(string ...$variables): self
|
||||
{
|
||||
return new self(
|
||||
id: $this->id,
|
||||
name: $this->name,
|
||||
titleTemplate: $this->titleTemplate,
|
||||
bodyTemplate: $this->bodyTemplate,
|
||||
channelTemplates: $this->channelTemplates,
|
||||
defaultPriority: $this->defaultPriority,
|
||||
requiredVariables: $variables,
|
||||
defaultVariables: $this->defaultVariables
|
||||
);
|
||||
}
|
||||
|
||||
public function withDefaultVariables(array $defaults): self
|
||||
{
|
||||
return new self(
|
||||
id: $this->id,
|
||||
name: $this->name,
|
||||
titleTemplate: $this->titleTemplate,
|
||||
bodyTemplate: $this->bodyTemplate,
|
||||
channelTemplates: $this->channelTemplates,
|
||||
defaultPriority: $this->defaultPriority,
|
||||
requiredVariables: $this->requiredVariables,
|
||||
defaultVariables: [...$this->defaultVariables, ...$defaults]
|
||||
);
|
||||
}
|
||||
|
||||
public function hasChannelTemplate(NotificationChannel $channel): bool
|
||||
{
|
||||
return isset($this->channelTemplates[$channel]);
|
||||
}
|
||||
|
||||
public function getChannelTemplate(NotificationChannel $channel): ?ChannelTemplate
|
||||
{
|
||||
return $this->channelTemplates[$channel] ?? null;
|
||||
}
|
||||
|
||||
public function validateVariables(array $variables): void
|
||||
{
|
||||
foreach ($this->requiredVariables as $required) {
|
||||
if (!array_key_exists($required, $variables)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Required variable '{$required}' is missing"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user