Container Class
Dependency Injection Container
The Container class is a lightweight Dependency Injection (DI) Container in v2.0.0. It provides a central registry for core GeniXCMS services, decouping them from global states and hardcoded static calls.
This architecture transition enables easier unit testing, service mocking, and improved maintainability of the codebase.
โก Core Principles
GeniXCMS uses a Service Registry pattern:
- Centralization: All major services (Database, Session, User, etc.) are registered during system initialization.
- Decoupling: Classes do not need to know how to instantiate their dependencies; they just request them from the Container.
- Singleton Nature: Each service key typically points to a persistent instance for the duration of the request.
๐๏ธ Initialization & Lifecycle
Core services are registered by the System class constructor at the very beginning of the application lifecycle:
// inc/lib/System.class.php
Container::set('db', new Db());
Container::set('hooks', new Hooks());
Container::set('user', new User());
// ... and more
Registered Core Services
| Key | Class | Description |
|---|---|---|
db |
Db |
PDO-based database connectivity. |
hooks |
Hooks |
System-wide action and filter registry. |
user |
User |
Authentication and role-based access engine. |
session |
Session |
Encapsulated session management. |
options |
Options |
Site configuration manager. |
http |
Http |
Request and response abstraction. |
router |
Router |
URL scraping and routing logic. |
language |
Language |
Localization and i18n support. |
โ๏ธ How to Use
1. Basic Retrieval
You can fetch any service instance manually if you are working outside the standard controller flow:
// Manual retrieval
$db = Container::get('db');
$rows = $db->query("SELECT * FROM `posts`")->result();
2. Static Shortcut Methods
For cleaner code, the Container provides static helpers for the most frequently used services:
$db = Container::db();
$user = Container::user();
$hooks = Container::hooks();
3. Usage in Controllers (Preferred)
All controllers extending BaseControl are automatically injected with these services via the constructor. Avoid using static class calls inside controllers and instead use internal properties:
class MyControl extends BaseControl
{
public function run($param)
{
// โ BAD: Static call (hard to test)
$posts = Posts::fetch();
// โ
GOOD: Using injected service property
if ($this->user->isLoggedin()) {
$data = $this->db->query("...")->fetch();
}
}
}
๐ Managing Services
Container::set(string $key, object $instance)
Maps a service key to an object instance. If the key already exists, it will be overridden.
Container::set('mailer', new MyCustomMailer());
Container::get(string $key)
Retrieves the object associated with the key. Returns null if not found.
๐งช Benefits for Testing
The primary advantage of the Container is the ability to swap real services with Mocks during unit tests:
// In a test environment
$mockDb = $this->createMock(Db::class);
$mockDb->method('query')->willReturn(...);
// Inject the mock into the container
Container::set('db', $mockDb);
// Now, any code calling Container::db() will receive the mock!
See Also
- BaseControl Class โ How core services are injected into controllers.
- System Class โ The location where services are initialized.
- Db Class โ Reference for the core database service.