I wrote a custom DQL function. In this function I use the same parameter twice:
public function getSql(SqlWalker $sqlWalker)
{
$point1_lat = $this->point1_lat->dispatch($sqlWalker);
$point1_lon = $this->point1_lon->dispatch($sqlWalker);
$point2_lat = $this->point2_lat->dispatch($sqlWalker);
$point2_lon = $this->point2_lon->dispatch($sqlWalker);
$unitFactor = 6366.56486; // earth radius in km
return "
$unitFactor *
2 *
ASIN(
SQRT(
POWER(
SIN(($point1_lat - $point2_lat) * pi()/180/2),
2
) +
COS($point1_lat * pi()/180) *
COS($point2_lat * pi()/180) *
POWER(
SIN(($point1_lon - $point2_lon) * pi()/180/2),
2
)
)
)
";
}
This is how the query is executed:
$q = \App::get()->getEntityManager()->createQuery('
SELECT
s,
GEO_DISTANCE(
:lat,
:lng,
s.glat,
s.glng
) AS distance
FROM
\Application\Geo\Entity\Street s
');
$q->setMaxResults(10);
$q->setParameters(array(
'lat' => 52.25948,
'lng' => 6.76403,
));
$result = $q->getResult();
This however gives me the following exception:
Message: SQLSTATE[HY093]: Invalid parameter number: number of bound variables does not match number of tokens
The following SQL is returned by getSql():
6366.56486 *
2 *
ASIN(
SQRT(
POWER(
SIN((? - g0_.glat) * pi()/180/2),
2
) +
COS(? * pi()/180) *
COS(g0_.glat * pi()/180) *
POWER(
SIN((? - g0_.glng) * pi()/180/2),
2
)
)
)
So I guess the exception is thrown because the named parameters are returned as indexed parameters. Is this a bug in doctrine or am I doing something wrong?
This is not a bug, you can only use each parameter once, as the dispatch()
function puts the value on the stack once, to match one ?
placeholder in the query.
As a workaround, you can call dispatch() several times:
public function getSql(SqlWalker $sqlWalker)
{
$point1_lat_a = $this->point1_lat->dispatch($sqlWalker);
$point1_lat_b = $this->point1_lat->dispatch($sqlWalker);
$point1_lon = $this->point1_lon->dispatch($sqlWalker);
$point2_lat_a = $this->point2_lat->dispatch($sqlWalker);
$point2_lat_b = $this->point2_lat->dispatch($sqlWalker);
$point2_lon = $this->point2_lon->dispatch($sqlWalker);
$unitFactor = 6366.56486; // earth radius in km
return "
$unitFactor *
2 *
ASIN(
SQRT(
POWER(
SIN(($point1_lat_a - $point2_lat_a) * pi()/180/2),
2
) +
COS($point1_lat_b * pi()/180) *
COS($point2_lat_b * pi()/180) *
POWER(
SIN(($point1_lon - $point2_lon) * pi()/180/2),
2
)
)
)
";
}