glagola
glagola

Reputation: 2232

How can I inject configured Application component into Model instance?

I have a problem described in subject. Let me explain. I use basic application template. I have simple model Search, which uses application component GoogleCustomSearch for search through Google Custom Search API. GoogleCustomSearch has to be configured with Google API key and Search Engine ID. I specifying Google API key and Search Engine ID via application config config/web.php. I would like to inject configured instance of GoogleCustomSearch into an instance of the Search model. Is it possible to reach my goal in a cleaner way (workaround below)?

File: models/Search.php

namespace app\models;

use app\components\GoogleCustomSearch;
use yii\base\Model;

class Search extends Model
{
    /** @var GoogleCustomSearch */
    protected $googleCustomSearch;

    public function __construct(GoogleCustomSearch $googleCustomSearch, array $config = [])
    {
        $this->googleCustomSearch = $googleCustomSearch;
        parent::__construct($config);
    }
    ....
}

File: components/GoogleCustomSearch.php

namespace app\components;

use yii\base\Component;
use yii\base\InvalidValueException;

class GoogleCustomSearch extends Component
{
    public $searchEngineId;
    public $apiKey;
    ...
}

My current workaround below

File: config/bootstrap.php

use app\models\Search;
use yii\di\Container;
use yii\web\Application;

\Yii::$container->set('search', function (Container $container, $params, $config) {
    $googleCustomSearch = $container->get(Application::class)->googleCustomSearch;
    array_unshift($params, $googleCustomSearch);
    return $container->get(Search::class, $params, $config);
});

File: web/index.php

use yii\web\Application;

....

require (__DIR__ . '/../config/bootstrap.php');
$config = require(__DIR__ . '/../config/web.php');

\Yii::$container
    ->setSingleton(Application::class, [], [$config])
    ->get(Application::class)
    ->run()
;

And then call

/** @var Search $model */
$model = \Yii::createObject('search');

Is there cleaner way to inject configured component to an object instance?

Upvotes: 3

Views: 800

Answers (1)

Sam Dark
Sam Dark

Reputation: 5291

  • Your model part is good. It knows nothing about how dependency is injected and that's correct way of doing it.
  • In the bootstrap I'd set GoogleCustomSearch instead of search model:

    Yii::$container->set(GoogleCustomSearch::class, function (Container $container, $params, $config) { return Yii::$app->googleCustomSearch; });

  • Not sure about the purpose of modified index.php.

Upvotes: 1

Related Questions