Yii Framework Forum: Yii Dependency Injection Container - Tutorial - Yii Framework Forum

Jump to content

Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

Yii Dependency Injection Container - Tutorial How to integrate Pimple as Yii Dic

#1 User is offline   Th3N3rD 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 19-October 12
  • Location:Palermo

Posted 24 February 2013 - 03:28 PM

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!!! B)
2

#2 User is offline   maks feltrin 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 6
  • Joined: 17-February 10

Posted 07 May 2013 - 10:01 AM

Nice thought.

It would be great to have it in the core (maybe yii2) with:

Yii::app()->get('SERVICE') or Yii::app()->{ID} as actual shortcuts to Container::get() method.

DICs sounds as a very natural asset for Yii.
0

#3 User is offline   Blacksonic 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 1
  • Joined: 21-February 12
  • Location:Budapest

Posted 06 June 2013 - 01:20 PM

Cool, i was looking around for Dependency Injection to my Yii project, it helped a lot

It is much easier if u use composer for loading the components, the two import line becomes unnecessary at the top of the config file

The get method is nice in PHP versions before array dereferencing
Clean code enthusiast
0

#4 User is offline   Cherif 

  • Junior Member
  • Pip
  • Yii
  • Group: Members
  • Posts: 30
  • Joined: 05-June 09
  • Location:Algeria

Posted 03 August 2013 - 10:58 AM

View PostTh3N3rD, on 24 February 2013 - 03:28 PM, said:

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!!! B)


I use CWebApplication as Service container, if I have a complicated business logic I decompose it in small classes with CComponent and put everything together in a a Service class which is a CApplicationComponent and most of time this business logic can be accessed trough a module (I think CWebModule is a good facade).
0

#5 User is offline   winu 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 15
  • Joined: 24-February 14
  • Location:Kochi, Kerala

Posted 03 April 2014 - 04:10 AM

If this yiipimple is used, then how we can configure bootstrap file for phpunit?
0

#6 User is offline   Brad Kent 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 21-March 16

Posted 21 March 2016 - 11:59 AM

I'm still getting my feet wet with Yii v1.1 and attempting to follow this tutorial.

I'm having issues "initializing" the container

If I put the config snippet in the root of the config array then

Yii::app()->getContainer();
just returns the config value
array(
	'class' => 'CContainer',
	'services' => array(
	     // my services
	),
)


If I put the config snippet in the 'components' "subsection" of the config then
Yii::app()->getContainer();

returns a CContainer instance, but without any of the services I defined in the config

how do I define the services in the config?

is the WebApplication::setContainer method supposed to be called automatically?
0

#7 User is offline   Brad Kent 

  • Newbie
  • Yii
  • Group: Members
  • Posts: 2
  • Joined: 21-March 16

Posted 21 March 2016 - 12:55 PM

Solved my issue by updating getContainer()

    /**
     * Retrieve the DiC container.
     *
     * @return CContainer
     */
    public function getContainer()
    {
        if (is_array($this->container)) {
            // Container hasn't been initiated yet
            $this->setContainer($this->container);
        }
        if ($this->container === null) {
            $this->container = new CContainer();
        }
        return $this->container;
    }


0

Share this topic:


Page 1 of 1
  • You cannot start a new topic
  • You cannot reply to this topic

1 User(s) are reading this topic
0 members, 1 guests, 0 anonymous users