Nette\Security\User (nebo \Nette\Http\UserStorage) do Nette\Database\Connection::$onConnect

emil
Člen | 9
+
0
-

Zdravím komunitu a obracím s prosbou o pomoc. Jak přes DI nainjektovat Nette\Security\User (nebo Nette\Http\UserStorage) do Nette\Database\Connection, resp. do $onConnect bez využítí konfiguračního parametru lazy? Potřebuji dostat do DB připojení nějaké SQL nastavení po připojení. Jedná se především o username, který ukládám do „proměnné“ RDBMS (PgSQL via SET myapp.user = 'xyz'). V trigerech db aplikací řeším auditování, kde mimo jiné potřebuji info o přihlášeném z aplikace.

Tím, že se $onConnect vykonává v konstruktoru Nette\Database\Connection, tak Nette\Security\User (nebo Nette\Http\UserStorage) je „prázdný“ (objekt není aktivovaný, Nette\Http\UserStorage::getIdentity() vrací null). Díky za radu.

h4kuna
Backer | 740
+
0
-

Takto zaregistruješ službu do metody Container::initialize(), která se vždy spouští po vyžádání kontejneru. Doporučuji použít to co jsem popsal v následujícím příspěvku.

neon:

services:
	connectionEvent:
		class: App\Events\Connection
		autowired: no
		tags:
			- run

Zde si navěsíš událost:

<?php

namespace App\Events;

use Nette\Database,
	Nette\Security;

class Connection
{

	public function __construct(Database\Connection $connection, Security\User $user)
	{
		$connection->onConnect[] = static function ($connection) use ($user) {
			$connection->query('login_user(?)', $user->getId());
		};
	}

}

Editoval h4kuna (28. 12. 2017 9:39)

h4kuna
Backer | 740
+
+1
-

Celkem mi na tom předchozím řešení vadilo, že se služby drží v paměti a přitom mají sloužit jednoúčelově. Tak jsem napsal jednoduché rozšíření. Kdy si napíšeš vlastní obsluhu události a vše bude fungovat. S předchozí třídou je toto rozšíření kompatibilní.

Rozšíření:

<?php

namespace App;

use Nette;
use Nette\DI as NDI;

class RunInicializeExtension extends NDI\CompilerExtension
{

	/** @var array */
	private $defaults = [
		'services' => [],
	];

	public function loadConfiguration()
	{
		$config = $this->config + $this->defaults;
		$builder = $this->getContainerBuilder();
		$this->defaults = [];
		foreach ($config['services'] as $class) {
			$this->defaults[] = $name = $this->prefix(str_replace('\\', '_', is_object($class) ? $class->getEntity() : $class));

			$builder->addDefinition($name)
				->setAutowired(false)
				->setFactory($class);
		}
	}

	public function afterCompile(Nette\PhpGenerator\ClassType $class)
	{
		$initialize = $class->getMethod('initialize');

		foreach ($this->defaults as $name) {
			$initialize->addBody('$this->{self::getMethodName(?)}();', [$name]);
		}
	}

}

Registrace v neonu:

extensions:
	runExtension: App\RunInicializeExtension

runExtension:
	services:
		- App\Events\Connection
		# - App\Events\Other

Použití:

<?php

namespace App\Events;


use Nette\Database,
	Nette\Security;

class Connection
{
	public function __construct(Database\Connection $connection, Security\User $user)
	{
		$connection->onConnect[] = static function ($connection) use ($user) {
			$connection->query('login_user(?)', $user->getId());
		};
	}
}

V Container::initialize to vytvoří následující:

$this->{self::getMethodName('runExtension.36_App_Events_Connection')}();

Výhody

  • není potřeba anotace
  • není potřeba interface
  • není potřeba procházet všechny služby
  • není event manager
  • jde určovat pořadí vykonání přidaných tříd
  • služby se nikde nedrží v paměti
  • doplní automaticky autowired: no

EDIT
Doplněno slovíčko static před anonymní funkci

Editoval h4kuna (28. 12. 2017 9:43)

Felix
Nette Core | 1183
+
0
-

@h4kuna Nestacilo by pridat sluzbam tag run?

https://api.nette.org/…ion.php.html#…

Editoval Felix (19. 9. 2017 8:18)

h4kuna
Backer | 740
+
+1
-

Viz první odstavec a nebo předchozí příspěvek. @Felix ne, protože když přidáš run tak se to sestaví jako getService() a drží se služba zbytečně v paměti během života aplikace, která vlastně nic nedělá, pak už je dobrý takovým službám dát autowired: no a v neposlední řadě není to tak ukecaný.

Nemusíš to mít jen na navěšování událostí, ale na jakoukoliv logiku, kterou potřebuješ vykonat po spuštění aplikace. Díky rozšíření jde také určovat pořadí spouštění.

Editoval h4kuna (19. 9. 2017 20:14)

Felix
Nette Core | 1183
+
0
-

Pardon, nevsiml jsem si. :-)

Uz chapu tvuj zamer, ono hodne zalezi co ta trida vykonava. Jestli si na Connection navesis svuj callback, tak sice tridu nedrzis v ramci DIC, ale je v Connection.

h4kuna
Backer | 740
+
+1
-

Good point, je jako reference v anonymní funkci, ikdyž ji nepoužiju.

class Connection
{
	public function __construct(Database\Connection $connection, Security\User $user)
	{
		$connection->onConnect[] = static function ($connection) use ($user) {
			$connection->query('login_user(?)', $user->getId());
		};
	}
}

Editoval h4kuna (19. 9. 2017 20:14)

h4kuna
Backer | 740
+
+1
-

@Felix ještě jinak aby se nedržel kontext tak existuje anonymní statická funkce. Sám jsem to nevěděl.

static function() {
}

Editoval h4kuna (19. 9. 2017 17:00)

Felix
Nette Core | 1183
+
0
-

Take jsem neznal, super. :-)