Jak rozsirit UserStorage?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
juzna.cz
Člen | 248
+
0
-

Stahl jsem aktualni nette z gitu a snazim se nastavit si vlastni UserStorage, aby mi nacitalo uzivatele z Doctrine. Chtel bych, aby se do session ukladalo pouze id uzivatele, a pri kazdem requestu se uzivatel nacetl z DB.

Myslel jsem, ze neco takoveho by mohlo fungovat:

class MyUserStorage extends UserStorage {
	public function setIdentity(IIdentity $identity = NULL) {
		// ukladma pouze id
		$this->getSessionSection(TRUE)->identityId = $identity ? $identity->getId() : null;
		return $this;
	}


	public function getIdentity() {
		if(!$session = $this->getSessionSection(FALSE)) return NULL;
		if(!$id = $session->identityId) return NULL;

		// nactu z doctrine
		return $this->em->getRepository(IdentityEntity::getClassName())->find($id);
	}
}

Toto vsak nefunguje, protoze metoda getSessionSection mi cele session smaze, jestlize v nem neni instance IIdentity. Musim tedy zkopirovat tuto metodu a kvuli ni celou tridu (kvuli private properties).

Mate nekdo nejake elegantni reseni? (A tim nemyslim takove hromady kodu jako ma treba HosipLan v Kdyby)

Editoval juzna.cz (16. 1. 2012 12:10)

Filip Procházka
Moderator | 4668
+
0
-

Pošli si pull

189: - if (!$section->identity instanceof IIdentity || !is_bool($section->authenticated)) {
189: + if (empty($section->identity) || !is_bool($section->authenticated)) {

Já se toho kódu taky rád zbavím ;)

juzna.cz
Člen | 248
+
0
-

@HosipLan: To by chtelo jeste trosku lip – treba nevynucovat jmeno promenne v session (identity), protoze ja bych radeji pouzil identityId.

Chce to promyslet, treba jeste zrefaktorovat tu zaklazni UserStorage ;)

David Grudl
Nette Core | 8228
+
0
-

Ale na ten interface je navázáno všechno další. A jméno proměnné v session je věcí interní implementace, ne?

pave.kucera
Člen | 122
+
0
-

Dá se to docela jednoduše obejít, používám:

<?php
/**
 * @param \Nette\Security\IIdentity
 * @return UserStorage
 */
public function setIdentity(\Nette\Security\IIdentity $identity = NULL)
{
	$this->identity = $identity;
	if ($identity instanceof Model\UserEntity) {
		$identity = new \Nette\Security\Identity($identity->getID());
	}
	return parent::setIdentity($identity);
}


/**
 * @return \Nette\Security\IIdentity|NULL
 */
public function getIdentity() {
	$identity = parent::getIdentity();
	if (!$identity) {
		return NULL;
	}

	// Find user
	$identity = $this->userDao->find($identity->getId());
	return $identity;
}
?>
juzna.cz
Člen | 248
+
0
-

Opet jsem narazil na tento stary problem. S pouzitim interfacu je vse v poradku, proti tomu zadna. Problem nastane, kdyz si chci trosku zmenit chovani UserStorage. Vetsinu logiky ale chci zachovat. Kopirovat si tuto tridu a zmenit v ni kousek kodu nechci, rad bych ji reusoval a pretizil metody.

Vnitrni implementace moji pretizene tridy by se mela chovat trosku jinak, a to ze do session ulozi jen ID uzivatele. Metody {g/s}etIdentity si ze session vytahnou co potrebuji a pretvori to na instanci IIdentity – a uz je na me, jak si to udelam.
(sice je to detail, ale v ramci tohoto si zmenim i nazev promenne v session na identityId/userId, aby davalo vice smysl)

Problem je, ze se UserStorage neda jednoduse pretizit prave kvuli tomu jednomu prikazu – musel bych vykopirovat celou metodu getSessionSecton.

(az budu doma u PC zkusim udelat pull request)

juzna.cz
Člen | 248
+
0
-

Pull Request a zde ukazka meho rozsireneho UserSrorage. Ted si tam muzu delat jakekoliv cachry machry a nemusim si vykopirovavat celou tridu z frameworku. To, co se kam uklada do session, lze nastavit ve 4 pretizenych metodach. Veskery zbytek logiky (expirace, kontrola browseru) zustane pekne v Nette a nemusim na ni sahat a funguje.

<?php
/**
 * Extended Nette's storage for users - stores only ID to session and always loads full user from database
 *
 * @author Jan Dolecek <juzna.cz@gmail.com>
 */
class UserStorage extends Nette\Http\UserStorage
{
	/** @var UserService */
	private $userService;

	/** @var User cached, loaded from database */
	private $user;



	public function __construct(\Nette\Http\Session $sessionHandler, UserService $userService)
	{
		parent::__construct($sessionHandler);
		$this->userService = $userService;
	}



	public function setIdentity(IIdentity $user = NULL)
	{
		$this->user = $user;
		$this->getSessionSection(TRUE)->identityId = $user ? $user->getId() : NULL;
		return $this;
	}



	public function getIdentity()
	{
		if ($this->user) return $this->user;

		$session = $this->getSessionSection(FALSE);
		return $session && $session->identityId ? $this->user = $this->userService->fetch($session->identityId) : NULL;
	}



	protected function isSessionValid(SessionSection $section)
	{
		return !empty($section->identityId) && is_bool($section->authenticated);
	}



	protected function clearSession(SessionSection $section)
	{
		unset($section->identityId);
	}

}
?>
juzna.cz
Člen | 248
+
0
-

Opet jsem na to narazil v dalsi app, takze znovu vykopavam ;) Nebude se to nejak resit, at nemusim delat zbytecne hacky? Dik

Majkl578
Moderator | 1364
+
0
-

Není to tak dlouho, co jsem řešil totéž – integraci Doctrine entity jako IIdentity. Došel jsem tehdy k řešení, které mi přišlo poměrně čisté a bez problémů jej používám doteď. Princip je jednoduchý – místo entity do storage ukládám jen jednoduchý objekt fake identity, která udržuje ID, nic víc.
Zde je Gist.

pekelnik
Člen | 462
+
0
-

Pouzival jsem vlastni reseni s pomerne hodne prekopanym UserStorage, ale obcas mi to blblo, od te doby co pouzivam Majklovu FakeIdentity je to v pohode, protoze na UserStorage se nemusi temer sahat.