Skip to content

PdoPaymentAttemptStore: ошибки записи проглатываются на соединении MODX (ERRMODE_SILENT) #752

Description

@biz87

Проблема

PdoPaymentAttemptStore (#604) пишет через соединение MODX, а modX открывает $modx->pdo с PDO::ERRMODE_SILENT (core/src/Revolution/modX.php перекрывает driver_options). Хранилище рассчитывает на исключения и результат execute() не проверяет:

  • create()$stmt->execute([...]) без проверки;
  • update()$stmt->execute($params) без проверки;
  • fetchOne() — то же.

Исключение ловится только в recordEvent().

Проверено на dev (MariaDB 10.6.23, beta ac8e267e, sql_mode = STRICT_TRANS_TABLES,…) вызовами самого хранилища на $modx->pdo:

PDO ERRMODE: 0 (SILENT)
created attempt #1 status=new currency=RUB
update(status=paid, currency=40 символов) → вернул status=new currency=RUB
строка в БД: {"status":"new","currency":"RUB"}

update() завершился «успешно», вернул прежнюю строку, в журнал ничего не попало. У create() при ошибке будет RuntimeException('Failed to load created payment attempt') — отказ есть, но текст скрывает причину.

Последствие

В PaymentLifecycleService::commit() попытка обновляется через writeWithEvent(), затем вызывается syncOrderStatus(). Если update() молча не прошёл, событие будет записано как обработанное, попытка останется в прежнем статусе, а статус заказа всё равно сменится. Вероятность низкая — вебхук пишет короткие поля (status, refunded_amount, refund_external_id, refundedon), — но расхождение не будет видно ни в журнале, ни в ответе.

Что сделать

В PdoShipmentStore::executeWrite() уже есть нужный образец: проверяется результат execute(), разбирается errorInfo(), дубль отличается от прочих ошибок, остальное бросается наружу.

  • Применить тот же приём в create(), update(), fetchOne().
  • create(): при нарушении уникальности — понятное исключение или возврат существующей попытки; при прочих ошибках — исключение с errorInfo.
  • Тест хранилища на соединении с ERRMODE_SILENT, как у MODX.

Критерии приёмки

  • Ошибка SQL в update() не проглатывается
  • create() различает дубль и прочие ошибки
  • MySQL-тест хранилища на соединении с ERRMODE_SILENT

Контекст

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions