Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use Doctrine2 to work with GeoSpatial Queries using PostGIS?

I have a public facing app that is based on Postgres and PostGIS.

I have tried Googling for hours but have been unable to find any documentation that can show some basic geospatial stuff like getting distance between two points using Doctrine2. Not being able to use an ORM is a big deal for me in terms of determining my database of choice.

Can someone show me a basic example of lets say showing all points within a radius of lets say 10 miles using Doctrine?

like image 957
kratos Avatar asked Jul 29 '12 22:07

kratos


2 Answers

I wrote an article on my blog, explaining how to use Doctrine 2 (version 2.2+) and Postgis. The article is in French, but the code is PHP, which an international language :

http://web.archive.org/web/20161118060448/http://blog.fastre.info:80/2012/02/doctrine2-2-2-et-types-geographiques/

As you will see, importing data from database to an object need some conversion:

  1. The data are converted to geojson by postgis (json is readable by php, using json_decode function)
  2. The data are transformed into a Point object

And from the object's world to database:

  1. The object Point is converted into WKT. Why WKT and not json ? Because Postgis has a ST_GeogFromWKT function, but not (yet) a ST_GeogFromGeoJson function.
  2. The data are inserted into the database.

I also wrote a custom DQL function class which dealt with the "covered" operation in DQL queries. This is not exactly what you ask, but you may inspire from this and adapt the code.

namespace Progracqteur\WikipedaleBundle\Resources\Doctrine\Functions;

use Doctrine\ORM\Query\AST\Functions\FunctionNode;
use Doctrine\ORM\Query\Lexer;

/**
*
* @author Julien Fastré <julien arobase fastre point info>
*/
class Covers extends FunctionNode {

    private $polygon = null;
    private $point = null;


    public function getSql(\Doctrine\ORM\Query\SqlWalker $sqlWalker) {
        return 'ST_Covers('.$this->polygon->dispatch($sqlWalker).', '.$this->point->dispatch($sqlWalker).')';
    }

    public function parse(\Doctrine\ORM\Query\Parser $parser) {

        $parser->match(Lexer::T_IDENTIFIER);
        $parser->match(Lexer::T_OPEN_PARENTHESIS);

        $this->polygon = $parser->StringExpression();

        $parser->match(Lexer::T_COMMA);

        $this->point = $parser->StringPrimary();

        $parser->match(Lexer::T_CLOSE_PARENTHESIS);

    }
}

and this function is added to doctrine using app/config/config.yml :

        dql:
          string_functions:
            covers: Progracqteur\WikipedaleBundle\Resources\Doctrine\Functions\Covers

Be careful: to use this function, you will have to create other functions which will use the 'ST_FromWKT' function before, and convert your point to WKT in your getSql (using the __toString function ?). I did not need it in my application, so I do not have code for this to present to you.

This is an example of using my function : ($entity->getPolygon() return the postgis's string, without any conversion - i do not need to dealt with a polygon's object in my app.)

$em->createQuery('SELECT p from MyEntity p where covers(:polygon, p.geom) = true)
            ->setParameter('polygon', $entity->getPolygon());
like image 62
Julien Fastré Avatar answered Nov 11 '22 01:11

Julien Fastré


I know this is a little bit old but may help others.

I've found this library:

https://github.com/djlambert/doctrine2-spatial

They support Postgis and MySQL.

The Postgis functions are:

  • ST_Area
  • ST_AsBinary
  • ST_AsText
  • ST_Centroid
  • ST_ClosestPoint
  • ST_Contains
  • ST_ContainsProperly
  • ST_CoveredBy
  • ST_Covers
  • ST_Crosses
  • ST_Disjoint
  • ST_Distance
  • ST_Envelope
  • ST_GeomFromText
  • ST_Length
  • ST_LineCrossingDirection
  • ST_StartPoint
  • ST_Summary
like image 3
Jonathas Pacífico Avatar answered Nov 10 '22 23:11

Jonathas Pacífico