PHPackages                             craue/geo-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. craue/geo-bundle

ActiveSymfony-bundle[Utility &amp; Helpers](/categories/utility)

craue/geo-bundle
================

Doctrine functions for calculating geographical distances in your Symfony project.

1.9.0(4y ago)128350.6k↓31.8%20[3 PRs](https://github.com/craue/CraueGeoBundle/pulls)1MITPHPPHP ^7.3|^8

Since Feb 28Pushed 2y ago8 watchersCompare

[ Source](https://github.com/craue/CraueGeoBundle)[ Packagist](https://packagist.org/packages/craue/geo-bundle)[ Docs](https://github.com/craue/CraueGeoBundle)[ RSS](/packages/craue-geo-bundle/feed)WikiDiscussions master Synced 1mo ago

READMEChangelogDependencies (13)Versions (13)Used By (1)

Information
===========

[](#information)

[![Build Status](https://camo.githubusercontent.com/37cdaa73aeb4f7e8b87653fb10d9324b457dfeb5f4cbfe0c1032cc2f764d8aff/68747470733a2f2f6170702e7472617669732d63692e636f6d2f63726175652f437261756547656f42756e646c652e7376673f6272616e63683d6d6173746572)](https://app.travis-ci.com/craue/CraueGeoBundle)

CraueGeoBundle provides Doctrine functions for your Symfony project which allow you to calculate geographical distances within database queries. This bundle is independent of any web service, so once you got it running, it will keep running. There are two Doctrine functions, which return a distance in km:

- `GEO_DISTANCE` takes latitude + longitude for origin and destination
- `GEO_DISTANCE_BY_POSTAL_CODE` takes country + postal code for origin and destination

Installation
============

[](#installation)

Get the bundle
--------------

[](#get-the-bundle)

Let Composer download and install the bundle by running

```
composer require craue/geo-bundle
```

in a shell.

Enable the bundle
-----------------

[](#enable-the-bundle)

If you don't use Symfony Flex, register the bundle manually:

```
// in config/bundles.php
return [
	// ...
	Craue\GeoBundle\CraueGeoBundle::class => ['all' => true],
];
```

Or, for Symfony 3.4:

```
// in app/AppKernel.php
public function registerBundles() {
	$bundles = [
		// ...
		new Craue\GeoBundle\CraueGeoBundle(),
	];
	// ...
}
```

Prepare the table with geographical data needed for calculations
----------------------------------------------------------------

[](#prepare-the-table-with-geographical-data-needed-for-calculations)

The `GEO_DISTANCE_BY_POSTAL_CODE` function, if you'd like to use it, relies on some data which has to be added to your database first.

### Create the table

[](#create-the-table)

The `GeoPostalCode` entity provided contains the structure for the geographical data. You import it by calling either

```
# in a shell
php bin/console doctrine:migrations:diff
php bin/console doctrine:migrations:migrate
```

or

```
# in a shell
php bin/console doctrine:schema:update
```

or however you like.

### Import the geographical data

[](#import-the-geographical-data)

This is probably the most annoying step: Storing all postal codes with their geographical positions for the countries you need. Fortunately, it's not that hard to get this information and import it into your database.

Go to  and download the archives for the countries you need. Let's just take `DE.zip`. Unzip the included `DE.txt` file, e.g. to `/tmp/DE.txt`.

Create a fixture class (in a separate folder to be able to load only this one) which extends the provided base class:

```
// MyCompany/MyBundle/Doctrine/Fixtures/CraueGeo/MyGeonamesPostalCodeData.php
namespace MyCompany\MyBundle\Doctrine\Fixtures\CraueGeo;

use Craue\GeoBundle\Doctrine\Fixtures\GeonamesPostalCodeData;
use Doctrine\Common\Persistence\ObjectManager;

class MyGeonamesPostalCodeData extends GeonamesPostalCodeData {

	public function load(ObjectManager $manager) {
		$this->clearPostalCodesTable($manager);
		$this->addEntries($manager, '/tmp/DE.txt');
	}

}
```

Now, backup your database! Don't blame anyone else for data loss if something goes wrong. Then import the fixture and remember to use the `--append` parameter.

Choose the following steps depending on the version of DoctrineFixturesBundle you're using.

 DoctrineFixturesBundle &lt; 3.0Load the fixture(s) in the given folder.

```
# in a shell
php bin/console doctrine:fixtures:load --append --fixtures="src/MyCompany/MyBundle/Doctrine/Fixtures/CraueGeo"
```

 DoctrineFixturesBundle &gt;= 3.11. a) You first need to register the fixture as a service with a group of your choice.

```
# in app/config/config.yml
services:
  my_geonames_postal_code_data:
    class: MyCompany\MyBundle\Doctrine\Fixtures\CraueGeo\MyGeonamesPostalCodeData
    public: false
    tags:
     - { name: doctrine.fixture.orm, group: my_geo_data }
```

1. b) It's also possible to register all classes in a specific folder as services.

```
# in app/config/config.yml
services:
  MyCompany\MyBundle\Doctrine\Fixtures\CraueGeo\:
    resource: '../../src/MyCompany/MyBundle/Doctrine/Fixtures/CraueGeo/*'
    public: false
    tags:
     - { name: doctrine.fixture.orm, group: my_geo_data }
```

2. Then, load the fixture(s) of that group.

```
# in a shell
php bin/console doctrine:fixtures:load --append --group=my_geo_data
```

That's it.

You can also use other data sources you have access to, and write a custom fixture to import it.

If you have out of memory issues when importing a large number of entries try adding the `--no-debug` switch to avoid logging every single Doctrine query.

Usage
=====

[](#usage)

Let's say you have an entity `Poi` containing countries and postal codes. Now you wish to find all entities within a specific geographical distance with a radius of `$radiusInKm` from a given postal code `$postalCode` in country `$country`, and order them by distance.

```
use MyCompany\MyBundle\Entity\Poi;

// example values which could come from a form, remember to validate/sanitize them first
$country = 'DE';
$postalCode = '10115';
$radiusInKm = 10;

// create a query builder
$queryBuilder = $this->getDoctrine()->getEntityManager()->getRepository(Poi::class)->createQueryBuilder('poi');

// build the query
$queryBuilder
	->select('poi, GEO_DISTANCE_BY_POSTAL_CODE(:country, :postalCode, poi.country, poi.postalCode) AS HIDDEN distance')
	->having('distance select('poi, GEO_DISTANCE_BY_POSTAL_CODE(:country, :postalCode, poi.country, poi.postalCode) AS HIDDEN distance')
	->having('GEO_DISTANCE_BY_POSTAL_CODE(:country, :postalCode, poi.country, poi.postalCode)
