@inject kdekoliv nebo jen v presenteru?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
sKopheK
Člen | 207
+
0
-

nette 2.1dev
predpokladam, ze anotaci @inject muzu pouzit jen v presenterech, protoze jinde mi nejde… nebo se pletu?

David Matějka
Moderator | 6445
+
0
-

myslim, ze to nejak jde.. ale nepouzivej to :) ve sluzbach bys mel injectovat jen pres konstruktor

Tomáš Jablonický
Člen | 115
+
0
-

v presenterech a v controleru jinak v modelu už jen přes konstruktor nebo setr.

zaachi
Člen | 4
+
0
-

Zdravím,
mám problém v Nette 2.1 s manuálním vytvořením presenteru.

Jedná se o třídu Mailer, ve které bych rád využíval všechny fce a výhody presenteru, stejně jako své fce, které jsem již napsal do BasePresenteru:

<?php
	class MailerPresenter extends BasePresenter {}
?>

Vytvoření instance v BasePresenteru:

<?php
	protected $mailer;

	public function startup()
	{
		$this->mailer = new MailerPresenter();
		// Zde je třeba předat context Presenteru, ale bohužel nevím jak na to
		// Ve staré verzi Nette stačilo Environment::getContext
	}

	public function renderXXX()
	{
		// Ukazka uziti
		$this->mailer->registrationWebuserEmail(array('firstname' => 'Aaaa', 'email' => 'nejaky@email.cz'));
	}
?>

Zkoušel jsem předat context i za pomocí Service:

services:
	- App\FrontModule\Tools\MailerPresenter

A pak v BasePresenteru:

<?php
	/** @var \App\FrontModule\Tools\MailerPresenter @inject */
	public $mailer;
?>

Presenter se vytvoří správně, bohužel se nedaří předat potřebné závislosti. Děkuji za každou radu.

David Matějka
Moderator | 6445
+
0
-

@zaachi: priste prosim zaloz novy topic.

A k otazce: tohle neni spravny zpusob jak pouzivat presenter. Mailer by mela byt sluzba, ktera rozhodne od presenteru nededi. Co presne potrebujes za „fce a vyhody presenteru“?

Pavel Macháň
Člen | 282
+
0
-

zaachi napsal(a):

Zdravím,
mám problém v Nette 2.1 s manuálním vytvořením presenteru.

Jedná se o třídu Mailer, ve které bych rád využíval všechny fce a výhody presenteru, stejně jako své fce, které jsem již napsal do BasePresenteru:

<?php
	class MailerPresenter extends BasePresenter {}
?>

Vytvoření instance v BasePresenteru:

<?php
	protected $mailer;

	public function startup()
	{
		$this->mailer = new MailerPresenter();
		// Zde je třeba předat context Presenteru, ale bohužel nevím jak na to
		// Ve staré verzi Nette stačilo Environment::getContext
	}

	public function renderXXX()
	{
		// Ukazka uziti
		$this->mailer->registrationWebuserEmail(array('firstname' => 'Aaaa', 'email' => 'nejaky@email.cz'));
	}
?>

Zkoušel jsem předat context i za pomocí Service:

services:
	- App\FrontModule\Tools\MailerPresenter

A pak v BasePresenteru:

<?php
	/** @var \App\FrontModule\Tools\MailerPresenter @inject */
	public $mailer;
?>

Presenter se vytvoří správně, bohužel se nedaří předat potřebné závislosti. Děkuji za každou radu.

v BasePresenter chceš závislost na MailerPresenter? To je dost divný né? Neměla to být spíš nějaká mailer služba než presenter?

zaachi
Člen | 4
+
0
-

matej21 napsal(a):

@zaachi: priste prosim zaloz novy topic.

A k otazce: tohle neni spravny zpusob jak pouzivat presenter. Mailer by mela byt sluzba, ktera rozhodne od presenteru nededi. Co presne potrebujes za „fce a vyhody presenteru“?

Nechtěl jsem zakládat nový topic, protože jinak na každém fóru tě hned zjedou, proč jsem to nevložil do již vytvořeného..

Uznávám, že to není úplně správné užití presenteru, ale potřebuju některé jeho součásti pro vytváření templat pro emaily.

  • $this->link()
  • $this->createTemplate()
  • helpery
  • překlady
  • ..

Spíš by mě zajímalo jestli a jak je možné předat závislosti presenteru, vytvořenému ručně.

Díky

David Matějka
Moderator | 6445
+
+2
-

@zaachi: v 2.2 by melo byt vytvareni sablon snadnejsi, nez pred tim. Pro preklady si muzes kdekoliv injectnout ITranslator. Problem jsou ty linky..
ale neded presenter, myslim, ze by to mohlo zpusobit i dalsi problemy a vsechno by nemuselo fungovat korektne, pouzij radeji:

class Mailer
{
	protected $application;

	public function __construct(Nette\Application\Application $application)
	{
		$this->application = $application;
	}

	public function send()
	{
		$presenter = $this->application->getPresenter();
		$presenter->createTemplate();
		$presenter->link(...);
		...
	}
}
zaachi
Člen | 4
+
0
-

matej21 napsal(a):

@zaachi: v 2.2 by melo byt vytvareni sablon snadnejsi, nez pred tim. Pro preklady si muzes kdekoliv injectnout ITranslator. Problem jsou ty linky..
ale neded presenter, myslim, ze by to mohlo zpusobit i dalsi problemy a vsechno by nemuselo fungovat korektne, pouzij radeji:

class Mailer
{
	protected $application;

	public function __construct(Nette\Application\Application $application)
	{
		$this->application = $application;
	}

	public function send()
	{
		$presenter = $this->application->getPresenter();
		$presenter->createTemplate();
		$presenter->link(...);
		...
	}
}

mohl by jsi prosím ještě přidat způsob, jak naplníš třídu Mailer parametrem $application?

existuje tedy v Nette 2.1 alternativa pro tento kód ze starší verze?

<?php
	$presenter = new SomePresenter(Environment::getContext());
	$presenter->....
?>
David Matějka
Moderator | 6445
+
0
-

Mailer registrujes jako sluzbu v neonu a injectnes kam potrebujes – o predani zavislosti se postara nette

akadlec
Člen | 1326
+
0
-

Ať nezakládám nové téma. Jak to je s metodami inject v komponentách? Je lepší je používat nebo tam vše cpát přes kontruktor? Dejme tomu že mám komponentu na formy a injectuju tam kdyby/translation. Pokud si nezapnu inject: true v neonu tak se mi tam ta služba nedostane.

zaachi
Člen | 4
+
0
-

matej21 napsal(a):

Mailer registrujes jako sluzbu v neonu a injectnes kam potrebujes – o predani zavislosti se postara nette

Ahoj,
zkusil jsme řešení, které jsi navrhl, ale nefunguje mi zcela optimálně:

<?php
class Mailer
{
	private $application;
	private $presenter;

	public function __construct(\Nette\Application\Application $application)
	{
		$this->application = $application;
		$this->my_presenter = $this->application->getPresenter();
	}

	public function registrationWebuserEmail($webuser)
	{
		$template = $this->my_presenter->createTemplate();
	}
}
?>

Vytvoření služby

	mailer: App\FrontModule\Tools\Mailer

Init

	/** @var \App\FrontModule\Tools\Mailer @inject */
	public $mailer;

Užití

$this->mailer->registrationWebuserEmail(array(''));

Dostanu hlášku:

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

Pokud to napíšu takhle:

<?php
	$presenter = $this->application->getPresenter();
	$template = $presenter->createTemplate();
?>

Dostanu:

Call to undefined method parent::createTemplate()

Ale například metoda link() funguje správně. Takže to vypadá na problém u templat. Nakonec budu muset asi užít FileTemplate zvlášť.

Tomáš Votruba
Moderator | 1114
+
0
-

@akadlec: pro komponenty konstruktor a pro base komponentu factory – napr. takto https://github.com/…mFactory.php

@zaachi: Muzes take „vykrast“ presenter:

$template = clone $this->application->presenter->template;
akadlec
Člen | 1326
+
0
-

@Tomáš Votruba: ok, no mě se zdálo divné že musím všude zapnout inject že mě to nechce překládat ;)

akadlec
Člen | 1326
+
+1
-

@Tomáš Votruba: hele teď zkouším dostávat služby do komponent přes konstruktor a je to docela peklo, pokud finální komponenta dědí od třeba 3 tříd kde každá z nich neco injectuje tak finální konstruktor bude fakt obr, je to takto ok?

Zax
Člen | 370
+
0
-

@akadlec: Po vášnivé diskuzi na téma @inject bych řekl, že není úplně od věci si zapnout inject všude (třeba pomocí CompilerExtension, ať nemusíš všude psát inject: true) a pak v base třídách používat metody inject*, v konkrétních třídách pak konstruktor. Je to praktické (konstruktor si necháš volný pro potomky) a snad i docela čisté (nemůžu posoudit, viz můj podpis XD ).

Tomáš Votruba
Moderator | 1114
+
+1
-

@akadlec: Myslím, že to jde jednoduše. Na form factory jsem tě již odkázal. Všimni si event handleru onCreate (případně přidej vlastní dle potřeby na jiné místo).

Pokud to máš rozjeté a do formuláře chceš něco přidat, např. upravit jeho rendrování ve stylu bootstrap, stačí přidat event.

Je to takto srozumitelné?

Pokud na tvou situaci nelze uplatit, zkus ji sem popsat. Myslím, že existuje lepší řešení, než je mnohonásobná dědičnost.

akadlec
Člen | 1326
+
0
-

Takhle, mám normální komponenty (komponenty a formy) a ty dědí od BaseControl aplikace. A v této BaseControl která zase dědí od Nette se vkládá translator a další pomocné služby (gravatary, obrázky, atd.) a tyto služby se aktuálně předávají přes inject metody. Takže kdybych to z inject přesunul do konstruktoru tak mě tam přibude dalších cca 5 předávaných služeb.

Tomáš Votruba
Moderator | 1114
+
0
-

Rozumím, stačí použít control místo form. Tedy místo interface si vytvoříš továrničku, ukázka.

akadlec
Člen | 1326
+
0
-

Továrničky mám přes interface tak jak je uvedeno na tvém linku

Editoval akadlec (9. 6. 2014 10:30)

Tomáš Votruba
Moderator | 1114
+
0
-

Můj link vede na jiný příspěvek, ten mám na mysli.

akadlec
Člen | 1326
+
0
-

Jop vím, jen sem ukázal jak to řeším já ;) dělat ještě vlastní factory classu mě připadá zase jako tuna kódu navíc ne? Navíc mi pak uniká kde se použije ten interface co je právě v tom postu co si linknul ty. Použije se tedy jako klasický interface te factory classy? Takže se pak vytvoří služba z té factory classy která bude řešit závislosti?

Tomáš Votruba
Moderator | 1114
+
0
-

Záleží na tom, jestli chceš vytvářet přehledné závislosti (vhodné když s kódem pracuje více lidí) nebo psát co nejméně (kód vidíš jen ty sám). Je-li pro tebe důležité to druhé, používej @inject i v modelových třídách, ušetří-li ti to práci a čas.

Myslím ale, že je lepší závislosti neskrývat (hůře se hledají :)) + v i presenteru lze použít konstruktor místo @inject poměrně snadno. Pokud se rozhodneš pro tuto variantu (ten můj odkaz na jiné téma není nejlepší řešení, když na to teď koukám), odkážu tě tedy na příspěvek výše
Je to méně psaní, než dědit komponentu pokaždé, když tam budu chtít přidat závislost.

Pokud tě to zajímá, vyzkoušej implementaci sám a ptej se konkrétně.

Editoval Tomáš Votruba (9. 6. 2014 15:04)

akadlec
Člen | 1326
+
0
-

No a jak tedy správě? Udělat si BaseControlFactory a od ní pak dědit v samotných komponentách? Důvodem proč mám BaseControl je ten že v něm mám vytvořenou vlastní render metoru která se chová podle toho co to je za komponenta atd.

Tomáš Votruba
Moderator | 1114
+
0
-

Popiš mi, čeho potřebuješ přesně docílit, ať se mám čeho chytit.

akadlec
Člen | 1326
+
0
-

;) V podstatě ani ničeho velkého. Jednoduše mám komponentu „Avatar“ ta dědí od BaseControl aplikace a ta zase od Nettí control. A co tady řeším je inject vs constructor ;)

Komponenta avatar dostane přes konstruktor služby které vyžaduje (model, image službu atd.) V BaseControl aplikace je zase přidání služeb typu translator, gravatar, images, atd. Některé jsou napřímo přes injectMetody a něco je přes traity.

Samotná komponenta se pak vytvoří pomocí autmatické továrničky z interface. A co řeším je inject VS constructor. Protože pokud budu volat parent::__constrcut() tak si budu muset předávat vše co je postupně nutné, takže když bude komponenta avatar chtít sama o sobě 3 služby tak k nim budu muset přidat dalších cca 5 co jsou přes inject a už pak ten constructor bobtná.

Tomáš Votruba
Moderator | 1114
+
0
-

Myslíš, že bys sem mohl hodit kód (gist) všech tříd, jak to řešíš teď?

Editoval Tomáš Votruba (10. 6. 2014 19:17)

akadlec
Člen | 1326
+
0
-

Hele můžu ale fakt tam nehledej nic extra než sem v předchozím postu popsal ;)

class Control extends IPub\AppModule\Application\UI\Control
{
	/**
	 * @param User $user
	 * @param IFilesManager $filesManager
	 * @param IUserFacade $userFacade
	 */
	public function __construct(
		User $user,
		IFilesManager $filesManager,
		IUserFacade $userFacade
	) {
		parent::__construct();

		// Owner identity
		$this->userEntity	= $user->getIdentity();
		// File manager
		$this->filesManager	= $filesManager;
		// Module facades
		$this->userFacade	= $userFacade;
	}
}
abstract class Control extends \IPub\Application\UI\Control
{
	/**
	 * Implements autowiring extension
	 */
	use \Kdyby\Autowired\AutowireComponentFactories;

	/**
	 * Implement secured links for handle
	 */
	use \Nextras\Application\UI\SecuredLinksPresenterTrait;
}
abstract class Control extends \Nette\Application\UI\Control implements IObservable
{
	/**
	 * @param ITranslator $translator
	 */
	public function injectTranslator(ITranslator $translator)
	{
		$this->translator = $translator;
	}
}

Tady v ukázce vidíš jen jednu inject metodu, ale mám tam ještě 3 traity kde jsou taky inject metody. A o co mě jdě, jak správně ty komponenty vytvářet a předávat ji služby co požaduje.

Editoval akadlec (10. 6. 2014 20:04)

Filip Procházka
Moderator | 4668
+
0
-

Tohle rozhodně nikdy v konstruktoru nedělej

$this->userEntity = $user->getIdentity();

identita se to může v průběhu života aplikace změnit a pak bude komponenta ukazovat blbosti.

Tomáš Votruba
Moderator | 1114
+
0
-

@akadlec: Osobně bych snížil počet závislostí. Dříve jsem měl také velké komponenty, které uměly hodně věcí, kde byl inject potřeba. Např. $translator využíváš jak? Šablona a formulář jej můžou získat sami.

Vypadá to, že to máš komplikované, takže inject je na místě.


Co bys mohl (krok na delší cestě), je používat settery v configu.

akadlec
Člen | 1326
+
0
-

@Filip Procházka: mno koukám to je tam prehistorický kousek ;) ta komponenta má pak ještě vlastní setter na user account.

@Tomáš Votruba: Takhle ty přímé závislosti co vyžaduje komponenta se ji předí v konstruktoru, to je bych řek ok, v těch dalších parentech je pak už jen fakt ten translator, a služby co se využijí v šabloně, ale zase jen u některých komponent, třeba gravatar využije jen komponenta avataru či výpisu mailových adres, jiné ne apod.
Jinak translator se využívá jak v šabloně tak v některých částech kdy se přeloží třeba hlavička confirm dialogu, či vytváření nějakých elementů formu co je potřeba přeložit přímo než aby to překládalo nette.

btw jak může šablona dostat translator? Měl jsem za to že ji ho musím předat v createTemplate? Totéž form, pokud mu jej nepředám v setTranslator či nezapnu inject tak jej tam nemám ne?

Tomáš Votruba
Moderator | 1114
+
+1
-

Používám Kdyby\Translation, které šablony řeší samo. Tedy v presenteru ani komponentě translator nemám, přesto mám vše přeložené.

Do formu je můžeš předat jednou pomocí továrničky, viz výše. Předávat translator komponentě jen proto, abys ho mohl předat formuláři, by bylo zbytečné.

akadlec
Člen | 1326
+
0
-

nn do formu to taky dostávám přes továrničku. Kdyby\Translation mám taky a bez tohoto se mě šablony nepřekladaji:

protected function createTemplate($class = NULL)
{
    $template = parent::createTemplate($class);
    $template->registerHelperLoader(callback($this->translator->createTemplateHelpers(), 'loader'));

    return $template;
}
Tomáš Votruba
Moderator | 1114
+
0
-

Díky této sekci to není potřeba. Máš nejnovější verzi?

akadlec
Člen | 1326
+
0
-

nop ještě jsem nepřešel na nette 2.2 tak nějak mám z toho vítr že zas budu měsíc přepisovat ;)

Tomáš Votruba
Moderator | 1114
+
0
-

Přechod doporučuju :) Kdybys chtěl, budu na pixdevday a můžem na to mrknout.

akadlec
Člen | 1326
+
0
-

mno vím že mě to čeká ;) kupodivu dnes sem tu appku znova nahazoval na server a šup práskla se mě tam dvadvojka tak to asi nebudu odkládat ;)

akadlec
Člen | 1326
+
0
-

Takže zkouším přechod na 2.2 a zatím zjištuji že ty traity co sem měl pro extension aby dostaly do templaty své služby atd již nebudou potřeba, pokud jsem to pochopil správně? Přes latte makra a helpery šablony které si initnu v DI se ke všemu dostanu, je to správný postup? Udělal jsem si třeba helper getGravatarService() co mi vrátí službu gravataru a pak v makru {gravatar} k němu přistoupím přes:

$template->getGravatarService()

je to správný postup? Takto se zbavím docela dost inject metod.

Filip Procházka
Moderator | 4668
+
+1
-

Je to hack, je potřeba to mít na paměti. Ovšem funguje výborně :)

akadlec
Člen | 1326
+
0
-

Mno já takhle tedy přepsal Gravatar ext ale teď teda nevím zda to ponechat a nebo je to špatná cesta? Osobně se mě to líbí, protože se to vše pořeší extension a user nemusí nic dělat.

Filip Procházka
Moderator | 4668
+
0
-

Pokud bude mít @David Grudl, nebo kdokoliv jiný, lepší nápad, rád to přepíšu.