BaseControl inject – nefunguje?

- Jiří Nápravník
 - Člen | 710
 
Chci používat komponentu pro práci s flashMessages napíč všemi komponenty, tak jsem si vytvořil BaseControl.
namespace AppModule\Component;
use Nette\Application\UI\Control;
class BaseControl extends Control
{
	/**
	 * @var JiriNapravnik\Component\FlashMessage\IFlashMessageFactory
	 * @inject
	 */
	public $flashMessageFactory;
	public function __construct(){
		parent::__construct();
	}
	protected function createComponentFlashMessages()
	{
		return $this->flashMessageFactory->create();
	}
}
v neonu mám potom:
services:
	-
		class: AppModule\Component\BaseControl
		inject: true
Pokud však zadám v šabloně
{control flashMessages}
Dostanu Call to a member function create() on a non-object. Prostě $this->flashMessageFactory je nullový…
Přitom když se podívám do vygenerovaného kontejneru, tak je zdá se vše v pořádku:
	/**
	 * @return AppModule\Component\BaseControl
	 */
	public function createService__122()
	{
		$service = new AppModule\Component\BaseControl;
		$service->flashMessageFactory = $this->getService('97_JiriNapravnik_Component_FlashMessage_IFlashMessageFactory');
		return $service;
	}
pokud v tom createComponentFlashMessages udělám před return na zkoušku, tohle, jestli nevrací null místo služby, tak to funguje dle očekávání…
$this->flashMessageFactory = $this->getPresenter()->context->getByType('JiriNapravnik\Component\FlashMessage\IFlashMessageFactory');
				
- Oli
 - Člen | 1215
 
Zkoušel jsi to přes inject metodu? Nevím jestli to pomůže, jen takovej nápad. Viz. cheatsheet o di.

- Jiří Nápravník
 - Člen | 710
 
Zkoušel výsledek je stejný. Jen vygenerovaný kód DI kontejneru se liší, že místo:
/**
 * @return AppModule\Component\BaseControl
 */
public function createService__122()
{
    $service = new AppModule\Component\BaseControl;
    $service->flashMessageFactory = $this->getService('97_JiriNapravnik_Component_FlashMessage_IFlashMessageFactory');
    return $service;
}
je
/**
 * @return AppModule\Component\BaseControl
 */
public function createService__122()
{
    $service = new AppModule\Component\BaseControl;
    $service->injectFlashMessageFactory($this->getService('97_JiriNapravnik_Component_FlashMessage_IFlashMessageFactory'));
    return $service;
}
ale nefunguje stejně

- David Matějka
 - Moderator | 6445
 
jak vytvaris konkretni komponentu (ukaz jak registraci v neonu tak presenter)? proc mas basecontrol registrovany jako sluzbu?

- Jiří Nápravník
 - Člen | 710
 
BaseControl mam jako sluzbu, z toho duvodu abych tam mohl dat tu FlashMessageFactory. Pokud bych ji musel dat pres konstruktor, tak bych pak musel prespisovat vsechny konstruktory, co od ni dedi a dopadlo by to stejne jako kdybych injectoval v Presenteru.
Tady je pak třeba ta komponenta, co od BaseControlu pak dědí:
final class ForgottenPasswordForm extends BaseControl
{
	private $formFactory;
	private $userFacade;
	public function __construct(FormFactory $formFactory, UserFacade $userFacade)
	{
		parent::__construct();
		$this->formFactory = $formFactory;
		$this->userFacade = $userFacade;
	}
	protected function createComponentForm()
	{
		$form = $this->formFactory->create();
		...
		$form->onSuccess[] = array($this, 'processForm');
		return $form;
	}
	public function processForm(UI\Form $form)
	{
		...
	}
	public function render()
	{
		....
	}
}
interface IForgottenPasswordFormFactory
{
	/**
	 * @return ForgottenPasswordForm
	 */
	public function create();
}
Neon:
services:
	- UserModule\FrontModule\Components\User\ForgottenPassword\IForgottenPasswordFormFactory
šablona:
{control flashMessages}
{control form}
				
- David Matějka
 - Moderator | 6445
 
ta registrace BaseControlu je naprosto zbytecna, ta sluzba se nikde
nevyuzije, budes vyuzivat jen tu IForgottenPasswordFormFactory ⇒ musis
nastavit inject: true u kazde konkretni factory

- Jiří Nápravník
 - Člen | 710
 
Ježkovi voči, já jsem debil:D Jo máš pravdu, mě to nějak vůbec nedošlo, že to je jen klasický dědění a čumím to na to jak blbec:)
A nenapadá tě nějaké lepší řešení, jak bych tohle mohl udělat jen jednou a nemusel zapínat pro každý Control inject: true? Protože od BaseControlu budu chtít dědit každou komponentu, a nechce se mi moc všude připisovat inject: true. Viděl jsem tu někde i řešení, že se nastavil inject pro vše, ale to zase moc nechci. Prostě jak nejjednodušeji vyřešit, abych měl v každé komponentně ten flashMessage.

- David Matějka
 - Moderator | 6445
 
mozna by slo pouzit dedicnost sluzeb, ale moc si tim nepomuzes. nebo si vytvorit compiler extension, ktery to zapne

- Jiří Nápravník
 - Člen | 710
 
Nakonec jsem to vyřešil trošku ošklivě přes sáhnutí na context a vytáhnutím getByType.
A pokud by chtěl někdo jiný, tak ten enabler, je třeba tady.
Díky za pomoc

- Filip Procházka
 - Moderator | 4668
 
No a nebo použiješ Kdyby/Autowired component factories, které fungují i v komponentách :)

- Filip Procházka
 - Moderator | 4668
 
@Šaman nechceš napsat rozšíření které projde služby a zapne inject pokud je to komponenta? Mohlo by to přijímat list interfaců na které by to ty injecty zapínalo :) Presentery, komponenty, …