Service container & bootstrap¶
Dit document beschrijft hoe de applicatie opstart (bootstrap) en hoe services worden aangemaakt en opgehaald via ServiceRegistry.
Bootstrap — _www/appconfig/bootstrap.php¶
bootstrap.php is de eerste stap bij elk HTTP-request en bij CLI-uitvoering. Het bestand wordt geladen door zowel _www/index.php:3, _www/api.php:3 (via require_once) als cli.php:15. _api/index.php:18 laadt het via het bare require-keyword (niet require_once).
Stap-voor-stap (_www/appconfig/bootstrap.php)¶
// bootstrap.php:8
require_once __DIR__ . '/../../vendor/autoload.php';
src/, alle files-entries).
// bootstrap.php:9
require_once __DIR__ . '/constants.php';
APP_*-constanten, AJAX_FUNCTION, database-constanten en omgevingsconstanten (via environment_constants.php). Zie Configuratie & environment.
// bootstrap.php:10
require_once APP_CORE_PATH . '/config/autoload_classes.php';
atx\-suffix-autoloader via spl_autoload_register. Zie Autoloading & namespaces.
// bootstrap.php:13–22
\Sentry\init([
'dsn' => SENTRY_DSN,
'environment' => ENVIRONMENT,
'release' => require APP_PROJECT_DIR . '/.version.php',
'max_value_length' => 2048,
'max_request_body_size'=> 'always',
'traces_sample_rate' => 1.0,
'profiles_sample_rate' => 1.0,
'enable_logs' => is_prod(),
]);
constants.php, de huidige omgeving en de releasetag. Tracing en profiling zijn op 100% ingesteld.
// bootstrap.php:24–35
register_shutdown_function(function() {
$error = error_get_last();
if ($error !== null && in_array($error['type'], [E_ERROR, E_CORE_ERROR, ...], true)) {
\Sentry\captureMessage(...);
}
\Sentry\logger()->flush();
});
// bootstrap.php:37–44
if (!is_cli() && !(isset($_SESSION['username']) && $_SESSION['username'] === 'updating')) {
\atx\SessionDAO::startSession();
if (!isset($_SESSION['taal'])) {
$_SESSION['taal'] = \atx\system\Language::DEFAULT_LOCALE;
}
} else {
$_SESSION['taal'] = \atx\system\Language::DEFAULT_LOCALE;
$_SESSION['username'] = 'updating';
}
$_SESSION['username'] === 'updating'). Stelt de standaardtaal in als er nog geen sessietaal is. De else-tak simuleert $_SESSION['taal'] en $_SESSION['username'] — dit geldt voor zowel CLI-uitvoering als voor HTTP-requests waarbij de sessie al op 'updating' staat.
// bootstrap.php:47–49
if (checkManage()) {
ini_set('display_errors', '1');
}
manage.atraxion.com).
ServiceRegistry — service-locator met League Container¶
_core/model/classes/atx/system/ServiceRegistry.php is de centrale dependency injection-laag. Het combineert een service-locator-patroon met een League Container als onderliggend IoC-systeem.
Structuur¶
// ServiceRegistry.php:12
final class ServiceRegistry
{
private static $instance; // singleton
private $container; // League\Container\Container
private array $instances = []; // instantiecache
}
Initialisatie (eerste aanroep van ServiceRegistry::get())¶
Bij de eerste aanroep roept de private methode getInstance() (ServiceRegistry.php:176) new self() aan, wat de constructor (ServiceRegistry.php:29) triggert. Alle initialisatiestappen gebeuren in die constructor:
-
Maak een
League\Container\Containeraan en steldefaultToShared()in (ServiceRegistry.php:31–32): alle services zijn standaard singletons. -
Laad service-providers uit
_core/config/service-providers.php(ServiceRegistry.php:34–36):
foreach (require APP_CORE_PATH . '/config/service-providers.php' as $className) {
$this->container->addServiceProvider(new $className);
}
De service-providers.php bevat 57 actieve service-providers (o.a. DoctrineServiceProvider, TwigServiceProvider, MailServiceProvider, ExchangeServiceProvider, EdiServiceProvider, …).
-
Bij CLI-uitvoering: laad ook command-providers uit
_core/config/command-providers.php(ServiceRegistry.php:38–41). Deze registreren Symfony Console-commands (o.a.BirthdayEmailQueueCommandProvider,OrderDocumentsCommandProvider, …).CacheWarmupCommandheeft geen eigen entry in dit bestand en wordt via een generieke provider geregistreerd (bijv.CommonCommandProvider). -
Delegeer onbekende services aan een fallback-container (
ServiceRegistry.php:44–73): als een klasse niet via een service-provider geregistreerd is, maakt de delegate container gewoonnew $id()aan en voerthydrateService()uit.
getInstance() zelf is alleen een singleton-bewaker: als self::$instance al bestaat, retourneert het die; anders roept het new self() aan en slaat het op (ServiceRegistry.php:176–183).
Ophalen van een service¶
$service = ServiceRegistry::get(SomeClass::class);
ServiceRegistry::get() (ServiceRegistry.php:88–98):
- Kijkt in de interne
$instances-cache. - Zo niet: roept
createService($service, false)aan →$container->get($service). - Roept
hydrateService($instance)aan. - Slaat op in
$instances.
Hydratatie (hydrateService)¶
ServiceRegistry::hydrateService() (ServiceRegistry.php:188–197) zorgt voor automatische dependency-injectie:
- Als de service
HasDependenciesimplementeert: roeptresolveDependencies()aan, die viagetDependencyList()de afhankelijkheden opsomt en injecteert (via setter of property). - Als de service
EntityManagerAwareimplementeert: injecteert de DoctrineEntityManager.
Aanmaken van een nieuwe (niet-gedeelde) instantie¶
$service = ServiceRegistry::createService(SomeClass::class); // new = true
createService() roept $container->getNew($service) aan (slaat niet op in de cache).
Handige statische snelkoppelingen¶
| Methode | Wat |
|---|---|
ServiceRegistry::getEntityManager() |
Retourneert de Doctrine EntityManager via DoctrineService |
ServiceRegistry::getRepository($fqcn) |
Retourneert een Doctrine-repository |
ServiceRegistry::getEventManager() |
Retourneert de EventManager |
ServiceRegistry::getSettings() |
Retourneert de SettingService |
ServiceRegistry::getContainer() |
Retourneert de rauwe League\Container\Container |
Service-providers¶
Elke service-provider implementeert League\Container\ServiceProvider\ServiceProviderInterface en registreert één of meer services in de container. Providers worden één keer geladen bij de eerste ServiceRegistry::get()-aanroep.
Voorbeelden van service-providers (_core/config/service-providers.php):
| Provider | Wat hij registreert |
|---|---|
DoctrineServiceProvider |
DoctrineService, EntityManager |
TwigServiceProvider |
Twig Environment |
MailServiceProvider |
SendMailFactory, maildiensten |
ExchangeServiceProvider |
Pay.nl exchange-controller |
EdiServiceProvider |
EDI-orderverwerking |
TranssmartServiceProvider |
Transsmart-verzendings-client |
ArteelServiceProvider |
Arteel loyaliteits-client |
LoyaltyServiceProvider |
Loyaliteitsmodule |
OrderDocumentsServiceProvider |
Orderdocumenten + virusscan |
BirthdayEmailQueueServiceProvider |
Verjaardags-e-mailwachtrij |
VirusTotalServiceProvider |
VirusTotal-client |
CLI-bootstrap — cli.php¶
cli.php deelt dezelfde bootstrap als de webapplicatie:
// cli.php:15
require_once __DIR__ . '/_www/appconfig/bootstrap.php';
Daarna haalt het de Symfony Console Application op uit de ServiceRegistry:
// cli.php:38
$app = ServiceRegistry::get(Application::class);
$app->setDispatcher($dispatcher);
$app->run();
De Application wordt geregistreerd door Atraxion\Container\ServiceProvider\ConsoleServiceProvider (één van de command-providers in _core/config/command-providers.php:4). Alle individuele commands worden door hun eigen command-provider-klasse aan de Application toegevoegd.
Een foutlistener (ConsoleEvents::ERROR) logt console-fouten via LogUpdateDAO (cli.php:21–36). De doeldatabase wordt bepaald door LogUpdateDAO::Table() (vermoedelijk atx_log, maar niet rechtstreeks in cli.php zichtbaar).
Samenvatting bootstrap-volgorde¶
graph TD
A[index.php / api.php / _api/index.php / cli.php] --> B[bootstrap.php]
B --> C[vendor/autoload.php]
B --> D[constants.php + environment_constants.php]
B --> E[autoload_classes.php — spl_autoload_register]
B --> F[Sentry::init]
B --> G[SessionDAO::startSession]
C --> H[ServiceRegistry — eerste get]
H --> I[League Container initialiseren]
I --> J[service-providers.php — 57 actieve providers]
I -->|CLI| K[command-providers.php — CLI commands]
H --> L[delegate container — fallback new $id]
Zie ook: Tech stack · Autoloading & namespaces · Request lifecycle & routing · Configuratie & environment