Doctrine2 2.2 et types géographiques

Une lacune des premières version de Doctrine2 était de restreindre l’emploi de données géographiques. C’est maintenant comblé avec la version 2.2: une demande d’amélioration a été implémentée dans la nouvelle version, sortie le 29 janvier 2012. A l’heure d’écrire ces lignes, les nouvelles fonctionnalités n’ont pas encore été documentées.

Mise à jour les développeurs ont intégré les modifications proposées dans la documentation, qui sont reprises ici.

Voici comment je suis arrivé à créer un type “point” avec Symfony2 et Doctrine2.2, sur une base de donnée géographiques Postgresql + Postgis.

Toute la difficulté résidait dans le fait que les données géographique sont stockées dans des colonnes qui n’étaient pas directement exploitable, dans un format qui n’est pas “standard” (La documentation de postgis signale que le format n’est pas directement utilisable). Dès lors, pour les lire et les exploiter, il faut transformer les données vers un format connu, comme le geoJson (qui est utilisé dans cette exemple) ou le WKT.

Pour suivre cet exemple, l’installation de l’extension géographique postgis doit avoir été réalisée au préalable.

Tout d’abord, j’ai créé une classe Point, qui me servira, par la suite, à effectuer la manipulation de cet objet particulier.

 

Notez que j’ai rendu le constructeur privé afin de pouvoir forcer les vérifications des coordonnées. Le principe est discutable et je serai ravi d’entendre d’autres opinions.

J’ai ensuite créé une classe PointType qui étend la classe Type de Doctrine2, tel que décrit dans la documentation de Doctrine2

Notez ces trois fonctions, importantes, qui font la différence entre la version 2.1 et la version 2.2 de Doctrine:

La première transforme le type géographique de la base de donnée en une chaine GeoJSON, chaine qui sera ensuite transformée en objet Point par la fonction convertToPHPValue :

La deuxième transforme la chaine de la requete SQL qui introduit les coordonnées géographique J’avais donc supposé que j’aurais dû utiliser le constructeur ST_GeographyFromText de postgis et que la fonction soit la suivante :

Mais, pour une raison que je ne m’explique pas, cette chaine doit rester identique: apparemment une conversion a déjà lieu automatiquement quelque part.

(Encore une fois, vos idées sont les bienvenues). Dès lors, il n’est pas nécessaire, ici, de la modifier (elle n’a même pas besoin d’être surchargée). Nous la laissons donc en l’état :

La dernière rend effective les deux autres: pour des raisons de performances: elle doit renvoyer “true” pour activer l’utilisation des deux autres:

Il ne suffit plus, alors, que de renseigner le type “PointType” à Doctrine. Dans Symfony2 en Yaml, cela se fait de la manière suivante :

Post a comment or leave a trackback: Trackback URL.

Comments

  • Pierre-Leo Bourbonnais  On 3 avril 2012 at 22 h 53 min

    J’ai eu le même besoin que vous (implanter des types PostGIS dans symfony2).

    Le problème est que je n’arrive pas à générer le schéma à l’aide des fonctions: doctrine:database:create ou doctrine:migrations:diff

    J’obtiens le message suivant:
    [Doctrine\DBAL\DBALException]
    Unknown database type geography requested, Doctrine\DBAL\Platforms\PostgreSqlPlatform may not support it.

    J’ai bien installé Doctrine 2.2

    Merci!

  • Julien  On 4 avril 2012 at 12 h 19 min

    Bonjour,

    Je me suis également frotté à cette difficulté et j’ai eu le message d’erreur.

    De ce qu’il me semble, la classe Type a des champs statiques qui “stockent” dans un tableau les types supportés. La fonction statique Type::AddType (ou qqch comme ça) sert à ajouter une nouvelle classe (ayant Type pour héritage) dans ce tableau.

    Il semble ici que votre classe n’y soit pas ajoutée.

    Avez-vous vérifié que vous utilisiez bien les bons espaces de noms ? Parfois, un “use” manquant change tout… Vérifiez bien pour toutes les classes que vous utilisez.

    Je pense avoir débogué le problème en créant un Controller et une action vide qui m’indiquait quels types étaient stockées (il y une focntion pour les retrouver toutes). Ca permettra peut-être de vérifier qu’il s’agit bien de ce problème et de trouver des pistes de solution.

    Julien

  • aitiahcne  On 26 avril 2012 at 10 h 59 min

    Comment avez vous résolu le soucis ?? j’ai le meme soucis !!

  • seveinfo  On 20 juillet 2012 at 15 h 59 min

    Bonjour,
    en essayant de récupere les info de la base j’ai un message d’erreur “Undefined function: 7 ERREUR: la fonction st_asgeojson(point) n’existe pas
    LINE 1: …t AS updated_at11, t0.deleted_at AS deleted_at12, ST_AsGeoJS…
    ^
    HINT: Aucune fonction ne correspond au nom donné et aux types d’arguments.”

    Avez vous ce type d’erreur?
    Merci
    Cordialement
    Christophe

  • Julien  On 27 juillet 2012 at 9 h 09 min

    Bonjour,

    Avez-vous pu résoudre le problème ?

    Sinon, pourriez-vous poster plus d’informations, comme le contenu de votre classe ‘Type’ ?

    Julien

  • Jonathan Derrough  On 3 septembre 2012 at 9 h 12 min

    Bonjour,

    Je reviens sur l’erreur :

    [Doctrine\DBAL\DBALException]
    Unknown database type geography requested, Doctrine\DBAL\Platforms\PostgreSqlPlatform may not support it.

    Exception trace:
    () at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Platforms/AbstractPlatform.php:261
    Doctrine\DBAL\Platforms\AbstractPlatform->getDoctrineTypeMapping() at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/PostgreSqlSchemaManager.php:285
    Doctrine\DBAL\Schema\PostgreSqlSchemaManager->_getPortableTableColumnDefinition() at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php:672
    Doctrine\DBAL\Schema\AbstractSchemaManager->_getPortableTableColumnList() at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php:159
    Doctrine\DBAL\Schema\AbstractSchemaManager->listTableColumns() at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php:254
    Doctrine\DBAL\Schema\AbstractSchemaManager->listTableDetails() at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php:242
    Doctrine\DBAL\Schema\AbstractSchemaManager->listTables() at /…/Symfony/vendor/doctrine-dbal/lib/Doctrine/DBAL/Schema/AbstractSchemaManager.php:830
    Doctrine\DBAL\Schema\AbstractSchemaManager->createSchema() at /…/Symfony/vendor/doctrine/lib/Doctrine/ORM/Tools/SchemaTool.php:689
    Doctrine\ORM\Tools\SchemaTool->getUpdateSchemaSql() at /…/Symfony/vendor/doctrine/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/UpdateCommand.php:103
    Doctrine\ORM\Tools\Console\Command\SchemaTool\UpdateCommand->executeSchemaCommand() at /…/Symfony/vendor/doctrine/lib/Doctrine/ORM/Tools/Console/Command/SchemaTool/AbstractCommand.php:59
    Doctrine\ORM\Tools\Console\Command\SchemaTool\AbstractCommand->execute() at /…/Symfony/vendor/symfony/src/Symfony/Bundle/DoctrineBundle/Command/Proxy/UpdateSchemaDoctrineCommand.php:62
    Symfony\Bundle\DoctrineBundle\Command\Proxy\UpdateSchemaDoctrineCommand->execute() at /…/Symfony/vendor/symfony/src/Symfony/Component/Console/Command/Command.php:226
    Symfony\Component\Console\Command\Command->run() at /…/Symfony/vendor/symfony/src/Symfony/Component/Console/Application.php:194
    Symfony\Component\Console\Application->doRun() at /…/Symfony/vendor/symfony/src/Symfony/Bundle/FrameworkBundle/Console/Application.php:76
    Symfony\Bundle\FrameworkBundle\Console\Application->doRun() at /…/Symfony/vendor/symfony/src/Symfony/Component/Console/Application.php:118
    Symfony\Component\Console\Application->run() at /…/Symfony/app/console:22

    J’y fais face lorsque je tente un update automatique de ma base de données (php app/console doctrine:schema:update –force –verbose).
    D’après ce que je comprends du stacktrace, Symfony2 récupère la liste des colonnes de la table contenant un type géographique (ex: geography(Point,4326)) et ne gardera pour ce dernier que ‘geography’. D’où l’erreur : alors que le type ‘point’ est bien mappé, il n’existe pas de mapping pour ‘geography’. Le problème se répète pour tout autre type géographique mappé.

    J’ai essayé d’adapter le mapping de différentes manières, mais la clé du problème semble être le tronquage du type de la colonne géographique par Symfony2 lors de récupération du type mappé (geography(Point,4326) => geography, geography(LineString,4326) => geography, …).

    Quelqu’un aurait-il une idée ?

    Merci,
    Jonathan

    • Julien  On 3 septembre 2012 at 9 h 20 min

      Bonjour,

      C’est tout à fait possible: j’ai également quelques soucis avec les mises à jour du schéma des bases de données. Dans ce cas, ça serait un bug dans Symfony / Doctrine.

      Pourriez-vous communiquer votre classe “Type” et éventuellement le SQL produit par Symfony ?

      Julien

      • Jonathan Derrough  On 3 septembre 2012 at 18 h 21 min

        Bonsoir,

        J’utilise votre classe PointType verbatim. :)
        Le type PostGIS généré est ‘geography(Point,4326)’.
        Les opération d’input / output dans la db se déroule sans problème. Le pb ne se produit que lorsque la table a déjà été créée et qu’il s’agit de la mettre à jour.

        Merci !
        Jonathan

        • Julien  On 4 septembre 2012 at 8 h 28 min

          A mon avis, il faudrait ouvrir une issue ici : http://www.doctrine-project.org/jira/browse/DDC

          J’ai aussi des soucis lors d’update du schéma de la base de donnée. Je pensais que c’était dû à un ancien type que j’avais supprimé – le message d’erreur se rapportait à celui-là (bizarre, vraiment!)

          Il y a peut être des fonctions à ajouter pour introduire les modifications dans la base de donnée: la structure du code sql de modification généré ne semble pas nécessaire à celui des autres types “classiques”.

          Julien

          PS: que penseriez-vous de créer une extension à doctrine “géographique” à doctrine ?

          • Jonathan Derrough  On 4 septembre 2012 at 9 h 42 min

            J’ai créé une issue la plus détaillée possible : http://www.doctrine-project.org/jira/browse/DBAL-337

            Je suis novice en la matière mais la création d’une extension géographique me semble pertinente et intéressante. Je suis partant ! :)
            Poursuivons cette discussion en privé… ;)

  • Jonathan Derrough  On 4 septembre 2012 at 16 h 27 min

    J’ai changé le mapping pour que le type geography soit reconnu:

    $em = $this->container->get(‘doctrine.orm.default_entity_manager’);
    $conn = $em->getConnection();
    if (!Type::hasType(‘point’)) {
    Type::addType(‘point’, ‘Demo\GeoBundle\Lib\Type\PointType’);
    $conn->getDatabasePlatform()->registerDoctrineTypeMapping(‘geography’, ‘point’);
    }

    Cela permet de passer outre les erreurs et semble fonctionner avec plusieurs types PostGIS mappés, toutefois je n’ai pas fait de tests intensifs.

Répondre à Pierre-Leo Bourbonnais Annuler la réponse.

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

*

Vous pouvez utiliser ces balises et attributs HTML : <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>