Komponenty a předávání závislostí
- Fakjo
- Člen | 7
Zdravíčko,
chtěl bych se zeptat spíše na námět, jak to řešíte. V podstatě se ptám na BasePresenter vs. BaseKomponenta.
Ukážu na příkladu (berte to jenom demonstračně):
use App\Helper\ImportantService;
abstract class BasePresenter extends App\Presenters\BasePresenter
{
/** @var ImportantService @inject */
public $importantService;
}
class AnotherPresenter extends BasePresenter
{
public function doAny(): void
{
$this->importantService->doAny(); // Je dostupná v pohodě a nemusí se dělat okliky přes konstruktor
}
}
Jenže komponenta:
use App\Helper\ImportantService;
abstract class BaseControl extends UI\Control
{
/** @var ImportantService @inject */
protected $importantService;
public function __construct(ImportantService $importantService)
{
$this->importantService = $importantService;
}
}
class AnotherControl extends BaseControl
{
// Jak udělat, abych si v této komponentě injectnul nějakou nedůležitou službu, kterou bude používat jen tato třída?
}
Dokáži si představit, že buď všechno nasypu do BaseControl, jenže to je prasárna. Jak teď jednoduše si vyžádám jednu nedůležitou službu a zároveň budu mít dostupnou i tu důležitou z té BaseControl?
Co třeba takto (nezkoušel jsem, jen myšlenka):
use App\Helper\NonImportantService;
class AnotherControl extends BaseControl
{
/** @var NonImportantService @inject */
protected $nonImportantService;
public function __construct(NonImportantService $nonImportantService)
{
parent::__construct();
$this->nonImportantService = $nonImportantService;
}
public function doAny(): void
{
$this->importantService->doAny(); // bude OK?
$this->nonImportantService->doAny(); // bude OK?
}
}
Je to správný postup, idea? Nebude to házet chybu při volání toho rodičovského konstruktoru bez parametru?
Děkuji předem za odpovědi.
Editoval Fakjo (22. 8. 2019 18:34)
- Ondřej Kubíček
- Člen | 494
volání parent::__construct();
bez toho parametru ti
samozřejmě vyhodí error
- Ondřej Kubíček
- Člen | 494
jinak teda ty si můžeš povolit inject přes annotaci
-
class: AnotherControl
inject: true
takže můžeš pak jak v presenteru a nepotřebuješ constuctor
/** @var NonImportantService @inject */
public $nonImportantService;
ale jako neříkám že to je nejlepší řešení
- Fakjo
- Člen | 7
Chápu, ale spíše bych se vyhnul tomu konfigu..
use App\Helper\ImportantService;
use App\Helper\NonImportantService;
public function __construct(NonImportantService $nonImportantService)
{
parent::__construct(ImportantService $importantService);
$this->nonImportantService = $nonImportantService;
}
Takže takhle jo? To je dost nepohodlné.
Editoval Fakjo (22. 8. 2019 18:54)
- MajklNajt
- Člen | 502
Fakjo napsal(a):
Chápu, ale spíše bych se vyhnul tomu konfigu..
use App\Helper\ImportantService; use App\Helper\NonImportantService; public function __construct(NonImportantService $nonImportantService) { parent::__construct(ImportantService $importantService); $this->nonImportantService = $nonImportantService; }
Takže takhle jo? To je dost nepohodlné.
takto ti to nebude fungovať, musíš si v podedenom konštruktore vyžiadať obe závislosti:
<?php
public function __construct(ImportantService $importantService, NonImportantService $nonImportantService)
{
parent::__construct($importantService);
$this->nonImportantService = $nonImportantService;
}
?>
Editoval MajklNajt (22. 8. 2019 19:43)
- Fakjo
- Člen | 7
CZechBoY napsal(a):
Co to je za službu že ji potřebuješ v každý komponentě? Já mám BaseComponent jen kvůli zjišťování cesty k šabloně, jinak tam nic jinýho nemám.
Ahoj, například nějaký Logger pro storage dat. Nebo já nevím třeba \Kdyby\Translation\Translator. Tohle všechno se mi hodí pro používání ve všech komponentách :)
- Fakjo
- Člen | 7
MajklNajt napsal(a):
Fakjo napsal(a):
Chápu, ale spíše bych se vyhnul tomu konfigu..
use App\Helper\ImportantService; use App\Helper\NonImportantService; public function __construct(NonImportantService $nonImportantService) { parent::__construct(ImportantService $importantService); $this->nonImportantService = $nonImportantService; }
Takže takhle jo? To je dost nepohodlné.
takto ti to nebude fungovať, musíš si v podedenom konštruktore vyžiadať obe závislosti:
<?php public function __construct(ImportantService $importantService, NonImportantService $nonImportantService) { parent::__construct($importantService); $this->nonImportantService = $nonImportantService; } ?>
No právě a tomuhle se chci vyhnout, když si to představím, že to používám u X komponent. :-/
- Fakjo
- Člen | 7
Gappa napsal(a):
Nehodil by se tady decorator?
Ahoj, zkus navázat příkladem na to mé, ať vidíme to použití. Není to co psal Ondřej Kubíček?
- Fakjo
- Člen | 7
CZechBoY napsal(a):
Co to je za službu že ji potřebuješ v každý komponentě? Já mám BaseComponent jen kvůli zjišťování cesty k šabloně, jinak tam nic jinýho nemám.
Zároveň si myslím, že tvořit ,,BaseKomponentu" je tak trochu anti-pattern (špatný návrh) …
Editoval Fakjo (23. 8. 2019 10:56)
- Gappa
- Nette Blogger | 209
Fakjo napsal(a):
Gappa napsal(a):
Nehodil by se tady decorator?
Ahoj, zkus navázat příkladem na to mé, ať vidíme to použití. Není to co psal Ondřej Kubíček?
Tak trochu, ale ne úplně – prostě se tam předá přesně daná závislost.
abstract class BaseControl extends Control
{
/** @var MyService */
protected $myService;
public function setMyService(MyService $myService): void
{
$this->myService = $myService;
}
}
config.neon
services:
myService: App\MyService
decorator:
BaseControl:
setup:
- setMyService(@myService)
Píšu to po paměti bez testování, tak to nemusí nutně fungovat na první dobrou :)