AlkantarClanX12
| Current Path : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/classes/ |
| Current File : /www/capitalgmcbuickregina_830/public/wp-content/plugins/leadbox/classes/api.php |
<?php if (!defined('ABSPATH'))
exit;
final class LB_API_Client
{
private $apiUrl;
private $apiKey;
private $apiLeadKey;
private $usecache;
public function __construct($apiUrl, $apiKey, $apiLeadKey, $usecache)
{
$this->apiUrl = $apiUrl;
$this->apiKey = $apiKey;
$this->apiLeadKey = $apiLeadKey;
$this->usecache = $usecache;
}
public static function getInstance()
{
$settings = LB_API_Settings::getInstance();
return new LB_API_Client(
$settings->getApiUrl(),
$settings->getApiKey(),
$settings->getApiLeadKey(),
$settings->getApiCache()
);
}
/**
* Create a standardized API response
*
* @param bool $success Whether the operation succeeded
* @param mixed $data The response data (or null on error)
* @param string|null $message User-friendly message
* @param string|null $error_code Machine-readable error code
* @return array Standardized response array
*/
private function create_response($success, $data, $message = null, $error_code = null)
{
return array(
'success' => $success,
'data' => $data,
'count' => is_array($data) ? count($data) : 0,
'message' => $message,
'error_code' => $error_code,
'timestamp' => time()
);
}
public function CreateLead($lead)
{
if (FALSE == ($lead instanceof LB_Lead_Dto)) {
throw new Exception('$lead needs to be instance of Lead Object');
}
$useLeadKey = !empty($this->apiLeadKey);
$result = $this->POSTAsync('lead', $lead->ToArray(), $useLeadKey);
// POSTAsync returns error string on failure
if (is_string($result)) {
return $this->create_response(
false,
null,
'Unable to submit lead. Please try again later.',
'LEAD_SUBMISSION_FAILED'
);
}
// If result is array with success key (structured response), pass it through
if (is_array($result) && isset($result['success'])) {
return $result;
}
// Success - return the result from POSTAsync
return $this->create_response(
true,
$result,
'Lead submitted successfully',
null
);
}
public function VehicleSearch($parameters)
{
$result = $this->GET('vehicle/search', $parameters, 10);
// If GET already returned a structured error response, pass it through
if (is_array($result) && isset($result['success']) && !$result['success']) {
return $result;
}
// Validate response structure for vehicle search
if (!is_object($result) && !is_array($result)) {
return $this->create_response(
false,
null,
'Received unexpected data format from vehicle database.',
'API_INVALID_RESPONSE'
);
}
// Convert object to array for consistency
if (is_object($result)) {
$result = json_decode(json_encode($result), true);
}
// Check if we have vehicles in the response
$vehicles = isset($result['vehicles']) ? $result['vehicles'] : $result;
// Success with results or empty results
return $this->create_response(
true,
$vehicles,
empty($vehicles) ? 'No vehicles match your search criteria' : null,
null
);
}
public function VehicleCustomSearch($parameters)
{
$result = $this->GET('vehicle/customsearch', $parameters, 10);
// If GET already returned a structured error response, pass it through
if (is_array($result) && isset($result['success']) && !$result['success']) {
return $result;
}
// Validate response structure
if (!is_object($result) && !is_array($result)) {
return $this->create_response(
false,
null,
'Received unexpected data format from vehicle database.',
'API_INVALID_RESPONSE'
);
}
// Convert object to array for consistency
if (is_object($result)) {
$result = json_decode(json_encode($result), true);
}
// Check if we have vehicles in the response
$vehicles = isset($result['vehicles']) ? $result['vehicles'] : $result;
// Success with results or empty results
return $this->create_response(
true,
$vehicles,
empty($vehicles) ? 'No vehicles match your search criteria' : null,
null
);
}
public function VehicleDetail($id)
{
if (FALSE == is_numeric($id)) {
throw new Exception('id is not a valid number');
}
$result = $this->GET('vehicle/' . $id, FALSE, 15);
// If GET already returned a structured error response, pass it through
if (is_array($result) && isset($result['success']) && !$result['success']) {
return $result;
}
// Validate response structure
if (!is_object($result) && !is_array($result)) {
return $this->create_response(
false,
null,
'Vehicle not found.',
'API_INVALID_RESPONSE'
);
}
// Success - return vehicle details
return $this->create_response(
true,
$result,
null,
null
);
}
public function VehicleSimilars($id)
{
if (FALSE == is_numeric($id)) {
throw new Exception('id is not a valid number');
}
$result = $this->GET('vehicle/' . $id . '/similars', FALSE, 60);
// If GET already returned a structured error response, pass it through
if (is_array($result) && isset($result['success']) && !$result['success']) {
return $result;
}
// Validate response structure
if (!is_object($result) && !is_array($result)) {
return $this->create_response(
false,
null,
'Unable to find similar vehicles.',
'API_INVALID_RESPONSE'
);
}
// Convert object to array for consistency
if (is_object($result)) {
$result = json_decode(json_encode($result), true);
}
// Success with results or empty results
return $this->create_response(
true,
$result,
empty($result) ? 'No similar vehicles found' : null,
null
);
}
public function VehicleMatches($parameters)
{
return $this->GET('vehicle/search/totalmatches', $parameters, 10);
}
public function AvailableYears($parameters = FALSE)
{
return $this->GET('resource/year', $parameters, 60 * 6);
}
public function AvailableMakes($parameters = FALSE)
{
return $this->GET('resource/make', $parameters, 60 * 6);
}
public function AvailableModels($parameters = FALSE)
{
return $this->GET('resource/model', $parameters, 60 * 6);
}
public function AvailableTransmissions($parameters = FALSE)
{
return $this->GET('resource/transmission', $parameters, 60 * 6);
}
public function AvailableTypes($parameters = FALSE)
{
return $this->GET('resource/type', $parameters, 60 * 6);
}
public function AvailableColors($parameters = FALSE)
{
return $this->GET('resource/color', $parameters, 60 * 6);
}
public function AvailableEngineCyliders($parameters = FALSE)
{
return $this->GET('resource/enginecylinders', $parameters, 60 * 6);
}
public function AvailableDriveTrain($parameters = FALSE)
{
return $this->GET('resource/drivetrain', $parameters, 60 * 6);
}
public function AvailableEngineDisplacement($parameters = FALSE)
{
return $this->GET('resource/enginedisplacement', $parameters, 60 * 6);
}
public function AvailableCab($parameters = FALSE)
{
return $this->GET('resource/cab', $parameters, 60 * 6);
}
public function AvailableFeatures($parameters = FALSE)
{
return $this->GET('resource/category/full', $parameters, 60 * 6);
}
public function AvailableLocations($parameters = FALSE)
{
return $this->GET('resource/location', $parameters, 60 * 6);
}
public function AvailableConditions($parameters = FALSE)
{
return $this->GET('resource/condition', $parameters, 60 * 6);
}
public function Locations()
{
return $this->GET('resource/location/info/all', FALSE, 60 * 6);
}
public function LocationInfo($name)
{
if (empty($name)) {
throw new Exception('Location name cannot be empty');
}
return $this->GET('resource/location/info?name=' . $name, FALSE, 60 * 6);
}
public function SaveVisitorVehicle($email, $carId)
{
if (FALSE == is_numeric($carId)) {
throw new Exception('id is not a valid number');
}
$SaveVisitor = array();
$SaveVisitor["email"] = $email;
$SaveVisitor["vehicleId"] = $carId;
return $this->POST('visitors', $SaveVisitor);
}
public function SaveVisitorVehiclesIds($email, $Ids)
{
$SaveVisitorIds = array();
$SaveVisitorIds["email"] = $email;
$SaveVisitorIds['vehicleIds'] = $Ids;
return $this->POST('visitors', $SaveVisitorIds);
}
public function GetVisitorVehicles($email)
{
return $this->GET('visitors?email=' . $email, false, false);
}
public function GetVisitorVehiclesFull($email)
{
return $this->GET('visitors/full?email=' . $email, false, false);
}
public function DeleteVisitorVehicle($email, $carId)
{
$Deletevisitor = array();
$Deletevisitor["email"] = $email;
$Deletevisitor["vehicleId"] = $carId;
return $this->DELETE('visitors', $Deletevisitor);
}
private function GET($url, $parameters = FALSE, $cachetime = 5, $useLeadKey = FALSE)
{
if (empty($url)) {
throw new Exception('$url cannot be empty');
}
if ($parameters != FALSE) {
if (FALSE == ($parameters instanceof SearchParameters)) {
throw new Exception('$parameters needs to be instance of SearchParameters Object');
}
$aParameters = $parameters->ToArray();
foreach ($aParameters as $key => $value) {
if (is_bool($value)) {
$aParameters[$key] = ($value) ? 'true' : 'false';
}
}
$endpoint = $this->apiUrl . '/api/v1/' . $url . '?' . http_build_query($aParameters);
} else {
$endpoint = $this->apiUrl . '/api/v1/' . $url;
}
$cache_key = md5($endpoint);
$cached = get_transient($cache_key);
// Return cached data if available
if ($this->usecache && $cached !== false) {
return $cached;
}
$args = array(
'timeout' => 120,
'headers' => array(
'Authorization' => $useLeadKey ? $this->apiLeadKey : $this->apiKey
)
);
$result = wp_remote_get($endpoint, $args);
// Connection error
if (is_wp_error($result)) {
$error_message = 'Unable to connect to vehicle database. Please try again later.';
if (defined('WP_DEBUG') && WP_DEBUG) {
$error_message .= ' (' . $result->get_error_message() . ')';
}
// Log error if logger is available
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API Connection Failed', array(
'endpoint' => $endpoint,
'error' => $result->get_error_message()
));
}
$response = $this->create_response(
false,
null,
$error_message,
'API_CONNECTION_FAILED'
);
// Try to return stale cache if available
$stale_cache = get_transient($cache_key . '_stale');
if ($stale_cache !== false) {
$response['data'] = $stale_cache;
$response['count'] = is_array($stale_cache) ? count($stale_cache) : 0;
$response['message'] = 'Showing cached results. Live data temporarily unavailable.';
$response['error_code'] = 'USING_STALE_CACHE';
}
return $response;
}
// HTTP error status
$status_code = wp_remote_retrieve_response_code($result);
if ($status_code !== 200) {
$error_message = 'Vehicle database returned an error. Please try again later.';
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API HTTP Error', array(
'endpoint' => $endpoint,
'status_code' => $status_code
));
}
return $this->create_response(
false,
null,
$error_message,
'API_HTTP_ERROR_' . $status_code
);
}
// Parse response
$body = wp_remote_retrieve_body($result);
$data = json_decode($body, true);
// JSON parse error
if (json_last_error() !== JSON_ERROR_NONE) {
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API Parse Error', array(
'endpoint' => $endpoint,
'json_error' => json_last_error_msg()
));
}
return $this->create_response(
false,
null,
'Received invalid data from vehicle database.',
'API_PARSE_ERROR'
);
}
// Validate that we got some data
if (!is_array($data) && !is_object($data)) {
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API Invalid Response', array(
'endpoint' => $endpoint,
'data_type' => gettype($data)
));
}
return $this->create_response(
false,
null,
'Received unexpected data format from vehicle database.',
'API_INVALID_RESPONSE'
);
}
// Success! Cache the raw data as before for backwards compatibility
if ($this->usecache && $data) {
set_transient($cache_key, $data, 60 * $cachetime);
// Also save as stale cache (longer TTL for fallback)
set_transient($cache_key . '_stale', $data, 24 * HOUR_IN_SECONDS);
}
return $data;
}
private function POST($url, $payload, $useLeadKey = FALSE)
{
if (FALSE == is_array($payload)) {
throw new Exception('$payload needs to be array object');
}
$args = array(
'timeout' => 120,
'headers' => array(
'Authorization' => $useLeadKey ? $this->apiLeadKey : $this->apiKey
),
'body' => $payload
);
$endpoint = $this->apiUrl . '/api/v1/' . $url;
$result = wp_remote_post($endpoint, $args);
// Connection error
if (is_wp_error($result)) {
$error_message = 'Unable to connect to server. Please try again later.';
if (defined('WP_DEBUG') && WP_DEBUG) {
$error_message .= ' (' . $result->get_error_message() . ')';
}
// Log error if logger is available
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API POST Connection Failed', array(
'endpoint' => $endpoint,
'error' => $result->get_error_message()
));
}
return $this->create_response(
false,
null,
$error_message,
'API_CONNECTION_FAILED'
);
}
// HTTP error status
$status_code = wp_remote_retrieve_response_code($result);
if ($status_code < 200 || $status_code >= 300) {
$error_message = 'Server returned an error. Please try again later.';
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API POST HTTP Error', array(
'endpoint' => $endpoint,
'status_code' => $status_code
));
}
return $this->create_response(
false,
null,
$error_message,
'API_HTTP_ERROR_' . $status_code
);
}
// Parse response
$body = wp_remote_retrieve_body($result);
$data = json_decode($body, true);
// JSON parse error
if (json_last_error() !== JSON_ERROR_NONE) {
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API POST Parse Error', array(
'endpoint' => $endpoint,
'json_error' => json_last_error_msg()
));
}
return $this->create_response(
false,
null,
'Received invalid data from server.',
'API_PARSE_ERROR'
);
}
// Success!
return $data;
}
private function GetCurlSession($url, $payload, $key)
{
$headers = array(
'Content-Type:application/json',
'Accept:application/json',
'Authorization:' . $key
);
$endpoint = $this->apiUrl . '/api/v1/' . $url;
$body = json_encode($payload);
$session = curl_init($endpoint);
curl_setopt($session, CURLOPT_POST, true);
curl_setopt($session, CURLOPT_POSTFIELDS, $body);
curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_HTTPHEADER, $headers);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($session, CURLOPT_TIMEOUT_MS, 5000);
// Devolver el manejador cURL
return $session;
}
private function POSTAsync($url, $payload, $useLeadKey = false)
{
if (!is_array($payload)) {
throw new Exception('$payload needs to be an array object');
}
$authorizationKey = $useLeadKey ? $this->apiLeadKey : $this->apiKey;
try {
// Obtener el manejador cURL sin ejecutar la petición
$session = $this->GetCurlSession($url, $payload, $authorizationKey, true);
if (!($session instanceof CurlHandle)) {
throw new Exception('GetCurlSession() did not return a valid cURL handle');
}
$mh = curl_multi_init();
curl_multi_add_handle($mh, $session);
// Ejecutar multi-cURL
$active = null;
do {
$status = curl_multi_exec($mh, $active);
if ($active) {
curl_multi_select($mh);
}
} while ($active && $status == CURLM_OK);
// Obtener la respuesta y código HTTP
$response = curl_multi_getcontent($session);
$http_code = curl_getinfo($session, CURLINFO_HTTP_CODE);
// Verificar si hubo error en cURL
if (curl_errno($session)) {
$error_msg = curl_error($session);
leadbox_logger()->error('Backend connection failed', array(
'error' => $error_msg,
'curl_errno' => curl_errno($session),
'endpoint' => $url,
));
if (curl_errno($session) == CURLE_OPERATION_TIMEOUTED) {
// Timeout específico
throw new Exception('Timeout while connecting to the backend');
}
throw new Exception('Backend not available: ' . $error_msg);
}
curl_multi_remove_handle($mh, $session);
curl_multi_close($mh);
// Validación del backend
if ($http_code !== 200) {
leadbox_logger()->error('Backend returned non-200 status', array(
'http_code' => $http_code,
'endpoint' => $url,
));
throw new Exception('Backend not available: HTTP Code ' . $http_code);
}
return json_decode($response, true); // Retornar respuesta si es válida
} catch (Exception $e) {
leadbox_logger()->error('POSTAsync failed', array(
'error' => $e->getMessage(),
'endpoint' => $url,
'trace' => $e->getTraceAsString(),
));
return $e->getMessage();
}
}
private function DELETE($url, $payload)
{
if (FALSE == is_array($payload)) {
throw new Exception('$payload needs to be array object');
}
$args = array(
'method' => 'DELETE',
'timeout' => 120,
'headers' => array(
'Authorization' => $this->apiKey
),
'body' => $payload
);
$endpoint = $this->apiUrl . '/api/v1/' . $url;
$result = wp_remote_request($endpoint, $args);
// Connection error
if (is_wp_error($result)) {
$error_message = 'Unable to connect to server. Please try again later.';
if (defined('WP_DEBUG') && WP_DEBUG) {
$error_message .= ' (' . $result->get_error_message() . ')';
}
// Log error if logger is available
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API DELETE Connection Failed', array(
'endpoint' => $endpoint,
'error' => $result->get_error_message()
));
}
return $this->create_response(
false,
null,
$error_message,
'API_CONNECTION_FAILED'
);
}
// HTTP error status
$status_code = wp_remote_retrieve_response_code($result);
if ($status_code < 200 || $status_code >= 300) {
$error_message = 'Server returned an error. Please try again later.';
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API DELETE HTTP Error', array(
'endpoint' => $endpoint,
'status_code' => $status_code
));
}
return $this->create_response(
false,
null,
$error_message,
'API_HTTP_ERROR_' . $status_code
);
}
// Parse response
$body = wp_remote_retrieve_body($result);
$data = json_decode($body, true);
// JSON parse error
if (json_last_error() !== JSON_ERROR_NONE) {
if (function_exists('leadbox_logger')) {
leadbox_logger()->error('API DELETE Parse Error', array(
'endpoint' => $endpoint,
'json_error' => json_last_error_msg()
));
}
return $this->create_response(
false,
null,
'Received invalid data from server.',
'API_PARSE_ERROR'
);
}
// Success!
return $data;
}
}
?>