Model access Di Settings

Hello!

I used slim for some projects and its really nice!
Most of the time i combine it with eloquent model orm which works fine together.

Now i try to use the eloquent mutator and accesor to encrypt some model attributes ( DB fields)

For this my model needs to access some vars from the settings, which are stored in the DI Container.
I cant find a way to do this.

I cant figure out how to do this. Has anyone done this before or knows how to do this?

https://laravel.com/docs/8.x/eloquent-mutators#defining-a-mutator

Using slim v4.
Regards Nico

Can someone help me?
I can’t figure it out

$container->set('settings', function () {
    $settings = require "settings.php";
    return $settings;
});

Example user.php Class

<?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?
       ...
   }
}

Hi @Paetni1

Have you tried this?

To autowire objects with a DI container you may try to declare an object in the class constructor.

Here is an example Configiguration setup for Slim 4+.

Example class:

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 :frowning:

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?

That is really bad.

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 :frowning_face:

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 :frowning_face:

For good reasons, see above.

What could be the issues or downside of using this method of accessing DI-Container directly?

The short answer is, because it breaks the most important OOP design principles: SOLID, especially the Dependency inversion principle.

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.

1 Like