Sie sind hier Home » PHP Programmierung » Symfony » Umkreissuche mit OpenGeoDB und Symfony

Umkreissuche mit OpenGeoDB und Symfony

Es ist bekannt, es ist beliebt. Jeder braucht es und keiner möchte es, sofern er es denn kennt, wieder missen.

Die beliebtesten Anwendungen in Verbindung mit der OpenGeoDB sind die Entfernungssuche zwischen zwei Postleitzahlen, sowie die Umkreissuche zu einer bestimmten Postleitzahl.

Heute stelle ich Ihnen die Umkreissuche in Verbindung mit dem PHP Framework Symfony vor.

Was wird benötigt?

  • Zuerst einmal brauchen wir eine aktuelle GeoDB http://opengeodb.giswiki.org/wiki/OpenGeoDB_Downloads
  • Des Weiteren wird symfony in der Version 1.2 benötigt http://www.symfony-project.org/installation/1_2
  • Wie man Symfony installiert und konfiguriert ist unter http://www.symfony-project.org/jobeet/1_2/Propel/en/ in einem sehr guten Tutorial beschrieben

    Die OpenGeoDB installieren wir am besten in einer separaten Datenbank, da nicht die komplette DB für unsere Zwecke benötigt wird. Nach der Installation, beginnen wir eine Tabelle zu erstellen, welche nur die Postleitzahlen mit den Ortsnamen und ihren entsprechenden Koordinaten beinhaltet.

     
    CREATE TABLE `zip_coordinates` (
        zc_id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
        zc_loc_id INT NOT NULL ,
        zc_zip VARCHAR( 10 ) NOT NULL ,
        zc_location_name VARCHAR( 255 ) NOT NULL ,
        zc_lat DOUBLE NOT NULL ,
        zc_lon DOUBLE NOT NULL
    )
     

    In diese Tabelle werden dann die benötigten Daten für die Postleitzahlen importiert.

     
    INSERT INTO zip_coordinates 
          (zc_loc_id, zc_zip, zc_location_name, zc_lat, zc_lon)
    SELECT gl.loc_id, plz.text_val, name.text_val, coord.lat, coord.lon
    FROM geodb_textdata plz
    LEFT JOIN geodb_textdata name ON name.loc_id = plz.loc_id
    LEFT JOIN geodb_locations gl ON gl.loc_id = plz.loc_id
    LEFT JOIN geodb_coordinates coord ON plz.loc_id = coord.loc_id
    WHERE plz.text_type =500300000/* ID für Postleitzahl */
      AND name.text_type =500100000/* ID für name */
      AND (
            gl.loc_type =100600000/* ID für pol. Gliederung */
            OR 
            gl.loc_type =100700000/* ID für Ortschaft */
      );
     

    Nun können wir die Tabelle zip_coordinates in unsere Datenbank, welche das Symfony Projekt vorhält, exportieren. Hierzu eignet sich am besten PHPmyadmin. Um mit den Daten arbeiten zu können, benötigen wir für die Datenbanktabelle das entsprechende Model. Dies erstellen wir über die Konsole:

     
    php symfony propel:build-schema
    php symfony propel:build-model
     

    In der entsprechenden Funktion der actions.class.php können wir nun die Daten für eine Umkreissuche abfragen und aufbereiten. Wir gehen hierbei davon aus, dass für die Anfrage eine entsprechendes Formular genutzt wird, welches "zipcode" für die Postleitzahl und "zipcodedistance" für die gewünschte Entfernung der Umkreissuche beinhaltet. Ob diese Formularelemente nun einfache inputs sind oder als select Elemente gestaltet werden, ist unrelevant. Auf eine entsprechende Validierung der Daten möchte ich an dieser Stelle auch nicht näher eingehen, da dies die Grundaufgabe eines jeden Programmierers ist.

     
    <?php 
    class someActions extends sfActions
    {
      public function executeDistancesearch(sfWebRequest $request){
        $this->resultset = null; 
        $zipcode = $request->getParameter("zipcode");
        $zipcodedistance = $request->getParameter("zipcodedistance");
        //Criteria bilden
        $c = new Criteria();
        $c->add(ZipCoordinatesPeer::ZC_ZIP, $zipcode, Criteria::EQUAL);
        $zippo = ZipCoordinatesPeer::doSelectOne($c);
        //Koordinaten vorhanden? 
        if(is_object($zippo)){
          $sql = 'SELECT DISTINCT zc_zip
              FROM zip_coordinates
              WHERE ACOS(
                SIN(RADIANS(zc_lat)) * SIN(RADIANS('.$zippo->getZcLat().')) 
                + COS(RADIANS(zc_lat)) * COS(RADIANS('.$zippo->getZcLat().')) 
                * COS(RADIANS(zc_lon)
                - RADIANS('.$zippo->getZcLon().'))
                ) * 6380 <= '.$zipcodedistance.' 
              AND zc_id <> '.$zippo->getZcId().';';
          //händische SQL Abfrage ausführen
          $con = Propel::getConnection(BaseUserPeer::DATABASE_NAME);
          $stmt = $con->prepare($sql);
          $stmt->execute();
          $zips = array(); 
          while($row = $stmt->fetch()) { 
            array_push($zips,$row['zc_zip']);
          }
          if(count($zips)>0){
            //erhaltene Postleitzahlen weiterverarbeiten
            // hole alle Benutzer aus Tabelle `users` die ihre PLZ im Umkreis haben
            $regex = UserPeer::ZIPCODE." IN(".implode(", ",$zips).")";
            $criteria = new Criteria();
            $criteria->add(UserPeer::ZIPCODE, $regex, Criteria::CUSTOM);
            $this->resultset = UserPeer::doSelect($criteria);
          }
        }
      }
    }
    ?>
     
Lassen Sie uns ein Feedback zu diesem Artikel zukommen

Bookmark