Подключение и регистрация сердечника¶
Как панель собирается при загрузке: один служебный контейнер, как он заполняется и как модули помещают свои маршруты, события, команды, записи cron и элементы навигационной панели в основные реестры.
Эта страница является сквозное повествование и потребительская сторона одним из основных реестров. То авторская сторона каждой точки расширения задокументирована в другом месте и связана с What lives elsewhere — this page does not repeat it.
Один контейнер¶
Все зависит от одного процесса в масштабах всего процесса ServiceContainer
(src/Core/Container/ServiceContainer.php), синглтон PSR-11 ContainerInterface, полученный с помощью
ServiceContainer::getInstance(). XC_Bootstrap::boot() создает его, заполняет его, и каждый последующий
потребитель (XC_Bootstrap::getContainer(), модуль boot(), разрешение обработчика маршрута) считывает то же самое
пример. Тесты сбрасывают его с помощью ServiceContainer::resetInstance().
Для основных служб есть значение автоматическое обнаружение поставщика услуг отсутствует: зарегистрирован канонический набор
обязательно с помощью bootstrap (см. ниже), а модули добавляют свои собственные сервисы в свои
boot(). То, что вы видите зарегистрированным, в точности соответствует коду set() — ничто не подключено с помощью
сканирование условных обозначений или аннотаций.
Заполнение контейнера при загрузке¶
Это основа системы. XC_Bootstrap::boot() регистрация услуг осуществляется в два этапа.
Early (in boot() itself), before any subsystem loads:
| Ключ | Ценность | Источник |
|---|---|---|
context |
активное строковое значение BootContext |
src/bootstrap.php |
options |
массив $options, переданный в boot() |
src/bootstrap.php |
config |
ConfigReader::getAll() (проанализировано config.ini) |
src/bootstrap.php |
Набор канонических служб — XC_Bootstrap::populateContainer() (выполняется для каждого контекста, за исключением
Minimal, т.е. как только база данных будет запущена):
| Ключ | Ценность | Записи |
|---|---|---|
db |
дескриптор Database |
защищенный (см. ниже) |
settings |
SettingsManager::getAll() |
защищенный |
servers |
ServerRepository::getAll() |
|
bouquets |
BouquetService::getAll() |
|
categories |
CategoryService::getFromDatabase() |
|
redis |
RedisManager::instance() |
только тогда, когда для этого контекста был загружен Redis |
translator |
Translator::class |
|
events |
новый экземпляр EventDispatcher |
также подключен к статическому фасаду (см. События) |
Сразу после этого XC_Bootstrap::assertContainerHealth() жестко требует, чтобы events было
присутствует (плюс db/redis, когда они были загружены) и выдает ошибку, если нет — гарантия громкий сбой
этот более поздний код может предполагать, что эти службы существуют, вместо того, чтобы проверять каждую из них на нулевой уровень.
Записи
context/config/settings/servers/bouquets/categoriesпредставляют собой простые данные снимки, сделанные при загрузке, а не на ленивых заводах — они считываются, а не пересчитываются, на протяжении всего срока службы устройства. запрос.
Ссылка на сервисный контейнер¶
Все установщики могут быть объединены в цепочку (return $this).
| Метод | Цель |
|---|---|
set(id, value) |
Зарегистрируйте сервис. Значение Closure становится ленивая фабрика синглетов (сначала вызывается один раз для get(), затем кэшируется); все остальное — скаляр, объект или массив [Class, 'method'] — сохраняется как готовое значение. |
factory(id, callable) |
Зарегистрируйте фабрику, которая возвращает значение новый экземпляр для каждого get() (без кэширования). |
register(array) |
Скопируйте set() с карты id => value. |
get(id) |
Разрешить службу. Возвращает кэшированный синглтон, если он присутствует; в противном случае запускает фабрику один раз, кэширует ее и применяет декораторы. Защищает от циклических фабрик и выдает CircularDependencyException; выдает NotFoundException для неизвестного идентификатора. |
getOrDefault(id, default) |
Как get(), но возвращает default вместо того, чтобы выбрасывать при отсутствии. |
has(id) / keys() / remove(id) / dump() |
Самоанализ и разрушение. |
decorate(id, decorator, priority) |
Завершите работу с существующей службой, наивысший приоритет которой был применен последним. Запрещенный в защищенных службах ['db', 'settings', 'config', 'auth'] — выберите один из вариантов оформления. Смотрите Пункты расширения модуля. |
tag(id, tag) / getTagged(tag) |
Сгруппируйте службы под одной меткой для пакетного поиска. |
Метки в настоящее время не используются основной проводкой.
tag()/getTagged()существует, но путь загрузки собирает вклады модулей путем проверкиinstanceofпо списку загруженных модулей (см.bootAll), нет по тегу. Исходный документированный блок все еще описывает теги как механизм сбора данных для подписчиков/cron/маршрутов, который описывает предполагаемый дизайн, а не текущий код. Не полагайтесь на коллекцию на основе тегов, пока она не будет создана на самом деле. реализованный.
Resolving a [Class, 'method'] handler (used by the Router) goes through the container, so
классы-обработчики разграничиваются при регистрации, а в противном случае возвращаются к new.
ModuleLoader::bootAll — организатор¶
После того, как ModuleLoader::loadAll() обнаружил, отфильтровал и топологически отсортированный отобрал модули
(see Module Lifecycle), bootAll() is the single place that pushes each
вклад модуля в основные реестры. Он проверяет каждое значение подинтерфейс на instanceof
таким образом, модуль реализует только те перехватчики, которые ему нужны (ModuleInterface - это их совокупность).
Порядок для каждого модуля внутри bootAll(ServiceContainer $container, ?Router $router, ?StreamPipeline $pipeline):
- Сначала основная навигационная панель, один раз —
(new CoreNavbarProvider())->registerNavbar(...)перед любым модулем, поэтому узлы основного меню существуют как родительские. ServiceProviderInterface→boot($container)затемregisterEventSubscribers()— службы регистрируются до подключения слушателей этого модуля.StreamMiddlewareProviderInterface→registerStreamMiddleware($pipeline)— только в том случае, если было передано значение$pipeline.RouteProviderInterface→registerRoutes($router)— только в том случае, если было передано значение$router($router !== null).NavbarProviderInterface→registerNavbar(...).
Два вклада равны отдельные проходы, не являющиеся частью bootAll:
registerAllCommands($registry)— Команды CLI, каждый модуль которых заключен в try / catch, поэтому один сломанный модуль не может заблокировать весь CLI.collectCronEntries()— строки crontab, собранные изCronProviderInterface::getCronEntries(), используемые командами запуска/состояния.
Потому что маршруты и потоковое промежуточное программное обеспечение стробируются на основе необязательных аргументов $router/$pipeline,
одно и то же значение bootAll() выполняет различную работу в зависимости от точки входа — интерфейс командной строки не передает ни,
таким образом, к нему подключены только подписчики services + event (и безвредная навигационная панель).
События¶
EventDispatcher (src/Core/Events/EventDispatcher.php) - это синглтон со статическим фасадом.
populateContainer() выполняет new EventDispatcher() → EventDispatcher::setInstance($d) →
$container->set('events', $d), таким образом, запись контейнера events и статический
EventDispatcher::dispatch()/listen() общий доступ к хранилищу прослушивателей один. Модули регистрируют прослушиватели
во время шага 2 из bootAll, описанного выше, с помощью атрибута getEventSubscribers() или #[ListensTo].
Полная информация - регистрационные формы, приоритеты, мероприятия, которые можно отменить, встроенный каталог мероприятий — приведена ниже. в системе событий; на этой странице описывается только где в последовательности загрузки прослушиватели подключись к сети.
Регистрация команд CLI¶
Путь к интерфейсу CLI (src/console.php) создает свой набор команд в два этапа:
- Автоматическое обнаружение ядра.
new CommandRegistry(), затем глобусCli/Commands/*.phpиCli/CronJobs/*.php, сопоставьте каждый каталог с его пространством имен и с помощью отраженияregister()каждый неабстрактный класс, реализующийCommandInterface. Таким образом, добавление основной команды - это просто удаление класса в одном из этих каталогов — никакой ручной регистрации. - Команды модуля.
ModuleLoader::registerAllCommands($registry)вызывает каждыйCommandProviderInterface::registerCommands().
CommandRegistry (src/Cli/CommandRegistry.php) - это простая карта name → CommandInterface:
register(), dispatch($argv) (обрабатывает --list/--help, группирует справку по префиксу group: в
название команды), get($name), getAll().
Сквозная загрузка — администрирование (web)¶
src/Public/index.php:
XC_Bootstrap::boot(BootContext::Admin)— создает контейнер; устанавливаетcontext/options/config; загружает константы; выполняет проверку флуда/хостинга;bootAdmin()(сессия, база данных,LegacyInitializer, Redis, API администратора/реселлера, транслятор, обработчик завершения работы, константы состояния);populateContainer();assertContainerHealth().Router::getInstance(), затемrequireосновные файлы маршрутовroutes/{scope}.php(+routes/api.php).- Блок загрузки модуля:
router->beginModuleRegistration()→new ModuleLoader; loadAll(); bootAll($container, $router)→router->endModuleRegistration()→drainRouteCollisions(). Режим регистрации модуля выполняет выигрывают основные маршруты по любому маршруту модуля с одинаковым путем; коллизии фиксируются, а не перезаписываются автоматически. Router::dispatch()/dispatchApi()обрабатывает запрос, разрешая[Class, 'method']обработчики через контейнер.
Смотрите Контексты начальной загрузки, чтобы узнать, какие именно подсистемы инициализируются в каждом контексте, и Обработка HTTP-запросов для API маршрутизатора и диспетчеризации.
Сквозная загрузка — CLI¶
src/console.php:
require bootstrap.php;XC_Bootstrap::boot(BootContext::Cli)— DB,LegacyInitializer, необязательно Redis, заголовок процесса, затем такой жеpopulateContainer()(таким образом,eventsи friends также существуют в CLI).new CommandRegistry(); автоматическое обнаружение ядраCli/Commands+Cli/CronJobs(глобус + отражение) →register().new ModuleLoader; loadAll(); registerAllCommands($registry)(команды модуля, доbootAll), затемbootAll(getContainer())без маршрутизатора и трубопровода — таким образом, маршруты и потоковое промежуточное программное обеспечение пропускаются; подключаются только службы модуля + подписчики событий.registry->dispatch($argv)выполняет запрошенную команду.
Что живет в другом месте¶
Чтобы избежать дублирования, информация об авторе и каждой подсистеме размещается на отдельных страницах:
| Тема | Страница |
|---|---|
Which subsystems each context initialises; boot() options; idempotency |
Контексты начальной загрузки |
| Формы регистрации на мероприятия, приоритеты, мероприятия, которые можно отменить, каталог мероприятий | Система событий |
API маршрутизатора, begin/endModuleRegistration, диспетчеризация, разрешение обработчика |
Обработка HTTP-запросов |
| Конструктор элементов навигационной панели, правила видимости, рендеринг | Рендеринг навигационной панели |
| Обнаружение модулей, фильтрация env, топосортировка, включение/ выключение, установка / обновление | Жизненный цикл модуля |
| DI—оформление, потоковое промежуточное программное обеспечение, cron, миграции - хуки автора модуля | Точки расширения модуля |
| Написание модуля (манифест, контракт класса, макет каталога) | Разработка модуля |
Связанные файлы¶
| Файл | Роль |
|---|---|
src/Core/Container/ServiceContainer.php |
Контейнер DI: set/factory/get/decorate/tag |
src/bootstrap.php |
XC_Bootstrap::boot, populateContainer, assertContainerHealth |
src/Core/Module/ModuleLoader.php |
bootAll, registerAllCommands, collectCronEntries |
src/Core/Events/EventDispatcher.php |
Диспетчер событий + статический фасад, объединенный в events |
src/Cli/CommandRegistry.php |
Карта команд CLI + dispatch |
src/console.php |
Точка входа в интерфейс командной строки: автоматическое обнаружение основной команды + загрузка модуля |
src/Public/index.php |
Веб-точка входа: файлы маршрута + загрузочный блок модуля |