Nette\Security\User (nebo \Nette\Http\UserStorage) do Nette\Database\Connection::$onConnect
- emil
- Člen | 9
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
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
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 | 1245
@h4kuna Nestacilo by pridat sluzbam tag run?
https://api.nette.org/…ion.php.html#…
Editoval Felix (19. 9. 2017 8:18)
- h4kuna
- Backer | 740
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)
- h4kuna
- Backer | 740
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)