Lze nastavit konkrétní implementaci služby pro službu generovanou továrnou?

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

Zdravím,
mám formulář, který odesílá nějaký data po api – takže dostane v konstruktoru nějakej interface na api, kam potom pošle odeslaná data. Klasicky v 99% případů používám jednu třídu, kterou mám teď v dic a normálně se autowirem předá.
Teďka potřebuju tomu formuláři dát nějakou jinou implementaci api. Jak to udělat?
Co mě zatím napadlo je udělat setter tomu formuláři a apinu dodatečně nastavit. Problém je kde sehnat instanci tý nový api – když ji registruju jako službu v dic tak mi vyběhne hláška, že mám 2 služby stejnýho typu (IApi třeba).
Šlo by to vyřešit i bez toho setteru? Že bych tý tovární třídě (automaticky generovaná přes nette interface) řekl, že pro tenhle presenter tam dosaď (v presenteru mám inject) tuhle třídu, jinak autowire.

Snad jsem to popsal pochopitelně.

Díky za reakce.

ondraondra81
Člen | 82
+
0
-

U te druhe sluzby v config neon pridej autowire: false a nejak si ji pojmenuj

A pak ji muzes pro ten dany form predat zase v configu primo do konstruktoru.

sorry odpovidam z mobilu takze presny kod ti ted nenapisu

CZechBoY
Člen | 3608
+
0
-

No ale ja mam generovanou tovarnu pro ten form, tzn. jak dic pozna ze chci tovarnu, ktera udela form s touhle sluzbou misto s touhle?
Pojmenovana sluzba myslim neni treba :-) stacilo by @App\DruhaApi

CZechBoY
Člen | 3608
+
0
-

Jde treba registrovat do DIC sluzbu, ale zakazat autowire na ten interface? V tom nette 2.4rc se da nejak vypnout autowire, ne? :-) ze bych si updatnul nejak…

David Grudl
Nette Core | 8082
+
0
-

Zkus sem dat konfig a kod, nerozumim moc zadani.

CZechBoY
Člen | 3608
+
0
-

Presenter využívající apiA (defaultní autowired)

class ApiAPresenter extends Presenter
{
	/** @var IFormFactory @inject */
	public $formFactory;

	protected function createComponentForm()
	{
		return $this->formFactory->create();
	}
}

Presenter využívající apiB

class ApiBPresenter extends Presenter
{
 	/** @var IFormFactory @inject */
	public $formFactory;

	protected function createComponentForm()
	{
		$form = $this->formFactory->create();
		$form->setApi(new ApiB); // toho new bych se chtěl minimálně zbavit a vyžádaj nějak službu
		// nebo nějak do tohohle presenteru dostat už nastavenou factory

		return $form;
	}
}

formulář používající api

/**
 * @method setApi(IApi $api) <-- tohohle bych se chtěl taky zbavit a rovnou v konstruktoru předat správnou službu
 */
class Form extends UI\Form
{
	private $api;
	public function __construct(IApi $api)
	{
		$this->api = $api;

		$this->setupForm();
	}

	private function create()
	{
		$this->addText(...);
		$this->onSuccess[] = function (Form $form, ArrayHash $values) {
			...
			$this->api->process(...);
		});
	}
}

interface IFormFactory
{
	/** @return Form */
	function create();
}

Editoval CZechBoY (13. 5. 2016 22:25)

Unlink
Člen | 298
+
+1
-

No dalo by sa vytvoriť druhú továrničku, len v tom druhom presenteri ju musíš injectnúť pomocou konštruktoru.

services
    - Model\ApiA			# Api A - Autowirovaná
	apiBService: 			# Api B - neautowirovaná
		class: Model\ApiB
		autowired: false
	- MyApp\IFormFactory	# Štandartná automaticky generovaná továrnička
	apiBFormFactory:		# Druhá automaticky vygenerovaná tovarnička, využívajúca ApiB
		class: MyApp\Form
		implement: MyApp\IFormFactory
		autowired: false
		arguments: [@apiBService]

	- ApiBPresenter(@apiBFormFactory) # Pomocou konštruktoru vložime druhú tovarničku
class ApiBPresenter extends Presenter
{
    /** @var IFormFactory */
    public $formFactory;

    public function __construct(IFormFactory $formFactory)
    {
        $this->formFactory = $formFactory;
    }

    protected function createComponentForm()
    {
        $form = $this->formFactory->create();
        return $form;
    }
}

v 2.4 by teoreticky malo fungovať aj

interface IFormFactory2 extends IFormFactory
{
}
-
		class: MyApp\Form
		implement: MyApp\IFormFactory2
		autowired: ['MyApp\IFormFactory2']
		arguments: [@apiBService]

A potom si klasicky injectneješ len MyApp\IFormFactory2

Editoval Unlink (14. 5. 2016 9:03)

CZechBoY
Člen | 3608
+
0
-

Moc diky za napady.

No rikam si, ze prece nebudu delat dve tovarny pro jednu vec, jen s jinym parametrem…

Takze tovarnu v dic jde v pohode jednoduse nastavit, ted uz zbejva jen ji nejak dopravit do presenteru.
Nastavit parametr inject metody by treba neslo?
Vola se driv inject nebo setup? :D
Asi teda pouziju konstruktorovy predani, protoze s tim injectem by byl jen problem.

Jeste jednou diky :-)

Unlink
Člen | 298
+
0
-

CZechBoY napsal(a):

No rikam si, ze prece nebudu delat dve tovarny pro jednu vec, jen s jinym parametrem…

No ono defakto sú dve, len si ich nette vygeneruje samo

Ono by bola ešte jedna možnosť, naimplementovať si tú továrničku sám a potom spraviť nejaký parameter pre metódu create.

class FormFactory {

    private $apiA;
    private $apiB;

    function __construct(ApiA $apiA, ApiB $apiB) {
        $this->apiA = $apiA;
        $this->apiB = $apiB;
    }

    function create($api = 'A') {
	   if ($api == 'A) {
           ...
       }
       else {
       }
	}

}

Nevýhodou je to, že sa viac napíšeš a nieje tie api služby sa nevytvárajú lazy.