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, …