Jak predavat zavislosti jako nove instance?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Luděk Veselý
Člen | 29
+
+4
-

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?

Jan Suchánek
Člen | 404
+
-2
-

Místo ILoggerFactory, mít LoggerFactory jako servisu? Ale nechápu výhodu.

looky
Člen | 99
+
-4
-
services:
	- LoggerFactory::create
class LoggerFactory
{
	/**
	 * @return Logger
	 */
	public static function create()
	{
		return new Logger();
	}
}
newPOPE
Člen | 648
+
+3
-

@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
+
0
-

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.

David Grudl
Nette Core | 8129
+
+4
-

Tuším

services:
  - Logger
  - MyModel(@\Logger())
newPOPE
Člen | 648
+
0
-

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.

Jan Suchánek
Člen | 404
+
0
-

Nehodí se na Logger spíš události? Kdyby\Events?

greeny
Člen | 405
+
+1
-

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