lundi 14 janvier 2019

Symfony DI: Is it possible to get the database class from the container without "initializing" it in my main init file?

Up until now, I had a static method in my "Database" class:

public static function getInstance()
{
    if (!isset(self::$instance)) 
        self::$instance = new Database();

    return self::$instance;
}

Where I call to a $this->db = Database::getInstance(); variable in every class __construct. And keep my db connection open (I have more than one database to connect to).

And since my post on code review - I discovered "Dependency Injections". I'm trying to understand how DIs work. Specifically with Symfony, and how it can solve my problem.

This is my previous post: Symfony DI: Uncaught ArgumentCountError: Too few arguments to function App::__construct(), 0 passed in index.php on line 28 and exactly 1 expected

Where I understood that what the Symfony container does is basically define my classes (and "initialize" them) from the beginning of my code (index.php) and when I "inject" a class-object via __construct, I wont get any errors for "missing variables", since my container knows which object it should inject + the object is already created, and does that for me: 'when I have a SystemUser class I "expect" a Database class injected'.

Meaning, I have to create an object in my index.php file, to inject a dependency. I cannot initialize every class that uses the Database class since there are too many.

I'll give a very simple example for using the database class more than once:

index.php

require_once 'vendor/autoload.php';



use TestingDI\App;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

$containerBuilder = new ContainerBuilder();
$containerBuilder->register('database', '\TestingDI\Database');

$containerBuilder->register('system.user', '\TestingDI\SystemUser')
                 ->addArgument(new Reference('database'));

$containerBuilder->register('controller', '\TestingDI\Controller')
                 ->addArgument(new Reference('database'));

$containerBuilder->register('app', '\TestingDI\App')
                 ->addArgument(new Reference('system.user'));


$database       = $containerBuilder->get('database');
$systemUser     = $containerBuilder->get('system.user');
$app            = $containerBuilder->get('app');

App.php:

  • Gets the SystemUser class from the construct (thanks to the DI container).

  • Sets $this->systemUser variable obj - Which uses the Database class (again, thanks to DI container).

  • And then calls a Controller class

This is the code:

namespace TestingDI;

use TestingDI\SystemUser; 


class App {

    public $systemUser; 

    public function __construct(SystemUser $systemUser)
    {
        $this->systemUser = $systemUser;
        echo "im in app and i have system user with me <br>";
        var_dump($this->systemUser);

        $controller = new Potato();
    }
}

SystemUser.php:

namespace TestingDI;

use TestingDI\Database;

class SystemUser {

    public $db; 

    public function __construct( Database $database )
    {
        $this->db = $database;
        echo $this->db->test . " <br>";
        $this->db->test = 2;
        echo $this->db->test . " <br>";
    }
}

Database.php:

namespace TestingDI;


class Database {

    public $pdo = "DATABASE: I'm a pdo instance <br>"; 
    public $test = 1; 

    public function __construct()
    {
        echo "DATABASE: init construct database <br>";
    }

    public function hello()
    {
        echo "DATABASE: hello database <br>";
    }
}

And a Potato class:

  • that needs the Database object (and i do not want to initialize potato , since i wont be using it on ever page on my app).

  • Has the customer class - that also needs to use the Database class - but do not want to initialize customers, since it's not gonna be in use in every page.

this is the code:

<?php 
namespace TestingDI;

class Potato 
{

    public $db;

    public function __construct( Database $db)
    {

        $customer = new Customer();     
        $this->db = $db; 
        echo "---------------------------------";
        var_dump($db);
        echo "---------------------------------";
    }
}

How do I use the Database class from the container in new created objects? Or at least in a proper way, regarding my situation.

Aucun commentaire:

Enregistrer un commentaire