release cityscan juin 2024

Guide de migration du widget annonce

01 Introduction

Si vous avez lu la release note, vous savez qu’un nouveau widget est désormais en production.

● Deadline

Nous fixons comme date de maintien en service de nos serveurs hébergeant les widgets V1 au 31/12/2024.

02 Vos nouvelles documentations

03 Exemple de projet PHP V1

Imaginons que vous avez un projet PHP simple. Votre annonce immobilière est représenté par un modèle de données dont les champs sont en français. Voici à quoi devraient ressembler :

  • votre DTO
				
					<?php

class RealtyDTO
{
    private BienImmobilier $bienImmobilier;

    public function __construct(BienImmobilier $bienImmobilier)
    {
        $this->bienImmobilier = $bienImmobilier;
    }

    /**
     * Converts the DTO data into the payload format expected by the API.
     *
     * @return array
     */
    public function toApiPayload(): array
    {
        return [
            'extAddressId' => $this->bienImmobilier->identifiant,
            'route' => $this->bienImmobilier->route,
            'postalCode' => $this->bienImmobilier->codePostal,
            'city' => $this->bienImmobilier->ville,
            'lat' => $this->bienImmobilier->latitude,
            'lon' => $this->bienImmobilier->longitude
        ];
    }
}
				
			
  • votre client API cityscan
				
					<?php

class CityscanClient
{
    private $apiBaseUrl;
    private $apiKey;

    public function __construct()
    {
        // Load configuration from a config file
        $config = require 'config.php';
        $this->apiBaseUrl = $config['api_base_url'];
        $this->apiKey = $config['api_key'];
    }

    /**
     * Sends a GET request to retrieve an evaluation.
     *
     * @param string $myOwnId
     *
     * @return mixed The response from the API or false if not found.
     */
    public function getEvaluationByExternalId(string $myOwnId) : ?array
    {
        $url = "{$this->apiBaseUrl}/api/evaluations/external/{$myOwnId}";

        // Initialize cURL
        $curl = curl_init();

        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'ApiKey: ' . $this->apiKey
            ],
        ]);

        // Execute the request and get the response
        $response = curl_exec($curl);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        curl_close($curl);

        // Check for success and decode response
        if ($httpCode == 200) {
            $decodedResponse = json_decode($response, true);
            return $decodedResponse['content']['evaluation'] ?? null;
        } else {
            return null;
        }
    }

    /**
     * Sends a POST request to create an evaluation.
     *
     * @param array $payload The payload data to send.
     *
     * @return mixed The response from the API or an error message.
     */
    public function createEvaluation(array $payload) : array
    {
        $url = $this->apiBaseUrl.'/api/evaluations';

        // Convert the payload to JSON format
        $jsonPayload = json_encode($payload);

        // Initialize cURL
        $curl = curl_init();

        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'ApiKey: ' . $this->apiKey
            ],
            CURLOPT_POSTFIELDS => $jsonPayload,
        ]);

        // Execute the request and get the response
        $response = curl_exec($curl);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        curl_close($curl);

        // Check for success and decode response
        if ($httpCode == 201) {
            $decodedResponse = json_decode($response, true);
            return $decodedResponse['content']['evaluation'];
        } else {
            throw new Exception("Failed to create evaluation. Response: " . $response);
        }
    }
}
				
			
  • votre code d’appel à Cityscan
				
					<?php

require_once 'RealtyDTO.php';
require_once 'CityscanClient.php';
require_once 'BienImmobilier.php';

// Votre instance de bien immobilier
$bienImmobilier = new BienImmobilier(
    'ABC123',       // identifiant
    '73 rue lecourbe', // route
    '75015',        // codePostal
    'Paris',        // ville
    '48.843353',    // latitude
    '2.305336',     // longitude
);

$realtyDTO = new RealtyDTO($bienImmobilier);

$client = new CityscanClient();

// Récupération de l'évaluation Cityscan
$cityscanEvaluation = $client->getEvaluationByExternalId($bienImmobilier->identifiant);

if (!$cityscanEvaluation) { // Si le bien n'existe pas sur Cityscan
    $cityscanEvaluation = $client->createEvaluation($realtyDTO->toApiPayload()); // On le crée
    echo "Evaluation created: " . $cityscanEvaluation['id'];
} else {
    echo "Evaluation found: " . $cityscanEvaluation['id'];
}
				
			

04 Migration vers la V2

  • Enrichissez la base de connaissance d’une intelligence artificielle avec la collection Open Api Location Insight
  • Vous obtenez votre nouveau DTO avec le nouveau mapping de champs.
 
On a intégré la confidentialité de l’adresse directement dans l’objet address que vous nous envoyez. Lisez bien la documentation, c’est une nouveauté non négligeable. Ici, on a considéré que vous aviez une propriété adresseMasquee directement dans votre modèle de donnée BienImmobilier.
				
					<?php

class RealtyDTO
{
    private BienImmobilier $bienImmobilier;

    public function __construct(BienImmobilier $bienImmobilier)
    {
        $this->bienImmobilier = $bienImmobilier;
    }

    /**
     * Converts the DTO data into the payload format expected by the API.
     *
     * @return array
     */
    public function toApiPayload(): array
    {
        return [
            'externalId' => $this->bienImmobilier->identifiant,
            'route' => $this->bienImmobilier->route,
            'postalCode' => $this->bienImmobilier->codePostal,
            'city' => $this->bienImmobilier->ville,
            'lat' => $this->bienImmobilier->latitude,
            'lon' => $this->bienImmobilier->longitude,
            'locationType' => $this->bienImmobilier->adresseMasquee ?
                'buffer' : 'exact',
            'buffer' => $this->bienImmobilier->adresseMasquee ? 
                300 : null, // Only if locationType is 'buffer'
        ];
    }
}
				
			
  • Le GPT vous propose une mise à jour de votre config et de votre client. Tout est bon à prendre, vous pourriez maintenant renommer getEvaluation et createEvaluation en getAddress et createAddress (ou getLocationInsightAddress et createLocationInsightAddress, si vous manipulez les objets adresses de plusieurs de nos produits).
				
					<?php
// config.php
return [
    'api_base_url' => 'https://api.cityscan.fr',  // Replace with the actual API base URL
         // 'api_base_url' => 'https://api.staging.cityscan.fr',
    'identifier' => 'your-identifier',            // Replace with your API identifier
    'secret' => 'your-secret',                    // Replace with your API secret
    'guid' => 'my-unique-guid',                   // Replace with your API solution GUID
];
				
			
				
					<?php

class CityscanClient
{
    private $apiBaseUrl;
    private $token;
    private $guid;

    public function __construct()
    {
        // Load configuration from config file
        $config = require 'config.php';
        $this->apiBaseUrl = $config['api_base_url'];
        $this->guid = $config['guid'];

        // Authenticate to get a JWT token (assuming this is the process)
        $this->authenticate($config['identifier'], $config['secret']);
    }

    /**
     * Authenticates and retrieves a JWT token for subsequent API calls.
     */
    private function authenticate(string $identifier, string $secret): void
    {
        $url = "{$this->apiBaseUrl}/security/authenticate";

        $payload = json_encode([
            'identifier' => $identifier,
            'secret' => $secret,
        ]);

        $curl = curl_init();

        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
            ],
            CURLOPT_POSTFIELDS => $payload,
        ]);

        $response = curl_exec($curl);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
        curl_close($curl);

        if ($httpCode == 200) {
            $decodedResponse = json_decode($response, true);
            $this->token = $decodedResponse['token'] ?? null;
        } else {
            throw new Exception("Authentication failed: {$response}");
        }
    }

    /**
     * Sends a GET request to retrieve an evaluation by external ID.
     *
     * @param string $externalId
     * @return mixed The response from the API.
     */
    public function getEvaluationByExternalId(string $externalId)
    {
        $url = "{$this->apiBaseUrl}/solution/location-insight/{$this->guid}/addresses/external/{$externalId}";

        $curl = curl_init();

        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'GET',
            CURLOPT_HTTPHEADER => [
                "Content-Type: application/json",
                "Authorization: Bearer {$this->token}",
            ],
        ]);

        $response = curl_exec($curl);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        curl_close($curl);

        if ($httpCode == 200) {
            $decodedResponse = json_decode($response, true);
            return $decodedResponse['items'] ?? null;
        } else {
            return false;
        }
    }

    /**
     * Sends a POST request to create an evaluation.
     *
     * @param array $payload The payload data to send.
     * @return mixed The response from the API.
     */
    public function createEvaluation(array $payload)
    {
        $url = "{$this->apiBaseUrl}/solution/location-insight/{$this->guid}/addresses";

        $jsonPayload = json_encode($payload);

        $curl = curl_init();

        curl_setopt_array($curl, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_CUSTOMREQUEST => 'POST',
            CURLOPT_HTTPHEADER => [
                "Content-Type: application/json",
                "Authorization: Bearer {$this->token}",
            ],
            CURLOPT_POSTFIELDS => $jsonPayload,
        ]);

        $response = curl_exec($curl);
        $httpCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);

        curl_close($curl);

        if ($httpCode == 201) {
            $decodedResponse = json_decode($response, true);
            return $decodedResponse;
        } else {
            return "Failed to create evaluation. Response: " . $response;
        }
    }
}
				
			

Le tour est joué, vous avez créé une adresse Cityscan (ABC123 si on reprend l’exemple de code). Votre widget est visible en intégrant ce code iframe :

				
					<!-- PRODUCTION -->
<iframe src="https://location-insight.cityscan.fr/my-unique-guid/external/ABC123" />

<!-- STAGING -->
<iframe src="https://location-insight.staging.cityscan.fr/my-unique-guid/external/ABC123" />
				
			

05 Conclusion

Vous trépignez désormais d’impatience d’obtenir votre identifier et secret pour tester la nouvelle formule.

  • Mettez vos commerciaux en contact avec nos commerciaux pour refaire un point sur les besoins fonctionnels, les volumes de données, et la tarification.
  • Nous organisons alors une réunion kickoff avec les deux équipes techniques si besoin, où nous repassons la documentation et votre méthode d’intégration.
  • L’équipe technico-commerciale met en place les comptes de tests et vous obtenez votre paire d’identifiants pour démarrer les tests en environnement staging.