Přepis MySQL dotazu do Nette Database Explorer

cafesk8
Člen | 103
+
0
-

Zdravím,

mám SQL dotaz pro hledání nejbližších lokací v tabulce pro zadané GPS souřadnice. Funguje to jak má:

<?php
	$vysledek = $this->db->query('
    	SELECT id, lat, lng, address,
			111.045
			* DEGREES(ACOS(COS(RADIANS(latpoint))
			* COS(RADIANS(lat))
			* COS(RADIANS(longpoint) - RADIANS(lng))
			+ SIN(RADIANS(latpoint))
			* SIN(RADIANS(lat)))) AS distance_in_km
		FROM advert
		JOIN (
			SELECT  '.$lat.'  AS latpoint,  '.$lng.' AS longpoint
		) AS p ON 1=1
		#HAVING distance_in_km < 10
		ORDER BY distance_in_km
		LIMIT 15'
	);
?>

Avšak rád bych si to nějak přepsal do Database Exploreru něco jako:

<?php
	$vysledek = $this->db->table('advert')->where(/* zde nějak přepsat ten výpočet s JOIN apod.? */)->limit(15);
?>

Jde mi o to, abych výsledky měl spíše jako objekty, mám pak různé tabulky s daty o lokacích propojené přes ID v této tabulce a rád bych pak v šabloně volal něco jako

<?php
	{foreach $vysledek->related('advert_property') as $lokace}
		{$lokace}
	{/foreach}
?>

Nevím jestli jsem se správně vyjádřil, nebo zda to je správný postup, ale ocením každý tip a radu.

Díky

Ondřej Kubíček
Člen | 494
+
0
-

klidně to můžeš nechat takhle, šak to query vrací ResultSet, na kterým zavoláš třeba fetchAll() a to vrátí pole ActiveRow, kde si můžeš volat related, nebo to ti ted nejde? co to teda vrací?

cafesk8
Člen | 103
+
0
-

Šablona

<?php
foreach $vysledek as $v}
	{dump $v}
{/foreach}
?>

Vrací instance Nette\Database\Row namísto ActiveRow a potom tedy, když si zavolám

<?php
{foreach $vysledek as $v}
	{foreach $v->related('advert_meta') as $meta}
		{dump $meta}
	{/foreach}
{/foreach}
?>

Tak to logicky řve Call to undefined method Nette\Database\Row::related()

V presenteru to mám takto:

<?php

$vysledek = $this->db->query('
	    SELECT id, lat, lng, address,
			111.045
			* DEGREES(ACOS(COS(RADIANS(latpoint))
			* COS(RADIANS(lat))
			* COS(RADIANS(longpoint) - RADIANS(lng))
			+ SIN(RADIANS(latpoint))
			* SIN(RADIANS(lat)))) AS distance_in_km
		FROM advert
		JOIN (
			SELECT  '.$lat.'  AS latpoint,  '.$lng.' AS longpoint
		) AS p ON 1=1
		#HAVING distance_in_km < 10
		ORDER BY distance_in_km
		LIMIT 15'
	)->fetchAll();

$this->template->vysledek	= $vysledek;
?>
Ondřej Kubíček
Člen | 494
+
0
-

hmm tak sorry, ono to fakt vrací jen Row, ne ActiveRow, jak jsem původně myslel

cafesk8
Člen | 103
+
0
-

To jsem volal v presenteru. Když dám v šabloně

<?php
{foreach $vysledek->fetchAll() as $v}
    {dump $v}
{/foreach}
?>

Tak to na mě hned zařve: Call to a member function fetchAll() on array

Šaman
Člen | 2635
+
0
-

Protože voláš fetchAll() dvakrát. Jednou, než vrátíš výsledek (takže vracíš již pole) a podruhé v tom foreach. V tom presenteru to fetchAll smaž.

//edit: vlastně můžeš smazat kterýkoliv, ale obecně se doporučuje držet objekt až do poslední chvíle před vykreslením. Protože na té query můžeš ještě dodatečně chtít nějaké limity, offsety, nebo řazení (typicky kvůli stránkování).

Editoval Šaman (20. 7. 2018 12:45)

cafesk8
Člen | 103
+
0
-

Šaman napsal(a):

Protože voláš fetchAll() dvakrát. Jednou, než vrátíš výsledek (takže vracíš již pole) a podruhé v tom foreach. V tom presenteru to fetchAll smaž.

//edit: vlastně můžeš smazat kterýkoliv, ale obecně se doporučuje držet objekt až do poslední chvíle před vykreslením. Protože na té query můžeš ještě dodatečně chtít nějaké limity, offsety, nebo řazení (typicky kvůli stránkování).

Já to původně v tom presenteru neměl, respektive vždy jsem to volal jenom jednou, ale ať dám to fetchAll() v presenteru nebo v šabloně, tak to vrací Row namísto ActiveRow. Problém je, že na Row nemůžu volat ve smyčce

<?php
$v->related('neco');
?>

Skončím, tam kde jsem začal, tudíž Call to undefined method Nette\Database\Row::related()

norbe
Backer | 405
+
+1
-

Že jsem tak smělý, jaký význam má ten join kde si vybereš akorát statické hodnoty? Proč je nepoužiješ rovnou v tom výpočtu?

Tedy cca takto:

$this->db->table('advert')
	->select('id, lat, lng, address,
            111.045
            * DEGREES(ACOS(COS(RADIANS(?))
            * COS(RADIANS(lat))
            * COS(RADIANS(?) - RADIANS(lng))
            + SIN(RADIANS(?))
            * SIN(RADIANS(lat)))) AS distance_in_km', $lat, $lng, $lat)
	->order('distance_in_km')
	->fetchAll()
cafesk8
Člen | 103
+
0
-

norbe napsal(a):

Že jsem tak smělý, jaký význam má ten join kde si vybereš akorát statické hodnoty? Proč je nepoužiješ rovnou v tom výpočtu?

Tedy cca takto:

$this->db->table('advert')
	->select('id, lat, lng, address,
            111.045
            * DEGREES(ACOS(COS(RADIANS(?))
            * COS(RADIANS(lat))
            * COS(RADIANS(?) - RADIANS(lng))
            + SIN(RADIANS(?))
            * SIN(RADIANS(lat)))) AS distance_in_km', $lat, $lng, $lat)
	->order('distance_in_km')
	->fetchAll()

Super, po pravdě jsem ten dotaz celý zkopíroval, takže mi nedošlo, že to tam je zbytečně. Takto to funguje, díky moc!

Editoval cafesk8 (20. 7. 2018 15:01)