Browse Source

Resource et Service pour les Coordonnées GPS

Vincent GUFFON 4 years ago
parent
commit
4b18bab346

+ 139 - 0
src/ApiResources/Utils/GpsCoordinate.php

@@ -0,0 +1,139 @@
+<?php
+declare(strict_types=1);
+
+namespace App\ApiResources\Utils;
+
+use ApiPlatform\Core\Annotation\ApiProperty;
+use ApiPlatform\Core\Annotation\ApiResource;
+
+/**
+ * Classe resource qui contient les champs de recherche des coordonnées GPS d'une adresse
+ *
+ * @ApiResource(
+ *     compositeIdentifier=false,
+ *     collectionOperations={
+ *          "get"={
+ *             "method"="GET",
+ *             "path"="/gps-coordinate-searching"
+ *          }
+ *     },
+ *     itemOperations={
+ *         "get"={
+ *             "method"="GET",
+ *             "path"="/gps-coordinate-reverse/{latitude}/{longitude}"
+ *          }
+ *     }
+ * )
+ */
+class GpsCoordinate
+{
+    /**
+     * @ApiProperty(identifier=true)
+     */
+    private $latitude;
+    /**
+     * @ApiProperty(identifier=true)
+     */
+    private $longitude;
+    private $streetAddress;
+    private $streetAddressSecond;
+    private $streetAddressThird;
+    private $cp;
+    private $city;
+    private $country;
+
+    public function __construct()
+    {
+        $this->setLatitude(0.0);
+        $this->setLongitude(0.0);
+    }
+
+    public function setLatitude(?float $latitude): self
+    {
+        $this->latitude = $latitude;
+        return $this;
+    }
+
+    public function getLatitude(): ?float
+    {
+        return $this->latitude;
+    }
+
+
+    public function getLongitude(): ?float
+    {
+        return $this->longitude;
+    }
+
+    public function setLongitude(?float $longitude): self
+    {
+        $this->longitude = $longitude;
+        return $this;
+    }
+
+    public function getStreetAddress(): ?string
+    {
+        return $this->streetAddress;
+    }
+
+    public function setStreetAddress(?string $streetAddress): self
+    {
+        $this->streetAddress = $streetAddress;
+        return $this;
+    }
+
+    public function getStreetAddressSecond(): ?string
+    {
+        return $this->streetAddressSecond;
+    }
+
+    public function setStreetAddressSecond(?string $streetAddressSecond): self
+    {
+        $this->streetAddressSecond = $streetAddressSecond;
+        return $this;
+    }
+
+    public function getStreetAddressThird(): ?string
+    {
+        return $this->streetAddressThird;
+    }
+
+    public function setStreetAddressThird(?string $streetAddressThird): self
+    {
+        $this->streetAddressThird = $streetAddressThird;
+        return $this;
+    }
+
+    public function getCp(): ?string
+    {
+        return $this->cp;
+    }
+
+    public function setCp(?string $cp): self
+    {
+        $this->cp = $cp;
+        return $this;
+    }
+
+    public function getCity(): ?string
+    {
+        return $this->city;
+    }
+
+    public function setCity(?string $city): self
+    {
+        $this->city = $city;
+        return $this;
+    }
+
+    public function getCountry(): ?string
+    {
+        return $this->country;
+    }
+
+    public function setCountry(?string $country): self
+    {
+        $this->country = $country;
+        return $this;
+    }
+}

+ 68 - 0
src/DataProvider/Utils/GpsCoordinateSearchingDataProvider.php

@@ -0,0 +1,68 @@
+<?php
+
+declare(strict_types=1);
+
+namespace App\DataProvider\Utils;
+
+use ApiPlatform\Core\DataProvider\CollectionDataProviderInterface;
+use ApiPlatform\Core\DataProvider\ItemDataProviderInterface;
+use ApiPlatform\Core\DataProvider\RestrictedDataProviderInterface;
+use ApiPlatform\Core\Identifier\CompositeIdentifierParser;
+use App\ApiResources\Utils\GpsCoordinate;
+use App\Service\Utils\GpsCoordinateUtils;
+use Symfony\Component\HttpFoundation\RequestStack;
+
+/**
+ * Class GpsCoordinateSearchingDataProvider : custom provider pour assurer l'alimentation de la ressource GpsCoordinate
+ * @package App\DataProvider\Utils
+ */
+final class GpsCoordinateSearchingDataProvider implements ItemDataProviderInterface, CollectionDataProviderInterface, RestrictedDataProviderInterface
+{
+    private GpsCoordinateUtils $gpsCoordinateUtils;
+    private RequestStack $requestStack;
+
+    public function __construct(
+        GpsCoordinateUtils $gpsCoordinateUtils,
+        RequestStack $requestStack
+    )
+    {
+        $this->gpsCoordinateUtils = $gpsCoordinateUtils;
+        $this->requestStack = $requestStack;
+    }
+
+    public function supports(string $resourceClass, string $operationName = null, array $context = []): bool
+    {
+        return GpsCoordinate::class === $resourceClass;
+    }
+
+    public function getCollection(string $resourceClass, string $operationName = null): iterable
+    {
+        $request = $this->requestStack->getCurrentRequest();
+        $responses = [];
+        try{
+            $addresses = $this->gpsCoordinateUtils->searchGpsCoordinates(
+                $request->get('street'),
+                $request->get('cp'),
+                $request->get('city')
+            );
+            foreach ($addresses as $address){
+                $responses[] = $this->gpsCoordinateUtils->createGpsCoordinate($address);
+            }
+        }catch (\Exception $exception){
+            $responses[] = new GpsCoordinate();
+        }
+        return $responses;
+    }
+
+    public function getItem(string $resourceClass, $id, string $operationName = null, array $context = []): GpsCoordinate
+    {
+        $ids = CompositeIdentifierParser::parse($id);
+        try{
+            $address = $this->gpsCoordinateUtils->reverseGpsCoordinates(floatval($ids['latitude']), floatval($ids['longitude']));
+            $gpsCoordinateResponse = $this->gpsCoordinateUtils->createGpsCoordinate($address);
+        }catch (\Exception $exception){
+            $gpsCoordinateResponse = new GpsCoordinate();
+        }
+        return $gpsCoordinateResponse;
+    }
+}

+ 94 - 0
src/Service/Utils/GpsCoordinateUtils.php

@@ -0,0 +1,94 @@
+<?php
+declare(strict_types=1);
+
+namespace App\Service\Utils;
+
+use App\ApiResources\Utils\GpsCoordinate;
+use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
+use Symfony\Contracts\HttpClient\HttpClientInterface;
+
+/**
+ * Class GpsCoordinateSearching : service aidant à la manipulation de l'API OpenStreetMap
+ * @package App\Service\Utils
+ */
+class GpsCoordinateUtils
+{
+    private HttpClientInterface $clientOpenStreetMap;
+
+    public function __construct(
+        HttpClientInterface $openstreetmap
+    )
+    {
+        $this->clientOpenStreetMap = $openstreetmap;
+    }
+
+    /**
+     * Renvoi un tableau d'adresse existante correspondant à la recherche d'adresse demandée
+     * @param string|null $street
+     * @param string|null $cp
+     * @param string|null $city
+     * @return array
+     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+     */
+    public function searchGpsCoordinates(?string $street, ?string $cp, ?string $city): array {
+        $url = sprintf('search?addressdetails=1&format=json&limit=10&street=%s&postalcode=%s&city=%s', $street, $cp, $city);
+        $response = $this->clientOpenStreetMap->request('GET', $url)->getContent();
+        if(empty($response))
+            throw new NotFoundHttpException('no_cooresponding_gps_coordinate');
+
+        return json_decode($response, true);
+    }
+
+    /**
+     * Renvoi l'adresse correspondant à la latitude et longitude demandée
+     * @param $latitude
+     * @param $longitude
+     * @return array
+     * @throws \Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface
+     * @throws \Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface
+     */
+    public function reverseGpsCoordinates(float $latitude, float $longitude): array {
+        $url = sprintf('reverse?addressdetails=1&format=json&lat=%s&lon=%s', $latitude, $longitude);
+        $response = $this->clientOpenStreetMap->request('GET', $url)->getContent();
+        if(empty($response))
+            throw new NotFoundHttpException('no_reverse_gps_coordinate');
+
+        return json_decode($response, true);
+    }
+
+    /**
+     * Transforme une réponse d'API en ressource GpsCoordinate
+     * @param array $gpsApiResponse
+     * @return GpsCoordinate
+     */
+    public function createGpsCoordinate(array $gpsApiResponse):GpsCoordinate{
+        $address = $this->transformAddress($gpsApiResponse['address']);
+        $gpsCoordinate = new GpsCoordinate();
+        $gpsCoordinate
+            ->setLatitude(floatval($gpsApiResponse['lat']))
+            ->setLongitude(floatval($gpsApiResponse['lon']))
+            ->setCity($address['city'])
+            ->setCp($address['cp'])
+            ->setStreetAddress($address['streetAddress'])
+            ->setStreetAddressSecond($address['streetAddressSecond']);
+        return $gpsCoordinate;
+    }
+
+    /**
+     * Permet de faire correspondre le bloc adresse renvoyé par l'API avec des éléments plus communs
+     * @param array $address
+     * @return array
+     */
+    public function transformAddress(array $address): array{
+        $addressTransformed['streetAddress'] = key_exists('road', $address) ? $address['road'] : (key_exists('hamlet', $address) ? $address['hamlet'] : null);
+        $addressTransformed['streetAddressSecond'] =  key_exists('road', $address) && key_exists('hamlet', $address)  ? $address['hamlet'] : null;
+        $addressTransformed['city'] = key_exists('town', $address) ? $address['town'] : (key_exists('village', $address) ? $address['village'] : null);
+        $addressTransformed['cp'] = key_exists('postcode', $address) ? $address['postcode'] : null;
+        return $addressTransformed;
+    }
+}