- Nowa tabela sms_templates (name + body + is_active) + minimalny CRUD.
- /settings/sms-templates: lista + formularz z paleta zmiennych (pill chips).
- Wydzielono Sms\SmsVariableResolver ze wspolna logika placeholderow;
Email\VariableResolver staje sie cienka fasada — EmailSendingService bez zmian.
- Dropdown "Wybierz szablon" w zakladce SMS na /orders/{id} z fetch
GET /orders/{id}/sms/template + OrderProAlerts.confirm przy nadpisaniu.
- Stopka SMSPLANET dalej doklejana wylacznie przez SmsConversationService
(Phase 122 contract preserved).
- Sidebar Ustawien: nowy link "Szablony SMS".
Migration: 20260512_000112_create_sms_templates.sql (CREATE TABLE).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
122 lines
3.1 KiB
PHP
122 lines
3.1 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Modules\Sms;
|
|
|
|
use App\Core\Http\ToggleableRepositoryTrait;
|
|
use PDO;
|
|
use RuntimeException;
|
|
|
|
final class SmsTemplateRepository
|
|
{
|
|
use ToggleableRepositoryTrait;
|
|
|
|
public function __construct(
|
|
private readonly PDO $pdo
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function listAll(): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, name, body, is_active, created_at, updated_at
|
|
FROM sms_templates
|
|
ORDER BY name ASC'
|
|
);
|
|
$statement->execute();
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
return is_array($rows) ? $rows : [];
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string, mixed>>
|
|
*/
|
|
public function listActive(): array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, name, body
|
|
FROM sms_templates
|
|
WHERE is_active = 1
|
|
ORDER BY name ASC'
|
|
);
|
|
$statement->execute();
|
|
$rows = $statement->fetchAll(PDO::FETCH_ASSOC);
|
|
|
|
return is_array($rows) ? $rows : [];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>|null
|
|
*/
|
|
public function findById(int $id): ?array
|
|
{
|
|
$statement = $this->pdo->prepare(
|
|
'SELECT id, name, body, is_active, created_at, updated_at
|
|
FROM sms_templates
|
|
WHERE id = :id'
|
|
);
|
|
$statement->execute(['id' => $id]);
|
|
$row = $statement->fetch(PDO::FETCH_ASSOC);
|
|
|
|
return is_array($row) ? $row : null;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $data
|
|
*/
|
|
public function save(array $data): int
|
|
{
|
|
$name = trim((string) ($data['name'] ?? ''));
|
|
$body = (string) ($data['body'] ?? '');
|
|
if ($name === '') {
|
|
throw new RuntimeException('Nazwa szablonu jest wymagana.');
|
|
}
|
|
if (trim($body) === '') {
|
|
throw new RuntimeException('Tresc szablonu jest wymagana.');
|
|
}
|
|
|
|
$id = isset($data['id']) && $data['id'] !== '' ? (int) $data['id'] : null;
|
|
$params = [
|
|
'name' => $name,
|
|
'body' => $body,
|
|
'is_active' => isset($data['is_active']) && $data['is_active'] ? 1 : 0,
|
|
];
|
|
|
|
if ($id !== null) {
|
|
$params['id'] = $id;
|
|
$statement = $this->pdo->prepare(
|
|
'UPDATE sms_templates
|
|
SET name = :name, body = :body, is_active = :is_active
|
|
WHERE id = :id'
|
|
);
|
|
$statement->execute($params);
|
|
|
|
return $id;
|
|
}
|
|
|
|
$statement = $this->pdo->prepare(
|
|
'INSERT INTO sms_templates (name, body, is_active)
|
|
VALUES (:name, :body, :is_active)'
|
|
);
|
|
$statement->execute($params);
|
|
|
|
return (int) $this->pdo->lastInsertId();
|
|
}
|
|
|
|
public function delete(int $id): void
|
|
{
|
|
$statement = $this->pdo->prepare('DELETE FROM sms_templates WHERE id = :id');
|
|
$statement->execute(['id' => $id]);
|
|
}
|
|
|
|
public function toggleStatus(int $id): void
|
|
{
|
|
$this->toggleActive('sms_templates', $id);
|
|
}
|
|
}
|