Navigation

Related Articles

Back to Latest Articles

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


Samuel Breton
Géolocalisation ou comment créer ses propres...

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.

Show Comments (8)

Comments

  • Christophe

    Excellent ! (+)
    Je vais tester ça rapidement.

    • Article Author
  • Marvin

    Super article ! Vous pourriez cependant expliquer la méthode getSql un peu plus en détail s’il vous plaît ? J’ai du mal à saisir ce passage, et il n’y a pas trop de doc sur le sujet ailleurs…vous en avez trouvée où ?

    Merci et bonne continuation !

    • Article Author
  • yoye

    @marvin je viens de mettre à jour l’article. Concrètement lorsque tu parses ton DQL tu peux extraire plusieurs type d’expression (comparaison, condition, etc …) que tu peux ensuite utiliser pour construire ton SQL.

    • Article Author
  • Marvin

    D’accord, en fait je comprenais pas pourquoi vous utilisiez ComparisonExpression, mais c’était pour récupérer simplement les deux valeurs. Merci ^^

    • Article Author
  • Marvin

    D\’accord, en fait je comprenais pas pourquoi vous utilisiez ComparisonExpression, mais c\’était pour récupérer simplement les deux valeurs. Merci ^^

    • Article Author
  • Alexandre

    Bonjour,

    merci pour ce tutorial. Souhaitant également intégrer un système de localisation sur mon application Symfony, j’ai voulu intégrer votre solution, mais je rencontre une erreur Doctrine que je n’arrive pas à résoudre :
    Invalid parameter number: number of bound variables does not match number of tokens

    Cette erreur arrive plutôt quand il y a plus de données que de valeurs à changer ou vice versa, mais impossible de trouver d’où cela vient.

    Avez-vous une idée ?

    Merci,

    Cordialement,

    Alexandre

    • Article Author
  • MisterMo

    Hello,

    Merci pour ce super exemple qui m’a été bien utile et m’a permis de dormir un peu plus longtemps que prévu la nuit dernière 😉

    Je cherche à modifier l’alias qui est automatiquement généré par SqlWalker – genre sclr4 – pour pouvoir ensuite appliquer une clause SQL HAVING sur cette colonne. Apparemment plus facile à dire qu’à faire… Quelqu’un a-t-il une idée de comment spécifier un alias de colonne ?

    Merci d’avance!
    MisterMo

    • Article Author
  • Gabriel

    Excellent ! Merci pour l\’astuce.

    • Article Author

Recevez nos articles