Nefunguje inject v komponentach

ondrej1
Člen | 13
+
0
-

Nevie niekto co robim zle?

Mam model:

namespace App\Model;

use Nette;

class Clanok extends Nette\Object {
	/** @var Nette\Database\Context */
	private $database;

	public function __construct(Nette\Database\Context $database) {
		$this->database = $database;
	}

	public function find($typClankov) {
		...
		return $clanky;
	}
}

a komponentu

namespace App\Components;

use Nette\Application\UI;

class Clanok extends UI\Control {

	/** @var \App\Model\Clanok @inject */
	public $clanok;

	/** @var string */
	private $typClankov = "vsetky";

	public function setTypClankov($typClankov) {
		$this->typClankov = $typClankov;
	}

	public function render() {
		$template = $this->template;
		$template->setFile(__DIR__ . '/clanok.latte');

		**$template->clanky = $this->clanok->find('prvy');**

		$template->render();
	}
}

v config.neon

services:
	- App\Model\Clanok

ale dostanem chybu:

Call to a member function find() on a non-object

(na zvyraznenom riadku v komponente clanok)

Editoval ondrej1 (16. 8. 2017 18:27)

David Matějka
Moderator | 6445
+
+2
-

ahoj, mrkni do doc

Zuben45
Člen | 268
+
0
-

V komponentě předávej závislosti přes konstruktor ;) http://nette.matej21.cz/cs/di

Editoval Zuben45 (16. 8. 2017 20:51)

ondrej1
Člen | 13
+
0
-

To vyzera trochu komplikovane. Pri vytvarani komponenty v presenteri cez new musim potom dodavat zavislost.
presenter:

/** @var \App\Model\Clanok */
private $clanokModel;

public function __construct(\App\Model\Clanok $clanokModel) {
	$this->clanokModel = $clanokModel;
}

protected function createComponentVsetkyClanky() {
	$clanok = new \App\Components\Clanok($this->clanokModel);
	$clanok->setTypClankov("vsetky");

	return $clanok;
}

Editoval ondrej1 (19. 8. 2017 14:27)

CZechBoY
Člen | 3608
+
0
-

@ondrej1 potom si může vytvořit továrnu na komponentu.
viz odkaz do dokumentace od @DavidMatějka https://doc.nette.org/…n/components#…

Šaman
Člen | 2632
+
+2
-

Při použití operátoru new bys musel stejně ty závislosti předat ručně. Buď do property (protože public property a anotace inject je pořád jen public property) anebo, lépe, pomocí inject metody (což je jen přejmenovaný setter).
Anotace a inject metody jsou jen konvence, kterým rozumí Nette DI kontejner a zohledňuje je, pokud sám vytváři instanci dané třídy. Když ji ale vytvoříš pomocí new, tak ti nepředá nikdo nic. Ani kdybys zkoušel pomocí new vytvořit presenter (ve kterém defaultně funguje i anotace).

Takže to, že ony závislosti vyžaduje už konstruktor je dobře! Hned při vytváření vidíš, co musíš předat. Pokud to bude pomocí setteru (inject metoda) nebo dokonce pomocí ošklivého zápisu do vnitřní public proměnné (inject anotace nad public property), tak to jsou závislosti skryté a tedy velmi nebezpečné z hlediska výskytu chyb (nezařve to hned při spuštění, ale bude se to chovat nesprávně).


A obecně platí: pokud chceš správně používat DI kontejner, tak se operátoru new vyhýbej. Kromě drobností jako new DateTime() a podobných (třeba tříd z Nette\Utils).

Editoval Šaman (19. 8. 2017 15:54)

CZechBoY
Člen | 3608
+
+1
-

@šaman i datetime je dobrý předávat přes di, třeba kvůli testování nebo konzistentnímu času v průběhu requestu

FantomX1
Člen | 3
+
0
-

@inject Nefunguje v componentach ani v nicom co sa z tych komponent vola co sa tyka Nette 2, v trojke som to este neskusal

Petr Parolek
Člen | 455
+
0
-

@CZechBoY OT: nikdy by mě nenapadlo dělat DateTime přes DI, ani nevím, jak bych instanci vytvářel. Mohl bys mi prosím popsat řešení?

Editoval ppar (21. 1. 2019 22:20)

CZechBoY
Člen | 3608
+
0
-

composer require kdyby/datetime-provider