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');
		}
	}
}