Database Explorer insert() vrací null

libik
Člen | 96
+
0
-

Ahoj,

snažím se zprovoznit logování SQL dotazů do databáze (pro INSERT a UPDATE). Našel jsem, že by k tomu šla využít událost Nette\Database\Connection událost onQuery.

Logování probíhá tak, že při ukládání záznamu A do db v libovolné fasádě se spustí onQuery, kteoru mám ve službě dblogger a uloží se záznam B do logovací tabulky.
V takovém případě ale Nette\Database\Explorer insert() nevrátí ActiveRow s vloženým záznamem A, ale vrátí null.

Zřejmě je to vlastnost, protože mezi vrácením ActiveRow proběhne ještě další ukládání do databáze logerem. Když logger vypustím, ActiveRow dostanu. Lze to ale nějak ošetřit?

fasáda (v ní je právě $row null):

class UzivateleFacade implements Authenticator
{

    private Explorer $database;
    private Passwords $passwords;

    /**
     *
     * @param \Nette\Database\Explorer $database
     * @param \Nette\Security\Passwords $passwords
     */
    public function __construct(Explorer $database, Passwords $passwords, DbLogger $dblogger)
    {
        $this->database = $database;
        $this->passwords = $passwords;
        $this->dblogger = $dblogger;
    }

    /**
     *
     * @param \Nette\Utils\ArrayHash $user
     * @return void
     */
    public function create(\Nette\Utils\ArrayHash $user): void
    {
        $row = $this->database->table('uzivatele')->insert([
            'jmeno' => $user->jmeno,
            'heslo' => $this->passwords->hash($user->heslo),
            'id_skupiny' => 0,
            'aktivni' => $user->aktivni
        ]);
    }

sluzba dblogger (vypíchnuto jen to podstatné)

class DbLogger
{

    use \Nette\SmartObject;

    private LogFacade $logFacade;
    private Connection $connection;
    protected Application $application;

    public function __construct(Connection $connection, LogFacade $logFacade, Application $application)
    {
        $connection->onQuery[] = \Closure::fromCallable([$this, 'logSql']);
        $this->logFacade = $logFacade;
        $this->application = $application;
    }

    public function logSql(Connection $connection, ResultSet|DriverException $result): Connection
    {
        $this->logFacade->create($log);
    }

}

fasáda pro dblogger

class LogFacade
{

    private Explorer $database;

    /**
     *
     * @param \Nette\Database\Explorer $database
     */
    public function __construct(Explorer $database)
    {
        $this->database = $database;
    }

    public function create($log): void
    {
                $this->database->table('log')->insert([
                    'datum' => new \Nette\Utils\DateTime(),
                    'zdroj' => $log->getZdroj(),
                    'log' => $log->getLog(),
                    'skript' => $log->getSkript(),
                    'chyba' => $log->getChyba()]);

    }

}

Díky za nějaký tip.

L

MajklNajt
Člen | 498
+
0
-

Ahoj, najjednoduchšie mi prode pre ten DB logger používať druhé spojenie, čiže si nakonfiguruj dve pripojenia, tomu sekundárnemu vypni autowiring a predaj ho ručne do LogFacade

uestla
Backer | 799
+
0
-

@libik Napadá mě přidat stavový boolean do loggeru, který řekne, že „se právě loguje“.

Něco ve stylu

class DbLogger
{
	private bool $logging = false;

	public function logSql(...)
	{
		if ($this->logging) {
			return ;
		}

		$this->logging = true;
		$this->logFacade->create($log);
		$this->logging = false;
	}
}

Tím pádem se ti query, které vyvolá fasáda, nebude logovat.

libik
Člen | 96
+
0
-

@MajklNajt super, díky za tip, funguje. Už dostávám, co potřebuju.

@uestla tohle jsem měl pořešené, jinak by docházelo k zacyklení (logování logování :)