Dependency injection

Table of Contents 


Dependency injection allows logic to be decoupled between objects by using the inversion of control principle.

Temma automatically creates a component to handle dependency injection into business objects. This component is the backbone that all objects in your application can rely on to access each other.
It is available in controllers under the private attribute $_loader.

By default, the component contains the following:

  • $loader->dataSources: Associative array containing the connection objects to the data sources (see the controllers documentation).
  • $loader->session: Session management object (see sessions).
  • $loader->config: Configuration management object, which gives access to all configuration directives.
  • $loader->request: Management object of the incoming request, which allows to handle the execution flow of the framework.
  • $loader->response: Object used by the framework to manage the response to the client.

Usage with your objects

An object that implements the \Temma\Base\Loadable interface can be loaded by the component. Its constructor must then take a single parameter, of type \Temma\Base\Loader.

Here is an example of an object that writes data to a var/list.txt file (in the project tree):

class List implements \Temma\Base\Loadable {
    /** Path to the file to write in. */
    private $_path = null;

     * Constructor.
     * @param \Temma\Base\Loader $loader Component.
    public function __construct(\Temma\Base\Loader $loader) {
        $this->_path = $loader->config->appPath . '/var/liste.txt';

     * Method which writes into the file.
     * @param string $text The text to write.
    public function write(string $text) {
        file_put_contents($this->_path, "$text\n", FILE_APPEND);
  • Line 1: The object implements the \Temma\Base\Loadable interface.
  • Line 3: A private attribute will contain the full path to the file in which we will write later.
  • Line 9: Constructor of the object, which receives as a parameter an instance of the dependency injection component.
    • Line 10: We build the path to the file, using the configuration object, whose appPath attribute gives the path to the root of the project.
  • Line 17: The add() method can be used to write to the file.

For this object to be loadable by the framework, it must be accessible in the inclusion paths of the project. By default, this means that we will save it in a file named List.php, placed in the lib/ directory of the project.

From that point on, the object is available directly as if it were an attribute of the component. Only one instance of the object will be created (the first time the object is called).

Here is an example of a controller that uses the List object thanks to the component:

class Homepage extends \Temma\Web\Controller {
    /** Root action. */
    public function index() {
        // write in the file
        $this->_loader->List->write('Ça marche');
  • Line 5: We go through the component to access the List object, then to its write() method.

Now imagine that we create another business object, loadable via the component, which uses the List object.

class Compute implements \Temma\Base\Loadable {
    /** Instance of the dependency injection component. */
    private $_loader = null;

     * Constructor.
     * @param \Temma\Base\Loader $loader Composant.
    public function __construct(\Temma\Base\Loader $loader) {
        $this->_loader = $loader;

     * Method that performs an addition.
     * @param int $i Number.
     * @param int $j Number.
     * @return int Result of the addition.
    public function add(int $i, int $j) : int {
        $result = $i + $j;
        $this->_loader->List->ecrit("Computed: $result");
        return ($result);
  • Line 3: Unlike the List object, this object will keep the instance of the dependency injection component in a private attribute.
  • Line 10: In the constructor, we copy the instance of the component (received as a parameter) into the private attribute.
  • Line 21: We use the component to call the List object.

This illustrates how business objects can call each other, with the component that handles accesses and instantiations.

Alternative access

The examples seen previously assume that the objects managed by the component are placed in the root namespace (in other words, they are not in an explicit namespace), and that their codes are in files placed in the lib/ directory of the project.

But sometimes you're going to want to use objects that are in deep namespaces. In this case, you will have to access the objects using an associative array type writing, and no longer object oriented.

For example, if we want to use the add() method of the \Math\Base\Compute object, we will have to write:

$res = $this->_loader['\Math\Base\Calcul']->add(3, 4);

It is also possible to use the get() method:

$res = $this->_loader->get('\Math\Base\Calcul')->addition(3, 4);

Explicit additions in the component

You also have the option of creating the object yourself and adding it to the component by specifying the name you want to give it:

// we create the instance of the object
$compute = new \Math\Base\Compute($this->_loader);

// we add the instance in the component
// (the three writings are equivalent))
// - with an object-oriented writing
$this->_loader->calculator = $compute;
// - with an associative array writing
$this->_loader['calculator'] = $compute;
// - or by using the set() method
$this->_loader->set('calculator', $compute);

// now that the instance is registered in the component,
// we can use it wherever the component is accessible
$res = $this->_loader->calculator->add(3, 4);

Additions by callback

It is also possible to assign an anonymous function. This function will be executed during the first call via the component; it must return the object which will then be returned by the component.

Here is an example of a controller:

class Homepage extends \Temma\Web\Controller {
    // method called before the action
    public function __wakeup() {
        $this->_loader->calc = function($loader) {
            if ($this['param'] == 'base')
                return (new \Math\Base\Compute($loader);
            return (new \Math\Other\Compute($loader));

    // action
    public function compute($type) {
        $this['param'] = $type:
        $this['res'] = $this->_loader->calc->add(3, 4);

    // another action
    public function compute2() {
        $this['res'] = $this->_loader->calc->add(3, 4);
  • Line 3: We use the __wakeup() method to initialize the controller.
  • Line 4: We create the calc key in the component, by assigning an anonymous function to it. This function takes a single parameter, which will receive the component instance. The function must return the object which will be returned later.
  • Lines 5 to 7: The variable $this refers to the controller itself. We look at the value contained by the param template variable to know which implementation will be returned.
  • Line 13: We assign to the param template variable the value received in the $type parameter.
  • Line 14: We use the component without having to worry about which implementation is used.
  • Line 19: We use the component. Here it will always be the \Math\Other\Compute object that is used, but that could change without needing to modify the action.

Additions by builder

A builder is a function that takes care of managing instantiations, and that we register with the setBuilder() method of the component.
This function takes two parameters: the first is an instance of the component; the second is the name of the object we are trying to access.

Here is an example:

// definition of the builder
$this->_loader->setBuilder(function($loader, $key) {
    // we see if the name of the requested object ends with
    // "BO" or "DAO"
    if (substr($key, -2) == 'Bo') {
        $classname = substr($key, 0, -2);
        return new \MyApp\Bo\$classname($loader);
    } else if (substr($key, -3) == 'Dao') {
        $classname = substr($key, 0, -3);
        return new \MyApp\Dao\$classname($loader);

// this call will use the \MyApp\Bo\Mail object

// this call will use the \MyApp\Dao\User object

Redefinition of the loader in configuration

Rather than explicitly call the setBuilder() method, it is possible to specify a loader object in the etc/temma.json file (see the configuration documentation). This object must inherit from the \Temma\Base\Loader class, and contain a protected builder() method. This method must take the name of the object to instantiate as a parameter, and return an instance of the latter.

Here is an example. To start, the Temma configuration in the etc/temma.json file:

    "application": {
        "loader": "MyLoader"

Then, in the lib/MyLoader.php file:

class MyLoader extends \Temma\Base\Loader {
    protected function builder(string $key) {
        if ($key == 'User')
            return new \MyApp\Dao\User($this);
        else if ($key == 'HttpClient')
            return new \Utils\Http\Client($this);
        throw new Exception("Unknown object '$key'.");

Then it becomes possible to write:

// use \MyApp\Dao\User
$user = $this->_loader->User->get($userId);

// use \Utils\Http\Client
$this->_loader->HttpClient->post($url, $data);
Previous: Views
Next: Sessions

Table of Contents