Nette Documentation Preview

syntax
Kaj je zabojnik DI?
*******************

.[perex]
Zabojnik za vbrizgavanje odvisnosti (DIC) je razred, ki lahko instancira in konfigurira objekte.

Morda vas bo presenetilo, vendar v številnih primerih ne potrebujete vsebnika za vbrizgavanje odvisnosti, da bi izkoristili prednosti vbrizgavanja odvisnosti (na kratko DI). Navsezadnje smo tudi v [prejšnjem poglavju |introduction] prikazali konkretne primere DI, pri čemer vsebnik ni bil potreben.

Če pa morate upravljati veliko število različnih predmetov z veliko odvisnostmi, bo vsebnik za vbrizgavanje odvisnosti resnično uporaben. To je morda primer spletnih aplikacij, zgrajenih na ogrodju.

V prejšnjem poglavju smo predstavili razreda `Article` in `UserController`. Oba imata nekaj odvisnosti, in sicer podatkovno bazo in tovarno `ArticleFactory`. In za ta razreda bomo zdaj ustvarili vsebnik. Seveda za tako preprost primer ni smiselno imeti vsebnika. Vendar ga bomo ustvarili, da pokažemo, kako izgleda in deluje.

Tukaj je preprost vsebnik s trdim kodiranjem za zgornji primer:

```php
class Container
{
	public function createDatabase(): Nette\Database\Connection
	{
		return new Nette\Database\Connection('mysql:', 'root', '***');
	}

	public function createArticleFactory(): ArticleFactory
	{
		return new ArticleFactory($this->createDatabase());
	}

	public function createUserController(): UserController
	{
		return new UserController($this->createArticleFactory());
	}
}
```

Uporaba bi bila videti takole:

```php
$container = new Container;
$controller = $container->createUserController();
```

Za predmet samo zaprosimo vsebnik in nam ni več treba vedeti, kako ga ustvariti ali kakšne so njegove odvisnosti; vsebnik vse to ve. Odvisnosti vsebnik vnese samodejno. V tem je njegova moč.

Do zdaj je bilo v vsebniku vse zakodirano. Zato naredimo naslednji korak in dodamo parametre, da bo vsebnik resnično uporaben:

```php
class Container
{
	public function __construct(
		private array $parameters,
	) {
	}

	public function createDatabase(): Nette\Database\Connection
	{
		return new Nette\Database\Connection(
			$this->parameters['db.dsn'],
			$this->parameters['db.user'],
			$this->parameters['db.password'],
		);
	}

	// ...
}

$container = new Container([
	'db.dsn' => 'mysql:',
	'db.user' => 'root',
	'db.password' => '***',
]);
```

Bolj pozorni bralci so morda opazili težavo. Vsakič, ko dobim predmet `UserController`, se ustvari tudi nova instanca `ArticleFactory` in podatkovna zbirka. Tega vsekakor ne želimo.

Zato dodamo metodo `getService()`, ki bo vedno znova vračala iste instance:

```php
class Container
{
	private array $services = [];

	public function __construct(
		private array $parameters,
	) {
	}

	public function getService(string $name): object
	{
		if (!isset($this->services[$name])) {
			// getService('Database') pokliče createDatabase()
			$method = 'create' . $name;
			$this->services[$name] = $this->$method();
		}
		return $this->services[$name];
	}

	// ...
}
```

Pri prvem klicu npr. na `$container->getService('Database')` bo `createDatabase()` ustvaril objekt podatkovne zbirke, ki ga bo shranil v polje `$services` in ga ob naslednjem klicu neposredno vrnil.

Tudi preostali del vsebnika spremenimo tako, da bo uporabljal `getService()`:

```php
class Container
{
	// ...

	public function createArticleFactory(): ArticleFactory
	{
		return new ArticleFactory($this->getService('Database'));
	}

	public function createUserController(): UserController
	{
		return new UserController($this->getService('ArticleFactory'));
	}
}
```

Mimogrede, izraz storitev se nanaša na kateri koli predmet, ki ga upravlja vsebnik. Od tod tudi ime metode `getService()`.

Opravljeno. Imamo popolnoma funkcionalen vsebnik DI! In lahko ga uporabljamo:

```php
$container = new Container([
	'db.dsn' => 'mysql:',
	'db.user' => 'root',
	'db.password' => '***',
]);

$controller = $container->getService('UserController');
$database = $container->getService('Database');
```

Kot lahko vidite, ni težko napisati DIC. Pomembno je, da sami objekti ne vedo, da jih ustvarja vsebnik. Tako je mogoče na ta način ustvariti kateri koli objekt v PHP, ne da bi pri tem vplivali na njihovo izvorno kodo.

Ročno ustvarjanje in vzdrževanje razreda vsebnika lahko precej hitro postane nočna mora. Zato bomo v naslednjem poglavju govorili o [vsebniku Nette DI |nette-container], ki se lahko ustvari in posodablja skoraj samodejno.


{{maintitle: Kaj je vsebnik za vbrizgavanje odvisnosti?}}

Kaj je zabojnik DI?

Zabojnik za vbrizgavanje odvisnosti (DIC) je razred, ki lahko instancira in konfigurira objekte.

Morda vas bo presenetilo, vendar v številnih primerih ne potrebujete vsebnika za vbrizgavanje odvisnosti, da bi izkoristili prednosti vbrizgavanja odvisnosti (na kratko DI). Navsezadnje smo tudi v prejšnjem poglavju prikazali konkretne primere DI, pri čemer vsebnik ni bil potreben.

Če pa morate upravljati veliko število različnih predmetov z veliko odvisnostmi, bo vsebnik za vbrizgavanje odvisnosti resnično uporaben. To je morda primer spletnih aplikacij, zgrajenih na ogrodju.

V prejšnjem poglavju smo predstavili razreda Article in UserController. Oba imata nekaj odvisnosti, in sicer podatkovno bazo in tovarno ArticleFactory. In za ta razreda bomo zdaj ustvarili vsebnik. Seveda za tako preprost primer ni smiselno imeti vsebnika. Vendar ga bomo ustvarili, da pokažemo, kako izgleda in deluje.

Tukaj je preprost vsebnik s trdim kodiranjem za zgornji primer:

class Container
{
	public function createDatabase(): Nette\Database\Connection
	{
		return new Nette\Database\Connection('mysql:', 'root', '***');
	}

	public function createArticleFactory(): ArticleFactory
	{
		return new ArticleFactory($this->createDatabase());
	}

	public function createUserController(): UserController
	{
		return new UserController($this->createArticleFactory());
	}
}

Uporaba bi bila videti takole:

$container = new Container;
$controller = $container->createUserController();

Za predmet samo zaprosimo vsebnik in nam ni več treba vedeti, kako ga ustvariti ali kakšne so njegove odvisnosti; vsebnik vse to ve. Odvisnosti vsebnik vnese samodejno. V tem je njegova moč.

Do zdaj je bilo v vsebniku vse zakodirano. Zato naredimo naslednji korak in dodamo parametre, da bo vsebnik resnično uporaben:

class Container
{
	public function __construct(
		private array $parameters,
	) {
	}

	public function createDatabase(): Nette\Database\Connection
	{
		return new Nette\Database\Connection(
			$this->parameters['db.dsn'],
			$this->parameters['db.user'],
			$this->parameters['db.password'],
		);
	}

	// ...
}

$container = new Container([
	'db.dsn' => 'mysql:',
	'db.user' => 'root',
	'db.password' => '***',
]);

Bolj pozorni bralci so morda opazili težavo. Vsakič, ko dobim predmet UserController, se ustvari tudi nova instanca ArticleFactory in podatkovna zbirka. Tega vsekakor ne želimo.

Zato dodamo metodo getService(), ki bo vedno znova vračala iste instance:

class Container
{
	private array $services = [];

	public function __construct(
		private array $parameters,
	) {
	}

	public function getService(string $name): object
	{
		if (!isset($this->services[$name])) {
			// getService('Database') pokliče createDatabase()
			$method = 'create' . $name;
			$this->services[$name] = $this->$method();
		}
		return $this->services[$name];
	}

	// ...
}

Pri prvem klicu npr. na $container->getService('Database') bo createDatabase() ustvaril objekt podatkovne zbirke, ki ga bo shranil v polje $services in ga ob naslednjem klicu neposredno vrnil.

Tudi preostali del vsebnika spremenimo tako, da bo uporabljal getService():

class Container
{
	// ...

	public function createArticleFactory(): ArticleFactory
	{
		return new ArticleFactory($this->getService('Database'));
	}

	public function createUserController(): UserController
	{
		return new UserController($this->getService('ArticleFactory'));
	}
}

Mimogrede, izraz storitev se nanaša na kateri koli predmet, ki ga upravlja vsebnik. Od tod tudi ime metode getService().

Opravljeno. Imamo popolnoma funkcionalen vsebnik DI! In lahko ga uporabljamo:

$container = new Container([
	'db.dsn' => 'mysql:',
	'db.user' => 'root',
	'db.password' => '***',
]);

$controller = $container->getService('UserController');
$database = $container->getService('Database');

Kot lahko vidite, ni težko napisati DIC. Pomembno je, da sami objekti ne vedo, da jih ustvarja vsebnik. Tako je mogoče na ta način ustvariti kateri koli objekt v PHP, ne da bi pri tem vplivali na njihovo izvorno kodo.

Ročno ustvarjanje in vzdrževanje razreda vsebnika lahko precej hitro postane nočna mora. Zato bomo v naslednjem poglavju govorili o vsebniku Nette DI, ki se lahko ustvari in posodablja skoraj samodejno.