Files
orderPRO/bin/fix_status_codes.php
Jacek Pyziak c489891d15 Add Orders and Order Status repositories with pagination and management features
- Implemented OrdersRepository for handling order data with pagination, filtering, and sorting capabilities.
- Added methods for retrieving order status options, quick stats, and detailed order information.
- Created OrderStatusRepository for managing order status groups and statuses, including CRUD operations and sorting.
- Introduced a bootstrap file for test environment setup and autoloading.
2026-03-03 01:32:28 +01:00

217 lines
6.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Core\Database\ConnectionFactory;
use App\Core\Support\Env;
$basePath = dirname(__DIR__);
$vendorAutoload = $basePath . '/vendor/autoload.php';
if (is_file($vendorAutoload)) {
require $vendorAutoload;
} else {
spl_autoload_register(static function (string $class) use ($basePath): void {
$prefix = 'App\\';
if (!str_starts_with($class, $prefix)) {
return;
}
$relative = substr($class, strlen($prefix));
$file = $basePath . '/src/' . str_replace('\\', '/', $relative) . '.php';
if (is_file($file)) {
require $file;
}
});
}
Env::load($basePath . '/.env');
/** @var array<string, mixed> $dbConfig */
$dbConfig = require $basePath . '/config/database.php';
$dryRun = in_array('--dry-run', $argv, true);
$useRemote = in_array('--use-remote', $argv, true);
if ($useRemote) {
$remoteHost = (string) Env::get('DB_HOST_REMOTE', '');
if ($remoteHost !== '') {
$dbConfig['host'] = $remoteHost;
}
}
$pdo = ConnectionFactory::make($dbConfig);
echo 'Fix status codes script' . PHP_EOL;
echo $dryRun ? '[mode] dry-run (no DB changes)' . PHP_EOL : '[mode] apply' . PHP_EOL;
if ($useRemote) {
echo '[db] using DB_HOST_REMOTE for this run' . PHP_EOL;
}
try {
$resultGroups = fixGroupCodes($pdo, $dryRun);
$resultStatuses = fixStatusCodes($pdo, $dryRun);
echo PHP_EOL . 'Summary:' . PHP_EOL;
echo ' groups updated: ' . $resultGroups['updated'] . PHP_EOL;
echo ' statuses updated: ' . $resultStatuses['updated'] . PHP_EOL;
echo 'Done.' . PHP_EOL;
} catch (Throwable $exception) {
fwrite(STDERR, '[error] ' . $exception->getMessage() . PHP_EOL);
exit(1);
}
/**
* @return array{updated:int}
*/
function fixGroupCodes(PDO $pdo, bool $dryRun): array
{
$stmt = $pdo->query('SELECT id, name, code FROM order_status_groups ORDER BY id ASC');
$rows = $stmt !== false ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
if (!is_array($rows)) {
$rows = [];
}
$usedCodes = [];
foreach ($rows as $row) {
$existing = strtolower(trim((string) ($row['code'] ?? '')));
if ($existing !== '') {
$usedCodes[$existing] = true;
}
}
$updated = 0;
$updateStmt = $pdo->prepare('UPDATE order_status_groups SET code = :code, updated_at = :updated_at WHERE id = :id');
foreach ($rows as $row) {
$id = max(0, (int) ($row['id'] ?? 0));
if ($id <= 0) {
continue;
}
$currentCode = strtolower(trim((string) ($row['code'] ?? '')));
$base = normalizeCodeFromName((string) ($row['name'] ?? ''), 'group_' . $id);
$targetCode = ensureUniqueCode($base, $currentCode, $usedCodes);
if ($targetCode === $currentCode) {
continue;
}
echo ' [group #' . $id . '] ' . ($currentCode !== '' ? $currentCode : '(empty)') . ' -> ' . $targetCode . PHP_EOL;
if (!$dryRun) {
$updateStmt->execute([
'id' => $id,
'code' => $targetCode,
'updated_at' => date('Y-m-d H:i:s'),
]);
}
if ($currentCode !== '') {
unset($usedCodes[$currentCode]);
}
$usedCodes[$targetCode] = true;
$updated++;
}
return ['updated' => $updated];
}
/**
* @return array{updated:int}
*/
function fixStatusCodes(PDO $pdo, bool $dryRun): array
{
$stmt = $pdo->query('SELECT id, name, code FROM order_statuses ORDER BY id ASC');
$rows = $stmt !== false ? $stmt->fetchAll(PDO::FETCH_ASSOC) : [];
if (!is_array($rows)) {
$rows = [];
}
$usedCodes = [];
foreach ($rows as $row) {
$existing = strtolower(trim((string) ($row['code'] ?? '')));
if ($existing !== '') {
$usedCodes[$existing] = true;
}
}
$updated = 0;
$updateStmt = $pdo->prepare('UPDATE order_statuses SET code = :code, updated_at = :updated_at WHERE id = :id');
foreach ($rows as $row) {
$id = max(0, (int) ($row['id'] ?? 0));
if ($id <= 0) {
continue;
}
$currentCode = strtolower(trim((string) ($row['code'] ?? '')));
$base = normalizeCodeFromName((string) ($row['name'] ?? ''), 'status_' . $id);
$targetCode = ensureUniqueCode($base, $currentCode, $usedCodes);
if ($targetCode === $currentCode) {
continue;
}
echo ' [status #' . $id . '] ' . ($currentCode !== '' ? $currentCode : '(empty)') . ' -> ' . $targetCode . PHP_EOL;
if (!$dryRun) {
$updateStmt->execute([
'id' => $id,
'code' => $targetCode,
'updated_at' => date('Y-m-d H:i:s'),
]);
}
if ($currentCode !== '') {
unset($usedCodes[$currentCode]);
}
$usedCodes[$targetCode] = true;
$updated++;
}
return ['updated' => $updated];
}
/**
* @param array<string, bool> $usedCodes
*/
function ensureUniqueCode(string $base, string $currentCode, array $usedCodes): string
{
$normalizedCurrent = strtolower(trim($currentCode));
$candidate = $base;
$index = 2;
while ($candidate !== $normalizedCurrent && isset($usedCodes[$candidate])) {
$suffix = '_' . $index;
$candidate = mb_substr($base, 0, max(1, 64 - mb_strlen($suffix))) . $suffix;
$index++;
}
return $candidate;
}
function normalizeCodeFromName(string $name, string $fallback): string
{
$value = mb_strtolower(trim($name));
if ($value === '') {
$value = $fallback;
}
$value = strtr($value, [
mb_chr(261, 'UTF-8') => 'a', // ą
mb_chr(263, 'UTF-8') => 'c', // ć
mb_chr(281, 'UTF-8') => 'e', // ę
mb_chr(322, 'UTF-8') => 'l', // ł
mb_chr(324, 'UTF-8') => 'n', // ń
mb_chr(243, 'UTF-8') => 'o', // ó
mb_chr(347, 'UTF-8') => 's', // ś
mb_chr(378, 'UTF-8') => 'z', // ź
mb_chr(380, 'UTF-8') => 'z', // ż
]);
$value = preg_replace('/[^a-z0-9_\-\.]+/u', '_', $value) ?? '';
$value = trim($value, '_');
if ($value === '') {
$value = $fallback;
}
return mb_substr($value, 0, 64);
}