Architecture overview
This page is the engineer's map of an Exponential installation: which layer does what, where it lives on disk, and which architectural decisions shape everything else. The authoritative description, with a rule for each building block, is Kernel architecture; this page summarizes it and adds the reasoning.
Contents
- The layers
- The directory layout
- Five architectural decisions
- Where state lives
- What the architecture does not have
The layers
Browser / CLI / cron
|
Server: Apache or nginx + PHP-FPM | Velocity (qbix) | FrankenPHP
|
Entry points: index.php / bin/php/console / runcronjobs.php
|
Kernel: ezpKernel -> ezpKernelWeb settings -> extensions -> siteaccess -> session -> module
|
Modules and views: eZModule::run() -> view class (kernel/<module>/, extensions)
|
Domain: kernel/classes (content, users, roles, datatypes, workflows, caches)
|
Libraries: lib/ezdb (eZDB), lib/eztemplate (eZTemplate), lib/ezutils (eZINI, eZSys, ...)| Layer | Responsibility | Main classes |
|---|---|---|
| Server | Accept the connection, serve static files, run PHP | Velocity, PHP-FPM, FrankenPHP (Application servers) |
| Entry points | Start the right kernel for web, console or cron | index.php, bin/php/console, runcronjobs.php, eZScript |
| Kernel | Settings, extensions, siteaccess, session, dispatch | ezpKernel, ezpKernelWeb, eZSiteAccess, eZExtension |
| Modules and views | URL namespaces and pages, permission checks | eZModule, Exponential\Runnable\ModuleView |
| Domain | Content, users, roles, datatypes, workflows, notifications, caches | eZContentObject, eZContentObjectTreeNode, eZUser, eZRole, eZDataType, eZCache |
| Libraries | Database, templates, settings, files, locale, mail | eZDB, eZTemplate, eZINI, eZClusterFileHandler, eZLocale |
| Presentation | Templates, designs, overrides | design/<design>/templates, override.ini |
| Extensions | Everything an installation adds | extension/<name>/ |
The directory layout
From the installation book (1.2 The parts of an installation):
kernel/, lib/ the kernel: modules, classes, the template engine, the database layer
autoload/ the kernel's class map (autoload/ezp_kernel.php)
extension/ extensions: your application lives here
design/ designs: templates, stylesheets, images
settings/ shipped settings; settings/siteaccess/ and settings/override/ hold yours
var/ runtime: caches, logs, storage, the SQLite database
bin/php/console one entry point for every command
cronjobs/ the scripts runcronjobs.php runs
index.php the front controllerFive architectural decisions
- One front controller, one dispatch loop. Every web request goes through
index.phpandezpKernelWeb::run(); there is no second web entry point for normal pages. Special entry points exist for REST (index_rest.php), the tree menu (index_treemenu.php) and clustered file serving (index_cluster.php). - The siteaccess is the unit of configuration. A siteaccess is a named configuration selected per request (a site, the administration, a language); most behavior differences are settings, not code (Siteaccesses and configuration).
- Everything pluggable is named in settings. Modules, datatypes, workflow events, template operators, cronjob
parts, notification handlers, login handlers and cluster file handlers are found through INI lists, so an extension
plugs in by shipping a class and an
.ini.append.phpfile (Events, extension points and plugins). - A runtime-defined content model. Content classes are data, not code: administrators add classes and attributes without a deployment, and datatypes give each attribute storage, validation and templates (The content model for engineers).
- All cache files through the cluster file handler. Caches are written through
eZClusterFileHandler, so the same code runs on one disk or on shared storage for several web nodes (Scaling and clustering).
Where state lives
| State | Where | Shared between web nodes |
|---|---|---|
| Content, users, roles, URL aliases | the database | yes |
| Uploaded files and image variations | var/<site>/storage (or the cluster backend) | must be |
| Caches | var/<site>/cache, or Redis or Valkey with sevenx_valkey_cache | depends on the cache (Caching layers for engineers) |
| Sessions | PHP's session storage, or the ezsession table with ezpSessionHandlerDB | must be, for several nodes |
| Logs and audit records | var/log, var/<site>/log | per node unless collected |
| Settings | settings/, extension settings/ | deployed with the code |
What the architecture does not have
- No dependency injection container of its own. Classes are found through the class map and settings;
singletons such as
eZINI::instance()andeZDB::instance()are the norm. When the kernel runs inside Symfony,ezpKernel::hasServiceContainer()andgetServiceContainer()give access to Symfony's container. - Upgrade steps and migrations, from the console. Kernel and extension database updates are upgrade steps that
exp:upgradeapplies and records; a site's own changes are migrations thatexp:migration:migrateruns in order and records inexp_migration(Schema changes and migrations, Migrations). - No message broker in the kernel. Background work runs as cronjob parts, content jobs and the
expqueueextension (Console, cronjobs and background work). - No Symfony in the kernel. The Symfony platform products embed the kernel through the legacy bridge (Symfony and the legacy bridge).
Related pages
- The request lifecycle
- Kernel, lib and extensions: the layering
- Architecture for application creators
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.