Dependency injection container
Lenkrad uses auto-wiring to enable dependency injection in a convenient way.
Concept
The auto-wiring loading mechanism uses existing instances of injected classes or creates a new instance if the current controller is the first member using the class. Some classes are already instantiated by the app itself (e.g. Injections, Setup, NeoanApp).
Using the DI-Container
You can automatically inject any class adhering to the following:
- Has an invoke-method
- Invoke-method returns instance of the class itself (singleton)
Example
?php
namespace App\MyRoute;
use Auth;
use Neoan\NeoanApp;
use App\Middleware\RequiresAuth;
class MyRoute implements Routable
{
// simply define your required injections
public function __invoke(NeoanApp $app, RequiresAuth $authenticated): array
{
// and use them as you please
return [
'web-path' => $app->webPath,
'current-user' => $authenticated->user
];
}
}
Manual registration
If you want/need to ensure the existence of an instance and it's properties, you can use the injection provider directly:
?php
use Neoan\NeoanApp;
...
$app = new NeoanApp($setup);
$app->injectionProvider->set(App\MyClass, new App\MyClass())
...
Creating an injectable class
To inspire your creativity, let's look at some examples.
Example 1: Auth
?php
namespace App\Middleware;
use Neoan\Routing\Interfaces\Routable;
// using https://packagist.org/packages/neoan3-apps/stateless
use Neoan3\Apps\Stateless;
class Auth implements Routable
{
private ?array $auth;
public function __invoke(): self
{
try{
$this->auth = Stateless::validate();
} catch (\Exception $e) {
$this->auth = null;
}
return $this;
}
public function isLoggedIn(): bool
{
return (bool) $this->auth;
}
public function getUserId()
{
return $this->auth['id'] ?? null;
}
}
Example 2: Making a model injectable (this is esoteric!)
?php
namespace App\User;
use Neoan\Model\Attributes\IsPrimaryKey;
use Neoan\Model\Model;
class User extends Model
{
#[IsPrimaryKey]
public int $id;
...
public function __invoke(Auth $auth): static
{
$this->rehydrate($auth->getUserId())
return $this;
}
}
Injecting vs. Middleware
In these examples, one can see that auto-wiring injections often makes the use of chaining middleware in routes redundant. Choosing which path to take is not only a question of preference, however. One should take into consideration the project necessities and structure as a whole. To help you make that decision, we recommend the following (non-binding) rule:
Are values passed on?
Injection is probably the easier approach
Is the class conditional towards execution?
Middleware is probably the easier approach
Is both the case?
Design your class to be used as both and use it simultaneously as middleware and DI
Before you move on
Many references on this page assume default settings. Your project might differ in behavior, paths etc.