Jak predavat zavislosti jako nove instance?
- Luděk Veselý
- Člen | 29
Resim ted problem – vytvorim si service, kterou nasledne predavam do dalsich trid:
services:
- Logger
class MyModel
{
private $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
}
A ja bych potreboval, aby mi do konstruktoru prisla vzdy nova instance te
tridy Logger
. Chci si ji pak nejak nastavit a pokud to udelam
v dalsi tride, tak to ovlivni nastaveni te prvni, coz nechci.
Zatim nejlepsi reseni, ke kteremu jsem dospel je predavat si misto tridy
Logger
iterface ILoggerFactory
:
interface ILoggerFactory
{
/** @return Logger */
function create();
}
A v konstruktoru tridy MyClass
k si vytvaret nove
objekty takto:
public function __construct(ILoggerFactory $logger)
{
$this->logger = $loggger->create();
}
Funkcne to je ok, ale existuje reseni jak to vyresit bez toho interface,
pouze predanim Logger
?
- newPOPE
- Člen | 648
@LuděkVeselý riesenie je celkom v poriadku (Interface by mal mat prednost pred Implementaciou).
Ale suhlasim s @JanSuchánek nie je mi jasne na co je to dobre. A skor ako nastavovanim konkretnej instancie by som siel cestou viacerych servisov a injektnes si ten ktory potrebujes.
- Luděk Veselý
- Člen | 29
Uvedu jeste priklad, kvuli kteremu to resim. Logger ma metodu
setTag
, ktera nastavi znackovani logu, abych pak mohl vyhledavat
napriklad veci ktere souvisi s objednavkou, veci ktere souvisi
s prihlasovanim atd..
class Logger
{
private $tag;
public function setTag($tag)
{
$this->tag = $tag;
}
/** Print error message. */
public function error($message)
{
echo $this->tag . " | error | $message\n";
}
}
Nejde mi tedy o konfiguraci ve smyslu napr. nastaveni slozky do ktere se
loguje, ale o nejake dilci nastaveni, ktere chci provest jen jednou. To
tagovani bych mohl resit treba upravou metody error
public function error($message, $tag) {...
, ale radsi bych si to
nastavil jen jednou.
- newPOPE
- Člen | 648
Rozumiem. No ak to je len jeden „typ“ loggeru napr nejaky FileLogger tak mi pride lepsie ten „tag“ mat v metode (tak ako to ma https://api.nette.org/…ebugger.html#_log).
Ak su tie loggery zasadne ine (jeden do DB, druhy cloud, treti sms…) tak zas je vyhodnejsie ich mat samostatne.
- greeny
- Člen | 405
Když už jsi zmínil ty tagy, přijde mi lepší udělat si nějaké
rozhraní ITaggable nebo ILoggable, které bude mít jednu metodu
getTag()
. Tohle rozhraní pak implementujou třídy ze kterých se
bude něco logovat.
No a výsledek bude vypadat nějak takhle:
interface ITaggable
{
function getTag();
}
class Logger
{
public function log(ITaggable $taggable, $message) {
$message = $taggable->getTag() . '|' . $message;
// save $message somewhere
}
}
// examples of usage:
class Model implements ITaggable
{
private $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function getTag() {
return 'model';
}
public function getUsers() {
try {
// get users
} catch (ModelException $e) {
$this->logger->log($this, 'Unable to get users');
}
}
}
class Calculator implements ITaggable
{
private $logger;
public function __construct(Logger $logger) {
$this->logger = $logger;
}
public function getTag() {
return 'calculator';
}
public function calculate(array $numbers) {
try {
// calculate
} catch (CalculatorException $e) {
$this->logger->log($this, 'Unable to calculate');
}
}
}