<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
public function mySpecialFunction(){
// How to access the settings from DI Container here?
...
}
}
namespace App\Models;
use Laminas\Config\Config;
use Illuminate\Database\Eloquent\Model;
final class User extends Model
{
private Config $config;
public function __construct(Config $config)
{
$this->config = $config;
}
public function mySpecialFunction()
{
$value = $this->config->get('my_key');
// ...
}
}
The problem is that Eloquent is not optimized for dependency injection and uses a lot of static methods. So I guess this will not work.
Hi @odan,
I already tried your example with Laminas Config class.
But when i add it to my model and try to fetch a model from the db:
$user = User::find(1);
I always get an error because the constructor isn’t executed
Uncaught ArgumentCountError: Too few arguments to function App\Models\User::__construct(),0
passed in PATH\vendor\illuminate\database\Eloquent\Model.php on line 1902 and
exactly 1 expected in PATH\src\Models\User.php:49
That is really bad.
Do i have to implement these functions outside the eloquent model?
The eloquent model class is broken by design. As I mentioned that this may not work because of this static laravelish facade stuff. You may try other concepts, like Repositories instead. Sorry, I cannot help here.
There is a trick to achieve “Facade” like static approach to Slim 4.
// app/Factory/AppFactory.php
namespace App\Factory;
final class AppFactory extends \Slim\Factory\AppFactory
{
public static function getContainer()
{
return static::$container;
}
public static function make($id)
{
return static::$container->get($id);
}
}
Change this:
use Slim\Factory\AppFactory;
AppFactory::setContainer($container);
$app = AppFactory::create();
with this:
use App\Factory\AppFactory;
AppFactory::setContainer($container);
$app = AppFactory::create();
Now whenever you need to access the container instance you can use \App\Factory\AppFactory::getContainer() and \App\Factory\AppFactory::make($id) for DI.
In your case, user.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\Factory\AppFactory;
class User extends Model
{
public function mySpecialFunction(){
// How to access the settings from DI Container here?
$settings = AppFactory::make('settings');
}
}
I have no idea why Slim Factory doesn’t have this method
Now whenever you need to access the container instance you can use …
Please don’t. The application should never use the DI container directly. Use composition (dependency injection) instead. The DI-Container helps you with this, but don’t use the DI container directly.
I have no idea why Slim Factory doesn’t have this method
The longer answer: When you’re just calling static methods, that’s holds their own global state, you are basically just programming with global variables. And as we all know: Global variables are bad because of unwanted side effects, and they are not good testable. Instead each class should declare all its dependencies within the class constructor. This allows you to inject Null Adapter into classes when running tests.
There is one exception, the DI container should never be seen and used as a dependency within the core application because the DI container decides what to inject into a class and not the class itself.
The Laravel Facade (Anti-)Pattern and your example is basically just a Service Locator (Anti-Pattern) and should be avoided when you want to write clean and maintainable OOP code.