Géolocalisation ou comment créer ses propres fonctions DQL avec Doctrine2

Pour calculer les distances entre deux points géographiques il faut se baser sur leurs latitudes et longitudes. Lorsque l’on souhaite appliquer ce calcul en SQL on se retrouve avec une requête extrêmement verbeuse. Heureusement si vous utilisez Doctrine2 vous allez pouvoir créer votre propre fonction DQL qui vous permettra de faire ce calcul très simplement.

Dans un premier temps il va falloir ajouter les propriétés latitude et longitude à notre modèle, imaginons que nous souhaitons calculer la distance entre deux villes.

Une fois que nous avons nos colonnes nous pourrions écrire la requête suivante pour connaître la distance en kilométres qui sépare les villes de notre base de données de Montpellier:

Heureusement le parser de Doctrine2 va me permettre de créer une fonction DQL qui sera ensuite retranscris en SQL.

Que se passe t’il dans cette fonction ? Dans un premier temps la méthode Geo::parse() va parcourir le DQL et en extraire les parties souhaitées.

  • Le parser reconnaît ma fonction (ligne 28)
  • J’ouvre ma parenthèse (ligne 29)
  • Le parser récupère ma première expression : latitude = :latitude (ligne 30)
  • Je mets une virgule (ligne 31)
  • Le parser récupère ma seconde expression : longitude = :longitude (ligne 32)
  • Je ferme ma parenthèse

Maintenant que ma fonction est capable de parser mon DQL il va falloir qu’elle me genère du SQL, tout se passe dans la méthode getSql. Lorsque j’ai parsé mon DQL j’ai stocké les expressions correspondants à la longitude et latitude en tant qu’expression de comparaison (Parser::ComparisonExpression). Je vais ensuite pouvoir récupérer la partie qui m’intéresse pour construire mon SQL.

Désormais il me suffira décrire pour connaître la distance entre toutes les villes de ma base et Montpellier :

Pour terminer il va falloir enregistrer cette fonction sur votre EntityManager :

Doctrine2 permet donc d’étendre très facilement son système de fonction. Dans l’exemple donné ici il est évident que l’écriture d’une nouvelle fonction nous a simplifié l’écriture de nos futures requêtes DQL.

Partagez cet article