251 lines
7.7 KiB
PHP
251 lines
7.7 KiB
PHP
<?php
|
|
namespace Domain\Client;
|
|
|
|
class ClientRepository
|
|
{
|
|
private const MAX_PER_PAGE = 100;
|
|
|
|
private $db;
|
|
|
|
public function __construct($db)
|
|
{
|
|
$this->db = $db;
|
|
}
|
|
|
|
/**
|
|
* @return array{items: array<int, array<string, mixed>>, total: int}
|
|
*/
|
|
public function listForAdmin(
|
|
array $filters,
|
|
string $sortColumn = 'client_surname',
|
|
string $sortDir = 'ASC',
|
|
int $page = 1,
|
|
int $perPage = 15
|
|
): array {
|
|
$allowedSortColumns = [
|
|
'client_name' => 'c.client_name',
|
|
'client_surname' => 'c.client_surname',
|
|
'client_email' => 'c.client_email',
|
|
'client_phone' => 'c.client_phone',
|
|
'client_city' => 'c.client_city',
|
|
'total_orders' => 'c.total_orders',
|
|
'total_spent' => 'c.total_spent',
|
|
'client_type' => 'c.is_registered',
|
|
];
|
|
|
|
$sortSql = $allowedSortColumns[$sortColumn] ?? 'c.client_surname';
|
|
$sortDir = strtoupper(trim($sortDir)) === 'DESC' ? 'DESC' : 'ASC';
|
|
$page = max(1, $page);
|
|
$perPage = min(self::MAX_PER_PAGE, max(1, $perPage));
|
|
$offset = ($page - 1) * $perPage;
|
|
|
|
$where = [
|
|
'o.client_name IS NOT NULL',
|
|
'o.client_surname IS NOT NULL',
|
|
'o.client_email IS NOT NULL',
|
|
];
|
|
$params = [];
|
|
|
|
$name = $this->normalizeTextFilter($filters['name'] ?? '');
|
|
if ($name !== '') {
|
|
$where[] = 'o.client_name LIKE :name';
|
|
$params[':name'] = '%' . $name . '%';
|
|
}
|
|
|
|
$surname = $this->normalizeTextFilter($filters['surname'] ?? '');
|
|
if ($surname !== '') {
|
|
$where[] = 'o.client_surname LIKE :surname';
|
|
$params[':surname'] = '%' . $surname . '%';
|
|
}
|
|
|
|
$email = $this->normalizeTextFilter($filters['email'] ?? '');
|
|
if ($email !== '') {
|
|
$where[] = 'o.client_email LIKE :email';
|
|
$params[':email'] = '%' . $email . '%';
|
|
}
|
|
|
|
$clientType = trim((string)($filters['client_type'] ?? ''));
|
|
if ($clientType === 'registered') {
|
|
$where[] = 'o.client_id IS NOT NULL';
|
|
} elseif ($clientType === 'guest') {
|
|
$where[] = 'o.client_id IS NULL';
|
|
}
|
|
|
|
$whereSql = implode(' AND ', $where);
|
|
|
|
$aggregatedSql = "
|
|
SELECT
|
|
MAX(o.client_id) AS client_id,
|
|
o.client_name,
|
|
o.client_surname,
|
|
o.client_email,
|
|
MAX(o.client_phone) AS client_phone,
|
|
MAX(o.client_city) AS client_city,
|
|
COUNT(*) AS total_orders,
|
|
COALESCE(SUM(o.summary), 0) AS total_spent,
|
|
CASE
|
|
WHEN MAX(o.client_id) IS NOT NULL THEN 1
|
|
ELSE 0
|
|
END AS is_registered
|
|
FROM pp_shop_orders AS o
|
|
WHERE {$whereSql}
|
|
GROUP BY o.client_name, o.client_surname, o.client_email
|
|
";
|
|
|
|
$sqlCount = "
|
|
SELECT COUNT(0)
|
|
FROM ({$aggregatedSql}) AS c
|
|
";
|
|
|
|
$stmtCount = $this->db->query($sqlCount, $params);
|
|
$countRows = $stmtCount ? $stmtCount->fetchAll() : [];
|
|
$total = isset($countRows[0][0]) ? (int)$countRows[0][0] : 0;
|
|
|
|
$sql = "
|
|
SELECT
|
|
c.client_id,
|
|
c.client_name,
|
|
c.client_surname,
|
|
c.client_email,
|
|
c.client_phone,
|
|
c.client_city,
|
|
c.total_orders,
|
|
c.total_spent,
|
|
c.is_registered
|
|
FROM ({$aggregatedSql}) AS c
|
|
ORDER BY {$sortSql} {$sortDir}, c.client_surname ASC, c.client_name ASC
|
|
LIMIT {$perPage} OFFSET {$offset}
|
|
";
|
|
|
|
$stmt = $this->db->query($sql, $params);
|
|
$items = $stmt ? $stmt->fetchAll() : [];
|
|
|
|
if (!is_array($items)) {
|
|
$items = [];
|
|
}
|
|
|
|
foreach ($items as &$item) {
|
|
$item['client_id'] = !isset($item['client_id']) ? null : (int)$item['client_id'];
|
|
$item['client_name'] = (string)($item['client_name'] ?? '');
|
|
$item['client_surname'] = (string)($item['client_surname'] ?? '');
|
|
$item['client_email'] = (string)($item['client_email'] ?? '');
|
|
$item['client_phone'] = (string)($item['client_phone'] ?? '');
|
|
$item['client_city'] = (string)($item['client_city'] ?? '');
|
|
$item['total_orders'] = (int)($item['total_orders'] ?? 0);
|
|
$item['total_spent'] = (float)($item['total_spent'] ?? 0);
|
|
$item['is_registered'] = ((int)($item['is_registered'] ?? 0)) === 1 ? 1 : 0;
|
|
}
|
|
unset($item);
|
|
|
|
return [
|
|
'items' => $items,
|
|
'total' => $total,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
public function ordersForClient(string $name, string $surname, string $email): array
|
|
{
|
|
$name = trim($name);
|
|
$surname = trim($surname);
|
|
$email = trim($email);
|
|
|
|
if ($name === '' || $surname === '' || $email === '') {
|
|
return [];
|
|
}
|
|
|
|
$sql = "
|
|
SELECT
|
|
o.id,
|
|
o.date_order,
|
|
o.summary,
|
|
o.payment_method,
|
|
o.transport,
|
|
o.message
|
|
FROM pp_shop_orders AS o
|
|
WHERE o.client_name = :name
|
|
AND o.client_surname = :surname
|
|
AND o.client_email = :email
|
|
ORDER BY o.date_order DESC, o.id DESC
|
|
";
|
|
|
|
$stmt = $this->db->query($sql, [
|
|
':name' => $name,
|
|
':surname' => $surname,
|
|
':email' => $email,
|
|
]);
|
|
|
|
$rows = $stmt ? $stmt->fetchAll() : [];
|
|
if (!is_array($rows)) {
|
|
return [];
|
|
}
|
|
|
|
foreach ($rows as &$row) {
|
|
$row['id'] = (int)($row['id'] ?? 0);
|
|
$row['date_order'] = (string)($row['date_order'] ?? '');
|
|
$row['summary'] = (float)($row['summary'] ?? 0);
|
|
$row['payment_method'] = (string)($row['payment_method'] ?? '');
|
|
$row['transport'] = (string)($row['transport'] ?? '');
|
|
$row['message'] = (string)($row['message'] ?? '');
|
|
}
|
|
unset($row);
|
|
|
|
return $rows;
|
|
}
|
|
|
|
/**
|
|
* @return array{total_orders: int, total_spent: float}
|
|
*/
|
|
public function totalsForClient(string $name, string $surname, string $email): array
|
|
{
|
|
$name = trim($name);
|
|
$surname = trim($surname);
|
|
$email = trim($email);
|
|
|
|
if ($name === '' || $surname === '' || $email === '') {
|
|
return [
|
|
'total_orders' => 0,
|
|
'total_spent' => 0.0,
|
|
];
|
|
}
|
|
|
|
$sql = "
|
|
SELECT
|
|
COUNT(*) AS total_orders,
|
|
COALESCE(SUM(o.summary), 0) AS total_spent
|
|
FROM pp_shop_orders AS o
|
|
WHERE o.client_name = :name
|
|
AND o.client_surname = :surname
|
|
AND o.client_email = :email
|
|
";
|
|
|
|
$stmt = $this->db->query($sql, [
|
|
':name' => $name,
|
|
':surname' => $surname,
|
|
':email' => $email,
|
|
]);
|
|
$rows = $stmt ? $stmt->fetchAll() : [];
|
|
|
|
return [
|
|
'total_orders' => isset($rows[0]['total_orders']) ? (int)$rows[0]['total_orders'] : 0,
|
|
'total_spent' => isset($rows[0]['total_spent']) ? (float)$rows[0]['total_spent'] : 0.0,
|
|
];
|
|
}
|
|
|
|
private function normalizeTextFilter($value): string
|
|
{
|
|
$value = trim((string)$value);
|
|
if ($value === '') {
|
|
return '';
|
|
}
|
|
|
|
if (strlen($value) > 255) {
|
|
return substr($value, 0, 255);
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
}
|