Repository navigation
[Bug] Установка 1.14.0-beta1: Class ComposerAutoloaderInit… not found #779
Description
Описание проблемы
Установка пакета minishop3-1.14.0-beta1 падает на vendor/autoload.php:25: класс Composer autoloader не найден. Менеджер пишет, что пакет с этой подписью установить невозможно.
Шаги воспроизведения
- Скачать релиз v1.14.0-beta1, файл
minishop3-1.14.0-beta1.transport.zip. - Установить или обновить пакет через менеджер пакетов MODX.
- На шаге миграций resolver подключает
core/components/minishop3/vendor/autoload.php. - Установка обрывается с
Class "ComposerAutoloaderInit541a2bb3a6d325164f8600968e830d0d" not found.
Ожидаемое поведение
Пакет ставится или обновляется. Phinx-миграции в resolver_02_migrations.php проходят на цельном vendor/.
Фактическое поведение
Установка падает. Менеджер: «Невозможно установить пакет с подписью: minishop3-1.14.0-beta1».
Скриншоты
Не приложены.
Окружение
- MiniShop3: 1.14.0-beta1
- MODX: уточнить у репортера
- PHP: уточнить у репортера
- MySQL: уточнить у репортера
- Браузер: не применимо (установка из менеджера)
Логи ошибок
Логи из core/cache/logs/error.log
Error в /core/components/minishop3/vendor/autoload.php:25: Class "ComposerAutoloaderInit541a2bb3a6d325164f8600968e830d0d" not found
Невозможно установить пакет с подписью: minishop3-1.14.0-beta1
Дополнительный контекст
Официальный minishop3-1.14.0-beta1.transport.zip внутри согласован. И vendor/autoload.php, и vendor/composer/autoload_real.php объявляют один класс ComposerAutoloaderInit541a2bb3a6d325164f8600968e830d0d. Это тот же хэш, что в ошибке. ZIP как артефакт сборки не рассинхронен. Падение возникает на сайте в момент require из _build/resolvers/resolver_02_migrations.php через core/components/minishop3/phinx_vendor.php → vendor/autoload.php.
Типичный механизм при совпадающем имени класса в новом autoload.php:
- Upgrade / неполная замена
vendor/. На диске новыйautoload.php(хэш541a2bb3…), аcomposer/autoload_real.phpостался от прошлой установки (другойComposerAutoloaderInit…) или битый. File vehicle MODX перезаписывает файлы, но не удаляет лишние и не гарантирует атомарную замену всего дереваvendor/. require_once+ уже загруженный старыйautoload_real.phpв том же PHP-запросе. До копирования или из OPcache:require_onceпропускает повторную загрузку файла по пути, класс из новогоautoload.phpне определён.- OPcache после обновления пакета без сброса кэша опкодов.
Локальный vendor/ в working tree не обязан совпадать с релизом: каталог в .gitignore, сборка пакета берёт то, что было на машине релиза после composer install.
Отдельно, не как причина этого Class not found: в transport попал dev-vendor (в дереве есть пакеты вроде myclabs/deep-copy и PHPUnit-стек). composer.json кладёт phpunit в require-dev, а _build не вызывает composer install --no-dev. Это раздувает пакет и меняет хэш autoload. При цельном vendor/ само по себе Class not found не даёт. Follow-up для релизного процесса: собирать transport с composer install --no-dev.
Обходной путь
- Удалить каталог
core/components/minishop3/vendorцеликом. - Переустановить пакет. Либо в каталоге компонента выполнить
composer install --no-dev. - Сбросить OPcache (перезапуск PHP-FPM / Apache) и очистить кэш MODX.
Связанные файлы: _build/resolvers/resolver_02_migrations.php, core/components/minishop3/phinx_vendor.php.
Activity
biz87 commentedon Sep 24, 2026
Подтверждаю версию №2 из описания — она единственная верная, остальные две отпадают. Воспроизвёл на живом сайте и разобрал механизм построчно.
Механизм
core/components/minishop3/bootstrap.php:9подключает автолоадер компонента на каждом запросе MODX:Дальше в одном запросе обновления:
bootstrap.phpподключает установленныйvendor/autoload.php, тот —require_once composer/autoload_real.php. В памяти оказывается класс предыдущей версии.vendor/поверх.resolver_02_migrations.php→phinx_vendor.php→ms3PhinxResolveClassLoader()делаетrequire vendor/autoload.php. Файл на диске уже новый, читается заново.require_once __DIR__ . '/composer/autoload_real.php'— no-op: путь не изменился и уже в списке подключённых, файл не перечитывается.ComposerAutoloaderInit541a2bb3…::getLoader()— этот класс никто не объявлял. Fatal.То есть ZIP действительно согласован, и рассинхрона файлов на диске нет — рассинхрон между диском и памятью внутри одного запроса.
Версия №1 (частичная замена
vendor/) отпадает: у пострадавших на диске оба файла новые. Версия №3 (OPcache) тоже — OPcache кэширует содержимое файла, а не картуrequire_once; без него ошибка воспроизводится ровно так же.Почему сломалось именно на 1.14.0
Нужны два условия, и оба сошлись в этом релизе.
Первое — сменилось имя класса. Composer выводит суффикс из состава пакетов, а в
composer.jsonне былоautoloader-suffix. Между тегамиcomposer.lockизменился на 275 строк (добавилсяmodxkit/testbenchвrequire-dev) → новый хеш. Раньше состав между релизами не менялся, и имя класса совпадало случайно — шаг 5 тихо возвращал старый загрузчик.Второе — плоский
requireвместоrequire_once. Это наша регрессия из #726, она есть только в 1.14.0-beta1. До неё резолвер делал:require_onceна уже подключённом пути — no-op целиком, до строки 25 дело не доходило. В #726 понадобилось возвращаемое значение (ClassLoader),require_onceего на втором вызове не отдаёт — отсюда плоскийrequireи открытая ловушка.Замечание про dev-vendor в пакете верное и, как выясняется, не такое уж побочное: именно изменение состава
require-devи сдвинуло хеш. Плюс 45 МБ вместо примерно семи.Воспроизведение
Прогнал ту же последовательность на dev-сайте, где лежал старый хеш:
Тот же файл, та же строка 25.
Исправление
Важный момент: один
autoloader-suffixтекущих пострадавших не спасает. Они обновляются со старого хеша, и новыйautoload.phpвсё равно позовёт класс, которого нет в памяти. Лечит именно защита в резолвере — она приезжает внутри пакета и исполняется уже из новых файлов.phinx_vendor.php—ms3PhinxEnsureAutoloaderInit()вычитывает имя класса из новогоautoload.phpи, если оно не объявлено, требуетcomposer/autoload_real.phpнапрямую, в обход кэшаrequire_once. Новое имя с прежним не столкнётся — это и есть условие, при котором мы сюда попали. Снимает отказ при обновлении с любой прошлой версии.composer.json—config.autoloader-suffix: "MiniShop3". Имя класса больше не зависит от состава пакетов. Проверено: одинаково с--no-devи без._build/vendor_guard.php+ вызов вbuild.php— сборка отказывается паковатьvendor/сrequire-dev(читаетdevиdev-package-namesизinstalled.json) и печатает, что запустить.Тесты:
tests/PhinxVendorAutoloadUpgradeTest.phpвоспроизводит ловушку на поддельномvendor/и падает, если сценарий перестанет воспроизводиться;tests/BuildVendorGuardTest.phpзакрывает проверку сборки.Выпускаю 1.14.1-beta1. До него обходной путь из описания рабочий.
fix(install): survive an autoloader rename during package upgrade (1.…