Problém s přechodem na nette 2.1 – Nette\Security\User $user a Circular reference
- n.u.r.v.
- Člen | 485
Ahoj, právě převádím jeden ze starších projektů z nette 2.0.xx na 2.1, ale mám zásek na jedné chybě:
Nette\InvalidStateException
Circular reference detected for services: user, authenticator, 27_Todo_EmailRepository, 29_Todo_LogRepository.
public function createService__29_Todo_LogRepository()
168: {
169: $service = new Todo\LogRepository(new Nette\Database\Context($this->getService('nette.database.default'), NULL, $this->getService('cacheStorage')), $this->getService('session'), $this->getService('user'));
170: return $service;
171: }
Zjistil jsem, že to je tím, že v LogRepository mám v konstruktoru Nette\Security\User $user.
Nevíte někdo, jak to rozchodit? V LogRepository potřebuji totiž zjišťovat, zda je user přihlášen a jeho další atributy (jméno a pod…)
Díky
- jiri.pudil
- Nette Blogger | 1032
- do
Nette\Security\User
se v konstruktoru předává autentikátor, pozor na kruhové závislosti
- n.u.r.v.
- Člen | 485
jiri.pudil napsal(a):
- do
Nette\Security\User
se v konstruktoru předává autentikátor, pozor na kruhové závislosti
Hmm, to trochu nepobírám – co to pro mě znamená? Jak mám tedy dostat usera do modelu?
Zjistil jsem ale ještě jeden problém – při insertu do DB se automaticky provede select tohoto posledního záznamu, ale problém je, že moje DB tabulka á primární klíč nepojmenovaný jako id, takže mi vznikne následující chyba:
PDOException #42S22
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'mail_udalost.id' in 'where clause
SELECT *
FROM `mail_udalost`
WHERE (`mail_udalost`.`id` = '10')
označen řádek 109: $this->connection->table("mail_udalost")->insert($data);
To bude asi velký problém -že? Protože s DB nic neudělám…
Editoval n.u.r.v. (16. 1. 2014 13:13)
- Vojtěch Dobeš
- Gold Partner | 1316
Takováto potíž je skvělým nasměrováním k vhodnému refaktoringu :).
Proč je LogRepository
potřeba v autentikátoru? (Kvůli tomu
předpokládám vzniká ona kruhová závislost.)
- Vojtěch Dobeš
- Gold Partner | 1316
enumag: Osobně mi ale více v nepořádku připadá potřeba Usera v modelu.
Proč ti přijde User
v modelu špatně?
- n.u.r.v.
- Člen | 485
vojtech.dobes napsal(a):
Takováto potíž je skvělým nasměrováním k vhodnému refaktoringu :). Proč je
LogRepository
potřeba v autentikátoru? (Kvůli tomu předpokládám vzniká ona kruhová závislost.)
Mno LogRepository vůbec v authenticatoru nemám…do logu zapisuji pomocí presenteru.
Log repository je injectovaný v base:
public function injectRepository(...,Todo\LogRepository $logRepository){
...;
$this->logRepository = $logRepository;
}
a v prezenterech volám $this->logRepository->insertLog();
- přidávám se k dotazu uživatele vojtech.dobes
Teď se spíš děsím té DB, protože pokud nevyřeším jak nette 2.1 zprovoznit na DB, kde primary key není pojmenován jak „id“, tak budu muset zůstat u staršího nette…
Edit: Dočasně vyřešeno tak, že jsem
v nette/databse/context.php přepsal v konstruktoru
$this->reflection = $reflection ?: new Reflection\ConventionalReflection;
na
$this->reflection = $reflection ?: new
Reflection\DiscoveredReflection($this->connection);
Ale toto neberu jako řešení… na foru jsem se dočetl, že by to mělo jít přepnout v neon pomocí reflection: discovered, ale to mi nefunguje
Editoval n.u.r.v. (16. 1. 2014 14:20)
- enumag
- Člen | 2118
@vojtech.dobes: Protože důvodem je obvykle
automatické filtrování v závislosti na $user->getId()
, což
dle mého názoru není starost modelu ale controlleru/presenteru (nemluvím jen
o Nette). Tedy controller by měl předat ID uživatele při volání
konkrétního dotazu – už proto aby se např. admin mohl dívat na data
ostatních uživatelů. Že se nikdo neoprávněný nedostane k cizím datům
je starost presenteru a autorizátoru.
Editoval enumag (16. 1. 2014 14:48)
- n.u.r.v.
- Člen | 485
enumag napsal(a):
@vojtech.dobes: Protože důvodem je obvykle automatické filtrování v závislosti na
$user->getId()
, což dle mého názoru není starost modelu ale controlleru/presenteru (nemluvím jen o Nette). Tedy controller by měl předat ID uživatele při volání konkrétního dotazu – už proto aby se např. admin mohl dívat na data ostatních uživatelů. Že se nikdo neoprávněný nedostane k cizím datům je starost presenteru a autorizátoru.
Ok, problém je, že v mém případě může nastat situace že se user smaže (úplně, ne příznak) ale já potřebuji v logu vidět i potom jak byl user aktivní…tedy když budu zapisovat do logu jen id usera, tak po smazání tohoto usera mi bude id k „píp“… Proto musím zapisovat do logu i jeho jméno a příjmení a další informace.
Proto mám v metodě pro zápis do logu toto:
public function insertLog(...){
...
...
if ($this->user->isLoggedIn()) {
$data = array(
"CV" => $this->session->id_visitor,
"CU" => $this->us->getIdentity()->getId(),
"JMENO" => $this->us->getIdentity()->JMENO,
"PRIJMENI" => $this->us->getIdentity()->PRIJMENI,
"CLT" => $udalost,
"DATUM" => $this->datum,
...
...
);
} else {
$data = array(
"CV" => $this->session->id_visitor,
"CU" => 0,
"JMENO" => "",
"PRIJMENI" => "",
"CLT" => $udalost,
"DATUM" => $this->datum
...
...
);
}
$this->connection->table("log")->insert($data);
}
}
Tedy se nabízí dvě řešení:
- v prezenteru metodě předat pole s daty pro zápis již připravené
- v prezenteru předat metodě $this->user…
- enumag
- Člen | 2118
@n.u.r.v.: Ani 1, ani 2. Předal bych
$user->getIdentity()
.
EDIT: Nebo bych si vytáhl entitu uživatele z databáze dle ID a předal tu. Identita totiž ne vždy obsahuje aktuální data o uživateli. Děje se to v případech kdy se data uživatele změnila poté co se přihlásil. Samozřejmě jen pokud to nemáš ošetřené např. pomocí vlastního UserStorage.
Editoval enumag (16. 1. 2014 15:07)
- n.u.r.v.
- Člen | 485
enumag napsal(a):
@n.u.r.v.: Ani 1, ani 2. Předal bych
$user->getIdentity()
.EDIT: Nebo bych si vytáhl entitu uživatele z databáze dle ID a předal tu. Identita totiž ne vždy obsahuje aktuální data o uživateli. Děje se to v případech kdy se data uživatele změnila poté co se přihlásil. Samozřejmě jen pokud to nemáš ošetřené např. pomocí vlastního UserStorage.
Hmm, vlastní userstorage nemám, ale to načtení dat z db podle id je docela dobré řešení -id usera dokážu předat…zkusím…
- n.u.r.v.
- Člen | 485
Milo napsal(a):
Databáze a konfigurace v neonu.
https://doc.nette.org/cs/configuring#…
Ano, toto jsem našel, ale bohužel reflection: discovered nefunguje – tento údaj je ignorován – nemá u mě na nic vliv…
Ale mám jiný problém – jak jsem dočasně natvrdo
v nette/database/context.php přepsal v konstruktoru
$this->reflection = $reflection ?: new Reflection\ConventionalReflection;
na
$this->reflection = $reflection ?: new
Reflection\DiscoveredReflection($this->connection);
tak to sice funguje, jenže teď při každém dotazu na db si nette nejdříve osahává DB (SHOW FULL COLUMNS), takže mám teď dvojnásobný počet dotazů na db…Což je špatné.
- n.u.r.v.
- Člen | 485
enumag napsal(a):
Jako druhý parametr, podívej se do API… Anebo spíše ukaž co v tom neonu máš protože NetteExtension tam to storage dává automaticky a není důvod to dělat jinak.
toto je můj config.neon
common:
parameters:
includes:
- const.neon
php:
date.timezone: Europe/Prague
# zlib.output_compression: yes
nette:
application:
errorPresenter: Error
database:
default:
dsn: 'mysql:host=localhost;dbname=db1'
user: user1
password: heslo1
reflection: discovered
db_2:
dsn: 'mysql:host=ip2;dbname=db2'
user: user2
password: heslo2
reflection: discovered
db_3:
dsn: 'mysql:host=ip3;dbname=db3'
user: user3
password: heslo3
reflection: discovered
session:
services:
authenticator: Authenticator
routerFactory: RouterFactory
router: @routerFactory::createRouter
- Todo\FirstsignRepository
- Todo\FirmaRepository(Nette\Database\Context(@nette.database.db_2), Nette\Database\Context(@nette.database.db_3))
- Todo\UzivatelRepository
- Todo\SluzbaRepository
- Todo\EmailRepository(%email_odesilatel%, %email_smtp%, %email_odkaz%, Nette\Database\Context(@nette.database.default))
- Todo\MenuRepository
- Todo\LogRepository(Nette\Database\Context(@nette.database.default))
Pak mám ještě const.neon, kde mám uložené konstanty (parameters:)
koukal jsem do temp/cache a je tam složka co má v názvu mimo jiné i slovo database a v ní je několik souborů takže to asi něco do cache ukládá…
Je také zajímavé, že někdy si to DB ošahá a někdy ne – např vlezu do sekce pro výběr usera k editaci (tedy se provádí select v db tabulce userů – a v tomto případě proběhne jen samotný select. Zase ale na jiných stránkách to provádí SHOW FULL COLUMNS pořád – i když dám reload stránky)
Editoval n.u.r.v. (17. 1. 2014 9:38)
- n.u.r.v.
- Člen | 485
enumag napsal(a):
Aha, jasně. Změň
Nette\Database\Context(@nette.database.db_2)
na@nette.database.db_2.context
, podobně pro ostatní databáze.
jů, už to funguje – osahá si to tabulku jen při prvním přístupu, pak už ne – výborně…díky…
Mno ještě by mě zajímalo, zda bude pro nette 2.1 vydán nový BootstrapRenderer – ten starý mi píše u některých metod deprecated…