For coders TYPO3 Tech Corner

[PHP] Area search, distance calculation and address conversion in TYPO3

[PHP] Area search, distance calculation and address conversion in TYPO3

As a developer, you can easily implement a proximity search yourself, as long as MySQL or MariaDB provide functions such as cos(), acos(), sin() and radians(). Alternatively, a distance calculation is only possible with PHP. And we will also show you how to convert an address into geo-coordinates.

Last update of the post 2023-05-22

Radius search via MySQL

Here is an excerpt from a possible repository. In this example the table tx_any_domain_model_any has at least the columns uid, latitude and longitude:

<?php declare(strict_types=1); namespace Vendor\Any\Domain\Repository; use TYPO3\CMS\Core\Database\ConnectionPool; use TYPO3\CMS\Core\Utility\GeneralUtility; class AnyRepository { const TABLE_NAME = 'tx_any_domain_model_any'; public function findByRadius(float $latitude, float $longitude, int $distance): array { $connection = GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable(self::TABLE_NAME); return (array)$connection->executeQuery($this->getSqlForRadialSearch($latitude, $longitude, $distance)); } protected function getSqlForRadialSearch(float $latitude, float $longitude, int $distance): string { $sql = 'SELECT uid, latitude, longitude, ( 6371 * acos( cos( radians(' . $latitude . ') ) * cos( radians( latitude ) ) * cos( radians( longitude ) - radians(' . $longitude . ') ) + sin( radians(' . $latitude . ') ) * sin( radians( latitude ) ) ) ) AS distance FROM ' . self::TABLE_NAME . ' HAVING distance <= ' . $distance . ' ORDER BY distance ASC;'; return $sql; } }

Distance calculation between 2 points via PHP

Mit PHP kann man auch ganz einfach die Entfernung in KM missen, wenn man zwei Geo-Koordinaten (also 2 Breiten- und 2 Längengrade) zur Verfügung hat:

/** * Calculate distance between 2 geo coordinates (2x lat and lon) in KM * * @param float $latitude1 * @param float $longitude1 * @param float $latitude2 * @param float $longitude2 * @return float */ public function calculateDistance(float $latitude1, float $longitude1, float $latitude2, float $longitude2): float { $earthRadius = 6371; // in KM $lat1InRadians = deg2rad($latitude1); $lon1InRadians = deg2rad($longitude1); $lat2InRadians = deg2rad($latitude2); $lon2InRadians = deg2rad($longitude2); $deltaLat = $lat2InRadians - $lat1InRadians; $deltaLon = $lon2InRadians - $lon1InRadians; $angle = sin($deltaLat / 2) * sin($deltaLat / 2) + cos($lat1InRadians) * cos($lat2InRadians) * sin($deltaLon / 2) * sin($deltaLon / 2); $centralAngle = 2 * atan2(sqrt($angle), sqrt(1 - $angle)); $distanceInKm = $earthRadius * $centralAngle; return round($distanceInKm, 2); }

Address conversion to geolocation

Conversion of an address into its geo-coordinates (latitude and longitude) using OpenStreetMap:

/** * Use openstreetmap to convert an address to geo coordinates * * @param string $address "Kunstmühlstr. 12a, 83026 Rosenheim, Deutschland" * @return array ['latitude' => 0.0, 'longitude' => 0.0] * @throws RequestException */ public function getCoordinatesFromAddress(string $address): array { $coordinates = [ 'latitude' => 0.0, 'longitude' => 0.0, ]; $requestFactory = \TYPO3\CMS\Core\Utility\GeneralUtility::makeInstance(\TYPO3\CMS\Core\Http\RequestFactory::class); $request = $requestFactory->request( 'https://nominatim.openstreetmap.org/search?format=json&polygon=1&q=' . urlencode($address) ); if ($request->getStatusCode() !== 200) { throw new \RuntimeException('Could not connect to nominatim.openstreetmap.org', 1683405955); } $result = $request->getBody()->getContents(); $resultArray = json_decode($result, true); if (isset($resultArray[0]['lat']) && isset($resultArray[0]['lon'])) { $coordinates['latitude'] = (float)$resultArray[0]['lat']; $coordinates['longitude'] = (float)$resultArray[0]['lon']; } return $coordinates; }

"Code faster, look at the time" - does this sound familiar to you?

How about time and respect for code quality? Working in a team? Automated tests?

Join us

SQL: Show all tables sorted by size in descending order

Lately I've been using the SQL command more often to find out which tables in the TYPO3 database are the largest. I've published the snippet once.

Go to news

TYPO3 12 with CKEditor 5: Styles in a single selection

If you set a link in the RTE in TYPO3, you may have to choose between different link classes, for example to create buttons in the frontend. What's new in TYPO3 12 is that you can select not just one...

Go to news

Null-Safe Operator in the TYPO3 area

With the introduction of PHP8, problems with undefined arrays or variables in general can arise in many places. Here are a few examples and simple solutions.

Go to news

Delete the first/last lines of a (SQL) file

There isn't much to say about the following commands. Sometimes it can be useful to delete the first (or last) X lines from a file. And if the file is too large to open with a conventional program, a...

Go to news

b13/container: Add and modify child elements in edit view

Unlike gridelements, you cannot manage the child elements in the B13 Container extension when you open the container in the editing view. I would be happy to show you how you can quickly install this...

Go to news

Menu comparison: Numbers, numbers, numbers

Go to news