(или как я перестал бояться и полюбил писать вручную в 26 таблиц)

Знаете, есть такой старый анекдот про программиста, который искал иголку в стоге сена. Он поджег стог, а потом искал иголку в пепле. Примерно так же выглядит мой путь по рефакторингу интернет-магазина, который последние 10 лет жил своей жизнью на Joomla и VirtueMart.

Акт первый: Оптимизм

«Подумаешь, Joomla, — сказал я себе. — Обычная CMS, миллион сайтов на ней работает. VirtueMart? Тоже ничего, стандартный компонент для магазина. За пару дней перепишем фронт на нормальный PHP, и будем счастливы».

О, как же я ошибался.

Акт второй: Танцы с бубном вокруг таблиц

Первое, что меня встретило — это таблицы. Их было много. Очень много. Я насчитал 26 штук, которые так или иначе касались заказов, корзины и пользователей. Это как русский матрешка: открываешь virtuemart_orders, а там virtuemart_order_items, а в нем virtuemart_order_userinfos, а там... Вы поняли.

Самое веселое было, когда я понял, что VirtueMart хранит корзину в JSON внутри varbinary поля. Не в отдельной таблице, не в сессии, а в бинарном поле, которое еще и зашифровано непонятно чем. Расшифровка этого JSON'а заняла у меня полдня и пару седых волос.

Акт третий: Способ доставки, которого нет

VirtueMart — это как фокусник. Вы добавляете товар в корзину — он есть. Вы оформляете заказ — он есть. Вы идете в админку посмотреть заказ, а там: «No entry found in shipment for order id xxx».

Два дня я искал проблему. Два дня! Перепроверил все таблицы: orders — есть, order_items — есть, order_userinfos — есть. Где косяк?

Оказалось, VirtueMart создает две отдельные таблицы для доставки и оплаты: virtuemart_shipment_plg_weight_countries и virtuemart_payment_plg_standard. И если туда не записать — привет, ошибка. Кто знал?

Акт четвертый: Дата, которой не может быть

0000-00-00 00:00:00. Вы когда-нибудь пробовали вставить эту дату в MySQL в строгом режиме? Он вас пошлет, мягко говоря. Но VirtueMart использует ее повсеместно!

Мы долго бились с этой ошибкой: «Incorrect datetime value: '0000-00-00 00:00:00'». То поле locked_on не может быть NULL, то не может быть '0000-00-00', то не может быть NOW(). У каждой таблицы — свои правила, как у бабушки на базаре.

Решение нашлось не сразу: где-то нужно NULL, где-то '1970-01-01 00:00:00', где-то NOW(), а где-то вообще не указывать это поле. Где какое — угадай сам. Это как игра в русскую рулетку, только с датами.

Акт пятый: Хеши, пароли и соли

Отдельная песня — авторизация. Пароли в Joomla хранятся в bcrypt (нормально). А вот пароли продавцов — через password_verify($password . PASSWORD_SALT), где соль еще и хранится отдельно. Причем соль — константа, которую потерять — значит потерять доступ к админке навсегда.

Я до сих пор не знаю, что было у авторов VirtueMart на уме, когда они придумывали эту систему. Наверное, они думали: «А давайте сделаем так, чтобы через 10 лет какой-нибудь бедный программист проклинал нас весь день».

Эпилог: Жизнь есть

Но знаете что? Жизнь после Joomla и VirtueMart есть.

Мой сайт теперь работает на чистом PHP. Корзина сохраняется в БД и не теряется при очистке кэша. Заказы создаются корректно, все 26 таблиц заполняются как надо. Пользователи могут авторизоваться как через старую систему, так и через Joomla — и пароли работают.

Код стал понятным. Не идеальным, но понятным. Теперь я знаю, что происходит под капотом. И это знание стоит тех седых волос, которые я приобрел.

Совет будущим рефакторщикам:

  1. Запаситесь терпением. И кофе. Много кофе.
  2. Сделайте дамп БД. Потом еще один.
  3. Изучите структуру таблиц VirtueMart — это сэкономит вам дни.
  4. 0000-00-00 00:00:00 — ваш враг. Используйте NULL где возможно.
  5. И помните: если вам кажется, что вы нашли все таблицы, — вы не нашли все таблицы.

Жизнь после Joomla есть. Она сложная, нервная, но она есть. И знаете, я даже рад, что прошел через это. Хотя... если честно, лучше бы я просто выпил.

P.S. Спасибо ChatGPT за терпение и за то, что не послал меня куда подальше после 20-й правки функции createOrderFromCart. Мы справились! 🍻