<?php
declare(strict_types=1);
namespace Machweis\Backend;
use PDO;
final readonly class CompanyProfileService
{
public function __construct(private PDO $pdo) {}
/** @return array<string, string> */
public function one(string $tenantId): array
{
$statement = $this->pdo->prepare(
'SELECT t.name, COALESCE(p.owner_name, \'\') AS owner, COALESCE(p.email, \'\') AS email, '
. 'COALESCE(p.phone, \'\') AS phone, COALESCE(p.address, \'\') AS address, '
. 'COALESCE(p.tax_number, \'\') AS taxNumber, COALESCE(p.report_footer, \'\') AS reportFooter '
. 'FROM tenants t LEFT JOIN tenant_company_profiles p ON p.tenant_id = t.id '
. 'WHERE t.id = ? AND t.status = ? LIMIT 1'
);
$statement->execute([$tenantId, 'active']);
$profile = $statement->fetch();
if (!is_array($profile)) throw new \RuntimeException('Company profile not found.');
return array_map(static fn (mixed $value): string => (string) $value, $profile);
}
/** @param array<string, mixed> $data @return array<string, string> */
public function update(string $tenantId, array $data, ?string $actor = null): array
{
$before = $this->one($tenantId);
$profile = $this->normalize([...$before, ...$data]);
$this->pdo->beginTransaction();
try {
$tenant = $this->pdo->prepare('UPDATE tenants SET name = ? WHERE id = ? AND status = ?');
$tenant->execute([$profile['name'], $tenantId, 'active']);
$statement = $this->pdo->prepare(
'INSERT INTO tenant_company_profiles (tenant_id, owner_name, email, phone, address, tax_number, report_footer, updated_at) '
. 'VALUES (?, ?, ?, ?, ?, ?, ?, UTC_TIMESTAMP()) ON DUPLICATE KEY UPDATE '
. 'owner_name = VALUES(owner_name), email = VALUES(email), phone = VALUES(phone), address = VALUES(address), '
. 'tax_number = VALUES(tax_number), report_footer = VALUES(report_footer), updated_at = UTC_TIMESTAMP()'
);
$statement->execute([$tenantId, $profile['owner'], $profile['email'], $profile['phone'], $profile['address'], $profile['taxNumber'], $profile['reportFooter']]);
if ($actor !== null) (new AuditService($this->pdo))->record($tenantId, $actor, 'company_profile_updated', 'company_profile', $tenantId, $before, $profile);
$this->pdo->commit();
} catch (\Throwable $error) {
if ($this->pdo->inTransaction()) $this->pdo->rollBack();
throw $error;
}
return $this->one($tenantId);
}
/** @param array<string, mixed> $data @return array<string, string> */
private function normalize(array $data): array
{
$limits = ['name' => 200, 'owner' => 200, 'email' => 320, 'phone' => 80, 'address' => 2000, 'taxNumber' => 120, 'reportFooter' => 500];
$result = [];
foreach ($limits as $field => $limit) {
$value = trim((string) ($data[$field] ?? ''));
if (strlen($value) > $limit) throw new \InvalidArgumentException('Company profile field is too long.');
$result[$field] = $value;
}
if ($result['name'] === '') throw new \InvalidArgumentException('Company name is required.');
if ($result['email'] !== '' && filter_var($result['email'], FILTER_VALIDATE_EMAIL) === false) throw new \InvalidArgumentException('Company email is invalid.');
return $result;
}
}
