Recenlty I was looking for a solution to integrate e dependency injection pattern into yii without modify the core. Today I just integrated a little class, well known and written by Fabien Potencier, Pimple.
I will explain here all the steps to add a simple dependency injection into your application that is also capable to retrieve Yii components and parameters.
1. Install Pimple
Here is the github page: Pimple, you can use composer or just download the single class and put that into your components (or whatever) directory.
2. Extend Pimple
Create a Class CContainer that extends Pimple and put it into components.
class CContainer extends \Pimple
{
/**
* Retrieve parameter/service.
*
* @param string $id id of parameter/service
* to retrieve Yii specific param/service just use an id like "yii.core.paramName"
*
* @return mixed
*/
public function get($id)
{
$element = null;
if (strpos($id, 'yii.core.') !== false) {
$id = str_replace('yii.core.', '', $id);
$element = Yii::app()->{$id};
} else {
$element = $this[$id];
}
return $element;
}
/**
* Set a new parameter/service
*
* @param string $id id of parameter/service
* @param mixed $value value or callable
*
* @return void
*/
public function set($id, $value)
{
$this[$id] = $value;
}
}
3. Extends CWebApplication
class WebApplication extends CWebApplication
{
/**
* @var \Pimple dependency injection container
*/
protected $_container = null;
/**
* Configure DiC.
*
* @param array $config configuration parameters
* it consists of two main parameters:
* <pre>
* array(
* 'class' => 'CContainer',
* 'services' => array(
* 's1' => function($c) {
* return new S1();
* },
* 's2' => function($c) {
* return new S2($c['s1');
* }
* ),
* )
* </pre>
* @return void
*/
public function setContainer(array $config)
{
$container = isset($config['class']) && !empty($config['class']) ? $config['class'] : 'CContainer';
$services = isset($config['services']) && is_array($config['services']) && !empty($config['services'])
? $config['services']
: array();
$this->_container = new $container($services);
}
/**
* Retrieve the DiC container.
*
* @return CContainer
*/
public function getContainer()
{
if ($this->_container === null) {
$this->_container = new CContainer();
}
return $this->_container;
}
}
4. Change the entry scripts
We need now to change the index.php, index-test.php and test/bootstrap.php to use our new WebApplication Class.
Just change this
Yii::createWebApplication($config)->run();
into
require_once('pathtoprotected/components/WebApplication.php');
Yii::createApplication('WebApplication', $config)->run();
5. Now its time for configuration!
The last step is set the configuration elements we need
// import your files here or use an auoloader (better)
Yii::import('application.components.container.Pimple', true);
Yii::import('application.components.container.CContainer', true);
return array(
'basePath' => dirname(__FILE__) . DIRECTORY_SEPARATOR . '..',
'name' => 'Yii Dependency Injection Integration',
// application modules
'modules' => array(
// ...
),
// application components
'components' => array(
// ...
),
// dipendency injection configuration
'container' => array(
'class' => 'CContainer',
'services' => array(
// ... put here your services
);
),
// application-level parameters that can be accessed
'params' => array(
// ....
),
);
Now if everything is set up correctly you can access your dic in these ways:
// retrieve services1
$service_1 = Yii::app()->getContainer()->get('s1');
// retrieve yii urlManager
$url_manager = Yii::app()->getContainer()->get('yii.core.urlManager');
Hope you enjoy this tutorial!!! Feel free to ask for help!!!