Dependency injection

Note

For performance reasons, dependency injection is not used in the core part of the framework.

Dependency Injection (DI) is a design pattern used to implement IoC.
It allows the creation of dependent objects outside of a class and provides those objects to a class through different ways. Using DI, we move the creation and binding of the dependent objects outside of the class that depends on it.

Note

Ubiquity only supports property injection, so as not to require introspection at execution.
Only controllers support dependency injection.

Service autowiring

Service creation

Create a service

app/services/Service.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
namespace services;

     class Service{
         public function __construct($ctrl){
             echo 'Service instanciation in '.get_class($ctrl);
         }

         public function do($someThink=""){
             echo 'do '.$someThink ."in service";
         }
     }

Autowiring in Controller

Create a controller that requires the service

app/services/Service.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
     namespace controllers;

      /**
      * Controller Client
      **/
     class ClientController extends ControllerBase{

             /**
              * @autowired
              * @var services\Service
              */
             private $service;

             public function index(){}

             /**
              * @param \services\Service $service
              */
             public function setService($service) {
                     $this->service = $service;
             }
     }

In the above example, Ubiquity looks for and injects $service when ClientController is created.

The @autowired annotation requires that:
  • the type to be instantiated is declared with the @var annotation
  • $service property has a setter, or whether declared public

As the annotations are never read at runtime, it is necessary to generate the cache of the controllers:

Ubiquity init-cache -t=controllers

It remains to check that the service is injected by going to the address /ClientController.

Service injection

Service

Let’s now create a second service, requiring a special initialization.

app/services/ServiceWithInit.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
     class ServiceWithInit{
             private $init;

             public function init(){
                     $this->init=true;
             }

             public function do(){
                     if($this->init){
                             echo 'init well initialized!';
                     }else{
                             echo 'Service not initialized';
                     }
             }
     }

Injection in controller

app/controllers/ClientController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
namespace controllers;

      /**
      * Controller Client
      **/
     class ClientController extends ControllerBase{

             /**
              * @autowired
              * @var \services\Service
              */
             private $service;

             /**
              * @injected
              */
             private $serviceToInit;

             public function index(){
                     $this->serviceToInit->do();
             }

             /**
              * @param \services\Service $service
              */
             public function setService($service) {
                     $this->service = $service;
             }

             /**
              * @param mixed $serviceToInit
              */
             public function setServiceToInit($serviceToInit) {
                     $this->serviceToInit = $serviceToInit;
             }

     }

Di declaration

In app/config/config.php, create a new key for serviceToInit property to inject in di part.

"di"=>["ClientController.serviceToInit"=>function(){
                        $service=new \services\ServiceWithInit();
                        $service->init();
                        return $service;
                }
        ]

generate the cache of the controllers:

Ubiquity init-cache -t=controllers

Check that the service is injected by going to the address /ClientController.

Note

If the same service is to be used in several controllers, use the wildcard notation :

"di"=>["*.serviceToInit"=>function(){
                        $service=new \services\ServiceWithInit();
                        $service->init();
                        return $service;
                }
        ]

Injection with a qualifier name

If the name of the service to be injected is different from the key of the di array, it is possible to use the name attribute of the @injected annotation

In app/config/config.php, create a new key for serviceToInit property to inject in di part.

"di"=>["*.service"=>function(){
                        $service=new \services\ServiceWithInit();
                        $service->init();
                        return $service;
                }
        ]
/**
 * @injected("service")
 */
private $serviceToInit;

Service injection at runtime

It is possible to inject services at runtime, without these having been previously declared in the controller classes.

app/services/RuntimeService.php
1
2
3
4
5
6
7
namespace services;

     class RuntimeService{
         public function __construct($ctrl){
             echo 'Service instanciation in '.get_class($ctrl);
         }
     }

In app/config/config.php, create the @exec key in di part.

"di"=>["@exec"=>"rService"=>function($ctrl){
                        return new \services\RuntimeService($ctrl);
                }
        ]

With this declaration, the $rService member, instance of RuntimeService, is injected into all the controllers.
It is then advisable to use the javadoc comments to declare $rService in the controllers that use it (to get the code completion on $rService in your IDE).

app/controllers/MyController.php
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
namespace controllers;

      /**
      * Controller Client
      * property services\RuntimeService $rService
      **/
     class MyController extends ControllerBase{

             public function index(){
                     $this->rService->do();
             }
     }