Spojení dvou tabulek (opak ref)

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

Zdravim,

dejme tomu ze mam tabulku user se sloupci id, email, password, pak mam tabulku userdata se sloupci user_id, firstname, surname a useradata2 se sloupci user_id, address, city.

A potreboval bych nejdrive spojit user s userdata. Vim ze muzu pouzit

$user->related('userdata')->fetch()

ale to mi vybere jen data z druhe tabulky. Data z obou tabulek sice muzu vybrat takto:

$user->related('userdata')->select('user.*, userdata.*')->fetch()

ale zase pak nemuzu uz pouzit related na userdata2.

Chtelo by to neco co mi provede

SELECT user*, userdata.* FROM user INNER JOIN userdata ON user.id = userdata.user_id

a nevrati Row ale ActiveRow.

Delam neco spatne?

enumag
Člen | 2118
+
0
-

Ano, špatně to používáš. Znovu vybírat user.* nepotřebuješ, protože to již máš v $user. Obdobně data z tabulky userdata2 (doporučuji přejmenovat) máš získat druhým voláním related.

$data = $user->related('userdata2'); //vrátí Selection, pro zpracování použij foreach

Editoval enumag (22. 10. 2012 7:46)

thorewi
Člen | 84
+
0
-

Omlouvam se, to $user jsem tam dal jen pro zjednodušení, ve skutečnosti ho nemám, zasílám celou funkci:

	public function getOne($id) {
		$user = $this->connection->table('users')->get($id);

		if($user->role == 'client' || $user->role == 'tutor') {
			return $user->related($user->role)->select("user.*, $user->role.*")->fetch();
		}
		return $user;
	}

Z tohoto lze videt ze ty pomocne tabulky se jmenuji tutor nebo client a ja je chci spojit s tabulkou user podle toho, jakou ma uzivatel roli.

thorewi
Člen | 84
+
0
-

ale chapu ze to neni ORM takze to asi vyresim jinak… diky za ochotu

Editoval thorewi (22. 10. 2012 9:31)

petr.pavel
Člen | 535
+
0
-

Nemůžeš použít $user->related(), protože jak pravil enumag, $user není Selection.

Řešení 1:

public function getOne($id) {
	$user = $this->connection->table('users')->get($id);

	if (!in_array($user->role, array('client', 'tutor'))) {
		return $user;
	}

	return $this->connection->table('users')->where('id', $id)
		->related($user->role)->select("user.*, $user->role.*")->fetch();
}

Řešení 2: (ušetříš opakovaný dotaz do users)

public function getOne($id) {
	$user = iterator_to_array($this->connection->table('users')->get($id));

	if (!in_array($user['role'], array('client', 'tutor'))) {
		return $user;
	}

	$role = $this->connection->table($user['role'])->where('user_id', $id)->fetch();
	$user = array_merge($user, iterator_to_array($role));
	return $user;
}

Kdyby ti vadilo, že vrací pole, můžeš zkusit přetypovat na objekt přes return (object) $user;

thorewi
Člen | 84
+
0
-

Nechapu prvni vete – vsak related se pouziva na ActiveRow ne, takze proc bych to nemohl pouzit?

Jinak k tvemu reseni – presne takove jsem mel (reseni cislo 2), ale pak jsem si uvedomil ze chci vracet object, tak jsem to pretypoval na object… Pak jsem si uvedomil ze bych s tim rad pracoval jako s polem i jako s objektem, tak jsem to pretypoval na ArrayHash. A pak jsem si uvedomil, ze pozdeji na to potrebuju jeste pouzivat to related, takze jsem hledal reseni ktere mi vrati ActiveRow.

petr.pavel
Člen | 535
+
0
-

Ach jo, máš pravdu, napsal jsem úplnou blbost (řešení 1) a navíc jsem tvůj původní dotaz nečetl moc pozorně. Příště se pořádně vyspím, než budu radit. Soráč.

enumag
Člen | 2118
+
0
-

@thorewi: Základní nesmysl v té tvé funkci je, že related vrátí Selection, což je množina řádků, a ty to pomocí fetch() omezuješ na jeden. To je omluvitelné pouze pokud víš že dostaneš jen jeden (např. FK je unikátní) nebo pokud ti stačí libovolný. V obou případech je vhodné přidat před fetch ještě ->limit(1).

No a co s tím teda? Tohle se dělá úplně jednoduše, z té funkce prostě vrať $user (vždy) a to related volej až tam, kde ta data reálně potřebuješ. Tzn. roli kontroluj také až tam.