From 63bf6af68cd45ad5c3343ee2ed3bce82be539bfd Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Thu, 16 Jul 2020 18:12:10 +0200 Subject: [PATCH 01/85] =?UTF-8?q?Primo=20commit=C3=AC=20Fatta=20la=20class?= =?UTF-8?q?e=20che=20recupera=20il=20token=20ed=20istanzia=20le=20altre=20?= =?UTF-8?q?classi?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OpenApi.php | 319 ++++++++++++++++++++ classes/Imprese.php | 5 + classes/OpenApiBase.php | 20 ++ classes/UfficioPostale.php | 10 + classes/exception/OpenApiExceptionBase.php | 60 ++++ classes/exception/OpenApiTokenException.php | 16 + classes/utility/DummyCache.php | 19 ++ readme.md | 24 ++ 8 files changed, 473 insertions(+) create mode 100644 OpenApi.php create mode 100644 classes/Imprese.php create mode 100644 classes/OpenApiBase.php create mode 100644 classes/UfficioPostale.php create mode 100644 classes/exception/OpenApiExceptionBase.php create mode 100644 classes/exception/OpenApiTokenException.php create mode 100644 classes/utility/DummyCache.php create mode 100644 readme.md diff --git a/OpenApi.php b/OpenApi.php new file mode 100644 index 0000000..12bccc3 --- /dev/null +++ b/OpenApi.php @@ -0,0 +1,319 @@ +"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] oppure "GET:ws.ufficiopostale.com/comuni NOTA: il dominio NON deve mai avere lo stage + * @param string $username Username openapi + * @param string $apikey ApiKey openapi + * @param mixed $environment='test' uno tra: dev, test (default), production + */ + function __construct(array $scopes, string $username, string $apikey, $environment='test'){ + + $this->cache = new \OpenApi\classes\utility\DummyCache; + $this->header = null; + $this->rawResponse = null; + $realScopes = []; + $prefix = $environment=="production"?"":$environment."."; + $domains = []; + foreach($scopes as $s){ + if(is_array($s)){ + $domain = $s['domain']; + $realScope = $s['mode'].":".$prefix.$s['domain']."/".$s['method']; + }else{ + $realScope = str_replace(":",":{$prefix}", $s) ; + $domain = explode(":", $s)[1]; + $domain = explode("/", $domain)[0]; + } + if(!in_array($domain, $domains)){ + $domains[] = $domain; + } + if(!in_array($realScope,$realScopes)){ + $realScopes[] = $realScope; + } + } + $this->username = $username; + $this->apikey = $apikey; + $this->prefix = $prefix; + $this->scopes = $realScopes; + $token = $this->getToken(); + + + $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; + $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; + $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; + $nomi['imprese.altravia.com'] = "imprese"; + $clients = []; + foreach($domains as $d){ + if(isset($moduli[$d])){ + $modulo = $moduli[$d]; + $nome = $nomi[$d]; + $this->$nome = new $modulo($token->token, $this->cache); + $clients[] = $this->$nome; + } + } + } + + + /** + * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende + * {@see OpenApi\clasess\utility\DummyCache} + * + * @param mixed $cacheSys Istanza della classe da usare come sistema di cache + * @return void + */ + function setCacheSystem($cacheSys){ + $this->cache = $cacheSys; + foreach($this->clients as $c){ + $c->setCacheSystem($cacheSys); + } + } + + + /** + * + * Restituisce il token attualemnte in sessione, se non presente o non più valido lo rigenera + * + * @param boolean $force=FALSE Se impostato a TRUE forza la rigenerazione del token + * @return object il token + */ + function getToken($force=FALSE){ + if(!$force && !$this->isTokenCompatible()){ + + //TODO: Controllare se il token è ancora valido + if(!$this->mustRfreshToken()){ + return $_SESSION['openapi']['token']; + } + $this->renewToken(); + + return $_SESSION['openapi']['token']; + } + if($this->getOldToken()){ + if(!$this->mustRfreshToken()){ + return $_SESSION['openapi']['token']; + } + $this->renewToken(); + return $_SESSION['openapi']['token']; + } + return $this->generateNewToken(); + } + + + /** + * Rinnova il token in sessione + * + * @return object + */ + private function renewToken(){ + $param = ["expire" => 86400, "scopes" => $this->scopes]; + //var_dump($param);exit; + + $token = $this->connect("token/".$_SESSION['openapi']['token']->token,$param,"PUT"); + + if($token == NULL){ + throw new \OpenApi\classes\exception\OpenApiTokenException("REnew Token: Connection Error",40001); + } + if($token->success == false){ + $message = "REnew Token: unknow error"; + if(isset($token->message)) { + $message = "REnew Token: $token->message"; + } + $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); + $except->setServerResponse($token, $this->header, $this->rawResponse); + + throw $except; + } + if(isset($token->data) && isset($token->data[0])) + { + $token = $token->data[0]; + $_SESSION['openapi']['token'] = $token; + return $token; + } + + } + + + /** + * Controlla se il token in sessione deve essere o meno rinnovato in base alla sua data di scadenza + * + * @return bool + */ + private function mustRfreshToken(){ + $token = $_SESSION['openapi']['token']; + $diff = $token->expire-date("U"); + if($diff <= 6000){ + return TRUE; + } + return FALSE; + } + + + /** + * + * Recupera la lista di token per verificare se esiste uno utilizzabile con gli scopes di interesse, + * se si lo mette in sessione e ritorna TRUE + * + * @return boolean + */ + function getOldToken(){ + $param = ["scopes" => $this->scopes]; + $token = $this->connect("token",$param,"GET"); + $finded_token = NULL; + + if($token != NULL && isset($token->data)){ + foreach($token->data AS $token){ + if($this->hasValidScopes($token)){ + $finded_token = $token; + break 1; + } + } + + if($finded_token != NULL){ + $_SESSION['openapi']['token'] = $finded_token; + $_SESSION['openapi']['apikey'] = $this->apikey; + $_SESSION['openapi']['scopes'] = serialize($this->scopes); + $_SESSION['openapi']['username'] = $this->username; + $_SESSION['openapi']['prefix'] = $this->prefix; + return TRUE; + } + return FALSE; + } + } + + function hasValidScopes($token){ + foreach($this->scopes as $s){ + if(!in_array($s, $token->scopes)){ + return false; + } + } + return true; + } + + /** + * Genera un nuovo token + * @return object il token + */ + private function generateNewToken(){ + $param = ["scopes" => $this->scopes]; + $token = $this->connect("token",$param,"POST"); + if($token == NULL){ + throw new \OpenApi\classes\exception\OpenApiTokenException("Getting Token: Connection Error",40001); + } + if($token->success == false){ + $message = "Getting Token: unknow error"; + if(isset($token->message)) { + $message = "Getting Token: $token->message"; + } + $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); + $except->setServerResponse($token, $this->header, $this->rawResponse); + + throw $except; + } + + $invalid_scopes = []; + foreach($this->scopes as $s){ + if(!in_array($s, $token->scopes)){ + $invalid_scopes[] = $s; + } + } + if(count($invalid_scopes)>0){ + $message = "Getting Token: unknow error"; + if(isset($token->message)) { + + } + $message = "Getting Token: invalid scopes (".implode($invalid_scopes).")"; + $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40003); + $except->setServerResponse($token, $this->header, $this->rawResponse); + throw $except; + } + $_SESSION['openapi']['token'] = $token; + $_SESSION['openapi']['apikey'] = $this->apikey; + $_SESSION['openapi']['scopes'] = serialize($this->scopes); + $_SESSION['openapi']['username'] = $this->username; + $_SESSION['openapi']['prefix'] = $this->prefix; + return $token; + } + + + /** + * + * Constrolla se il token in sessione è compatibile con la richiesta + * + * @return boolean + */ + private function isTokenCompatible() { + if(!isset($_SESSION['openapi'])|| !isset($_SESSION['openapi']['token'])){ + return TRUE; + } + if($_SESSION['openapi']['prefix'] != $this->prefix || $_SESSION['openapi']['apikey'] != $this->apikey || $_SESSION['openapi']['username'] != $this->username){ + return TRUE; + } + $sessionScopes = unserialize($_SESSION['openapi']['scopes']); + if(!is_array($sessionScopes)){ + return TRUE; + } + foreach($this->scopes as $s){ + if(!in_array($s, $sessionScopes)){ + return TRUE; + } + } + return FALSE; + } + + + /** + * Effettua una connessione al server oauth + * + * @param string $endpoint path da recuperare + * @param array $param Lista dei parametri da passare + * @param mixed $mode metodo http da usare per la chiamata + * @return object + */ + private function connect(string $endpoint, $param = [], $mode="POST"){ + + $this->header = null; + $this->rawResponse = null; + $basePath = "https://".$this->prefix."oauth.altravia.com"; + $url = $basePath."/".$endpoint; + + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mode); + if($mode == "POST" || $mode == "PUT") + { + curl_setopt($ch, CURLOPT_POST, TRUE); + } + if($mode == "GET") + { + $param = http_build_query($param); + $url .= "?".$param; + + }else{ + $param = json_encode($param); + + curl_setopt($ch, CURLOPT_POSTFIELDS, $param); + } + + $baseauth = base64_encode($this->username.":".$this->apikey); + $headers = array( + 'Content-Type:application/json', + 'Authorization: Basic '. $baseauth // <--- + ); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_HEADER, 1); + $response = curl_exec($ch); + $this->rawResponse = $response; + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $this->header = substr($response, 0, $header_size); + $return = substr($response, $header_size); + + curl_close($ch); + return json_decode($return); + } +} diff --git a/classes/Imprese.php b/classes/Imprese.php new file mode 100644 index 0000000..3887ead --- /dev/null +++ b/classes/Imprese.php @@ -0,0 +1,5 @@ +token = $token; + $this->token = $cache; + } + + /** + * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende + * {@see OpenApi\clasess\utility\DummyCache} + * + * @param mixed $cacheSys Istanza della classe da usare come sistema di cache + * @return void + */ + function setCacheSystem($cacheSys){ + $this->cache = $cacheSys; + } + +} \ No newline at end of file diff --git a/classes/UfficioPostale.php b/classes/UfficioPostale.php new file mode 100644 index 0000000..352ef5f --- /dev/null +++ b/classes/UfficioPostale.php @@ -0,0 +1,10 @@ +serverData = NULL; + $this->serverHeader = NULL; + $this->serverRawResponse = NULL; + } + public function __toString() { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + } + + + /** + * + * Imposta alcune variabili utili in fase di debugging degli errori + * + * @param object $serverData Response del server già decodato dalla versione json + * @param string $serverHeader Stringa contentene gli header della response + * @param string $serverRawResponse Stringa contente la risposta raw del server + * + * @return [type] + */ + function setServerResponse(object $serverData, string $serverHeader, string $serverRawResponse){ + $this->serverData = $serverData; + $this->serverHeader = $serverHeader; + $this->serverRawResponse = $serverRawResponse; + } + + /** + * + * Restituisce la risposta del server già decodata da json + * + * @return object + */ + function getServerResponse(){ + return $this->serverData; + } + + /** + * + * Restituisce gli header della rispopsta del server + * + * @return string + */ + function getServerHeaderResponse(){ + return $this->serverHeader; + } + + /** + * + * Restituisce la risposta in formato RAW del server + * @return string + */ + function getServerRawResponse(){ + return $this->serverRawResponse; + } +} \ No newline at end of file diff --git a/classes/exception/OpenApiTokenException.php b/classes/exception/OpenApiTokenException.php new file mode 100644 index 0000000..b84a288 --- /dev/null +++ b/classes/exception/OpenApiTokenException.php @@ -0,0 +1,16 @@ +openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); + ``` + Dove ```$scopes``` è un array di stringhe o di oggetti in uno dei seguenti formati: + + ```php + $scopes=[ + "GET:ws.ufficiopostale.com/comuni", + ["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] + ]; + ``` + + A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: + ```php + $this->openapi->ufficioposale + $this->openapi->imprese + ``` + che possono essere usati al seguente modo: + ```php + $this->openapi->ufficioposale->getCitiesByCap('00132';) + ``` \ No newline at end of file From a206636ede48f5d24d565d4de88d9a88c222328b Mon Sep 17 00:00:00 2001 From: Simone Desantis <67371387+SimoneDesantisAltravia@users.noreply.github.com> Date: Fri, 17 Jul 2020 10:41:26 +0200 Subject: [PATCH 02/85] Set theme jekyll-theme-slate --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 0000000..c741881 --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-slate \ No newline at end of file From af690b1c3cd08370e47e8fe78e9b6c9948a86e34 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Thu, 30 Jul 2020 18:01:39 +0200 Subject: [PATCH 03/85] Aggiunta parte della gestione delle visure --- OpenApi.php | 123 ++++++---- classes/Imprese.php | 66 ++++++ classes/OpenApiBase.php | 152 ++++++++++++- classes/UfficioPostale.php | 26 ++- classes/VisEngine.php | 110 +++++++++ .../exception/OpenApiConnectionsException.php | 17 ++ classes/exception/OpenApiExceptionBase.php | 8 +- .../exception/OpenApiVisEngineException.php | 16 ++ classes/utility/CacheSystemInterface.php | 8 + classes/utility/DummyCache.php | 6 +- classes/utility/VisEngine/VisRequest.php | 212 ++++++++++++++++++ classes/utility/ci4SessionStoreToken.php | 18 ++ classes/utility/sessionStoreToken.php | 19 ++ classes/utility/storeTokenInterface.php | 8 + readme.md | 65 ++++-- 15 files changed, 778 insertions(+), 76 deletions(-) create mode 100644 classes/VisEngine.php create mode 100644 classes/exception/OpenApiConnectionsException.php create mode 100644 classes/exception/OpenApiVisEngineException.php create mode 100644 classes/utility/CacheSystemInterface.php create mode 100644 classes/utility/VisEngine/VisRequest.php create mode 100644 classes/utility/ci4SessionStoreToken.php create mode 100644 classes/utility/sessionStoreToken.php create mode 100644 classes/utility/storeTokenInterface.php diff --git a/OpenApi.php b/OpenApi.php index 12bccc3..303edc7 100644 --- a/OpenApi.php +++ b/OpenApi.php @@ -1,5 +1,5 @@ cache = new \OpenApi\classes\utility\DummyCache; + $this->store = $store; $this->header = null; $this->rawResponse = null; $realScopes = []; + $domainsRealScopes = []; $prefix = $environment=="production"?"":$environment."."; $domains = []; foreach($scopes as $s){ @@ -28,37 +32,57 @@ function __construct(array $scopes, string $username, string $apikey, $environme } if(!in_array($domain, $domains)){ $domains[] = $domain; + $domainsRealScopes[$domain] = []; } + if(!in_array($realScope,$realScopes)){ $realScopes[] = $realScope; + $domainsRealScopes[$domain][] = $realScope; } + } + $this->username = $username; $this->apikey = $apikey; $this->prefix = $prefix; $this->scopes = $realScopes; - $token = $this->getToken(); - - $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; - $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; - $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; - $nomi['imprese.altravia.com'] = "imprese"; - $clients = []; + $token = $this->getToken(); + //var_dump($token);exit; + list($moduli,$nomi) = $this->getListaModuli(); + $this->clients = []; foreach($domains as $d){ if(isset($moduli[$d])){ $modulo = $moduli[$d]; $nome = $nomi[$d]; - $this->$nome = new $modulo($token->token, $this->cache); - $clients[] = $this->$nome; + $this->$nome = new $modulo($token->token, $domainsRealScopes[$d], $this->cache, $prefix); + $this->clients[] = $nome; } } } + /** + * + * Restituisce la lista dei moduli disponibili + * + * @return array + */ + private function getListaModuli(){ + $moduli = []; + $nomi = []; + $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; + $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; + $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; + $nomi['imprese.altravia.com'] = "imprese"; + + $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; + $nomi['visengine2.altravia.com'] = "visengine"; + return array($moduli,$nomi); + } /** * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see OpenApi\clasess\utility\DummyCache} + * {@see OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) * * @param mixed $cacheSys Istanza della classe da usare come sistema di cache * @return void @@ -66,11 +90,11 @@ function __construct(array $scopes, string $username, string $apikey, $environme function setCacheSystem($cacheSys){ $this->cache = $cacheSys; foreach($this->clients as $c){ - $c->setCacheSystem($cacheSys); + $this->$c->setCacheSystem($cacheSys); } } - + /** * * Restituisce il token attualemnte in sessione, se non presente o non più valido lo rigenera @@ -81,20 +105,19 @@ function setCacheSystem($cacheSys){ function getToken($force=FALSE){ if(!$force && !$this->isTokenCompatible()){ - //TODO: Controllare se il token è ancora valido if(!$this->mustRfreshToken()){ - return $_SESSION['openapi']['token']; + return $this->store->get()['token']; } $this->renewToken(); - return $_SESSION['openapi']['token']; + return $this->store->get()['token']; } if($this->getOldToken()){ if(!$this->mustRfreshToken()){ - return $_SESSION['openapi']['token']; + return $this->store->get()['token']; } $this->renewToken(); - return $_SESSION['openapi']['token']; + return $this->store->get()['token']; } return $this->generateNewToken(); } @@ -106,13 +129,13 @@ function getToken($force=FALSE){ * @return object */ private function renewToken(){ - $param = ["expire" => 86400, "scopes" => $this->scopes]; + $param = ["expire" => time() + 86400, "scopes" => $this->scopes]; //var_dump($param);exit; - $token = $this->connect("token/".$_SESSION['openapi']['token']->token,$param,"PUT"); + $token = $this->connect("token/".$this->store->get()['token']->token,$param,"PUT"); if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("REnew Token: Connection Error",40001); + throw new \OpenApi\classes\exception\OpenApiTokenException("Renew Token: Connection Error",40001); } if($token->success == false){ $message = "REnew Token: unknow error"; @@ -127,7 +150,7 @@ private function renewToken(){ if(isset($token->data) && isset($token->data[0])) { $token = $token->data[0]; - $_SESSION['openapi']['token'] = $token; + $this->store->get()['token'] = $token; return $token; } @@ -140,7 +163,7 @@ private function renewToken(){ * @return bool */ private function mustRfreshToken(){ - $token = $_SESSION['openapi']['token']; + $token = $this->store->get()['token']; $diff = $token->expire-date("U"); if($diff <= 6000){ return TRUE; @@ -157,8 +180,9 @@ private function mustRfreshToken(){ * @return boolean */ function getOldToken(){ - $param = ["scopes" => $this->scopes]; + $param = ["scope" => $this->scopes]; $token = $this->connect("token",$param,"GET"); + $finded_token = NULL; if($token != NULL && isset($token->data)){ @@ -170,11 +194,12 @@ function getOldToken(){ } if($finded_token != NULL){ - $_SESSION['openapi']['token'] = $finded_token; - $_SESSION['openapi']['apikey'] = $this->apikey; - $_SESSION['openapi']['scopes'] = serialize($this->scopes); - $_SESSION['openapi']['username'] = $this->username; - $_SESSION['openapi']['prefix'] = $this->prefix; + $tostore['token'] = $finded_token; + $tostore['apikey'] = $this->apikey; + $tostore['scopes'] = serialize($this->scopes); + $tostore['username'] = $this->username; + $tostore['prefix'] = $this->prefix; + $this->session->save($tostore); return TRUE; } return FALSE; @@ -227,11 +252,14 @@ private function generateNewToken(){ $except->setServerResponse($token, $this->header, $this->rawResponse); throw $except; } - $_SESSION['openapi']['token'] = $token; - $_SESSION['openapi']['apikey'] = $this->apikey; - $_SESSION['openapi']['scopes'] = serialize($this->scopes); - $_SESSION['openapi']['username'] = $this->username; - $_SESSION['openapi']['prefix'] = $this->prefix; + $tostore['token'] = $token; + $tostore['apikey'] = $this->apikey; + $tostore['scopes'] = serialize($this->scopes); + $tostore['username'] = $this->username; + $tostore['prefix'] = $this->prefix; + + $this->store->save($tostore); + return $token; } @@ -243,13 +271,13 @@ private function generateNewToken(){ * @return boolean */ private function isTokenCompatible() { - if(!isset($_SESSION['openapi'])|| !isset($_SESSION['openapi']['token'])){ + if(!$this->store->isset()|| !isset($this->store->get()['token'])){ return TRUE; } - if($_SESSION['openapi']['prefix'] != $this->prefix || $_SESSION['openapi']['apikey'] != $this->apikey || $_SESSION['openapi']['username'] != $this->username){ + if($this->store->get()['prefix'] != $this->prefix || $this->store->get()['apikey'] != $this->apikey || $this->store->get()['username'] != $this->username){ return TRUE; } - $sessionScopes = unserialize($_SESSION['openapi']['scopes']); + $sessionScopes = unserialize($this->store->get()['scopes']); if(!is_array($sessionScopes)){ return TRUE; } @@ -276,7 +304,12 @@ private function connect(string $endpoint, $param = [], $mode="POST"){ $this->rawResponse = null; $basePath = "https://".$this->prefix."oauth.altravia.com"; $url = $basePath."/".$endpoint; - + if($mode == "GET") + { + $param = http_build_query($param); + $param = preg_replace('/(%5B)\d+(%5D=)/i', '$1$2', $param); + $url .= "?".$param; + } $ch = curl_init($url); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mode); @@ -284,12 +317,8 @@ private function connect(string $endpoint, $param = [], $mode="POST"){ { curl_setopt($ch, CURLOPT_POST, TRUE); } - if($mode == "GET") + if($mode != "GET") { - $param = http_build_query($param); - $url .= "?".$param; - - }else{ $param = json_encode($param); curl_setopt($ch, CURLOPT_POSTFIELDS, $param); @@ -298,7 +327,7 @@ private function connect(string $endpoint, $param = [], $mode="POST"){ $baseauth = base64_encode($this->username.":".$this->apikey); $headers = array( 'Content-Type:application/json', - 'Authorization: Basic '. $baseauth // <--- + 'Authorization: Basic '. $baseauth ); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); @@ -309,10 +338,10 @@ private function connect(string $endpoint, $param = [], $mode="POST"){ curl_setopt($ch, CURLOPT_HEADER, 1); $response = curl_exec($ch); $this->rawResponse = $response; + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $this->header = substr($response, 0, $header_size); $return = substr($response, $header_size); - curl_close($ch); return json_decode($return); } diff --git a/classes/Imprese.php b/classes/Imprese.php index 3887ead..23b58e6 100644 --- a/classes/Imprese.php +++ b/classes/Imprese.php @@ -1,5 +1,71 @@ basePath = "https://imprese.altravia.com"; + } + /** + * + * Consente di recuperare i dati di una azienda a partire dalla partita IVA + * + * @param string $partitaIva La partita IVa da ricercare + * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + * + * @return object + */ + function getByPartitaIva(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("advance/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + + + } + + /** + * + * Cerca un'azienda o più utilizzando vari parametri + * + * @param string $denominazione Denominazione azienda + * @param string $provincia Provincia + * @param string $partitaIva=NULL Partita IVA + * @param string $codiceFiscale=NULL Codice Fiscale + * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + * + * @return array Lista delle aziende individuate + */ + function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ + $params=[]; + if($denominazione != NULL){ + $params['denominazione'] = $denominazione; + } + if($provincia != NULL){ + $params['provincia'] = $provincia; + } + if($partitaIva != NULL){ + $params['piva'] = $partitaIva; + } + if($codiceFiscale != NULL){ + $params['cf'] = $codiceFiscale; + } + + $data = $this->connect("advance/$partitaIva", "GET", $params, $ttr); + return $data->data; + } } \ No newline at end of file diff --git a/classes/OpenApiBase.php b/classes/OpenApiBase.php index 68572ac..a88dedb 100644 --- a/classes/OpenApiBase.php +++ b/classes/OpenApiBase.php @@ -1,20 +1,162 @@ token = $token; - $this->token = $cache; + $this->cache = $cache; + $this->scopes = $scopes; + $this->prefix = $prefix; + $this->basePath = null; } /** * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see OpenApi\clasess\utility\DummyCache} + * {@see \OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) * - * @param mixed $cacheSys Istanza della classe da usare come sistema di cache + * @param object $cacheSys Istanza della classe da usare come sistema di cache * @return void */ - function setCacheSystem($cacheSys){ + function setCacheSystem(object $cacheSys){ $this->cache = $cacheSys; } + + + /** + * Salva un oggetto nella cache + * @param string $key LA chiave utilizzata per salvare l'oggetto nella cache + * @param object $value L'oggetto da salvare nella cache + * @param int $ttr TEmpo in cui l'oggetto resta in cache + * + * @return void + */ + protected function setCacheObject(string $key, object $value, int $ttr){ + $ttr += rand ( 0 , 120 ); + $this->cache->save($key, $value, $ttr); + } + + /** + * + * Recupera un oggetto dalla cache se presente + * + * @param string $key LA chiave da utilizzare per recuperare l'oggetto in cache + * + * @return mixed L'oggetto o NUL se insesistente + */ + protected function getCacheObject(string $key){ + $cached = $this->cache->get($key); + if($cached){ + return $cached; + } + return false; + } + + /** + * + * Controlla se si ha lo scope necessario per poter invocare il metodo, in caso contrario scatena un'eccezione + * + * @param string $url + * + * @return void + */ + private function checkHasScope(string $url, string $type){ + $parsed = parse_url($url); + $permission = $type.":".$parsed['host']; + $path = $parsed['path']; + $path = explode("/", $path); + if(isset($path[1])){ + $permission .= "/".$path[1]; + } + if(!in_array($permission, $this->scopes)){ + throw new \OpenApi\classes\exception\OpenApiConnectionsException("Scope missed: $permission",40004); + } + + } + + /** + * @param string $endpoint Endpoint da richiamare + * @param string $type Tipo di chiamata + * @param array $param Parametri da passare alla chiamata + * @param int $ttr Tempo in cui la chiamata resta in cache (0 = no cache) + * + * @return mixed + */ + protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0){ + $url = $this->basePath; + $url = str_replace("https://","https://".$this->prefix,$url); + $url = str_replace("http://","http://".$this->prefix,$url); + $url .= "/".$endpoint; + $this->checkHasScope($url, $type); + if($type == "GET" && $ttr > 0 && $ret = $this->getCacheObject($url)) { + return $ret; + } + $ch = curl_init(); + if($type == "POST" || $type == "PUT") { + curl_setopt($ch, CURLOPT_POST, TRUE); + } + if($param != array()) { + if($type == "GET") { + $param = http_build_query($param); + $url .= "?".$param; + + }else{ + if($type == "PUT") { + $param = json_encode($param); + }else{ + $param = json_encode($param); + } + curl_setopt($ch, CURLOPT_POSTFIELDS, $param); + } + } + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type); + curl_setopt($ch,CURLOPT_HTTPHEADER,array("Authorization: Bearer ".$this->token)); + curl_setopt($ch, CURLOPT_HEADER, 1); + $response = curl_exec($ch); + $this->rawResponse = $response; + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $this->header = substr($response, 0, $header_size); + $return = substr($response, $header_size); + $httpCode = curl_getinfo ( $ch, CURLINFO_RESPONSE_CODE );; + curl_close($ch); + $data = json_decode($return); + if($data == NULL){ + throw new \OpenApi\classes\exception\OpenApiConnectionsException("Connection to $url: Connection Error",40001); + } + // var_dump($data);exit; + if($data->success == false){ + $message = "Connection to $url: unknow error"; + if(isset($data->message)) { + if(is_string(($data->message))){ + if($dataMessage = json_decode($data->message)){ + $data = $dataMessage; + } + $message = "Connection to $url: $data->message"; + }else{ + $message = "Connection to $url error"; + } + + + } + //var_dump($this->rawResponse); + $except = new \OpenApi\classes\exception\OpenApiConnectionsException($message,40002); + $except->setServerResponse($data, $this->header, $this->rawResponse, $httpCode); + + throw $except; + } + if($type == "GET" && $ttr > 0) { + $this->setCacheObject($url, $data, $ttr); + } + return $data; + } + } \ No newline at end of file diff --git a/classes/UfficioPostale.php b/classes/UfficioPostale.php index 352ef5f..42471ff 100644 --- a/classes/UfficioPostale.php +++ b/classes/UfficioPostale.php @@ -2,9 +2,29 @@ namespace OpenApi\classes; class UfficioPostale extends OpenApiBase { - function getCitiesByCap($cap){ - echo "QUI"; - var_dump($cap); + /** + * @param string $token Il token da utilizzare per il collegamento + * @param array $scopes Array con la lista degli scope per cui il token è abilitato + * @param object $cache Classe che gestisce la cahce, deve essere una classe che estende {@see OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) + */ + function __construct(string $token, array $scopes, object $cache, string $prefix){ + parent::__construct($token, $scopes, $cache, $prefix); + $this->basePath = "https://ws.ufficiopostale.com"; + } + + + /** + * + * A partire dal CAP restistuisce un'array di oggietti di tipo comune + * + * @param string $cap Il cap da ricercare + * @param int $ttl Il tempo di chache degli oggetti ritornati, 0 per no chche + * + * @return array + */ + function getCitiesByCap(string $cap, $ttl = 86400){ + $data = $this->connect("comuni/$cap", "GET", [], $ttl); + return $data->data; } } \ No newline at end of file diff --git a/classes/VisEngine.php b/classes/VisEngine.php new file mode 100644 index 0000000..76c015d --- /dev/null +++ b/classes/VisEngine.php @@ -0,0 +1,110 @@ +hash = NULL; + parent::__construct($token, $scopes, $cache, $prefix); + $this->basePath = "https://visengine2.altravia.com"; + } + + /** + * Imposta l'hash della Visura da utilizzare per tutti i dati + * @param string $hash + * + */ + function setHash(string $hash){ + $this->hash = $hash; + } + + function getFormTool(){ + if($this->hash == NULL){ + throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); + } + $url = $this->basePath; + $url = str_replace("https://","https://".$this->prefix,$url); + $url = str_replace("http://","http://".$this->prefix,$url); + $url .= "/visura/formTool/{$this->hash}.hs"; + return $url; + } + + + /** + * + * Prepara un nuovo oggetto di tipo VisRequest da utilizzare per inviare una nuova richiesta e lo restituisce + * @param int $ttr Time to Release sulla richiesta dei dati della visura + * + * @return object + */ + function createRequest($ttr = 500){ + if($this->hash == NULL){ + throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); + } + $this->visura = $this->connect("visure/$this->hash", "GET", [], $ttr); + defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); + return new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); + } + + + /** + * Invia una request, in base al contenuto della stessa distingue automaticamente se fare la chiamata in POST o PUT + * Restituisce la richiesa comprensiva di risposta del server + * @param \OpenApi\classes\utility\VisEngine\VisRequest $request + * + * @return object + */ + function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { + $params = new \stdClass(); + $params->state = $req->getState(); + $params->test = $req->getTest(); + $params->hash_visura = $this->hash; + if($req->getJson() != NULL){ + $params->json_visura = $req->getJson(); + } + if($req->getCallbackData() != NULL){ + $params->callback_data = $req->getCallbackData(); + } + if($req->getTargetEmail() != NULL){ + $params->email_target = $req->getTargetEmail(); + } + if($req->getNew()){ + $data = $this->connect("richiesta", "POST", $params); + $req->setNew(FALSE); + $req->setId($data->data->_id); + $req->setStatoRichiesta($data->data->stato_richiesta); + if(isset($data->data->ricerche)){ + $req->setRicerche($data->data->ricerche); + } + return $req; + } + + + } + + function getRequestByIdVisura($id_visura){ + $visura = $this->connect("richiesta/$id_visura", "GET"); + return $this->getRequetByData($visura); + } + + function getRequetByData($visura){ + $this->visura = $this->connect("visure/{$visura->data->hash_visura}", "GET", [], 0); + $this->hash = $visura->data->hash_visura; + defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); + $request = new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); + $request->setNew(FALSE); + $request->setId($visura->data->_id); + $request->setStatoRichiesta($visura->data->stato_richiesta); + if(isset($visura->data->ricerche)){ + $request->setRicerche($visura->data->ricerche); + } + return $request; + } + +} + + diff --git a/classes/exception/OpenApiConnectionsException.php b/classes/exception/OpenApiConnectionsException.php new file mode 100644 index 0000000..b8ef39f --- /dev/null +++ b/classes/exception/OpenApiConnectionsException.php @@ -0,0 +1,17 @@ +serverData = NULL; $this->serverHeader = NULL; $this->serverRawResponse = NULL; + $this->httpCode = NULL; } public function __toString() { return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; @@ -23,10 +24,11 @@ public function __toString() { * * @return [type] */ - function setServerResponse(object $serverData, string $serverHeader, string $serverRawResponse){ + function setServerResponse(object $serverData, string $serverHeader, string $serverRawResponse, $httpCode = NULL){ $this->serverData = $serverData; $this->serverHeader = $serverHeader; $this->serverRawResponse = $serverRawResponse; + $this->httpCode = $httpCode; } /** @@ -57,4 +59,8 @@ function getServerHeaderResponse(){ function getServerRawResponse(){ return $this->serverRawResponse; } + + function getHttpCode(){ + return $this->httpCode; + } } \ No newline at end of file diff --git a/classes/exception/OpenApiVisEngineException.php b/classes/exception/OpenApiVisEngineException.php new file mode 100644 index 0000000..0273ebc --- /dev/null +++ b/classes/exception/OpenApiVisEngineException.php @@ -0,0 +1,16 @@ + visengin",40008); + } + $this->visura = $visura; + $this->variables = []; + $this->new = TRUE; + $this->json = NULL; + $this->jsonValido = FALSE; + $this->state = 0; + $this->test = false; + $this->callback = NULL; + $this->email_target = NULL; + $this->id = NULL; + $this->statoRichiesta = NULL; + $this->ricerche = []; + foreach($visura->data->json_struttura->campi as $k => $v){ + $this->variables[$k] = FALSE; + } + } + + function setNew(bool $new){ + return $this->new = $new; + } + + function getNew(){ + return $this->new; + } + /** + * + * Imposta il JSON per inviare una nuova visura + * + * @param array $data IL JSON della visura da inviare + * + * @return boolean Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono stati compilati (attenzione, viene effettuata la sola validazione sui required, per la validazione del formato occcorre inviare la visura) + */ + function setJson(object $data){ + foreach($data as $k => $v){ + if(!isset($this->variables[$k])){ + throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); + } + $this->variables[$k] = TRUE; + } + $this->json = $data; + + $this->validaJSON(); + return $this->jsonValido; + } + + + + /** + * + * Restituisce il JSON della visura + * + * @return object + */ + function getJson(){ + return $this->json; + } + + /** + * Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON + * @return boolean + */ + function isValidJson(){ + return $this->jsonValido; + } + + /** + * + * Imposta i dati della callback + * + * @param string $url La url da richiamare per la callback + * @param object $data Oggetto data che verrà ripassato + * @param string $method='JSON' Metodo da usare JSON/POST + * @param string $field="visengineData" Nome del campo dove verranno passati i dati della visura + * + * @return void + */ + function setCallbackData(string $url, object $data, $method = "JSON", $field="visengineData"){ + $this->callback = (object)[ + "url" => $url, + "data" => $data, + "method" => $method, + "field" => $field + ]; + } + + + /** + * Restituisce i dati della callback + * + * @return object + */ + function getCallbackData(){ + return $this->callback; + } + + /** + * Impowsta il parametro state della visura + * @param int $stato + * + * @return void + */ + function setState($stato = 0){ + if($stato != 0 && !$this->jsonValido ){ + throw new \OpenApi\classes\exception\OpenApiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); + } + $this->state = $stato == 0 ? $stato : 1; + } + + /** + * Ritorna il parametro state + * @return int + */ + function getState(){ + return $this->state; + } + + /** + * Imposta il parametro email_target + * + * @param string $email_target + * + * @return void + */ + function setTargetEmail(string $email_target){ + $this->email_target = $email_target; + } + + /** + * Ritorna il parametro email_target + * @return string + */ + function getTargetEmail(){ + return $this->email_target; + } + + + /** + * + * Imposta il parametro test + * + * @param bool $test + * + * @return void + */ + function setTest(bool $test){ + $this->test = $test; + } + + + /** + * Restituisce il parametro test + * @return bool + */ + function getTest(){ + return $this->test; + } + + + /** + * Controlla il JSON e ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON + * @return boolean + */ + private function validaJSON(){ + $re = '/\$(\d)+/m'; + $validazione = $this->visura->data->json_struttura->validazione; + $subst = '$this->variables[\'$0\']'; + + $validazione = '$this->jsonValido = ' .preg_replace($re, $subst, $validazione).";"; + eval($validazione); + } + + function getId() { + return $this->id; + } + + function setId($id) { + $this->id = $id; + } + + function getStatoRichiesta() { + return $this->statoRichiesta; + } + + function setStatoRichiesta($statoRichiesta) { + $this->statoRichiesta = $statoRichiesta; + } + + function getRicerche() { + return $this->ricerche; + } + + function setRicerche($ricerche) { + $this->ricerche = $ricerche; + } + + function getStatoRicerca(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return $this->ricerche[count($this->ricerche) - 1]->stato_ricerca; + } +} \ No newline at end of file diff --git a/classes/utility/ci4SessionStoreToken.php b/classes/utility/ci4SessionStoreToken.php new file mode 100644 index 0000000..c01d873 --- /dev/null +++ b/classes/utility/ci4SessionStoreToken.php @@ -0,0 +1,18 @@ +set("openapi",$data); + } + + function clear(){ + session()->remove("openapi"); + } + + function isset(){ + return session()->has("openapi"); + } +} \ No newline at end of file diff --git a/classes/utility/sessionStoreToken.php b/classes/utility/sessionStoreToken.php new file mode 100644 index 0000000..066bbb9 --- /dev/null +++ b/classes/utility/sessionStoreToken.php @@ -0,0 +1,19 @@ +openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); - ``` - Dove ```$scopes``` è un array di stringhe o di oggetti in uno dei seguenti formati: - - ```php - $scopes=[ - "GET:ws.ufficiopostale.com/comuni", - ["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] - ]; - ``` - - A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: - ```php - $this->openapi->ufficioposale - $this->openapi->imprese - ``` - che possono essere usati al seguente modo: - ```php - $this->openapi->ufficioposale->getCitiesByCap('00132';) - ``` \ No newline at end of file +``` + +Dove ```$scopes``` è un array di stringhe o di oggetti in uno dei seguenti formati: + +```php +$scopes=[ +"GET:ws.ufficiopostale.com/comuni", +["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] +]; +``` + +A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: + +```php +$this->openapi->ufficiopostale +$this->openapi->imprese +... +``` + +che possono essere usati al seguente modo: + +```php +$this->openapi->ufficioposale->getCitiesByCap('00132'); +``` + +# Modulo ufficio postale + +# Modulo visure + +# Modulo imprese + +## `getByPartitaIva` + +### Introduction + +La funzione consente di recuperare i dati aziendali a partire dalla partita IVA + +### Description + +`function getByPartitaIva(string $partitaIva, $ttl = 86400):object` + +* $partitaIva: La partita IVA da cvercare +* $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta From f28c23d46c684eb2c77827f93d64823d5a36f09e Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Tue, 29 Sep 2020 11:47:40 +0200 Subject: [PATCH 04/85] Aggiunte le seguenti api: Comuni Geocoding Marche Temporali --- OpenApi.php | 6 + classes/Comuni.php | 103 ++++++ classes/Geocoding.php | 21 ++ classes/Imprese.php | 53 ++- classes/MarcheTemporali.php | 51 +++ classes/OpenApiBase.php | 14 +- classes/UfficioPostale.php | 14 +- classes/VisEngine.php | 64 +++- .../OpenApiMarcheTemporaliException.php | 13 + classes/utility/Plugins/FiscalCode.php | 317 ++++++++++++++++++ classes/utility/Plugins/Validations.php | 122 +++++++ classes/utility/VisEngine/VisRequest.php | 215 +++++++++++- composer.json | 18 + 13 files changed, 980 insertions(+), 31 deletions(-) create mode 100644 classes/Comuni.php create mode 100644 classes/Geocoding.php create mode 100644 classes/MarcheTemporali.php create mode 100644 classes/exception/OpenApiMarcheTemporaliException.php create mode 100644 classes/utility/Plugins/FiscalCode.php create mode 100644 classes/utility/Plugins/Validations.php create mode 100644 composer.json diff --git a/OpenApi.php b/OpenApi.php index 303edc7..bc87789 100644 --- a/OpenApi.php +++ b/OpenApi.php @@ -59,6 +59,8 @@ function __construct(array $scopes, string $username, string $apikey, $environme $this->clients[] = $nome; } } + + $this->validations = new \OpenApi\classes\utility\Plugins\Validations(); } /** @@ -77,6 +79,10 @@ private function getListaModuli(){ $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; $nomi['visengine2.altravia.com'] = "visengine"; + + + $moduli['comuni.openapi.it'] = "\\OpenApi\\classes\\Comuni"; + $nomi['comuni.openapi.it'] = "comuni"; return array($moduli,$nomi); } diff --git a/classes/Comuni.php b/classes/Comuni.php new file mode 100644 index 0000000..b7da833 --- /dev/null +++ b/classes/Comuni.php @@ -0,0 +1,103 @@ +basePath = "https://comuni.openapi.it"; + } + + + /** + * + * A partire dal CAP restistuisce un'array di oggietti di tipo comune + * + * @param string $cap Il cap da ricercare + * @param int $ttl Il tempo di chache degli oggetti ritornati, 0 per no chche + * + * @return array + */ + function getCitiesByCap(string $cap, $ttl = 86400){ + $data = $this->connect("cap/$cap", "GET", [], $ttl); + return $data->data; + } + + /** + * Restituisce la lista delle regioni italiani + * + * @return array + */ + function getRegioni($ttl = 86400){ + $data = $this->connect("regioni", "GET", [], $ttl); + $regioni = $data->data; + sort($regioni); + return $regioni; + } + + /** + * Restituisce la lsita delle province italiane (a partire dalla regione) + * @param string $regione La regione per la quale recuperare le regioni + * + * @return array + */ + function getProvince($regione = NULL, $ttl = 86400){ + if($regione == NULL){ + $data = $this->connect("province", "GET", [], $ttl); + $province = $data->data; + + $_province = []; + foreach($province as $key => $p){ + $provincia = new \stdClass(); + $provincia->nome_provincia = $p; + $provincia->sigla_provincia = $key; + $_province[] = $provincia; + } + + usort($_province,[$this, 'sortProcince']); + return $_province; + } + $regione = explode("/",$regione)[0]; + $regione = trim(\strtolower($regione)); + $regione = urlencode($regione); + + $data = $this->connect("regioni/$regione", "GET", [], $ttl); + + + $province = $data->data; + usort($province,[$this, 'sortProcince']); + return $province; + } + + function getComuni($provincia, $ttl = 86400){ + + $provincia = trim(\strtolower($provincia)); + $data = $this->connect("province/$provincia", "GET", [], $ttl); + + + $comuni = $data->data; + //sort($comuni->comuni); + //usort($comuni->dettaglio_comuni,[$this, 'sortComune']); + return $comuni; + + } + + private function sortComune($a, $b){ + if($a->nome == $b->nome){ + return 0; + } + return $a->nome < $b->nome ? -1 : 1; + } + + private function sortProcince($a, $b){ + if($a->nome_provincia == $b->nome_provincia){ + return 0; + } + return $a->nome_provincia < $b->nome_provincia ? -1 : 1; + } + +} \ No newline at end of file diff --git a/classes/Geocoding.php b/classes/Geocoding.php new file mode 100644 index 0000000..ca81382 --- /dev/null +++ b/classes/Geocoding.php @@ -0,0 +1,21 @@ +basePath = "https://geocoding.realgest.it"; + } + + function geocode(string $address, $ttl = 86400){ + $data = $this->connect("geocode", "POST", ["address" => $address], $ttl, TRUE); + + return $data; + } + +} \ No newline at end of file diff --git a/classes/Imprese.php b/classes/Imprese.php index 23b58e6..22255ab 100644 --- a/classes/Imprese.php +++ b/classes/Imprese.php @@ -38,6 +38,57 @@ function getByPartitaIva(string $partitaIva, $ttr = 86400){ } + function getClosed(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + function getVatGroup(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + function getPec(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + /** * * Cerca un'azienda o più utilizzando vari parametri @@ -53,7 +104,7 @@ function getByPartitaIva(string $partitaIva, $ttr = 86400){ function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ $params=[]; if($denominazione != NULL){ - $params['denominazione'] = $denominazione; + $params['denominazione'] = trim($denominazione); } if($provincia != NULL){ $params['provincia'] = $provincia; diff --git a/classes/MarcheTemporali.php b/classes/MarcheTemporali.php new file mode 100644 index 0000000..f7466ea --- /dev/null +++ b/classes/MarcheTemporali.php @@ -0,0 +1,51 @@ +basePath = "https://ws.marchetemporali.com"; + } + + function availability(string $type, int $qty){ + $data = $this->connect("availability/$type/$qty", "GET", []); + return $data->data; + } + + function checkLotto($username, $password){ + + if(substr($username,0,4) == "FAKE" && substr($password,0,4) == "FAKE"){ + $ret = new \stdClass(); + $ret->data = new \stdClass(); + $ret->data->available = 10; + $ret->data->used = 90; + $ret->message = "DESCR= Marche per $username; disponibili 10 consumate 0"; + $ret->success = TRUE; + $ret->error = NULL; + return $ret->data; + } + $data = $this->connect("check_lotto", "POST", ["username"=>$username, "password"=> $password]); + + return $data->data; + } + + function purcahse(string $type, int $qty){ + $data = $this->availability($type, $qty); + //var_dump($data);exit; + if($data->availability == 0){ + throw new \OpenApi\classes\exception\OpenApiMarcheTemporaliException("$qty $type time stamps is not availabile for purchase",40009); + } + //echo "marche/$type/$qty";exit; + $data = $this->connect("marche/$type/$qty", "GET", []); + //var_dump($data);exit; + return $data->data; + } + + + +} \ No newline at end of file diff --git a/classes/OpenApiBase.php b/classes/OpenApiBase.php index a88dedb..6b75432 100644 --- a/classes/OpenApiBase.php +++ b/classes/OpenApiBase.php @@ -89,12 +89,15 @@ private function checkHasScope(string $url, string $type){ * * @return mixed */ - protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0){ + protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false){ $url = $this->basePath; $url = str_replace("https://","https://".$this->prefix,$url); $url = str_replace("http://","http://".$this->prefix,$url); $url .= "/".$endpoint; - $this->checkHasScope($url, $type); + if(!$force){ + $this->checkHasScope($url, $type); + } + if($type == "GET" && $ttr > 0 && $ret = $this->getCacheObject($url)) { return $ret; } @@ -108,11 +111,7 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = $url .= "?".$param; }else{ - if($type == "PUT") { - $param = json_encode($param); - }else{ - $param = json_encode($param); - } + $param = json_encode($param); curl_setopt($ch, CURLOPT_POSTFIELDS, $param); } } @@ -122,6 +121,7 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = curl_setopt($ch,CURLOPT_HTTPHEADER,array("Authorization: Bearer ".$this->token)); curl_setopt($ch, CURLOPT_HEADER, 1); $response = curl_exec($ch); + //var_dump($response);exit; $this->rawResponse = $response; $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $this->header = substr($response, 0, $header_size); diff --git a/classes/UfficioPostale.php b/classes/UfficioPostale.php index 42471ff..ac83477 100644 --- a/classes/UfficioPostale.php +++ b/classes/UfficioPostale.php @@ -13,18 +13,6 @@ function __construct(string $token, array $scopes, object $cache, string $prefi } - /** - * - * A partire dal CAP restistuisce un'array di oggietti di tipo comune - * - * @param string $cap Il cap da ricercare - * @param int $ttl Il tempo di chache degli oggetti ritornati, 0 per no chche - * - * @return array - */ - function getCitiesByCap(string $cap, $ttl = 86400){ - $data = $this->connect("comuni/$cap", "GET", [], $ttl); - return $data->data; - } + } \ No newline at end of file diff --git a/classes/VisEngine.php b/classes/VisEngine.php index 76c015d..0080d58 100644 --- a/classes/VisEngine.php +++ b/classes/VisEngine.php @@ -29,7 +29,7 @@ function getFormTool(){ $url = $this->basePath; $url = str_replace("https://","https://".$this->prefix,$url); $url = str_replace("http://","http://".$this->prefix,$url); - $url .= "/visura/formTool/{$this->hash}.hs"; + $url .= "/visura/formTool/{$this->hash}.js"; return $url; } @@ -59,7 +59,11 @@ function createRequest($ttr = 500){ * @return object */ function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { - $params = new \stdClass(); + + + + if($req->getNew()){ + $params = new \stdClass(); $params->state = $req->getState(); $params->test = $req->getTest(); $params->hash_visura = $this->hash; @@ -72,8 +76,8 @@ function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { if($req->getTargetEmail() != NULL){ $params->email_target = $req->getTargetEmail(); } - if($req->getNew()){ $data = $this->connect("richiesta", "POST", $params); + $req->setNew(FALSE); $req->setId($data->data->_id); $req->setStatoRichiesta($data->data->stato_richiesta); @@ -81,17 +85,39 @@ function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { $req->setRicerche($data->data->ricerche); } return $req; - } + }else{ + $params = new \stdClass(); + $params->state = $req->getState(); + // $params->test = $req->getTest(); + + if($req->getJson() != NULL){ + $params->json_visura = $req->getJson(); + } + $id_visura = $req->getId(); + //echo json_encode($params);exit; + //var_dump($params);exit; + $data = $this->connect("richiesta/$id_visura", "PUT", $params); + + + $req->setNew(FALSE); + $req->setId($data->data->_id); + $req->setStatoRichiesta($data->data->stato_richiesta); + if(isset($data->data->ricerche)){ + $req->setRicerche($data->data->ricerche); + } + return $req; + } } function getRequestByIdVisura($id_visura){ $visura = $this->connect("richiesta/$id_visura", "GET"); - return $this->getRequetByData($visura); + return $this->getRequestByData($visura); } - function getRequetByData($visura){ + function getRequestByData($visura){ + $this->visura = $this->connect("visure/{$visura->data->hash_visura}", "GET", [], 0); $this->hash = $visura->data->hash_visura; defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); @@ -99,12 +125,38 @@ function getRequetByData($visura){ $request->setNew(FALSE); $request->setId($visura->data->_id); $request->setStatoRichiesta($visura->data->stato_richiesta); + if(isset($visura->data->ricerche)){ $request->setRicerche($visura->data->ricerche); + }else{ + $request->setRicerche([]); + } + return $request; + } + + function getDocument($id_visura){ + $request = $this->getRequestByIdVisura($id_visura); + $documento = $this->connect("documento/{$id_visura}", "GET", [], 0); + if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ + + $request->setDocument($documento->data); } return $request; } + function setRicerca($id_visura, $id_ricerca, $index){ + $index = str_replace("indice_","",$index); + $request = $this->getRequestByIdVisura($id_visura); + $hash_visura = $request->visura->data->hash_visura; + $param = ["id_ricerca"=>$id_ricerca, "indice"=> $index]; + + $visura = $this->connect("richiesta/{$id_visura}/ricerche", "PUT", $param, 0); + + $request->setStatoRichiesta($visura->data->stato_richiesta); + return $request; + + } + } diff --git a/classes/exception/OpenApiMarcheTemporaliException.php b/classes/exception/OpenApiMarcheTemporaliException.php new file mode 100644 index 0000000..072c875 --- /dev/null +++ b/classes/exception/OpenApiMarcheTemporaliException.php @@ -0,0 +1,13 @@ + 'A', 2 => 'B', 3 => 'C', 4 => 'D', 5 => 'E', + 6 => 'H', 7 => 'L', 8 => 'M', 9 => 'P', 10 => 'R', + 11 => 'S', 12 => 'T' + ); + + + protected $_pari = array( + '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, + '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, + 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, + 'F' => 5, 'G' => 6, 'H' => 7, 'I' => 8, 'J' => 9, + 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, + 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, + 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, + 'Z' => 25 + ); + + protected $_dispari = array( + '0' => 1, '1' => 0, '2' => 5, '3' => 7, '4' => 9, + '5' => 13, '6' => 15, '7' => 17, '8' => 19, '9' => 21, + 'A' => 1, 'B' => 0, 'C' => 5, 'D' => 7, 'E' => 9, + 'F' => 13, 'G' => 15, 'H' => 17, 'I' => 19, 'J' => 21, + 'K' => 2, 'L' => 4, 'M' => 18, 'N' => 20, 'O' => 11, + 'P' => 3, 'Q' => 6, 'R' => 8, 'S' => 12, 'T' => 14, + 'U' => 16, 'V' => 10, 'W' => 22, 'X' => 25, 'Y' => 24, + 'Z' => 23 + ); + + protected $_controllo = array( + '0' => 'A', '1' => 'B', '2' => 'C', '3' => 'D', + '4' => 'E', '5' => 'F', '6' => 'G', '7' => 'H', + '8' => 'I', '9' => 'J', '10' => 'K', '11' => 'L', + '12' => 'M', '13' => 'N', '14' => 'O', '15' => 'P', + '16' => 'Q', '17' => 'R', '18' => 'S', '19' => 'T', + '20' => 'U', '21' => 'V', '22' => 'W', '23' => 'X', + '24' => 'Y', '25' => 'Z' + ); + + /** + * Stringa di errore + */ + protected $_error = null; + + /** + * Separatore per la data di nascita + */ + protected $_dateSeparator = '-'; + + + /** + * Percorso del file del database SQLite + * dei codici catastali + */ + protected $_dbCatastali = null; + + + /** + * Trasforma la stringa passata in un array di lettere + * e lo incrocia con un ulteriore array + */ + protected function _getLettere($string, array $haystack) { + $letters = array(); + foreach(str_split($string) as $needle) { + if (in_array($needle, $haystack)) { + $letters[] = $needle; + } + } + return $letters; + } + + /** + * Ritorna un array con le vocali di una data stringa + */ + protected function _getVocali($string) { + return $this->_getLettere($string, $this->_vocali); + } + + /** + * Ritorna un array con le consonanti di una data stringa + */ + protected function _getConsonanti($string) { + return $this->_getLettere($string, $this->_consonanti); + } + + /** + * Pulisce la stringa filtrando tutti i caratteri che + * non sono lettere. Lo switch $toupper se impostato a TRUE + * converte la stringa risultante in MAIUSCOLO. + */ + protected function _sanitize($string, $toupper = true) { + $result = preg_replace('/[^A-Za-z]*/', '', $string); + return ($toupper) ? strtoupper($result) : $result; + } + + /** + * Se la stringa passata a funzione e' costituita + * da meno di 3 caratteri, rimpiazza le lettere + * mancanti con la lettera X. + */ + protected function _addMissingX($string) { + $code = $string; + while(strlen($code) < 3) { + $code .= 'X'; + } + return $code; + } + + /** + * Ottiene il codice identificativo del nome + */ + protected function _calcolaNome($string) { + $nome = $this->_sanitize($string); + + // Se il nome inserito e' piu' corto di 3 lettere + // si aggiungono tante X quanti sono i caratteri + // mancanti. + if (strlen($nome) < 3) { + return $this->_addMissingX($nome); + } + + $nome_cons = $this->_getConsonanti($nome); + $code = ""; + // Se le consonanti contenute nel nome sono minori + // o uguali a 3 vengono considerate nell'ordine in cui + // compaiono. + if (count($nome_cons) <= 3) { + $code = implode('', $nome_cons); + } else { + // Se invece abbiamo almeno 4 consonanti, prendiamo + // la prima, la terza e la quarta. + for($i=0; $i<4; $i++) { + if ($i == 1) continue; + if (!empty($nome_cons[$i])) { + $code .= $nome_cons[$i]; + } + } + } + + // Se compaiono meno di 3 consonanti nel nome, si + // utilizzano le vocali, nell'ordine in cui compaiono + // nel nome. + if (strlen($code) < 3) { + $nome_voc = $this->_getVocali($nome); + while (strlen($code) < 3) { + $code .= array_shift($nome_voc); + } + } + + return $code; + } + + protected function _calcolaCognome($string) { + $cognome = $this->_sanitize($string); + $code = ""; + + // Se il cognome inserito e' piu' corto di 3 lettere + // si aggiungono tante X quanti sono i caratteri + // mancanti. + if (strlen($cognome) < 3) { + return $this->_addMissingX($cognome); + } + + $cognome_cons = $this->_getConsonanti($cognome); + + // Per il calcolo del cognome si prendono le prime + // 3 consonanti. + for ($i=0; $i<3; $i++) { + if (array_key_exists($i, $cognome_cons)) { + $code .= $cognome_cons[$i]; + } + } + + // Se le consonanti non bastano, vengono prese + // le vocali nell'ordine in cui compaiono. + if (strlen($code) < 3) { + $cognome_voc = $this->_getVocali($cognome); + while (strlen($code) < 3) { + $code .= array_shift($cognome_voc); + } + } + + return $code; + } + + /** + * Imposta il separatore di data ( default: / ) + */ + public function setDateSeparator($char) { + $this->_dateSeparator = $char; + return $this; + } + + /** + * Ritorna la parte di codice fiscale corrispondente + * alla data di nascita del soggetto (Forma: AAMGG) + */ + protected function _calcolaDataNascita($data, $sesso) { + $dn = explode($this->_dateSeparator, $data); + + $giorno = (int) @$dn[2]; + $mese = (int) @$dn[1]; + $anno = (int) @$dn[0]; + + // Le ultime due cifre dell'anno di nascita + $aa = substr($anno, -2); + + // La lettera corrispondente al mese di nascita + $mm = $this->_mesi[$mese]; + + // Il giorno viene calcolato a seconda del sesso + // del soggetto di cui si calcola il codice: + // se e' Maschio si mette il giorno reale, se e' + // Femmina viene aggiungo 40 a questo numero. + $gg = (strtoupper($sesso) == 'M') ? $giorno : ($giorno + 40); + + // Bug #1: Thanks to Luca + if (strlen($gg) < 2) $gg = '0' . $gg; + + + return $aa . $mm . $gg; + } + + + + /** + * Ritorna la cifra di controllo sulla base dei + * 15 caratteri del codice fiscale calcolati. + */ + protected function _calcolaCifraControllo($codice) { + $code = str_split($codice); + $sum = 0; + + for($i=1; $i <= count($code); $i++) { + $cifra = $code[$i-1]; + $sum += ($i % 2) ? $this->_dispari[$cifra] : $this->_pari[$cifra]; + } + + $sum %= 26; + + return $this->_controllo[$sum]; + } + + + /** + * Imposta il messaggio di errore + */ + protected function _setError($string) { + $this->_error = $string; + } + + /** + * Verifica la presenza di un errore. + * Ritorna TRUE se presente, FALSE altrimenti. + */ + public function hasError() { + return !is_null($this->_error); + } + + /** + * Ritorna la stringa di errore + */ + public function getError() { + return $this->_error; + } + + /** + * Ritorna il codice fiscale utilizzando i parametri + * passati a funzione. Se si verifica + */ + public function calculate($nome, $cognome, $data, $sesso, $codice_catastale_comune) { + $codice = $this->_calcolaCognome($cognome) . + $this->_calcolaNome($nome) . + $this->_calcolaDataNascita($data, $sesso) . + $codice_catastale_comune; + + if ($this->hasError()) { + return false; + } + + $codice .= $this->_calcolaCifraControllo($codice); + + if (strlen($codice) != 16) { + $this->_setError(self::ERR_GENERIC); + return false; + } + + return $codice; + } +} \ No newline at end of file diff --git a/classes/utility/Plugins/Validations.php b/classes/utility/Plugins/Validations.php new file mode 100644 index 0000000..503f87d --- /dev/null +++ b/classes/utility/Plugins/Validations.php @@ -0,0 +1,122 @@ +9){ + $secondo=$secondo-9; + } + + $primo+=$secondo; + + } + if( (10-$primo%10)%10 != ord($variabile[10])-ord('0') ){ + return false; + } + + + return true; + + } +} \ No newline at end of file diff --git a/classes/utility/VisEngine/VisRequest.php b/classes/utility/VisEngine/VisRequest.php index 8b3597c..8aac5cb 100644 --- a/classes/utility/VisEngine/VisRequest.php +++ b/classes/utility/VisEngine/VisRequest.php @@ -20,6 +20,8 @@ function __construct($visura) $this->id = NULL; $this->statoRichiesta = NULL; $this->ricerche = []; + $this->document = NULL; + $this->format_errror = []; foreach($visura->data->json_struttura->campi as $k => $v){ $this->variables[$k] = FALSE; } @@ -45,13 +47,15 @@ function setJson(object $data){ if(!isset($this->variables[$k])){ throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); } - $this->variables[$k] = TRUE; + $this->variables[$k] = $v!=NULL; } $this->json = $data; $this->validaJSON(); return $this->jsonValido; } + + @@ -143,6 +147,39 @@ function getTargetEmail(){ return $this->email_target; } + function hasSearchResult(){ + return $this->visura->data->ricerca == 1 && $this->getStatoRichiesta() == "In ricerca" && $this->getStatoRicerca() == "Ricerca evasa"; + } + + function getSearchResult(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return json_decode($this->ricerche[count($this->ricerche) - 1]->json_risultato); + } + function getSearchId(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return $this->ricerche[count($this->ricerche) - 1]->id_ricerca; + } + + function getSearchCount(){ + return count($this->ricerche); + } + + function setDocument($document){ + $this->document = $document; + } + + function getDocument(){ + return $this->document; + } + + function getHash(){ + return $this->visura->data->hash_visura; + } + /** * @@ -171,12 +208,178 @@ function getTest(){ * @return boolean */ private function validaJSON(){ + if(!$this->validaPresenzaCampi()){ + $this->format_errror = []; + $this->jsonValido = FALSE; + return; + } + $this->format_errror = []; + if(!$this->validaFormatoCampi()){ + $this->jsonValido = FALSE; + return; + } + $this->jsonValido = TRUE; + + } + + private function validaFormatoCampi(){ + $error = FALSE; +// var_dump($this->visura->data->json_struttura->campi);exit; + + //cod_comune + //cod_provincia + //codice_fiscale_persona_fisica + foreach($this->visura->data->json_struttura->campi as $key => $campo){ + if(!isset($this->json->$key) || $this->json->$key == ""){ + continue; + } + if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale_persona_fisica'){ + $val = new \OpenApi\classes\utility\Plugins\Validations(); + if(!$val->italianFiscalCode($this->json->$key)){ + $this->format_errror[$key] = 'codice_fiscale_persona_fisica'; + $error = TRUE; + } + } + + if(isset($campo->tipo) && $campo->tipo == 'partita_iva'){ + $val = new \OpenApi\classes\utility\Plugins\Validations(); + if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ + $this->format_errror[$key] = 'partita_iva'; + $error = TRUE; + } + } + + if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale'){ + $val = new \OpenApi\classes\utility\Plugins\Validations(); + if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ + $this->format_errror[$key] = 'codice_fiscale'; + $error = TRUE; + } + } + if(isset($campo->tipo) && $campo->tipo == 'cod_comune'){ + $re = '/^[a-zA-Z]{1}[0-9]{3}$/m'; + + preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); + if(count($matches) == 0){ + $this->format_errror[$key] = 'cod_comune'; + $error = TRUE; + } + } + + if(isset($campo->tipo) && $campo->tipo == 'cod_provincia'){ + $re = '/^[a-zA-Z]{2}$/m'; + + preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); + if(count($matches) == 0){ + $this->format_errror[$key] = 'cod_provincia'; + $error = TRUE; + } + } + if(isset($campo->tipo) && $campo->tipo == 'data_iso8601'){ + $d = \DateTime::createFromFormat("d-m-Y", $this->json->$key); + + if(!($d && $d->format('d-m-Y') === $this->json->$key)){ + $this->format_errror[$key] = 'data_iso8601'; + $error = TRUE; + } + } + } + return !$error; + } + + private function validaPresenzaCampi(){ $re = '/\$(\d)+/m'; $validazione = $this->visura->data->json_struttura->validazione; $subst = '$this->variables[\'$0\']'; - - $validazione = '$this->jsonValido = ' .preg_replace($re, $subst, $validazione).";"; + $valida = TRUE; + $validazione = '$valida = ' .preg_replace($re, $subst, $validazione).";"; eval($validazione); + return $valida; + } + + public function getErrors(){ + if(count($this->format_errror) != 0){ + $ret['error_type'] = "format"; + $ret['error'] = $this->format_errror; + return $ret; + } + $this->expr = []; + $validazione = $this->visura->data->json_struttura->validazione; + + list($validazione, $expr) =$this->createExpression($validazione); + + //var_dump($validazione);exit; + $errori = $this->valida($validazione, $expr); + + $ret['error_type'] = "empty_fields"; + $ret['error'] = $errori; + return $ret; + + } + + private function valida($validazione,$expr, $errori = []){ + //var_dump($this->variables); + $errori = ["type"=>"and","list"=>[]]; + $and = explode('&&',$validazione); + foreach($and as $andItem){ + $andItem = trim($andItem); + $or = explode('||',$andItem); + if(count($or) == 1){ + $orItem = $or[0]; + if(substr($orItem,0,1)=='$'){ + if(!$this->variables[$orItem]){ + $errori['list'][] = $orItem; + } + }else{ + $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); + if(count($errors)){ + + $errori['list'] = array_merge($errori['list'], $errors['list']); + + } + } + }else{ + $errore = false; + $item = array(); + $hasError = true; + foreach($or as $orItem){ + $orItem = trim($orItem); + if(substr($orItem,0,1)=='$'){ + $item[] = $orItem; + if($this->variables[$orItem]){ + + $hasError = FALSE; + } + }else{ + $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); + if(count($errors['list'])){ + $item[] = $errors; + }else{ + $hasError = FALSE; + } + } + } + + if($hasError){ + $errori['list'][] = ["type"=>"or","list"=>$item]; + } + } + } + + return $errori; + } + + private function createExpression($validazione, $expr = []){ + $preg = "/\(([$\d&| e]*?)\)/"; + preg_match($preg, $validazione, $matches, PREG_OFFSET_CAPTURE, 0); + if(isset($matches[0]) && isset($matches[1])){ + $expr[] = $matches[1][0]; + $expn = count($expr)-1; + $validazione = str_replace($matches[0],"e{$expn}",$validazione); + return $this->createExpression($validazione, $expr); + } + return array($validazione, $expr); + } function getId() { @@ -197,7 +400,7 @@ function setStatoRichiesta($statoRichiesta) { function getRicerche() { return $this->ricerche; - } + } function setRicerche($ricerche) { $this->ricerche = $ricerche; @@ -209,4 +412,8 @@ function getStatoRicerca(){ } return $this->ricerche[count($this->ricerche) - 1]->stato_ricerca; } + + function getValidation(){ + return $validazione = $this->visura->data->json_struttura->validazione;; + } } \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..f399979 --- /dev/null +++ b/composer.json @@ -0,0 +1,18 @@ +{ + "name": "Altravia/OpenApi", + "description": "My first Composer project", + "authors": [ + { + "name": "Altravia", + "email": "info@altravia.com" + } + ], + "minimum-stability": "production", + "require": { + "php": ">=7.2.0" + }, + "autoload": { + "psr-0": { + "OpenApi": "OpenApi/" + } + } \ No newline at end of file From 8c8e304b0f99a81621029febf8cc2e782eb49a94 Mon Sep 17 00:00:00 2001 From: pberanrdiniAltravia <68341384+pberanrdiniAltravia@users.noreply.github.com> Date: Tue, 29 Sep 2020 11:52:58 +0200 Subject: [PATCH 05/85] modificato package.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index f399979..d2035c9 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "Altravia/OpenApi", - "description": "My first Composer project", + "description": "Librerie OpenApi PHP (https://openapi.it)", "authors": [ { "name": "Altravia", @@ -15,4 +15,4 @@ "psr-0": { "OpenApi": "OpenApi/" } - } \ No newline at end of file + } From ae31a55f149849f338dfd726a6a34034b2540406 Mon Sep 17 00:00:00 2001 From: pberanrdiniAltravia <68341384+pberanrdiniAltravia@users.noreply.github.com> Date: Tue, 29 Sep 2020 12:01:58 +0200 Subject: [PATCH 06/85] errore sul packee.json --- composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/composer.json b/composer.json index d2035c9..3a8c781 100644 --- a/composer.json +++ b/composer.json @@ -16,3 +16,4 @@ "OpenApi": "OpenApi/" } } +} From 571b5f660b17f316817884d9f7140fe0e1874e72 Mon Sep 17 00:00:00 2001 From: pberanrdiniAltravia <68341384+pberanrdiniAltravia@users.noreply.github.com> Date: Tue, 29 Sep 2020 12:05:15 +0200 Subject: [PATCH 07/85] modificato il package --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 3a8c781..aefde13 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "Altravia/OpenApi", + "name": "openapi/openapi", "description": "Librerie OpenApi PHP (https://openapi.it)", "authors": [ { From 9e7ef0b09bcd411646c38a02d568bef42ad444bb Mon Sep 17 00:00:00 2001 From: pberanrdiniAltravia <68341384+pberanrdiniAltravia@users.noreply.github.com> Date: Tue, 29 Sep 2020 12:06:31 +0200 Subject: [PATCH 08/85] modificato vendor name --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index aefde13..3618995 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "openapi/openapi", - "description": "Librerie OpenApi PHP (https://openapi.it)", + "name": "altravia/openapi", + "description": "OpenApi PHP Libraries (https://openapi.it)", "authors": [ { "name": "Altravia", From 75f9160b66d096090cf0ed8675688ee6f2117865 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Tue, 29 Sep 2020 12:10:33 +0200 Subject: [PATCH 09/85] spostato il sorgente dentro src --- _config.yml | 1 - OpenApi.php => src/OpenApi.php | 0 {classes => src/classes}/Comuni.php | 0 {classes => src/classes}/Geocoding.php | 0 {classes => src/classes}/Imprese.php | 0 {classes => src/classes}/MarcheTemporali.php | 0 {classes => src/classes}/OpenApiBase.php | 0 {classes => src/classes}/UfficioPostale.php | 0 {classes => src/classes}/VisEngine.php | 0 .../classes}/exception/OpenApiConnectionsException.php | 0 {classes => src/classes}/exception/OpenApiExceptionBase.php | 0 .../classes}/exception/OpenApiMarcheTemporaliException.php | 0 {classes => src/classes}/exception/OpenApiTokenException.php | 0 {classes => src/classes}/exception/OpenApiVisEngineException.php | 0 {classes => src/classes}/utility/CacheSystemInterface.php | 0 {classes => src/classes}/utility/DummyCache.php | 0 {classes => src/classes}/utility/Plugins/FiscalCode.php | 0 {classes => src/classes}/utility/Plugins/Validations.php | 0 {classes => src/classes}/utility/VisEngine/VisRequest.php | 0 {classes => src/classes}/utility/ci4SessionStoreToken.php | 0 {classes => src/classes}/utility/sessionStoreToken.php | 0 {classes => src/classes}/utility/storeTokenInterface.php | 0 22 files changed, 1 deletion(-) delete mode 100644 _config.yml rename OpenApi.php => src/OpenApi.php (100%) rename {classes => src/classes}/Comuni.php (100%) rename {classes => src/classes}/Geocoding.php (100%) rename {classes => src/classes}/Imprese.php (100%) rename {classes => src/classes}/MarcheTemporali.php (100%) rename {classes => src/classes}/OpenApiBase.php (100%) rename {classes => src/classes}/UfficioPostale.php (100%) rename {classes => src/classes}/VisEngine.php (100%) rename {classes => src/classes}/exception/OpenApiConnectionsException.php (100%) rename {classes => src/classes}/exception/OpenApiExceptionBase.php (100%) rename {classes => src/classes}/exception/OpenApiMarcheTemporaliException.php (100%) rename {classes => src/classes}/exception/OpenApiTokenException.php (100%) rename {classes => src/classes}/exception/OpenApiVisEngineException.php (100%) rename {classes => src/classes}/utility/CacheSystemInterface.php (100%) rename {classes => src/classes}/utility/DummyCache.php (100%) rename {classes => src/classes}/utility/Plugins/FiscalCode.php (100%) rename {classes => src/classes}/utility/Plugins/Validations.php (100%) rename {classes => src/classes}/utility/VisEngine/VisRequest.php (100%) rename {classes => src/classes}/utility/ci4SessionStoreToken.php (100%) rename {classes => src/classes}/utility/sessionStoreToken.php (100%) rename {classes => src/classes}/utility/storeTokenInterface.php (100%) diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c741881..0000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-slate \ No newline at end of file diff --git a/OpenApi.php b/src/OpenApi.php similarity index 100% rename from OpenApi.php rename to src/OpenApi.php diff --git a/classes/Comuni.php b/src/classes/Comuni.php similarity index 100% rename from classes/Comuni.php rename to src/classes/Comuni.php diff --git a/classes/Geocoding.php b/src/classes/Geocoding.php similarity index 100% rename from classes/Geocoding.php rename to src/classes/Geocoding.php diff --git a/classes/Imprese.php b/src/classes/Imprese.php similarity index 100% rename from classes/Imprese.php rename to src/classes/Imprese.php diff --git a/classes/MarcheTemporali.php b/src/classes/MarcheTemporali.php similarity index 100% rename from classes/MarcheTemporali.php rename to src/classes/MarcheTemporali.php diff --git a/classes/OpenApiBase.php b/src/classes/OpenApiBase.php similarity index 100% rename from classes/OpenApiBase.php rename to src/classes/OpenApiBase.php diff --git a/classes/UfficioPostale.php b/src/classes/UfficioPostale.php similarity index 100% rename from classes/UfficioPostale.php rename to src/classes/UfficioPostale.php diff --git a/classes/VisEngine.php b/src/classes/VisEngine.php similarity index 100% rename from classes/VisEngine.php rename to src/classes/VisEngine.php diff --git a/classes/exception/OpenApiConnectionsException.php b/src/classes/exception/OpenApiConnectionsException.php similarity index 100% rename from classes/exception/OpenApiConnectionsException.php rename to src/classes/exception/OpenApiConnectionsException.php diff --git a/classes/exception/OpenApiExceptionBase.php b/src/classes/exception/OpenApiExceptionBase.php similarity index 100% rename from classes/exception/OpenApiExceptionBase.php rename to src/classes/exception/OpenApiExceptionBase.php diff --git a/classes/exception/OpenApiMarcheTemporaliException.php b/src/classes/exception/OpenApiMarcheTemporaliException.php similarity index 100% rename from classes/exception/OpenApiMarcheTemporaliException.php rename to src/classes/exception/OpenApiMarcheTemporaliException.php diff --git a/classes/exception/OpenApiTokenException.php b/src/classes/exception/OpenApiTokenException.php similarity index 100% rename from classes/exception/OpenApiTokenException.php rename to src/classes/exception/OpenApiTokenException.php diff --git a/classes/exception/OpenApiVisEngineException.php b/src/classes/exception/OpenApiVisEngineException.php similarity index 100% rename from classes/exception/OpenApiVisEngineException.php rename to src/classes/exception/OpenApiVisEngineException.php diff --git a/classes/utility/CacheSystemInterface.php b/src/classes/utility/CacheSystemInterface.php similarity index 100% rename from classes/utility/CacheSystemInterface.php rename to src/classes/utility/CacheSystemInterface.php diff --git a/classes/utility/DummyCache.php b/src/classes/utility/DummyCache.php similarity index 100% rename from classes/utility/DummyCache.php rename to src/classes/utility/DummyCache.php diff --git a/classes/utility/Plugins/FiscalCode.php b/src/classes/utility/Plugins/FiscalCode.php similarity index 100% rename from classes/utility/Plugins/FiscalCode.php rename to src/classes/utility/Plugins/FiscalCode.php diff --git a/classes/utility/Plugins/Validations.php b/src/classes/utility/Plugins/Validations.php similarity index 100% rename from classes/utility/Plugins/Validations.php rename to src/classes/utility/Plugins/Validations.php diff --git a/classes/utility/VisEngine/VisRequest.php b/src/classes/utility/VisEngine/VisRequest.php similarity index 100% rename from classes/utility/VisEngine/VisRequest.php rename to src/classes/utility/VisEngine/VisRequest.php diff --git a/classes/utility/ci4SessionStoreToken.php b/src/classes/utility/ci4SessionStoreToken.php similarity index 100% rename from classes/utility/ci4SessionStoreToken.php rename to src/classes/utility/ci4SessionStoreToken.php diff --git a/classes/utility/sessionStoreToken.php b/src/classes/utility/sessionStoreToken.php similarity index 100% rename from classes/utility/sessionStoreToken.php rename to src/classes/utility/sessionStoreToken.php diff --git a/classes/utility/storeTokenInterface.php b/src/classes/utility/storeTokenInterface.php similarity index 100% rename from classes/utility/storeTokenInterface.php rename to src/classes/utility/storeTokenInterface.php From 5f1be3bdf64f215e82644f0546a378ba9fd23fee Mon Sep 17 00:00:00 2001 From: pberanrdiniAltravia <68341384+pberanrdiniAltravia@users.noreply.github.com> Date: Tue, 29 Sep 2020 12:13:35 +0200 Subject: [PATCH 10/85] modificato composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 3618995..031aa1f 100644 --- a/composer.json +++ b/composer.json @@ -7,13 +7,13 @@ "email": "info@altravia.com" } ], - "minimum-stability": "production", + "minimum-stability": "stable", "require": { "php": ">=7.2.0" }, "autoload": { "psr-0": { - "OpenApi": "OpenApi/" + "OpenApi": "src" } } } From f7cad4aeae55287008c37565c0e598f11c9a3bca Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Fri, 9 Oct 2020 15:16:40 +0200 Subject: [PATCH 11/85] aggiunti sms --- src/OpenApi.php | 21 +- src/classes/Comuni.php | 11 +- src/classes/FirrmaDigitale.php | 16 ++ src/classes/Geocoding.php | 7 + src/classes/OpenApiBase.php | 3 +- src/classes/Sms.php | 125 +++++++++ src/classes/UfficioPostale.php | 12 + src/classes/exception/OpenApiSMSException.php | 13 + .../UfficioPostale/Objects/Recipient.php | 262 ++++++++++++++++++ .../utility/UfficioPostale/Objects/Sender.php | 237 ++++++++++++++++ .../utility/UfficioPostale/Raccomandata.php | 9 + .../utility/UfficioPostale/ServiziPostali.php | 112 ++++++++ 12 files changed, 821 insertions(+), 7 deletions(-) create mode 100644 src/classes/FirrmaDigitale.php create mode 100644 src/classes/Sms.php create mode 100644 src/classes/exception/OpenApiSMSException.php create mode 100644 src/classes/utility/UfficioPostale/Objects/Recipient.php create mode 100644 src/classes/utility/UfficioPostale/Objects/Sender.php create mode 100644 src/classes/utility/UfficioPostale/Raccomandata.php create mode 100644 src/classes/utility/UfficioPostale/ServiziPostali.php diff --git a/src/OpenApi.php b/src/OpenApi.php index bc87789..292886e 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -46,9 +46,7 @@ function __construct(array $scopes, string $username, string $apikey, $environme $this->apikey = $apikey; $this->prefix = $prefix; $this->scopes = $realScopes; - $token = $this->getToken(); - //var_dump($token);exit; list($moduli,$nomi) = $this->getListaModuli(); $this->clients = []; foreach($domains as $d){ @@ -61,6 +59,8 @@ function __construct(array $scopes, string $username, string $apikey, $environme } $this->validations = new \OpenApi\classes\utility\Plugins\Validations(); + $this->fiscalCode = new \OpenApi\classes\utility\Plugins\FiscalCode(); + //$this->geocoding = new \OpenApi\classes\Geocoding($token->token, [], $this->cache, ""); } /** @@ -83,6 +83,21 @@ private function getListaModuli(){ $moduli['comuni.openapi.it'] = "\\OpenApi\\classes\\Comuni"; $nomi['comuni.openapi.it'] = "comuni"; + + + $moduli['ws.marchetemporali.com'] = "\\OpenApi\\classes\\MarcheTemporali"; + $nomi['ws.marchetemporali.com'] = "marcheTemporali"; + + + $moduli['geocoding.realgest.it'] = "\\OpenApi\\classes\\Geocoding"; + $nomi['geocoding.realgest.it'] = "geocoding"; + + $moduli['ws.messaggisms.com'] = "\\OpenApi\\classes\\Sms"; + $nomi['ws.messaggisms.com'] = "SMS"; + + + $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; + $nomi['ws.firmadigitale.com'] = "FirmaDigitale"; return array($moduli,$nomi); } @@ -205,7 +220,7 @@ function getOldToken(){ $tostore['scopes'] = serialize($this->scopes); $tostore['username'] = $this->username; $tostore['prefix'] = $this->prefix; - $this->session->save($tostore); + $this->store->save($tostore); return TRUE; } return FALSE; diff --git a/src/classes/Comuni.php b/src/classes/Comuni.php index b7da833..a86fca1 100644 --- a/src/classes/Comuni.php +++ b/src/classes/Comuni.php @@ -73,15 +73,20 @@ function getProvince($regione = NULL, $ttl = 86400){ return $province; } + + /** + * Restituisce la lista comuni a partire dalla provincia + * @param mixed $provincia provincia Es.: RM + * @param int $ttl time to reload cache + * + * @return array + */ function getComuni($provincia, $ttl = 86400){ $provincia = trim(\strtolower($provincia)); $data = $this->connect("province/$provincia", "GET", [], $ttl); - $comuni = $data->data; - //sort($comuni->comuni); - //usort($comuni->dettaglio_comuni,[$this, 'sortComune']); return $comuni; } diff --git a/src/classes/FirrmaDigitale.php b/src/classes/FirrmaDigitale.php new file mode 100644 index 0000000..de518c5 --- /dev/null +++ b/src/classes/FirrmaDigitale.php @@ -0,0 +1,16 @@ +basePath = "https://ws.firmadigitale.com"; + } + + +} \ No newline at end of file diff --git a/src/classes/Geocoding.php b/src/classes/Geocoding.php index ca81382..b0ec8bd 100644 --- a/src/classes/Geocoding.php +++ b/src/classes/Geocoding.php @@ -12,6 +12,13 @@ function __construct(string $token, array $scopes, object $cache, string $prefi $this->basePath = "https://geocoding.realgest.it"; } + /** + * Restituisce le coordinate geografiche a partire dall'indirizzo + * @param string $address Indirizzo + * @param int $ttl Tempo in cui la risposta resta in cahce + * + * @return object + */ function geocode(string $address, $ttl = 86400){ $data = $this->connect("geocode", "POST", ["address" => $address], $ttl, TRUE); diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php index 6b75432..3e5f602 100644 --- a/src/classes/OpenApiBase.php +++ b/src/classes/OpenApiBase.php @@ -97,6 +97,7 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = if(!$force){ $this->checkHasScope($url, $type); } + if($type == "GET" && $ttr > 0 && $ret = $this->getCacheObject($url)) { return $ret; @@ -121,7 +122,7 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = curl_setopt($ch,CURLOPT_HTTPHEADER,array("Authorization: Bearer ".$this->token)); curl_setopt($ch, CURLOPT_HEADER, 1); $response = curl_exec($ch); - //var_dump($response);exit; + // var_dump($response);exit; $this->rawResponse = $response; $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $this->header = substr($response, 0, $header_size); diff --git a/src/classes/Sms.php b/src/classes/Sms.php new file mode 100644 index 0000000..0a05d9d --- /dev/null +++ b/src/classes/Sms.php @@ -0,0 +1,125 @@ +basePath = "https://ws.messaggisms.com"; + $this->messageId = NULL; + } + + function addRecipeints($recipients, $finish = false){ + if($this->messageId == NULL){ + throw new \OpenApi\classes\exception\OpenApiSMSException("No message id presente",40010); + exit; + } + $data = $this->addRecipeintsByMessageId($this->messageId, $recipients, $finish ); + if($finish){ + $this->messageId = NULL; + } + return $data; + } + + function addRecipeintsByMessageId($messageId, $recipients, $finish = false){ + $param['recipients'] = $recipients; + $param['transaction'] = !$finish; + try{ + $data = $this->connect("messages/$messageId", "PUT", $param); + + return $data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + exit; + } + } + + function getRecipients($messageId, $number = NULL){ + try{ + $data = $this->connect("messages/$messageId/recipients/".$number, "GET", []); + return $data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + exit; + } + } + + function getMessage($messageId){ + try{ + $data = $this->connect("messages/$messageId", "GET", []); + return $data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + exit; + } + } + + function sendMore($sender, $recipients, $text, $transaction = false, $priority = 1,$options = NULL, $test = false){ + + $param['test'] = $test; + $param['sender'] = $sender; + $param['recipients'] = $recipients; + $param['body'] = $text; + $param['transaction'] = $transaction; + if($options != NULL){ + $param['priority'] = $priority; + } + try{ + $data = $this->connect("messages/", "POST", $param); + if(isset($data->data[0]) && $transaction){ + $this->messageId =$data->data[0]->id; + } + return $data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + exit; + } + } + + + function sendOne($sender, $recipient, $text, $prefix = NULL, $priority = 1,$options = NULL, $test = false){ + if($prefix != NULL){ + $recipient = $prefix."-".$recipient; + } + + $param['test'] = $test; + $param['sender'] = $sender; + $param['recipients'] = $recipient; + $param['body'] = $text; + $param['transaction'] = FALSE; + if($options != NULL){ + $param['priority'] = $priority; + } + + try{ + $data = $this->connect("messages/", "POST", $param); + + return $data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + exit; + } + } + +} \ No newline at end of file diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index ac83477..1bb0a49 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -12,6 +12,18 @@ function __construct(string $token, array $scopes, object $cache, string $prefi $this->basePath = "https://ws.ufficiopostale.com"; } + + /** + * Restiuisce un oggetto di tipo raccomandata + * @return object + */ + function createRaccomandata(){ + return new \OpenApi\classes\utility\UfficioPostale\Raccomandata($this->connect); + } + + //function createRaccomandataByData() + + diff --git a/src/classes/exception/OpenApiSMSException.php b/src/classes/exception/OpenApiSMSException.php new file mode 100644 index 0000000..c9ead61 --- /dev/null +++ b/src/classes/exception/OpenApiSMSException.php @@ -0,0 +1,13 @@ +errors = null; + $this->data = new \stdClass(); + $this->data->firstName = NULL; + $this->data->secondName = NULL; + $this->data->companyName = NULL; + $this->data->at = NULL; + $this->data->title = NULL; + $this->data->dug = NULL; + $this->data->address = NULL; + $this->data->huoseNumber = NULL; + $this->data->city = NULL; + $this->data->zip = NULL; + $this->data->province = NULL; + $this->data->country = "Italia"; + $this->data->email = NULL; + + + $this->itData = new \stdClass(); + $this->itData->nome = NULL; + $this->itData->cognome = NULL; + $this->itData->ragione_sociale = NULL; + $this->itData->co = NULL; + $this->itData->titolo = NULL; + $this->itData->dug = NULL; + $this->itData->indirizzo = NULL; + $this->itData->civico = NULL; + $this->itData->comune = NULL; + $this->itData->cap = NULL; + $this->itData->provincia = NULL; + $this->itData->nazione = "Italia"; + $this->itData->email = NULL; + + $this->validate = false; + + if($recipient == NULL){ + $this->createFromObject($recipient); + } + } + + public function createFromObject($object){ + $this->data->title = isset($object->title)?$object->title:(isset($object->titolo)?$object->titolo:NULL); + $this->data->at = isset($object->at)?$object->at:(isset($object->co)?$object->co:NULL); + $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); + $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); + $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); + $this->data->dug = isset($object->dug)?$object->dug:NULL; + $this->data->address = isset($object->address)?$object->address:(isset($object->indirizzo)?$object->indirizzo:NULL); + $this->data->huoseNumber = isset($object->huoseNumber)?$object->huoseNumber:(isset($object->civico)?$object->civico:NULL); + $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); + $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); + $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); + $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"Italia"); + $this->data->email = isset($object->email)?$object->email:NULL; + + + $this->itData->co = $this->data->at; + $this->itData->titolo = $this->data->title; + $this->itData->nome = $this->data->firstName; + $this->itData->cognome = $this->data->secondName; + $this->itData->ragione_sociale = $this->data->companyName; + $this->itData->dug = $this->data->dug; + $this->itData->indirizzo = $this->data->address; + $this->itData->civico = $this->data->huoseNumber; + $this->itData->comune = $this->data->city; + $this->itData->cap = $this->data->zip; + $this->itData->provincia = $this->data->province; + $this->itData->nazione = $this->data->country; + $this->itData->email = $this->data->email; + + } + + public function getObject($itNames = FALSE){ + if(!$itNames){ + return $this->data; + } + return $this->itData; + } + + public function getTitle(){ + return $this->data->title; + } + + public function getAt(){ + return $this->data->at; + } + + public function getFirstName(){ + return $this->data->firstName; + } + public function getSecondName(){ + return $this->data->secondName; + } + + public function getCompanyName(){ + return $this->data->companyName; + } + public function getDug(){ + return $this->data->dug; + } + public function getAddress(){ + return $this->data->address; + } + public function getHuoseNumber(){ + return $this->data->huoseNumber; + } + public function getCity(){ + return $this->data->city; + } + public function getZip(){ + return $this->data->zip; + } + public function getProvince(){ + return $this->data->province; + } + public function getCountry(){ + return $this->data->country; + } + public function getEmail(){ + return $this->data->email; + } + + public function setTitle(string $title){ + $this->data->title = $title; + $this->itData->titolo = $title; + } + + public function setAt(string $at){ + $this->data->at = $at; + $this->itData->co = $at; + } + + public function setFirstName(string $firstName){ + $this->data->firstName = $firstName; + $this->itData->nome = $firstName; + } + + public function setSecondName(string $secondName){ + $this->data->secondName = $secondName; + $this->itData->cognome = $secondName; + } + + public function setCompanyName(string $companyName){ + $this->data->companyName = $companyName; + $this->itData->ragione_sociale = $companyName; + } + + public function setDug(string $dug){ + $this->data->dug = $dug; + $this->itData->dug = $dug; + } + + public function setAddress(string $address){ + $this->data->address = $address; + $this->itData->indirizzo = $address; + } + public function setHuoseNumber(string $huoseNumber){ + $this->data->huoseNumber = $huoseNumber; + $this->itData->civico = $huoseNumber; + } + + public function setCity(string $city){ + $this->data->city = $city; + $this->itData->comune = $city; + } + + public function setZip(string $zip){ + $this->data->zip = $zip; + $this->itData->cap = $zip; + } + + public function setProvince(string $province){ + $this->data->province = $province; + $this->itData->privincia = $province; + } + + public function setCountry(string $country){ + $this->data->country = $country; + $this->itData->nazione = $country; + } + + public function setEmail(string $email){ + $this->data->email = $email; + $this->itData->email = $email; + } + + public function getErrors($validate = TRUE){ + if($validate){ + $this->validate(); + } + + return $this->errors; + } + + public function validate(){ + $this->errors = []; + if($this->data->zip == NULL){ + $this->errors['zip'] = (object)[ + "code"=> "required", + "text"=>"zip field is required" + ]; + } else if($this->data->country == "Italia" || $this->data->country == "Italy"){ + $re = '/^\d{5}$/'; + preg_match($re, $this->data->zip, $matches, PREG_OFFSET_CAPTURE, 0); + if(count($matches) == 0){ + $this->errors['zip'] = (object)[ + "code"=> "5_digit", + "text"=>"Italian ZIP must be 5 digits" + ]; + } + } + + if($this->data->city == NULL){ + $this->errors['city'] = (object)[ + "code"=> "required", + "text"=>"city is required" + ]; + } + + if($this->data->province == NULL){ + $this->errors['province'] = (object)[ + "code"=> "required", + "text"=>"province is required" + ]; + } + + + if($this->data->dug == NULL){ + $this->errors['dug'] = (object)[ + "code"=> "required", + "text"=>"dug is required" + ]; + } + + if($this->data->address == NULL){ + $this->errors['address'] = (object)[ + "code"=> "required", + "text"=>"address is required" + ]; + } + + if($this->data->huoseNumber == NULL){ + $this->errors['huoseNumber'] = (object)[ + "code"=> "required", + "text"=>"huose number is required" + ]; + } + + + $this->validate = count($this->errors) == 0; + return $this->validate; + } + +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/Sender.php b/src/classes/utility/UfficioPostale/Objects/Sender.php new file mode 100644 index 0000000..8ec3690 --- /dev/null +++ b/src/classes/utility/UfficioPostale/Objects/Sender.php @@ -0,0 +1,237 @@ +errors = null; + $this->data = new \stdClass(); + $this->data->firstName = NULL; + $this->data->secondName = NULL; + $this->data->companyName = NULL; + $this->data->dug = NULL; + $this->data->address = NULL; + $this->data->huoseNumber = NULL; + $this->data->city = NULL; + $this->data->zip = NULL; + $this->data->province = NULL; + $this->data->country = "Italia"; + $this->data->email = NULL; + + + $this->itData = new \stdClass(); + $this->itData->nome = NULL; + $this->itData->cognome = NULL; + $this->itData->ragione_sociale = NULL; + $this->itData->dug = NULL; + $this->itData->indirizzo = NULL; + $this->itData->civico = NULL; + $this->itData->comune = NULL; + $this->itData->cap = NULL; + $this->itData->provincia = NULL; + $this->itData->nazione = "Italia"; + $this->itData->email = NULL; + + $this->validate = false; + + if($sender == NULL){ + $this->createFromObject($sender); + } + } + + public function createFromObject($object){ + $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); + $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); + $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); + $this->data->dug = isset($object->dug)?$object->dug:NULL; + $this->data->address = isset($object->address)?$object->address:(isset($object->indirizzo)?$object->indirizzo:NULL); + $this->data->huoseNumber = isset($object->huoseNumber)?$object->huoseNumber:(isset($object->civico)?$object->civico:NULL); + $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); + $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); + $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); + $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"Italia"); + $this->data->email = isset($object->email)?$object->email:NULL; + + + $this->itData->nome = $this->data->firstName; + $this->itData->cognome = $this->data->secondName; + $this->itData->ragione_sociale = $this->data->companyName; + $this->itData->dug = $this->data->dug; + $this->itData->indirizzo = $this->data->address; + $this->itData->civico = $this->data->huoseNumber; + $this->itData->comune = $this->data->city; + $this->itData->cap = $this->data->zip; + $this->itData->provincia = $this->data->province; + $this->itData->nazione = $this->data->country; + $this->itData->email = $this->data->email; + + } + + public function getObject($itNames = FALSE){ + if(!$itNames){ + return $this->data; + } + return $this->itData; + } + + + public function getFirstName(){ + return $this->data->firstName; + } + public function getSecondName(){ + return $this->data->secondName; + } + + public function getCompanyName(){ + return $this->data->companyName; + } + public function getDug(){ + return $this->data->dug; + } + public function getAddress(){ + return $this->data->address; + } + public function getHuoseNumber(){ + return $this->data->huoseNumber; + } + public function getCity(){ + return $this->data->city; + } + public function getZip(){ + return $this->data->zip; + } + public function getProvince(){ + return $this->data->province; + } + public function getCountry(){ + return $this->data->country; + } + public function getEmail(){ + return $this->data->email; + } + + public function setFirstName(string $firstName){ + $this->data->firstName = $firstName; + $this->itData->nome = $firstName; + } + + public function setSecondName(string $secondName){ + $this->data->secondName = $secondName; + $this->itData->cognome = $secondName; + } + + public function setCompanyName(string $companyName){ + $this->data->companyName = $companyName; + $this->itData->ragione_sociale = $companyName; + } + + public function setDug(string $dug){ + $this->data->dug = $dug; + $this->itData->dug = $dug; + } + + public function setAddress(string $address){ + $this->data->address = $address; + $this->itData->indirizzo = $address; + } + public function setHuoseNumber(string $huoseNumber){ + $this->data->huoseNumber = $huoseNumber; + $this->itData->civico = $huoseNumber; + } + + public function setCity(string $city){ + $this->data->city = $city; + $this->itData->comune = $city; + } + + public function setZip(string $zip){ + $this->data->zip = $zip; + $this->itData->cap = $zip; + } + + public function setProvince(string $province){ + $this->data->province = $province; + $this->itData->privincia = $province; + } + + public function setCountry(string $country){ + $this->data->country = $country; + $this->itData->nazione = $country; + } + + public function setEmail(string $email){ + $this->data->email = $email; + $this->itData->email = $email; + } + + public function getErrors($validate = TRUE){ + if($validate){ + $this->validate(); + } + + return $this->errors; + } + + public function validate(){ + $this->errors = []; + if($this->data->zip == NULL){ + $this->errors['zip'] = (object)[ + "code"=> "required", + "text"=>"zip field is required" + ]; + } else if($this->data->country == "Italia" || $this->data->country == "Italy"){ + $re = '/^\d{5}$/'; + preg_match($re, $this->data->zip, $matches, PREG_OFFSET_CAPTURE, 0); + if(count($matches) == 0){ + $this->errors['zip'] = (object)[ + "code"=> "5_digit", + "text"=>"Italian ZIP must be 5 digits" + ]; + } + } + + if($this->data->city == NULL){ + $this->errors['city'] = (object)[ + "code"=> "required", + "text"=>"city is required" + ]; + } + + if($this->data->province == NULL){ + $this->errors['province'] = (object)[ + "code"=> "required", + "text"=>"province is required" + ]; + } + + + if($this->data->dug == NULL){ + $this->errors['dug'] = (object)[ + "code"=> "required", + "text"=>"dug is required" + ]; + } + + if($this->data->address == NULL){ + $this->errors['address'] = (object)[ + "code"=> "required", + "text"=>"address is required" + ]; + } + + if($this->data->huoseNumber == NULL){ + $this->errors['huoseNumber'] = (object)[ + "code"=> "required", + "text"=>"huose number is required" + ]; + } + + + $this->validate = count($this->errors) == 0; + return $this->validate; + } + +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Raccomandata.php b/src/classes/utility/UfficioPostale/Raccomandata.php new file mode 100644 index 0000000..c551100 --- /dev/null +++ b/src/classes/utility/UfficioPostale/Raccomandata.php @@ -0,0 +1,9 @@ +connect = $connect; + $this->sender = NULL; + $this->recipients = []; + $this->documents = []; + $this->textMessage = NULL; + $this->validRecipients = FALSE; + } + + + public function setSender($sender){ + if($sender instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Sender){ + $this->sender = $sender; + }else{ + $this->sender = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($sender); + } + if(!$this->sender->validate()){ + return FALSE; + } + return TRUE; + } + + public function getSender(){ + return $this->sender; + } + + public function getSenderError(){ + if($this->sender == NULL){ + return NULL; + } + return $this->sender->getErrors(); + } + + public function getRecpients(){ + return $this->recipients; + } + + public function getRecpientsErrors(){ + if($this->recipients == NULL){ + return NULL; + } + if($this->validRecipients){ + return []; + } + $errors = []; + foreach($this->recipient AS $r){ + $errors[] = $r->getErrors(); + } + return $errors; + } + + public function setTextMessage($message){ + $this->textMessage = $message; + } + + public function setRecipients($recipients){ + $this->clearRecipients(); + $valid = TRUE; + foreach($recipients as $key => $recipient){ + if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ + + $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); + } + if(!$recipient->validate()){ + $valid = FALSE; + } + $this->recipient[] = $recipient; + } + $this->validRecipients = $valid; + return $valid; + } + + public function addRecipient($recipient){ + if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ + $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); + } + $valid = TRUE; + if(!$recipient->validate()){ + $valid = FALSE; + } + $this->recipient[] = $recipient; + $this->validRecipients = $valid; + return $valid; + } + + public function clearRecipients(){ + $this->recipients = []; + } + + public function setDocuments($documents){ + $this->documents = $documents; + } + + public function addDocument($document){ + $this->documents[] = $document; + } + + public function clearDocuments(){ + $this->documents = []; + } +} \ No newline at end of file From 746ccd196408be8f6f0085cf7d7aa39e23c47f5c Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Fri, 9 Oct 2020 17:17:45 +0200 Subject: [PATCH 12/85] modificato composer.json --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 031aa1f..a2ec37e 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "php": ">=7.2.0" }, "autoload": { - "psr-0": { + "psr-4": { "OpenApi": "src" } } From 5a21e66125741851cb6196f6be78ea3d910975b8 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Fri, 9 Oct 2020 17:20:42 +0200 Subject: [PATCH 13/85] modificato composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index a2ec37e..f1eb223 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ }, "autoload": { "psr-4": { - "OpenApi": "src" + "OpenApi/": "src" } } } From c00a66bde604cc13342084d65f4513c62b0739d5 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Fri, 9 Oct 2020 17:54:11 +0200 Subject: [PATCH 14/85] modifica composer --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index f1eb223..e91e179 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ }, "autoload": { "psr-4": { - "OpenApi/": "src" + "OpenApi\\": "src" } } } From 4dd8b6fd8d4f9fefaccfe35104648518320cf704 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Fri, 16 Oct 2020 10:51:02 +0200 Subject: [PATCH 15/85] added FirmaDigitale and PecMassiva API --- src/OpenApi.php | 10 ++- src/classes/FirmaDigitale.php | 69 +++++++++++++++++ src/classes/OpenApiBase.php | 10 ++- src/classes/PecMassiva.php | 77 +++++++++++++++++++ .../exception/OpenApiPecMassivaException.php | 15 ++++ 5 files changed, 178 insertions(+), 3 deletions(-) create mode 100644 src/classes/FirmaDigitale.php create mode 100644 src/classes/PecMassiva.php create mode 100644 src/classes/exception/OpenApiPecMassivaException.php diff --git a/src/OpenApi.php b/src/OpenApi.php index 292886e..a77a501 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -21,7 +21,11 @@ function __construct(array $scopes, string $username, string $apikey, $environme $domainsRealScopes = []; $prefix = $environment=="production"?"":$environment."."; $domains = []; + //var_dump($scopes);exit; foreach($scopes as $s){ + if($s == NULL){ + continue; + } if(is_array($s)){ $domain = $s['domain']; $realScope = $s['mode'].":".$prefix.$s['domain']."/".$s['method']; @@ -47,6 +51,7 @@ function __construct(array $scopes, string $username, string $apikey, $environme $this->prefix = $prefix; $this->scopes = $realScopes; $token = $this->getToken(); + list($moduli,$nomi) = $this->getListaModuli(); $this->clients = []; foreach($domains as $d){ @@ -97,7 +102,10 @@ private function getListaModuli(){ $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; - $nomi['ws.firmadigitale.com'] = "FirmaDigitale"; + $nomi['ws.firmadigitale.com'] = "firmaDigitale"; + + $moduli['ws.pecmassiva.com'] = "\\OpenApi\\classes\\PecMassiva"; + $nomi['ws.pecmassiva.com'] = "pecMassiva"; return array($moduli,$nomi); } diff --git a/src/classes/FirmaDigitale.php b/src/classes/FirmaDigitale.php new file mode 100644 index 0000000..5f761ed --- /dev/null +++ b/src/classes/FirmaDigitale.php @@ -0,0 +1,69 @@ +basePath = "https://ws.firmadigitale.com"; + } + + + function getModule($id, $add_header = TRUE){ + + $pdf = $this->connect("richiesta/$id/modulo", "GET", [], 0, FALSE, TRUE); + if(!$add_header){ + return $pdf; + } + header("Content-type:application/pdf"); + header("Content-Disposition:attachment;filename={$id}.pdf"); + header('Content-Length: '.strlen( $pdf )); + header('Cache-Control: public, must-revalidate, max-age=0'); + header('Pragma: public'); + header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); + echo $pdf; + } + + + function requestProduct($data){ + $type = isset($data['tipo'])?$data['tipo']:NULL; + $codice_prodotto = isset($data['codice_prodotto'])?$data['codice_prodotto']:NULL; + $anagrafica = isset($data['anagrafica'])?$data['anagrafica']:NULL; + $spedizione = isset($data['spedizione'])?$data['spedizione']:NULL; + $urgenza = isset($data['urgenza'])?$data['urgenza']:NULL; + $assistenza = isset($data['assistenza'])?$data['assistenza']:NULL; + $callback = isset($data['callback'])?$data['callback']:NULL; + + $params = []; + if($anagrafica != NULL){ + if($type == "lettore"){ + $params['anagrafica_spedizione'] = $anagrafica; + }else{ + $params['anagrafica'] = $anagrafica; + } + + } + + if($spedizione != NULL && ($type == "lettore" || $type == "firma")){ + $params['spedizione'] = $spedizione; + } + + if($urgenza != NULL && ($type == "lettore" || $type == "firma")){ + $params['urgenza'] = $urgenza; + } + if($assistenza != NULL){ + $params['assistenza'] = $assistenza; + } + + if($callback != NULL){ + $params['callback'] = $callback; + } + $ret = $this->connect("richiesta/$codice_prodotto","POST",$params); + return $ret; + } + +} \ No newline at end of file diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php index 3e5f602..dd046e0 100644 --- a/src/classes/OpenApiBase.php +++ b/src/classes/OpenApiBase.php @@ -89,7 +89,7 @@ private function checkHasScope(string $url, string $type){ * * @return mixed */ - protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false){ + protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $addHeader = NULL){ $url = $this->basePath; $url = str_replace("https://","https://".$this->prefix,$url); $url = str_replace("http://","http://".$this->prefix,$url); @@ -119,7 +119,13 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type); - curl_setopt($ch,CURLOPT_HTTPHEADER,array("Authorization: Bearer ".$this->token)); + $header = array("Authorization: Bearer ".$this->token); + if($addHeader != NULL && is_array($addHeader) && count($addHeader)>0){ + $header = array_merge($header, $addHeader); + } + + + curl_setopt($ch,CURLOPT_HTTPHEADER,$header); curl_setopt($ch, CURLOPT_HEADER, 1); $response = curl_exec($ch); // var_dump($response);exit; diff --git a/src/classes/PecMassiva.php b/src/classes/PecMassiva.php new file mode 100644 index 0000000..dcb7f6b --- /dev/null +++ b/src/classes/PecMassiva.php @@ -0,0 +1,77 @@ +basePath = "https://ws.pecmassiva.com"; + $this->inizialized = FALSE; + + } + + function initialize(string $username, string $password){ + $this->username = $username; + $this->password = $password; + $this->inizialized = TRUE; + } + + function getStatus($messageId){ + if(!$this->inizialized){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + } + + + try{ + $header[] = 'x-username: '.$this->username; + $header[] = 'x-password: '.$this->password; + return $this->connect("send/$messageId","GET",[],0,false,$header); + + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if(isset($e->getServerResponse()->message_id)){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + } + throw $e; + + } + } + + function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ + if(!$this->inizialized){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + } + $sender = $sender ? $sender : $this->username; + + $params['username'] = $this->username; + $params['password'] = $this->password; + $params['recipient'] = $recipient; + $params['subject'] = $subject; + $params['body'] = $body; + if(count($attachments)>0){ + $params['attachments'] = $attachments; + } + $params['sender'] = $sender; + try{ + return $this->connect("send","POST",$params); + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if(isset($e->getServerResponse()->message_id)){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + } + throw $e; + + } + + } + + +} \ No newline at end of file diff --git a/src/classes/exception/OpenApiPecMassivaException.php b/src/classes/exception/OpenApiPecMassivaException.php new file mode 100644 index 0000000..31d9848 --- /dev/null +++ b/src/classes/exception/OpenApiPecMassivaException.php @@ -0,0 +1,15 @@ + Date: Fri, 30 Oct 2020 17:51:50 +0100 Subject: [PATCH 16/85] - --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 634775a..c4f92d6 100644 --- a/readme.md +++ b/readme.md @@ -47,5 +47,5 @@ La funzione consente di recuperare i dati aziendali a partire dalla partita IVA `function getByPartitaIva(string $partitaIva, $ttl = 86400):object` -* $partitaIva: La partita IVA da cvercare +* $partitaIva: La partita IVA da cercare * $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta From ba5356fd852cd209311c2c32212df73d2df0d717 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Fri, 30 Oct 2020 17:56:35 +0100 Subject: [PATCH 17/85] visengine: gestione fornitori --- src/classes/VisEngine.php | 11 +++++++++++ src/classes/utility/VisEngine/VisRequest.php | 7 +++++++ 2 files changed, 18 insertions(+) diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index 0080d58..f55fd59 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -22,6 +22,17 @@ function setHash(string $hash){ $this->hash = $hash; } + function getDatiFornitore($email){ + $data = $this->connect("fornitori/$email", "GET", []); + return $data; + } + + function getFornitori(){ + $data = $this->connect("fornitori", "GET", []); + return $data; + + } + function getFormTool(){ if($this->hash == NULL){ throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); diff --git a/src/classes/utility/VisEngine/VisRequest.php b/src/classes/utility/VisEngine/VisRequest.php index 8aac5cb..50af857 100644 --- a/src/classes/utility/VisEngine/VisRequest.php +++ b/src/classes/utility/VisEngine/VisRequest.php @@ -22,11 +22,18 @@ function __construct($visura) $this->ricerche = []; $this->document = NULL; $this->format_errror = []; + $this->fornitore = []; foreach($visura->data->json_struttura->campi as $k => $v){ $this->variables[$k] = FALSE; } } + function setFornitore($fornitore){ + $this->fornitore = $fornitore; + } + function getFornitore(){ + return $this->fornitore; + } function setNew(bool $new){ return $this->new = $new; } From f05435b8fd3df04c36ce5b728dba3a7cb6026f9e Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Wed, 11 Nov 2020 18:05:54 +0100 Subject: [PATCH 18/85] uploader --- src/OpenApi.php | 3 + src/classes/OpenApiBase.php | 41 ++- src/classes/Uploader.php | 78 +++++ .../exception/OpenApiUploaderException.php | 19 + src/classes/utility/Uploader/Collection.php | 327 ++++++++++++++++++ 5 files changed, 464 insertions(+), 4 deletions(-) create mode 100644 src/classes/Uploader.php create mode 100644 src/classes/exception/OpenApiUploaderException.php create mode 100644 src/classes/utility/Uploader/Collection.php diff --git a/src/OpenApi.php b/src/OpenApi.php index a77a501..ba80854 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -106,6 +106,9 @@ private function getListaModuli(){ $moduli['ws.pecmassiva.com'] = "\\OpenApi\\classes\\PecMassiva"; $nomi['ws.pecmassiva.com'] = "pecMassiva"; + + $moduli['uploader.altravia.com'] = "\\OpenApi\\classes\\Uploader"; + $nomi['uploader.altravia.com'] = "uploader"; return array($moduli,$nomi); } diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php index dd046e0..5d506b8 100644 --- a/src/classes/OpenApiBase.php +++ b/src/classes/OpenApiBase.php @@ -89,7 +89,7 @@ private function checkHasScope(string $url, string $type){ * * @return mixed */ - protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $addHeader = NULL){ + public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $addHeader = NULL){ $url = $this->basePath; $url = str_replace("https://","https://".$this->prefix,$url); $url = str_replace("http://","http://".$this->prefix,$url); @@ -132,15 +132,27 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = $this->rawResponse = $response; $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); $this->header = substr($response, 0, $header_size); + //var_dump($this->header);exit; + $this->parsedHEader = $this->parseHeader($this->header); $return = substr($response, $header_size); $httpCode = curl_getinfo ( $ch, CURLINFO_RESPONSE_CODE );; curl_close($ch); - $data = json_decode($return); + + if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { + + $data = json_decode($return); + }else if(json_decode($return) != NULL){ + $data = json_decode($return); + + }else{ + $data = $return; + } + if($data == NULL){ throw new \OpenApi\classes\exception\OpenApiConnectionsException("Connection to $url: Connection Error",40001); } - // var_dump($data);exit; - if($data->success == false){ + + if(is_object($data) && $data->success == false){ $message = "Connection to $url: unknow error"; if(isset($data->message)) { if(is_string(($data->message))){ @@ -166,4 +178,25 @@ protected function connect(string $endpoint, $type = "GET", $param = [], $ttr = return $data; } + private function parseHeader($headers){ + $headers = explode("\n",$headers); + $parsedHeaders = array(); + foreach ($headers as $header) { + $header = trim($header); + + $header = explode(":",$header); + + if(count($header) < 2){ + + continue; + } + $key = $header[0]; + unset($header[0]); + $parsedHeaders[trim($key)] = trim(implode(":",$header)); + } + // exit; + + return $parsedHeaders; + } + } \ No newline at end of file diff --git a/src/classes/Uploader.php b/src/classes/Uploader.php new file mode 100644 index 0000000..d8bbf3e --- /dev/null +++ b/src/classes/Uploader.php @@ -0,0 +1,78 @@ +basePath = "https://uploader.altravia.com"; + } + + function newCollection(){ + + return new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); + } + + function gateway(){ + + $endpoint = isset($_GET['endpoint'])?$_GET['endpoint']:null; + if($endpoint == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("No endpoint GET",40018); + } + + $method = $_SERVER['REQUEST_METHOD']; + $data = null; + if($method != "GET" && $method != "DELETE"){ + $data = file_get_contents("php://input"); + $data = json_decode($data); + } + $data = $this->connect($endpoint, $method,$data); + header("Content-Type: ",$this->parsedHEader['Content-Type']); + if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { + echo json_encode($data); + }else{ + echo $data; + } + } + + function createCollection($outputFormat, $outputSize = null, $inputTypes = null, $inputCount = null, $public = null, $watermark = null, $watermarkPosition = NULL, $expireTimestamp = null) { + $collection = new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); + $collection->setOutput($outputFormat); + $collection->setOutputSize($outputSize); + $collection->setInputTypes($inputTypes); + $collection->setInputCount($inputCount); + $collection->setPublic($public); + $collection->setWaterMark($watermark); + $collection->setWaterMarkPosition($watermarkPosition); + $collection->setExpireTimestamp($expireTimestamp); + $collection->save(); + } + + function getCollectionById($id){ + $coll = $this->connect("collections/$id","GET"); + $collection = new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); + if(isset($coll->data)){ + $collection->parseData($coll->data); + return $collection; + } + return null; + } + + function deleteCollectionById($id){ + return $this->connect("collections/$id","DELETE"); + } + + function getCollections(){ + $collections = $this->connect("collections","GET"); + foreach($collections->data as $d){ + $d->id =$d->_id->{'$oid'}; + unset($d->_id); + } + return $collections; + } + +} \ No newline at end of file diff --git a/src/classes/exception/OpenApiUploaderException.php b/src/classes/exception/OpenApiUploaderException.php new file mode 100644 index 0000000..eb79aa0 --- /dev/null +++ b/src/classes/exception/OpenApiUploaderException.php @@ -0,0 +1,19 @@ +connect = $connect; + } + + function save($state = false){ + $state = (bool)$state; + if($this->getOutput() == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Output format not setted",40017); + } + $this->state = $state; + $data['output_format'] = $this->getOutput(); + if($this->getOutputSize() != NULL){ + $data['output_size'] = $this->getOutputSize(); + } + if($this->getInputTypes() != NULL){ + $data['input_types'] = $this->getInputTypes(); + } + if($this->getInputCount() != NULL){ + $data['input_count'] = $this->getInputCount(); + } + $data['public'] = $this->isPublic(); + if($this->getWaterMark() != NULL){ + $data['watermark'] = $this->getWaterMark(); + $data['watermark_position'] = $this->getWaterMarkPosition(); + } + if($this->getExpireTimestamp() != NULL){ + $data['expire_timestamp'] = $this->getExpireTimestamp(); + } + $data['state'] = $state; + if($this->id == null){ + + $ret = call_user_func_array ($this->connect,["collections","POST",$data]); + $this->id = $ret->id; + return $ret->id; + }else{ + + $ret = call_user_func_array ($this->connect,["collections/$this->id","PATCH",$data]); + $this->id = $ret->id; + return $ret->id; + } + } + + function parseData($data){ + + $this->setOutput($data->output_format); + $this->setOutputSize($data->output_size); + $this->setInputTypes($data->input_types); + $this->setInputCount($data->input_count); + $this->setPublic($data->public); + $this->setWaterMark($data->watermark); + $this->setWaterMarkPosition($data->watermark_position); + $this->setExpireTimestamp($data->expire_timestamp); + $this->email = $data->email; + $this->creation_timestamp = $data->creation_timestamp; + $this->update_timestamp = $data->update_timestamp; + $this->documents_count = $data->documents_count; + $this->documents_bytes = $data->documents_bytes; + $this->documents = $data->documents; + $this->state = $data->state; + $this->id = $data->_id->{'$oid'}; + + } + + function getState(){ + return $this->state; + } + + function getDocuments(){ + $this->documents; + } + + function getDocumentBytes(){ + $this->documents_bytes; + } + + function getDocumentCount(){ + $this->documents_count; + } + + function getUpdateTimestamp(){ + $this->update_timestamp; + } + + function getCreationTimestamp(){ + $this->creation_timestamp; + } + + function getEmail(){ + $this->email; + } + + function getId(){ + return $this->id; + } + function setOutput($output){ + if($output != "image/png" && $output != "image/jpeg" && $output != "application/pdf"){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Output format not valid",40013); + } + if($output == "image/png" || $output == "image/jpeg") { + $this->outputGroup = false; + $this->cropSize = null; + } + $this->output = $output; + $this->checkOutputSize(); + } + + function getOutputSize(){ + return $this->outputSize; + } + + function getInputCount(){ + return $this->inputCount; + } + + function getWaterMark(){ + return $this->watermark; + } + + function setWaterMark($watermark){ + $this->watermark = $watermark; + } + + function getWaterMarkPosition(){ + return $this->watermarkPosition; + } + + + function setWaterMarkPosition($watermarkPosition){ + $this->watermarkPosition = $watermarkPosition; + } + + function setExpireTimestamp($expireTimestamp){ + if($expireTimestamp == NULL){ + $this->expireTimestamp = NULL; + return; + } + $this->expireTimestamp = (int)$expireTimestamp; + } + + function getExpireTimestamp(){ + return $this->expireTimestamp; + } + + function setInputCount($ic){ + if($ic == NULL){ + $this->inputCount = NULL; + return; + } + $this->inputCount = (int)$ic; + } + function setOutputGroup($outputGroup){ + if($outputGroup && ($this->output == "image/png" || $this->output == "image/jpeg")){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Output group not valid",40015); + } + $this->outputGroup = $outputGroup; + } + + function getOutputGroup(){ + return $this->outputGroup; + } + + function setPublic($public = true){ + $this->public = $public; + } + + function setPrivate($private = TRUE){ + $this->public = !$private; + } + + function isPublic(){ + return $this->public; + } + + function isPrivate(){ + return !$this->public; + } + + function setInputTypes($types){ + if(!is_array($types)){ + $types = [$types]; + } + foreach($types as $t){ + if($t != "image/png" && $t != "image/jpeg" && $t != "application/pdf"){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Input type not valid",40016); + } + } + $this->inputTypes = $types; + } + + function getInputTypes(){ + return $this->inputTypes; + } + + function setOutputSize($outputSize){ + $this->outputSize = $outputSize; + $this->checkOutputSize(); + } + + private function checkOutputSize(){ + if($this->output == null || $this->outputSize == NULL){ + return TRUE; + } + if($this->output == "application/pdf"){ + if(!in_array($this->outputSize,$this->validPdfFormats)){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Output size not valid",40014); + } + }else{ + if(!is_array($this->outputSize) || !isset($this->outputSize[0]) || !isset($this->outputSize[1]) || !is_int($this->outputSize[0]) || !is_int($this->outputSize[1])){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Output size not valid",40014); + } + } + } + + function setOutputJpeg(){ + $this->setOutput("image/jpeg"); + } + + function setOutputPng(){ + $this->setOutput("image/png"); + } + + function setOutputPdf(){ + $this->setOutput("application/pdf"); + } + + function getOutput(){ + return $this->output; + } + + function addDocument($name, $type,$file,$crop_size = null){ + if($this->id == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + } + + $data['name'] = $name; + $data['type'] = $type; + $data['file'] = $file; + $data['crop_size'] = $crop_size; + + $ret = call_user_func_array ($this->connect,["collections/$this->id","POST",$data]); + + $this->updateCollection(); + return $ret->id; + } + + function updateDocument($id_documento, $name = NULL,$type = NULL, $file = NULL, $crop_size = NULL){ + if($this->id == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + } + if($name != NULL){ + $data['name'] = $name; + } + if($type != NULL){ + $data['type'] = $type; + } + if($file != NULL){ + $data['file'] = $file; + } + if($crop_size != NULL){ + $data['crop_size'] = $crop_size; + } + + $ret = call_user_func_array ($this->connect,["collections/$this->id/$id_documento","PATCH",$data]); + + $this->updateCollection(); + return $ret->success; + } + + function deleteDocument($id_documento){ + if($this->id == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + } + + + $ret = call_user_func_array ($this->connect,["collections/$this->id/$id_documento","DELETE"]); + + $this->updateCollection(); + return $ret->success; + } + + private function updateCollection(){ + + $coll = call_user_func_array ($this->connect,["collections/$this->id","GET"]); + if(isset($coll->data)){ + $this->parseData($coll->data); + + } + } + + function getDocumento($id_documento){ + if($this->id == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + } + + + $ret = call_user_func_array ($this->connect,["collections/$this->id/$id_documento","GET"]); + + $this->updateCollection(); + return $ret; + } +} \ No newline at end of file From 6a8087e665e16890ce21c110f8edfe3a51f4832b Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Tue, 2 Feb 2021 11:35:28 +0100 Subject: [PATCH 19/85] =?UTF-8?q?aggiunte=20funzionalit=C3=A0=20UfficioPos?= =?UTF-8?q?tale?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/classes/Comuni.php | 14 +++ src/classes/FirmaDigitale.php | 11 ++- src/classes/MarcheTemporali.php | 4 +- src/classes/OpenApiBase.php | 7 +- src/classes/UfficioPostale.php | 5 +- src/classes/Uploader.php | 5 ++ src/classes/VisEngine.php | 85 ++++++++++++++----- src/classes/exception/OpenApiUPException.php | 14 +++ .../UfficioPostale/Objects/Recipient.php | 14 ++- .../utility/UfficioPostale/Objects/Sender.php | 16 ++-- .../utility/UfficioPostale/Raccomandata.php | 48 +++++++++++ .../utility/UfficioPostale/ServiziPostali.php | 85 ++++++++++++++++++- src/classes/utility/VisEngine/VisRequest.php | 18 ++-- 13 files changed, 286 insertions(+), 40 deletions(-) create mode 100644 src/classes/exception/OpenApiUPException.php diff --git a/src/classes/Comuni.php b/src/classes/Comuni.php index a86fca1..b9d1e50 100644 --- a/src/classes/Comuni.php +++ b/src/classes/Comuni.php @@ -27,6 +27,20 @@ function getCitiesByCap(string $cap, $ttl = 86400){ return $data->data; } + /** + * + * A partire dal CAP restistuisce un'array di oggietti di tipo comune + * + * @param string $cap Il cap da ricercare + * @param int $ttl Il tempo di chache degli oggetti ritornati, 0 per no chche + * + * @return array + */ + function getComuneByCatasto(string $codice_catastale, $ttl = 86400){ + $data = $this->connect("catastale/$codice_catastale", "GET", [], $ttl); + return $data->data; + } + /** * Restituisce la lista delle regioni italiani * diff --git a/src/classes/FirmaDigitale.php b/src/classes/FirmaDigitale.php index 5f761ed..9e2abc0 100644 --- a/src/classes/FirmaDigitale.php +++ b/src/classes/FirmaDigitale.php @@ -37,17 +37,26 @@ function requestProduct($data){ $urgenza = isset($data['urgenza'])?$data['urgenza']:NULL; $assistenza = isset($data['assistenza'])?$data['assistenza']:NULL; $callback = isset($data['callback'])?$data['callback']:NULL; + $quantita = isset($data['quantita'])?$data['quantita']:NULL; $params = []; if($anagrafica != NULL){ - if($type == "lettore"){ + if($type == "lettore" || $type == "vergine"){ $params['anagrafica_spedizione'] = $anagrafica; + }elseif($type == "spid"){ + $params['email'] = $anagrafica->email; + $params['cellulare'] = $anagrafica->cellulare; }else{ $params['anagrafica'] = $anagrafica; } } + if($quantita != NULL && ($type == "lettore" || $type == "vergine")){ + $params['quantita'] = $quantita; + } + + if($spedizione != NULL && ($type == "lettore" || $type == "firma")){ $params['spedizione'] = $spedizione; } diff --git a/src/classes/MarcheTemporali.php b/src/classes/MarcheTemporali.php index f7466ea..b945083 100644 --- a/src/classes/MarcheTemporali.php +++ b/src/classes/MarcheTemporali.php @@ -17,7 +17,7 @@ function availability(string $type, int $qty){ return $data->data; } - function checkLotto($username, $password){ + function checkLotto($username, $password, $tipo){ if(substr($username,0,4) == "FAKE" && substr($password,0,4) == "FAKE"){ $ret = new \stdClass(); @@ -29,7 +29,7 @@ function checkLotto($username, $password){ $ret->error = NULL; return $ret->data; } - $data = $this->connect("check_lotto", "POST", ["username"=>$username, "password"=> $password]); + $data = $this->connect("check_lotto", "POST", ["username"=>$username, "password"=> $password,'type'=>$tipo]); return $data->data; } diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php index 5d506b8..4c014d6 100644 --- a/src/classes/OpenApiBase.php +++ b/src/classes/OpenApiBase.php @@ -137,7 +137,7 @@ public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $return = substr($response, $header_size); $httpCode = curl_getinfo ( $ch, CURLINFO_RESPONSE_CODE );; curl_close($ch); - + //echo $return;exit; if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { $data = json_decode($return); @@ -178,7 +178,7 @@ public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, return $data; } - private function parseHeader($headers){ + protected function parseHeader($headers){ $headers = explode("\n",$headers); $parsedHeaders = array(); foreach ($headers as $header) { @@ -199,4 +199,7 @@ private function parseHeader($headers){ return $parsedHeaders; } + + + } \ No newline at end of file diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index 1bb0a49..5922159 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -18,7 +18,10 @@ function __construct(string $token, array $scopes, object $cache, string $prefi * @return object */ function createRaccomandata(){ - return new \OpenApi\classes\utility\UfficioPostale\Raccomandata($this->connect); + return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + + return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); + }); } //function createRaccomandataByData() diff --git a/src/classes/Uploader.php b/src/classes/Uploader.php index d8bbf3e..dabf401 100644 --- a/src/classes/Uploader.php +++ b/src/classes/Uploader.php @@ -23,6 +23,7 @@ function gateway(){ if($endpoint == NULL){ throw new \OpenApi\classes\exception\OpenApiUploaderException("No endpoint GET",40018); } + //echo $endpoint;exit; $method = $_SERVER['REQUEST_METHOD']; $data = null; @@ -30,7 +31,11 @@ function gateway(){ $data = file_get_contents("php://input"); $data = json_decode($data); } + $data = $this->connect($endpoint, $method,$data); + //var_dump($data);exit; + + header("Content-Type: ",$this->parsedHEader['Content-Type']); if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { echo json_encode($data); diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index f55fd59..e67fcd0 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -22,17 +22,6 @@ function setHash(string $hash){ $this->hash = $hash; } - function getDatiFornitore($email){ - $data = $this->connect("fornitori/$email", "GET", []); - return $data; - } - - function getFornitori(){ - $data = $this->connect("fornitori", "GET", []); - return $data; - - } - function getFormTool(){ if($this->hash == NULL){ throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); @@ -69,10 +58,10 @@ function createRequest($ttr = 500){ * * @return object */ - function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { + function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req, $new_search = FALSE) { - + if($req->getNew()){ $params = new \stdClass(); $params->state = $req->getState(); @@ -84,37 +73,59 @@ function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { if($req->getCallbackData() != NULL){ $params->callback_data = $req->getCallbackData(); } + if($req->getFornitore() != NULL){ + $params->callback = $req->getFornitore(); + } if($req->getTargetEmail() != NULL){ $params->email_target = $req->getTargetEmail(); } $data = $this->connect("richiesta", "POST", $params); - + //var_dump($data);exit; $req->setNew(FALSE); $req->setId($data->data->_id); $req->setStatoRichiesta($data->data->stato_richiesta); + + if(isset($data->data->callback)){ + $req->setFornitore($data->data->callback); + }else{ + $req->setFornitore(NULL); + } if(isset($data->data->ricerche)){ $req->setRicerche($data->data->ricerche); } return $req; }else{ - + $params = new \stdClass(); $params->state = $req->getState(); // $params->test = $req->getTest(); - + $id_visura = $req->getId(); if($req->getJson() != NULL){ $params->json_visura = $req->getJson(); } - $id_visura = $req->getId(); + //echo json_encode($params);exit; //var_dump($params);exit; + $visura = $this->connect("richiesta/$id_visura", "GET"); + + if(!$new_search) + { $data = $this->connect("richiesta/$id_visura", "PUT", $params); - + }else{ + $data = $this->connect("richiesta/$id_visura", "POST", $params); + } + + // var_dump($data);exit; + + $req->setNew(FALSE); $req->setId($data->data->_id); $req->setStatoRichiesta($data->data->stato_richiesta); + if(isset($data->data->callback)){ + $req->setFornitore($data->data->callback); + } if(isset($data->data->ricerche)){ $req->setRicerche($data->data->ricerche); } @@ -122,11 +133,33 @@ function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { } } + function getDatiFornitore($email){ + $data = $this->connect("fornitori/$email", "GET", []); + return $data; + } + + function getFornitori(){ + $data = $this->connect("fornitori", "GET", []); + return $data; + + } + function getRequestByIdVisura($id_visura){ $visura = $this->connect("richiesta/$id_visura", "GET"); + + /*if($visura->data->callback){ + var_dump($visura->data->callback);exit; + }*/ + return $this->getRequestByData($visura); } + function cancelRequest($id_visura, $motivazione){ + $visura = $this->connect("richiesta/$id_visura", "DELETE",["motivo"=>$motivazione]); + return $this->getRequestByIdVisura($id_visura); + } + + function getRequestByData($visura){ $this->visura = $this->connect("visure/{$visura->data->hash_visura}", "GET", [], 0); @@ -136,12 +169,22 @@ function getRequestByData($visura){ $request->setNew(FALSE); $request->setId($visura->data->_id); $request->setStatoRichiesta($visura->data->stato_richiesta); - if(isset($visura->data->ricerche)){ $request->setRicerche($visura->data->ricerche); }else{ $request->setRicerche([]); } + if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ + $documento = $this->connect("documento/{$visura->data->_id}", "GET", [], 0); + $request->setDocument($documento->data); + } + if($visura->data->stato_richiesta == "Annullata"){ + $request->setReasonCancellation($visura->data->motivo_annullamento); + + } + if(isset($visura->data->callback) && $visura->data->callback){ + $request->setFornitore($visura->data->callback); + } return $request; } @@ -168,6 +211,10 @@ function setRicerca($id_visura, $id_ricerca, $index){ } + function getCatalog($ttr = 86400){ + return $this->connect("visure", "GET", NULL, $ttr); + } + } diff --git a/src/classes/exception/OpenApiUPException.php b/src/classes/exception/OpenApiUPException.php new file mode 100644 index 0000000..b80d6ed --- /dev/null +++ b/src/classes/exception/OpenApiUPException.php @@ -0,0 +1,14 @@ +validate = false; - if($recipient == NULL){ + if($recipient != NULL){ $this->createFromObject($recipient); } } public function createFromObject($object){ + if(is_array($object)){ + $object = (object)$object; + } + //var_dump($object);Exit; $this->data->title = isset($object->title)?$object->title:(isset($object->titolo)?$object->titolo:NULL); $this->data->at = isset($object->at)?$object->at:(isset($object->co)?$object->co:NULL); $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); @@ -58,9 +62,13 @@ public function createFromObject($object){ $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); - $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"Italia"); + $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"IT"); $this->data->email = isset($object->email)?$object->email:NULL; + $this->data->id = isset($object->id)?$object->id:NULL; + $this->data->state = isset($object->state)?$object->state:NULL; + + $this->itData->co = $this->data->at; $this->itData->titolo = $this->data->title; @@ -75,6 +83,8 @@ public function createFromObject($object){ $this->itData->provincia = $this->data->province; $this->itData->nazione = $this->data->country; $this->itData->email = $this->data->email; + $this->itData->id= $this->data->id; + $this->itData->state= $this->data->state; } diff --git a/src/classes/utility/UfficioPostale/Objects/Sender.php b/src/classes/utility/UfficioPostale/Objects/Sender.php index 8ec3690..b93ca55 100644 --- a/src/classes/utility/UfficioPostale/Objects/Sender.php +++ b/src/classes/utility/UfficioPostale/Objects/Sender.php @@ -18,7 +18,7 @@ function __construct($sender = NULL){ $this->data->city = NULL; $this->data->zip = NULL; $this->data->province = NULL; - $this->data->country = "Italia"; + $this->data->country = "IT"; $this->data->email = NULL; @@ -32,17 +32,21 @@ function __construct($sender = NULL){ $this->itData->comune = NULL; $this->itData->cap = NULL; $this->itData->provincia = NULL; - $this->itData->nazione = "Italia"; + $this->itData->nazione = "IT"; $this->itData->email = NULL; $this->validate = false; - if($sender == NULL){ + if($sender != NULL){ $this->createFromObject($sender); } } public function createFromObject($object){ + if(is_array($object)){ + $object = (object)$object; + } + // var_dump($object); $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); @@ -52,9 +56,9 @@ public function createFromObject($object){ $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); - $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"Italia"); + $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"IT"); $this->data->email = isset($object->email)?$object->email:NULL; - + // var_dump($this->data);exit; $this->itData->nome = $this->data->firstName; $this->itData->cognome = $this->data->secondName; @@ -182,7 +186,7 @@ public function validate(){ "code"=> "required", "text"=>"zip field is required" ]; - } else if($this->data->country == "Italia" || $this->data->country == "Italy"){ + } else if($this->data->country == "Italia" || $this->data->country == "Italy" || $this->data->country == "IT"){ $re = '/^\d{5}$/'; preg_match($re, $this->data->zip, $matches, PREG_OFFSET_CAPTURE, 0); if(count($matches) == 0){ diff --git a/src/classes/utility/UfficioPostale/Raccomandata.php b/src/classes/utility/UfficioPostale/Raccomandata.php index c551100..61ffce4 100644 --- a/src/classes/utility/UfficioPostale/Raccomandata.php +++ b/src/classes/utility/UfficioPostale/Raccomandata.php @@ -5,5 +5,53 @@ class Raccomandata extends ServiziPostali { function __construct($connect){ parent::__construct($connect); } + + function confirm(){ + if($this->getId() == NULL){ + throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + } + if($this->getState() != "NEW"){ + throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + } + $param['confirmed'] = TRUE; + $ret = call_user_func_array($this->connect,["raccomandate/".$this->getId(),"PATCH",$param]); + + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + + } + + function send(){ + $object = new \stdClass();; + $object->mittente = $this->sender->getObject(TRUE); + $object->destinatari = []; + foreach($this->getRecpients() as $r){ + $object->destinatari[] = $r->getObject(TRUE); + } + $object->documento =$this->documents; + $object->opzioni = new \stdClass(); + $object->opzioni->fronteretro = $this->getFronteRetro(); + $object->opzioni->colori = $this->getColori(); + $object->opzioni->ar = $this->getAR(); + $object->opzioni->autoconfirm = $this->getAutoconfirm(); + if($this->getCallback() != NULL){ + $callback = $this->getCallback(); + foreach($callback as $k => $v){ + $object->opzioni->$k = $v; + } + } + // var_dump($object);exit; + $ret = call_user_func_array($this->connect,["raccomandate/","POST",$object]); + $this->pricing = $ret->data[0]->pricing; + $this->id = $ret->data[0]->id; + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + //$ret= $this->connect->call($this,"raccomandate",$object,"POST"); + + } } \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/ServiziPostali.php b/src/classes/utility/UfficioPostale/ServiziPostali.php index efd2780..5dfc177 100644 --- a/src/classes/utility/UfficioPostale/ServiziPostali.php +++ b/src/classes/utility/UfficioPostale/ServiziPostali.php @@ -8,6 +8,15 @@ class ServiziPostali { protected $documents; protected $textMessage; protected $validRecipients; + protected $fronteretro; + protected $colori; + protected $ar; + protected $autoconfirm; + protected $pricing; + protected $id; + protected $confirmed; + protected $state; + protected $callback; function __construct($connect){ $this->connect = $connect; @@ -16,6 +25,61 @@ function __construct($connect){ $this->documents = []; $this->textMessage = NULL; $this->validRecipients = FALSE; + $this->fronteretro = FALSE; + $this->colori = FALSE; + $this->ar = FALSE; + $this->autoconfirm = FALSE; + $this->pricing = FALSE; + $this->id = FALSE; + $this->confirmed = FALSE; + $this->state = FALSE; + $this->callback = NULL; + } + + function getPricing(){ + return $this->pricing; + } + + function getId(){ + return $this->id; + } + + function getConfirmed(){ + return $this->confirmed; + } + + function getState(){ + return $this->state; + } + function setAutoconfirm($autoconfirm){ + $this->autoconfirm = $autoconfirm; + } + + function getAutoconfirm(){ + return $this->autoconfirm; + } + + function setColori($colori){ + $this->colori = $colori; + } + + function getColori(){ + return $this->colori; + } + function setFronteRetro($fronteretro){ + $this->fronteretro = $fronteretro; + } + + function getFronteRetro(){ + return $this->fronteretro; + } + + function setAR($ar){ + $this->ar = $ar; + } + + function getAR(){ + return $this->ar; } @@ -26,6 +90,7 @@ public function setSender($sender){ $this->sender = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($sender); } if(!$this->sender->validate()){ + // var_dump($this->sender->getErrors()); return FALSE; } return TRUE; @@ -75,21 +140,23 @@ public function setRecipients($recipients){ if(!$recipient->validate()){ $valid = FALSE; } - $this->recipient[] = $recipient; + $this->recipients[] = $recipient; } $this->validRecipients = $valid; return $valid; } public function addRecipient($recipient){ + if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); } + $valid = TRUE; if(!$recipient->validate()){ $valid = FALSE; } - $this->recipient[] = $recipient; + $this->recipients[] = $recipient; $this->validRecipients = $valid; return $valid; } @@ -109,4 +176,18 @@ public function addDocument($document){ public function clearDocuments(){ $this->documents = []; } + + public function setCallback($url, $custom = NULL,$callback_field = NULL){ + $callback = new \stdClass(); + $callback->callback_url = $url; + $callback->custom = $custom; + if($callback_field != NULL){ + $callback->callback_field = $callback_field; + } + $this->callback = $callback; + } + + public function getCallback(){ + return $this->callback; + } } \ No newline at end of file diff --git a/src/classes/utility/VisEngine/VisRequest.php b/src/classes/utility/VisEngine/VisRequest.php index 50af857..447219b 100644 --- a/src/classes/utility/VisEngine/VisRequest.php +++ b/src/classes/utility/VisEngine/VisRequest.php @@ -22,18 +22,20 @@ function __construct($visura) $this->ricerche = []; $this->document = NULL; $this->format_errror = []; - $this->fornitore = []; + $this->opzioni = null; foreach($visura->data->json_struttura->campi as $k => $v){ $this->variables[$k] = FALSE; } } - function setFornitore($fornitore){ - $this->fornitore = $fornitore; + function setOpzioni($opzioni){ + $this->opzioni = $opzioni; } - function getFornitore(){ - return $this->fornitore; + + function getOpzioni(){ + return $this->opzioni; } + function setNew(bool $new){ return $this->new = $new; } @@ -170,6 +172,12 @@ function getSearchId(){ } return $this->ricerche[count($this->ricerche) - 1]->id_ricerca; } + function getSearch(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return $this->ricerche[count($this->ricerche) - 1]; + } function getSearchCount(){ return count($this->ricerche); From 5e1289e81c144d693c010e79379a07251347d9d6 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Wed, 16 Jun 2021 14:20:09 +0200 Subject: [PATCH 20/85] Implementate ultime versioni API --- composer.json | 38 +- readme.md | 102 +-- src/OpenApi.php | 764 +++++++++--------- src/classes/FirmaDigitale.php | 13 + src/classes/Imprese.php | 244 +++--- src/classes/OpenApiBase.php | 412 +++++----- src/classes/Pec.php | 31 + src/classes/PecMassiva.php | 152 ++-- src/classes/UfficioPostale.php | 84 +- src/classes/Uploader.php | 43 +- src/classes/VisEngine.php | 110 +-- .../exception/OpenApiConnectionsException.php | 32 +- .../exception/OpenApiExceptionBase.php | 130 +-- .../exception/OpenApiPecMassivaException.php | 28 +- .../exception/OpenApiTokenException.php | 30 +- src/classes/utility/DummyCache.php | 44 +- .../UfficioPostale/Objects/Recipient.php | 29 + .../utility/UfficioPostale/Raccomandata.php | 26 + .../utility/UfficioPostale/ServiziPostali.php | 9 + src/classes/utility/Uploader/Collection.php | 17 + 20 files changed, 1241 insertions(+), 1097 deletions(-) create mode 100644 src/classes/Pec.php diff --git a/composer.json b/composer.json index e91e179..51fc60f 100644 --- a/composer.json +++ b/composer.json @@ -1,19 +1,19 @@ -{ - "name": "altravia/openapi", - "description": "OpenApi PHP Libraries (https://openapi.it)", - "authors": [ - { - "name": "Altravia", - "email": "info@altravia.com" - } - ], - "minimum-stability": "stable", - "require": { - "php": ">=7.2.0" - }, - "autoload": { - "psr-4": { - "OpenApi\\": "src" - } - } -} +{ + "name": "altravia/openapi", + "description": "OpenApi PHP Libraries (https://openapi.it)", + "authors": [ + { + "name": "Altravia", + "email": "info@altravia.com" + } + ], + "minimum-stability": "stable", + "require": { + "php": ">=7.2.0" + }, + "autoload": { + "psr-4": { + "OpenApi\\": "src" + } + } +} diff --git a/readme.md b/readme.md index c4f92d6..c6a0a76 100644 --- a/readme.md +++ b/readme.md @@ -1,51 +1,51 @@ -# OpenAPI Library - -## Usage - -### Instanza della classe - -``` - $this->openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); -``` - -Dove ```$scopes``` è un array di stringhe o di oggetti in uno dei seguenti formati: - -```php -$scopes=[ -"GET:ws.ufficiopostale.com/comuni", -["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] -]; -``` - -A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: - -```php -$this->openapi->ufficiopostale -$this->openapi->imprese -... -``` - -che possono essere usati al seguente modo: - -```php -$this->openapi->ufficioposale->getCitiesByCap('00132'); -``` - -# Modulo ufficio postale - -# Modulo visure - -# Modulo imprese - -## `getByPartitaIva` - -### Introduction - -La funzione consente di recuperare i dati aziendali a partire dalla partita IVA - -### Description - -`function getByPartitaIva(string $partitaIva, $ttl = 86400):object` - -* $partitaIva: La partita IVA da cercare -* $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta +# OpenAPI Library + +## Usage + +### Instanza della classe + +``` + $this->openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); +``` + +Dove ```$scopes``` è un array di stringhe o di oggetti in uno dei seguenti formati: + +```php +$scopes=[ +"GET:ws.ufficiopostale.com/comuni", +["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] +]; +``` + +A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: + +```php +$this->openapi->ufficiopostale +$this->openapi->imprese +... +``` + +che possono essere usati al seguente modo: + +```php +$this->openapi->ufficioposale->getCitiesByCap('00132'); +``` + +# Modulo ufficio postale + +# Modulo visure + +# Modulo imprese + +## `getByPartitaIva` + +### Introduction + +La funzione consente di recuperare i dati aziendali a partire dalla partita IVA + +### Description + +`function getByPartitaIva(string $partitaIva, $ttl = 86400):object` + +* $partitaIva: La partita IVA da cercare +* $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta diff --git a/src/OpenApi.php b/src/OpenApi.php index ba80854..89a6d44 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -1,380 +1,384 @@ -"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] oppure "GET:ws.ufficiopostale.com/comuni NOTA: il dominio NON deve mai avere lo stage - * @param string $username Username openapi - * @param string $apikey ApiKey openapi - * @param mixed $environment='test' uno tra: dev, test (default), production - */ - function __construct(array $scopes, string $username, string $apikey, $environment='test', $store = NULL){ - if($store == NULL) { - $store = new \OpenApi\classes\utility\sessionStoreToken; - } - $this->cache = new \OpenApi\classes\utility\DummyCache; - $this->store = $store; - $this->header = null; - $this->rawResponse = null; - $realScopes = []; - $domainsRealScopes = []; - $prefix = $environment=="production"?"":$environment."."; - $domains = []; - //var_dump($scopes);exit; - foreach($scopes as $s){ - if($s == NULL){ - continue; - } - if(is_array($s)){ - $domain = $s['domain']; - $realScope = $s['mode'].":".$prefix.$s['domain']."/".$s['method']; - }else{ - $realScope = str_replace(":",":{$prefix}", $s) ; - $domain = explode(":", $s)[1]; - $domain = explode("/", $domain)[0]; - } - if(!in_array($domain, $domains)){ - $domains[] = $domain; - $domainsRealScopes[$domain] = []; - } - - if(!in_array($realScope,$realScopes)){ - $realScopes[] = $realScope; - $domainsRealScopes[$domain][] = $realScope; - } - - } - - $this->username = $username; - $this->apikey = $apikey; - $this->prefix = $prefix; - $this->scopes = $realScopes; - $token = $this->getToken(); - - list($moduli,$nomi) = $this->getListaModuli(); - $this->clients = []; - foreach($domains as $d){ - if(isset($moduli[$d])){ - $modulo = $moduli[$d]; - $nome = $nomi[$d]; - $this->$nome = new $modulo($token->token, $domainsRealScopes[$d], $this->cache, $prefix); - $this->clients[] = $nome; - } - } - - $this->validations = new \OpenApi\classes\utility\Plugins\Validations(); - $this->fiscalCode = new \OpenApi\classes\utility\Plugins\FiscalCode(); - //$this->geocoding = new \OpenApi\classes\Geocoding($token->token, [], $this->cache, ""); - } - - /** - * - * Restituisce la lista dei moduli disponibili - * - * @return array - */ - private function getListaModuli(){ - $moduli = []; - $nomi = []; - $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; - $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; - $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; - $nomi['imprese.altravia.com'] = "imprese"; - - $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; - $nomi['visengine2.altravia.com'] = "visengine"; - - - $moduli['comuni.openapi.it'] = "\\OpenApi\\classes\\Comuni"; - $nomi['comuni.openapi.it'] = "comuni"; - - - $moduli['ws.marchetemporali.com'] = "\\OpenApi\\classes\\MarcheTemporali"; - $nomi['ws.marchetemporali.com'] = "marcheTemporali"; - - - $moduli['geocoding.realgest.it'] = "\\OpenApi\\classes\\Geocoding"; - $nomi['geocoding.realgest.it'] = "geocoding"; - - $moduli['ws.messaggisms.com'] = "\\OpenApi\\classes\\Sms"; - $nomi['ws.messaggisms.com'] = "SMS"; - - - $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; - $nomi['ws.firmadigitale.com'] = "firmaDigitale"; - - $moduli['ws.pecmassiva.com'] = "\\OpenApi\\classes\\PecMassiva"; - $nomi['ws.pecmassiva.com'] = "pecMassiva"; - - $moduli['uploader.altravia.com'] = "\\OpenApi\\classes\\Uploader"; - $nomi['uploader.altravia.com'] = "uploader"; - return array($moduli,$nomi); - } - - /** - * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) - * - * @param mixed $cacheSys Istanza della classe da usare come sistema di cache - * @return void - */ - function setCacheSystem($cacheSys){ - $this->cache = $cacheSys; - foreach($this->clients as $c){ - $this->$c->setCacheSystem($cacheSys); - } - } - - - /** - * - * Restituisce il token attualemnte in sessione, se non presente o non più valido lo rigenera - * - * @param boolean $force=FALSE Se impostato a TRUE forza la rigenerazione del token - * @return object il token - */ - function getToken($force=FALSE){ - if(!$force && !$this->isTokenCompatible()){ - - if(!$this->mustRfreshToken()){ - return $this->store->get()['token']; - } - $this->renewToken(); - - return $this->store->get()['token']; - } - if($this->getOldToken()){ - if(!$this->mustRfreshToken()){ - return $this->store->get()['token']; - } - $this->renewToken(); - return $this->store->get()['token']; - } - return $this->generateNewToken(); - } - - - /** - * Rinnova il token in sessione - * - * @return object - */ - private function renewToken(){ - $param = ["expire" => time() + 86400, "scopes" => $this->scopes]; - //var_dump($param);exit; - - $token = $this->connect("token/".$this->store->get()['token']->token,$param,"PUT"); - - if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("Renew Token: Connection Error",40001); - } - if($token->success == false){ - $message = "REnew Token: unknow error"; - if(isset($token->message)) { - $message = "REnew Token: $token->message"; - } - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); - $except->setServerResponse($token, $this->header, $this->rawResponse); - - throw $except; - } - if(isset($token->data) && isset($token->data[0])) - { - $token = $token->data[0]; - $this->store->get()['token'] = $token; - return $token; - } - - } - - - /** - * Controlla se il token in sessione deve essere o meno rinnovato in base alla sua data di scadenza - * - * @return bool - */ - private function mustRfreshToken(){ - $token = $this->store->get()['token']; - $diff = $token->expire-date("U"); - if($diff <= 6000){ - return TRUE; - } - return FALSE; - } - - - /** - * - * Recupera la lista di token per verificare se esiste uno utilizzabile con gli scopes di interesse, - * se si lo mette in sessione e ritorna TRUE - * - * @return boolean - */ - function getOldToken(){ - $param = ["scope" => $this->scopes]; - $token = $this->connect("token",$param,"GET"); - - $finded_token = NULL; - - if($token != NULL && isset($token->data)){ - foreach($token->data AS $token){ - if($this->hasValidScopes($token)){ - $finded_token = $token; - break 1; - } - } - - if($finded_token != NULL){ - $tostore['token'] = $finded_token; - $tostore['apikey'] = $this->apikey; - $tostore['scopes'] = serialize($this->scopes); - $tostore['username'] = $this->username; - $tostore['prefix'] = $this->prefix; - $this->store->save($tostore); - return TRUE; - } - return FALSE; - } - } - - function hasValidScopes($token){ - foreach($this->scopes as $s){ - if(!in_array($s, $token->scopes)){ - return false; - } - } - return true; - } - - /** - * Genera un nuovo token - * @return object il token - */ - private function generateNewToken(){ - $param = ["scopes" => $this->scopes]; - $token = $this->connect("token",$param,"POST"); - if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("Getting Token: Connection Error",40001); - } - if($token->success == false){ - $message = "Getting Token: unknow error"; - if(isset($token->message)) { - $message = "Getting Token: $token->message"; - } - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); - $except->setServerResponse($token, $this->header, $this->rawResponse); - - throw $except; - } - - $invalid_scopes = []; - foreach($this->scopes as $s){ - if(!in_array($s, $token->scopes)){ - $invalid_scopes[] = $s; - } - } - if(count($invalid_scopes)>0){ - $message = "Getting Token: unknow error"; - if(isset($token->message)) { - - } - $message = "Getting Token: invalid scopes (".implode($invalid_scopes).")"; - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40003); - $except->setServerResponse($token, $this->header, $this->rawResponse); - throw $except; - } - $tostore['token'] = $token; - $tostore['apikey'] = $this->apikey; - $tostore['scopes'] = serialize($this->scopes); - $tostore['username'] = $this->username; - $tostore['prefix'] = $this->prefix; - - $this->store->save($tostore); - - return $token; - } - - - /** - * - * Constrolla se il token in sessione è compatibile con la richiesta - * - * @return boolean - */ - private function isTokenCompatible() { - if(!$this->store->isset()|| !isset($this->store->get()['token'])){ - return TRUE; - } - if($this->store->get()['prefix'] != $this->prefix || $this->store->get()['apikey'] != $this->apikey || $this->store->get()['username'] != $this->username){ - return TRUE; - } - $sessionScopes = unserialize($this->store->get()['scopes']); - if(!is_array($sessionScopes)){ - return TRUE; - } - foreach($this->scopes as $s){ - if(!in_array($s, $sessionScopes)){ - return TRUE; - } - } - return FALSE; - } - - - /** - * Effettua una connessione al server oauth - * - * @param string $endpoint path da recuperare - * @param array $param Lista dei parametri da passare - * @param mixed $mode metodo http da usare per la chiamata - * @return object - */ - private function connect(string $endpoint, $param = [], $mode="POST"){ - - $this->header = null; - $this->rawResponse = null; - $basePath = "https://".$this->prefix."oauth.altravia.com"; - $url = $basePath."/".$endpoint; - if($mode == "GET") - { - $param = http_build_query($param); - $param = preg_replace('/(%5B)\d+(%5D=)/i', '$1$2', $param); - $url .= "?".$param; - } - - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mode); - if($mode == "POST" || $mode == "PUT") - { - curl_setopt($ch, CURLOPT_POST, TRUE); - } - if($mode != "GET") - { - $param = json_encode($param); - - curl_setopt($ch, CURLOPT_POSTFIELDS, $param); - } - - $baseauth = base64_encode($this->username.":".$this->apikey); - $headers = array( - 'Content-Type:application/json', - 'Authorization: Basic '. $baseauth - ); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - - - curl_setopt($ch, CURLOPT_TIMEOUT, 30); - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_HEADER, 1); - $response = curl_exec($ch); - $this->rawResponse = $response; - - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $this->header = substr($response, 0, $header_size); - $return = substr($response, $header_size); - curl_close($ch); - return json_decode($return); - } -} +"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] oppure "GET:ws.ufficiopostale.com/comuni NOTA: il dominio NON deve mai avere lo stage + * @param string $username Username openapi + * @param string $apikey ApiKey openapi + * @param mixed $environment='test' uno tra: dev, test (default), production + */ + function __construct(array $scopes, string $username, string $apikey, $environment='test', $store = NULL){ + if($store == NULL) { + $store = new \OpenApi\classes\utility\sessionStoreToken; + } + $this->cache = new \OpenApi\classes\utility\DummyCache; + $this->store = $store; + $this->header = null; + $this->rawResponse = null; + $realScopes = []; + $domainsRealScopes = []; + $prefix = $environment=="production"?"":$environment."."; + $domains = []; + //var_dump($scopes);exit; + foreach($scopes as $s){ + if($s == NULL){ + continue; + } + if(is_array($s)){ + $domain = $s['domain']; + $realScope = $s['mode'].":".$prefix.$s['domain']."/".$s['method']; + }else{ + $realScope = str_replace(":",":{$prefix}", $s) ; + $domain = explode(":", $s)[1]; + $domain = explode("/", $domain)[0]; + } + if(!in_array($domain, $domains)){ + $domains[] = $domain; + $domainsRealScopes[$domain] = []; + } + + if(!in_array($realScope,$realScopes)){ + $realScopes[] = $realScope; + $domainsRealScopes[$domain][] = $realScope; + } + + } + + $this->username = $username; + $this->apikey = $apikey; + $this->prefix = $prefix; + $this->scopes = $realScopes; + $token = $this->getToken(); + /* + if($_SERVER['REMOTE_ADDR'] == "37.163.55.217"){ + var_dump($token);exit; + } + */ + //var_dump($token); + list($moduli,$nomi) = $this->getListaModuli(); + $this->clients = []; + foreach($domains as $d){ + if(isset($moduli[$d])){ + $modulo = $moduli[$d]; + $nome = $nomi[$d]; + $this->$nome = new $modulo($token->token, $domainsRealScopes[$d], $this->cache, $prefix); + $this->clients[] = $nome; + } + } + + $this->validations = new \OpenApi\classes\utility\Plugins\Validations(); + $this->fiscalCode = new \OpenApi\classes\utility\Plugins\FiscalCode(); + // $this->ufficiopostale = new \OpenApi\classes\UfficioPostale($token->token, $domainsRealScopes[$d], $this->cache, $prefix); + } + + /** + * + * Restituisce la lista dei moduli disponibili + * + * @return array + */ + private function getListaModuli(){ + $moduli = []; + $nomi = []; + $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; + $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; + + $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; + $nomi['imprese.altravia.com'] = "imprese"; + + $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; + $nomi['visengine2.altravia.com'] = "visengine"; + + + $moduli['comuni.openapi.it'] = "\\OpenApi\\classes\\Comuni"; + $nomi['comuni.openapi.it'] = "comuni"; + + + $moduli['ws.marchetemporali.com'] = "\\OpenApi\\classes\\MarcheTemporali"; + $nomi['ws.marchetemporali.com'] = "marcheTemporali"; + + + $moduli['geocoding.realgest.it'] = "\\OpenApi\\classes\\Geocoding"; + $nomi['geocoding.realgest.it'] = "geocoding"; + + $moduli['uploader.altravia.com'] = "\\OpenApi\\classes\\Uploader"; + $nomi['uploader.altravia.com'] = "uploader"; + + $moduli['ws.messaggisms.com'] = "\\OpenApi\\classes\\Sms"; + $nomi['ws.messaggisms.com'] = "SMS"; + + $moduli['pec.openapi.it'] = "\\OpenApi\\classes\\Pec"; + $nomi['pec.openapi.it'] = "PEC"; + $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; + $nomi['ws.firmadigitale.com'] = "firmaDigitale"; + return array($moduli,$nomi); + } + + /** + * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende + * {@see OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) + * + * @param mixed $cacheSys Istanza della classe da usare come sistema di cache + * @return void + */ + function setCacheSystem($cacheSys){ + $this->cache = $cacheSys; + foreach($this->clients as $c){ + $this->$c->setCacheSystem($cacheSys); + } + } + + + /** + * + * Restituisce il token attualemnte in sessione, se non presente o non più valido lo rigenera + * + * @param boolean $force=FALSE Se impostato a TRUE forza la rigenerazione del token + * @return object il token + */ + function getToken($force=FALSE){ + if(!$force && !$this->isTokenCompatible()){ + + if(!$this->mustRfreshToken()){ + return $this->store->get()['token']; + } + $this->renewToken(); + + return $this->store->get()['token']; + } + if($this->getOldToken()){ + if(!$this->mustRfreshToken()){ + return $this->store->get()['token']; + } + $this->renewToken(); + return $this->store->get()['token']; + } + return $this->generateNewToken(); + } + + + /** + * Rinnova il token in sessione + * + * @return object + */ + private function renewToken(){ + $param = ["expire" => time() + 86400, "scopes" => $this->scopes]; + //var_dump($param);exit; + + $token = $this->connect("token/".$this->store->get()['token']->token,$param,"PUT"); + + if($token == NULL){ + throw new \OpenApi\classes\exception\OpenApiTokenException("Renew Token: Connection Error",40001); + } + if($token->success == false){ + $message = "REnew Token: unknow error"; + if(isset($token->message)) { + $message = "REnew Token: $token->message"; + } + $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); + $except->setServerResponse($token, $this->header, $this->rawResponse); + + throw $except; + } + if(isset($token->data) && isset($token->data[0])) + { + $token = $token->data[0]; + $this->store->get()['token'] = $token; + return $token; + } + + } + + + /** + * Controlla se il token in sessione deve essere o meno rinnovato in base alla sua data di scadenza + * + * @return bool + */ + private function mustRfreshToken(){ + $token = $this->store->get()['token']; + $diff = $token->expire-date("U"); + if($diff <= 6000){ + return TRUE; + } + return FALSE; + } + + + /** + * + * Recupera la lista di token per verificare se esiste uno utilizzabile con gli scopes di interesse, + * se si lo mette in sessione e ritorna TRUE + * + * @return boolean + */ + function getOldToken(){ + $param = ["scope" => $this->scopes]; + $token = $this->connect("token",$param,"GET"); + + $finded_token = NULL; + + if($token != NULL && isset($token->data)){ + foreach($token->data AS $token){ + if($this->hasValidScopes($token)){ + $finded_token = $token; + break 1; + } + } + + if($finded_token != NULL){ + $tostore['token'] = $finded_token; + $tostore['apikey'] = $this->apikey; + $tostore['scopes'] = serialize($this->scopes); + $tostore['username'] = $this->username; + $tostore['prefix'] = $this->prefix; + $this->store->save($tostore); + return TRUE; + } + return FALSE; + } + } + + function hasValidScopes($token){ + foreach($this->scopes as $s){ + if(!in_array($s, $token->scopes)){ + return false; + } + } + return true; + } + + /** + * Genera un nuovo token + * @return object il token + */ + private function generateNewToken(){ + $param = ["scopes" => $this->scopes]; + $token = $this->connect("token",$param,"POST"); + if($token == NULL){ + throw new \OpenApi\classes\exception\OpenApiTokenException("Getting Token: Connection Error",40001); + } + if($token->success == false){ + $message = "Getting Token: unknow error"; + if(isset($token->message)) { + $message = "Getting Token: $token->message"; + } + $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); + $except->setServerResponse($token, $this->header, $this->rawResponse); + + throw $except; + } + + $invalid_scopes = []; + foreach($this->scopes as $s){ + if(!in_array($s, $token->scopes)){ + $invalid_scopes[] = $s; + } + } + if(count($invalid_scopes)>0){ + $message = "Getting Token: unknow error"; + if(isset($token->message)) { + + } + $message = "Getting Token: invalid scopes (".implode($invalid_scopes).")"; + $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40003); + $except->setServerResponse($token, $this->header, $this->rawResponse); + throw $except; + } + $tostore['token'] = $token; + $tostore['apikey'] = $this->apikey; + $tostore['scopes'] = serialize($this->scopes); + $tostore['username'] = $this->username; + $tostore['prefix'] = $this->prefix; + + $this->store->save($tostore); + + return $token; + } + + + /** + * + * Constrolla se il token in sessione è compatibile con la richiesta + * + * @return boolean + */ + private function isTokenCompatible() { + if(!$this->store->isset()|| !isset($this->store->get()['token'])){ + return TRUE; + } + if($this->store->get()['prefix'] != $this->prefix || $this->store->get()['apikey'] != $this->apikey || $this->store->get()['username'] != $this->username){ + return TRUE; + } + $sessionScopes = unserialize($this->store->get()['scopes']); + if(!is_array($sessionScopes)){ + return TRUE; + } + foreach($this->scopes as $s){ + if(!in_array($s, $sessionScopes)){ + return TRUE; + } + } + return FALSE; + } + + + /** + * Effettua una connessione al server oauth + * + * @param string $endpoint path da recuperare + * @param array $param Lista dei parametri da passare + * @param mixed $mode metodo http da usare per la chiamata + * @return object + */ + private function connect(string $endpoint, $param = [], $mode="POST"){ + + $this->header = null; + $this->rawResponse = null; + $basePath = "https://".$this->prefix."oauth.altravia.com"; + $url = $basePath."/".$endpoint; + if($mode == "GET") + { + $param = http_build_query($param); + $param = preg_replace('/(%5B)\d+(%5D=)/i', '$1$2', $param); + $url .= "?".$param; + } + + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mode); + if($mode == "POST" || $mode == "PUT") + { + curl_setopt($ch, CURLOPT_POST, TRUE); + } + if($mode != "GET") + { + $param = json_encode($param); + + curl_setopt($ch, CURLOPT_POSTFIELDS, $param); + } + + $baseauth = base64_encode($this->username.":".$this->apikey); + $headers = array( + 'Content-Type:application/json', + 'Authorization: Basic '. $baseauth + ); + curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); + + + curl_setopt($ch, CURLOPT_TIMEOUT, 30); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_HEADER, 1); + $response = curl_exec($ch); + $this->rawResponse = $response; + + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $this->header = substr($response, 0, $header_size); + $return = substr($response, $header_size); + curl_close($ch); + return json_decode($return); + } +} diff --git a/src/classes/FirmaDigitale.php b/src/classes/FirmaDigitale.php index 9e2abc0..f0ed548 100644 --- a/src/classes/FirmaDigitale.php +++ b/src/classes/FirmaDigitale.php @@ -71,8 +71,21 @@ function requestProduct($data){ if($callback != NULL){ $params['callback'] = $callback; } + if(isset($data['options'])){ + foreach($data['options'] as $key =>$value){ + $params[$key] = $value; + } + } +//var_dump(json_encode($params));exit; + $ret = $this->connect("richiesta/$codice_prodotto","POST",$params); return $ret; } + function addVideoRiconoscimento($id_fd){ + $param['id'] = $id_fd; + $ret = $this->connect("richiesta/VIDEORIC","POST",$param); + return $ret; + } + } \ No newline at end of file diff --git a/src/classes/Imprese.php b/src/classes/Imprese.php index 22255ab..c4fa12f 100644 --- a/src/classes/Imprese.php +++ b/src/classes/Imprese.php @@ -1,122 +1,124 @@ -basePath = "https://imprese.altravia.com"; - } - - /** - * - * Consente di recuperare i dati di una azienda a partire dalla partita IVA - * - * @param string $partitaIva La partita IVa da ricercare - * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta - * - * @return object - */ - function getByPartitaIva(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("advance/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - - - } - - function getClosed(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - function getVatGroup(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - function getPec(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - /** - * - * Cerca un'azienda o più utilizzando vari parametri - * - * @param string $denominazione Denominazione azienda - * @param string $provincia Provincia - * @param string $partitaIva=NULL Partita IVA - * @param string $codiceFiscale=NULL Codice Fiscale - * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta - * - * @return array Lista delle aziende individuate - */ - function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ - $params=[]; - if($denominazione != NULL){ - $params['denominazione'] = trim($denominazione); - } - if($provincia != NULL){ - $params['provincia'] = $provincia; - } - if($partitaIva != NULL){ - $params['piva'] = $partitaIva; - } - if($codiceFiscale != NULL){ - $params['cf'] = $codiceFiscale; - } - - $data = $this->connect("advance/$partitaIva", "GET", $params, $ttr); - return $data->data; - } +basePath = "https://imprese.altravia.com"; + } + + /** + * + * Consente di recuperare i dati di una azienda a partire dalla partita IVA + * + * @param string $partitaIva La partita IVa da ricercare + * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + * + * @return object + */ + function getByPartitaIva(string $partitaIva, $ttr = 86400, $force = false){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("advance/$partitaIva", "GET", [], $ttr, true); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + + + } + + function getClosed(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + function getVatGroup(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + function getPec(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + /** + * + * Cerca un'azienda o più utilizzando vari parametri + * + * @param string $denominazione Denominazione azienda + * @param string $provincia Provincia + * @param string $partitaIva=NULL Partita IVA + * @param string $codiceFiscale=NULL Codice Fiscale + * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + * + * @return array Lista delle aziende individuate + */ + function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ + $params=[]; + if($denominazione != NULL){ + $params['denominazione'] = trim($denominazione); + } + if($provincia != NULL){ + $params['provincia'] = $provincia; + } + if($partitaIva != NULL){ + $params['piva'] = $partitaIva; + } + if($codiceFiscale != NULL){ + $params['cf'] = $codiceFiscale; + } + + $data = $this->connect("advance/$partitaIva", "GET", $params, $ttr); + return $data->data; + } } \ No newline at end of file diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php index 4c014d6..705bec4 100644 --- a/src/classes/OpenApiBase.php +++ b/src/classes/OpenApiBase.php @@ -1,205 +1,209 @@ -token = $token; - $this->cache = $cache; - $this->scopes = $scopes; - $this->prefix = $prefix; - $this->basePath = null; - } - - /** - * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see \OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) - * - * @param object $cacheSys Istanza della classe da usare come sistema di cache - * @return void - */ - function setCacheSystem(object $cacheSys){ - $this->cache = $cacheSys; - } - - - - /** - * Salva un oggetto nella cache - * @param string $key LA chiave utilizzata per salvare l'oggetto nella cache - * @param object $value L'oggetto da salvare nella cache - * @param int $ttr TEmpo in cui l'oggetto resta in cache - * - * @return void - */ - protected function setCacheObject(string $key, object $value, int $ttr){ - $ttr += rand ( 0 , 120 ); - $this->cache->save($key, $value, $ttr); - } - - /** - * - * Recupera un oggetto dalla cache se presente - * - * @param string $key LA chiave da utilizzare per recuperare l'oggetto in cache - * - * @return mixed L'oggetto o NUL se insesistente - */ - protected function getCacheObject(string $key){ - $cached = $this->cache->get($key); - if($cached){ - return $cached; - } - return false; - } - - /** - * - * Controlla se si ha lo scope necessario per poter invocare il metodo, in caso contrario scatena un'eccezione - * - * @param string $url - * - * @return void - */ - private function checkHasScope(string $url, string $type){ - $parsed = parse_url($url); - $permission = $type.":".$parsed['host']; - $path = $parsed['path']; - $path = explode("/", $path); - if(isset($path[1])){ - $permission .= "/".$path[1]; - } - if(!in_array($permission, $this->scopes)){ - throw new \OpenApi\classes\exception\OpenApiConnectionsException("Scope missed: $permission",40004); - } - - } - - /** - * @param string $endpoint Endpoint da richiamare - * @param string $type Tipo di chiamata - * @param array $param Parametri da passare alla chiamata - * @param int $ttr Tempo in cui la chiamata resta in cache (0 = no cache) - * - * @return mixed - */ - public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $addHeader = NULL){ - $url = $this->basePath; - $url = str_replace("https://","https://".$this->prefix,$url); - $url = str_replace("http://","http://".$this->prefix,$url); - $url .= "/".$endpoint; - if(!$force){ - $this->checkHasScope($url, $type); - } - - - if($type == "GET" && $ttr > 0 && $ret = $this->getCacheObject($url)) { - return $ret; - } - $ch = curl_init(); - if($type == "POST" || $type == "PUT") { - curl_setopt($ch, CURLOPT_POST, TRUE); - } - if($param != array()) { - if($type == "GET") { - $param = http_build_query($param); - $url .= "?".$param; - - }else{ - $param = json_encode($param); - curl_setopt($ch, CURLOPT_POSTFIELDS, $param); - } - } - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type); - $header = array("Authorization: Bearer ".$this->token); - if($addHeader != NULL && is_array($addHeader) && count($addHeader)>0){ - $header = array_merge($header, $addHeader); - } - - - curl_setopt($ch,CURLOPT_HTTPHEADER,$header); - curl_setopt($ch, CURLOPT_HEADER, 1); - $response = curl_exec($ch); - // var_dump($response);exit; - $this->rawResponse = $response; - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $this->header = substr($response, 0, $header_size); - //var_dump($this->header);exit; - $this->parsedHEader = $this->parseHeader($this->header); - $return = substr($response, $header_size); - $httpCode = curl_getinfo ( $ch, CURLINFO_RESPONSE_CODE );; - curl_close($ch); - //echo $return;exit; - if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { - - $data = json_decode($return); - }else if(json_decode($return) != NULL){ - $data = json_decode($return); - - }else{ - $data = $return; - } - - if($data == NULL){ - throw new \OpenApi\classes\exception\OpenApiConnectionsException("Connection to $url: Connection Error",40001); - } - - if(is_object($data) && $data->success == false){ - $message = "Connection to $url: unknow error"; - if(isset($data->message)) { - if(is_string(($data->message))){ - if($dataMessage = json_decode($data->message)){ - $data = $dataMessage; - } - $message = "Connection to $url: $data->message"; - }else{ - $message = "Connection to $url error"; - } - - - } - //var_dump($this->rawResponse); - $except = new \OpenApi\classes\exception\OpenApiConnectionsException($message,40002); - $except->setServerResponse($data, $this->header, $this->rawResponse, $httpCode); - - throw $except; - } - if($type == "GET" && $ttr > 0) { - $this->setCacheObject($url, $data, $ttr); - } - return $data; - } - - protected function parseHeader($headers){ - $headers = explode("\n",$headers); - $parsedHeaders = array(); - foreach ($headers as $header) { - $header = trim($header); - - $header = explode(":",$header); - - if(count($header) < 2){ - - continue; - } - $key = $header[0]; - unset($header[0]); - $parsedHeaders[trim($key)] = trim(implode(":",$header)); - } - // exit; - - return $parsedHeaders; - } - - - - +token = $token; + $this->cache = $cache; + $this->scopes = $scopes; + $this->prefix = $prefix; + $this->basePath = null; + } + + /** + * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende + * {@see \OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) + * + * @param object $cacheSys Istanza della classe da usare come sistema di cache + * @return void + */ + function setCacheSystem(object $cacheSys){ + $this->cache = $cacheSys; + } + + + + /** + * Salva un oggetto nella cache + * @param string $key LA chiave utilizzata per salvare l'oggetto nella cache + * @param object $value L'oggetto da salvare nella cache + * @param int $ttr TEmpo in cui l'oggetto resta in cache + * + * @return void + */ + protected function setCacheObject(string $key, object $value, int $ttr){ + $ttr += rand ( 0 , 120 ); + $this->cache->save($key, $value, $ttr); + } + + /** + * + * Recupera un oggetto dalla cache se presente + * + * @param string $key LA chiave da utilizzare per recuperare l'oggetto in cache + * + * @return mixed L'oggetto o NUL se insesistente + */ + protected function getCacheObject(string $key){ + $cached = $this->cache->get($key); + if($cached){ + return $cached; + } + return false; + } + + /** + * + * Controlla se si ha lo scope necessario per poter invocare il metodo, in caso contrario scatena un'eccezione + * + * @param string $url + * + * @return void + */ + private function checkHasScope(string $url, string $type){ + $parsed = parse_url($url); + $permission = $type.":".$parsed['host']; + $path = $parsed['path']; + $path = explode("/", $path); + if(isset($path[1])){ + $permission .= "/".$path[1]; + } + if(!in_array($permission, $this->scopes)){ + throw new \OpenApi\classes\exception\OpenApiConnectionsException("Scope missed: $permission",40004); + } + + } + + /** + * @param string $endpoint Endpoint da richiamare + * @param string $type Tipo di chiamata + * @param array $param Parametri da passare alla chiamata + * @param int $ttr Tempo in cui la chiamata resta in cache (0 = no cache) + * + * @return mixed + */ + public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $addHeader = NULL){ + $url = $this->basePath; + //if($url != "https://imprese.altravia.com"){ + $url = str_replace("https://","https://".$this->prefix,$url); + $url = str_replace("http://","http://".$this->prefix,$url); + $url .= "/".$endpoint; + if(!$force){ + $this->checkHasScope($url, $type); + } + + + /* if($type == "GET" && $ttr > 0 && $ret = $this->getCacheObject($url)) { + return $ret; + }*/ + $ch = curl_init(); + if($type == "POST" || $type == "PUT") { + curl_setopt($ch, CURLOPT_POST, TRUE); + } + if($param != array()) { + if($type == "GET") { + $param = http_build_query($param); + $url .= "?".$param; + + }else{ + $param = json_encode($param); + curl_setopt($ch, CURLOPT_POSTFIELDS, $param); + } + } + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); + curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type); + $header = array("Authorization: Bearer ".$this->token); + if($addHeader != NULL && is_array($addHeader) && count($addHeader)>0){ + $header = array_merge($header, $addHeader); + } + + + curl_setopt($ch,CURLOPT_HTTPHEADER,$header); + curl_setopt($ch, CURLOPT_HEADER, 1); + $response = curl_exec($ch); + // var_dump($response);exit; + $this->rawResponse = $response; + $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); + $this->header = substr($response, 0, $header_size); + //var_dump($this->header);exit; + $this->parsedHEader = $this->parseHeader($this->header); + $return = substr($response, $header_size); + $httpCode = curl_getinfo ( $ch, CURLINFO_RESPONSE_CODE );; + curl_close($ch); + //echo $return;exit; + if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { + + $data = json_decode($return); + }else if(json_decode($return) != NULL){ + $data = json_decode($return); + + }else{ + $data = $return; + } + + if($data == NULL){ + + throw new \OpenApi\classes\exception\OpenApiConnectionsException("Connection to $url: Connection Error",40001); + } + + if(is_object($data) && $data->success == false){ + + + $message = "Connection to $url: unknow error"; + if(isset($data->message)) { + if(is_string(($data->message))){ + if($dataMessage = json_decode($data->message)){ + $data = $dataMessage; + } + $message = "Connection to $url: $data->message"; + }else{ + $message = "Connection to $url error"; + } + + + } + //var_dump($this->rawResponse); + $except = new \OpenApi\classes\exception\OpenApiConnectionsException($message,40002); + $except->setServerResponse($data, $this->header, $this->rawResponse, $httpCode); + + throw $except; + } + if($type == "GET" && $ttr > 0) { + $this->setCacheObject($url, $data, $ttr); + } + return $data; + } + + protected function parseHeader($headers){ + $headers = explode("\n",$headers); + $parsedHeaders = array(); + foreach ($headers as $header) { + $header = trim($header); + + $header = explode(":",$header); + + if(count($header) < 2){ + + continue; + } + $key = $header[0]; + unset($header[0]); + $parsedHeaders[trim($key)] = trim(implode(":",$header)); + } + // exit; + + return $parsedHeaders; + } + + + + } \ No newline at end of file diff --git a/src/classes/Pec.php b/src/classes/Pec.php new file mode 100644 index 0000000..f88e565 --- /dev/null +++ b/src/classes/Pec.php @@ -0,0 +1,31 @@ +basePath = "https://pec.openapi.it"; + } + + function verify($pec){ + try{ + $data = $this->connect("verifica_pec/$pec", "GET"); + return $data; + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + $res = $e->getServerResponse(); + var_dump($res); + if(isset($res->message) && strpos($res->message,"not available") !== false){ + return ["success"=>true,"data"=>["available" => false]]; + } + + return $res; + } + + } + +} \ No newline at end of file diff --git a/src/classes/PecMassiva.php b/src/classes/PecMassiva.php index dcb7f6b..daafed0 100644 --- a/src/classes/PecMassiva.php +++ b/src/classes/PecMassiva.php @@ -1,77 +1,77 @@ -basePath = "https://ws.pecmassiva.com"; - $this->inizialized = FALSE; - - } - - function initialize(string $username, string $password){ - $this->username = $username; - $this->password = $password; - $this->inizialized = TRUE; - } - - function getStatus($messageId){ - if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); - } - - - try{ - $header[] = 'x-username: '.$this->username; - $header[] = 'x-password: '.$this->password; - return $this->connect("send/$messageId","GET",[],0,false,$header); - - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); - } - throw $e; - - } - } - - function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ - if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); - } - $sender = $sender ? $sender : $this->username; - - $params['username'] = $this->username; - $params['password'] = $this->password; - $params['recipient'] = $recipient; - $params['subject'] = $subject; - $params['body'] = $body; - if(count($attachments)>0){ - $params['attachments'] = $attachments; - } - $params['sender'] = $sender; - try{ - return $this->connect("send","POST",$params); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); - } - throw $e; - - } - - } - - +basePath = "https://ws.pecmassiva.com"; + $this->inizialized = FALSE; + + } + + function initialize(string $username, string $password){ + $this->username = $username; + $this->password = $password; + $this->inizialized = TRUE; + } + + function getStatus($messageId){ + if(!$this->inizialized){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + } + + + try{ + $header[] = 'x-username: '.$this->username; + $header[] = 'x-password: '.$this->password; + return $this->connect("send/$messageId","GET",[],0,false,$header); + + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if(isset($e->getServerResponse()->message_id)){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + } + throw $e; + + } + } + + function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ + if(!$this->inizialized){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + } + $sender = $sender ? $sender : $this->username; + + $params['username'] = $this->username; + $params['password'] = $this->password; + $params['recipient'] = $recipient; + $params['subject'] = $subject; + $params['body'] = $body; + if(count($attachments)>0){ + $params['attachments'] = $attachments; + } + $params['sender'] = $sender; + try{ + return $this->connect("send","POST",$params); + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if(isset($e->getServerResponse()->message_id)){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + } + throw $e; + + } + + } + + } \ No newline at end of file diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index 5922159..6ff1dec 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -1,33 +1,53 @@ -basePath = "https://ws.ufficiopostale.com"; - } - - - /** - * Restiuisce un oggetto di tipo raccomandata - * @return object - */ - function createRaccomandata(){ - return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ - - return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); - }); - } - - //function createRaccomandataByData() - - - - - +basePath = "https://ws.ufficiopostale.com"; + } + + + /** + * Restiuisce un oggetto di tipo raccomandata + * @return object + */ + function createRaccomandata(){ + return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + + return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); + }); + + + } + + function getRaccomandataById($id){ + $data = $this->connect("raccomandate/$id", "GET"); + + return $this->getRaccomandataByData($data->data); + } + + function getRaccomandataByData($data){ + $busta = $this->createRaccomandata(); + $busta->creaRaccomandataByData($data); + return $busta; + } + + function getPricing($type = NULL){ + return $this->connect("pricing/$type", "GET"); + } + + function track($tracking_code){ + return $this->connect("tracking/$tracking_code", "GET"); + } + + + + + } \ No newline at end of file diff --git a/src/classes/Uploader.php b/src/classes/Uploader.php index dabf401..1b5d67f 100644 --- a/src/classes/Uploader.php +++ b/src/classes/Uploader.php @@ -31,10 +31,47 @@ function gateway(){ $data = file_get_contents("php://input"); $data = json_decode($data); } - - $data = $this->connect($endpoint, $method,$data); - //var_dump($data);exit; + try{ + $data = $this->connect($endpoint, $method,$data); + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + $message = $e->getMessage(); + var_dump($message); + //var_dump($e->getServerRawResponse()); + $message = explode("name (must be one of",$message); + $valid_ext = ""; + if(isset($message[1])){ + $message = substr($message[1],0,-1); + + $message = explode(",",$message); + foreach($message as $m){ + $m = trim($m); + $m = explode("/",$m); + if(isset($m[1])){ + $m = $m[1]; + if($m == "jpeg"){ + $vext[] = "jpg"; + } + $vext[] = $m; + } + + + } + $valid_ext = ", è possibile caricare esclusivamente file con formato: ".implode(", ",$vext); + + } + $ret['success'] = FALSE; + $ret['message'] = "C'è stato un errore in fase di caricamento{$valid_ext}"; + $ret['error'] = $e->getCode(); + echo json_encode($ret); + exit; + }catch(\Exception $e){ + $ret['success'] = FALSE; + $ret['message'] = "C'è stato un errore in fase di caricamento inaspettato, riprovare, se il problema persiste contattare la nostra assistenza"; + echo json_encode($ret); + exit; + } header("Content-Type: ",$this->parsedHEader['Content-Type']); if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index e67fcd0..f55c496 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -58,74 +58,56 @@ function createRequest($ttr = 500){ * * @return object */ - function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req, $new_search = FALSE) { + function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { - + if($req->getNew()){ $params = new \stdClass(); - $params->state = $req->getState(); - $params->test = $req->getTest(); - $params->hash_visura = $this->hash; - if($req->getJson() != NULL){ - $params->json_visura = $req->getJson(); - } - if($req->getCallbackData() != NULL){ - $params->callback_data = $req->getCallbackData(); - } - if($req->getFornitore() != NULL){ - $params->callback = $req->getFornitore(); - } - if($req->getTargetEmail() != NULL){ - $params->email_target = $req->getTargetEmail(); - } + $params->state = $req->getState(); + $params->test = $req->getTest(); + $params->hash_visura = $this->hash; + if($req->getJson() != NULL){ + $params->json_visura = $req->getJson(); + } + if($req->getCallbackData() != NULL){ + $params->callback_data = $req->getCallbackData(); + } + if($req->getTargetEmail() != NULL){ + $params->email_target = $req->getTargetEmail(); + } + $opzioni = $req->getOpzioni(); + if($opzioni != NULL){ + $params->opzioni = $opzioni; + } $data = $this->connect("richiesta", "POST", $params); - //var_dump($data);exit; + //var_dump($data); $req->setNew(FALSE); $req->setId($data->data->_id); $req->setStatoRichiesta($data->data->stato_richiesta); - - if(isset($data->data->callback)){ - $req->setFornitore($data->data->callback); - }else{ - $req->setFornitore(NULL); - } if(isset($data->data->ricerche)){ $req->setRicerche($data->data->ricerche); } return $req; }else{ - + $params = new \stdClass(); $params->state = $req->getState(); // $params->test = $req->getTest(); - $id_visura = $req->getId(); + if($req->getJson() != NULL){ $params->json_visura = $req->getJson(); } - + $id_visura = $req->getId(); //echo json_encode($params);exit; //var_dump($params);exit; - $visura = $this->connect("richiesta/$id_visura", "GET"); - - if(!$new_search) - { $data = $this->connect("richiesta/$id_visura", "PUT", $params); - }else{ - $data = $this->connect("richiesta/$id_visura", "POST", $params); - } - - // var_dump($data);exit; - - + $req->setNew(FALSE); $req->setId($data->data->_id); $req->setStatoRichiesta($data->data->stato_richiesta); - if(isset($data->data->callback)){ - $req->setFornitore($data->data->callback); - } if(isset($data->data->ricerche)){ $req->setRicerche($data->data->ricerche); } @@ -133,64 +115,38 @@ function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req, $new_se } } - function getDatiFornitore($email){ - $data = $this->connect("fornitori/$email", "GET", []); - return $data; - } - - function getFornitori(){ - $data = $this->connect("fornitori", "GET", []); - return $data; - - } - function getRequestByIdVisura($id_visura){ $visura = $this->connect("richiesta/$id_visura", "GET"); - - /*if($visura->data->callback){ - var_dump($visura->data->callback);exit; - }*/ - return $this->getRequestByData($visura); } - function cancelRequest($id_visura, $motivazione){ - $visura = $this->connect("richiesta/$id_visura", "DELETE",["motivo"=>$motivazione]); - return $this->getRequestByIdVisura($id_visura); - } - - function getRequestByData($visura){ - + + $this->visura = $this->connect("visure/{$visura->data->hash_visura}", "GET", [], 0); + $this->hash = $visura->data->hash_visura; defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); $request = new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); $request->setNew(FALSE); $request->setId($visura->data->_id); $request->setStatoRichiesta($visura->data->stato_richiesta); + if(isset($visura->data->ricerche)){ + $request->setRicerche($visura->data->ricerche); }else{ $request->setRicerche([]); } - if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ - $documento = $this->connect("documento/{$visura->data->_id}", "GET", [], 0); - $request->setDocument($documento->data); - } - if($visura->data->stato_richiesta == "Annullata"){ - $request->setReasonCancellation($visura->data->motivo_annullamento); - - } - if(isset($visura->data->callback) && $visura->data->callback){ - $request->setFornitore($visura->data->callback); - } + // var_dump($request);exit; return $request; } function getDocument($id_visura){ + ini_set("memory_limit","1024M"); $request = $this->getRequestByIdVisura($id_visura); $documento = $this->connect("documento/{$id_visura}", "GET", [], 0); + //var_dump($documento);exit; if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ $request->setDocument($documento->data); @@ -211,10 +167,6 @@ function setRicerca($id_visura, $id_ricerca, $index){ } - function getCatalog($ttr = 86400){ - return $this->connect("visure", "GET", NULL, $ttr); - } - } diff --git a/src/classes/exception/OpenApiConnectionsException.php b/src/classes/exception/OpenApiConnectionsException.php index b8ef39f..15b5818 100644 --- a/src/classes/exception/OpenApiConnectionsException.php +++ b/src/classes/exception/OpenApiConnectionsException.php @@ -1,17 +1,17 @@ -serverData = NULL; - $this->serverHeader = NULL; - $this->serverRawResponse = NULL; - $this->httpCode = NULL; - } - public function __toString() { - return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; - } - - - /** - * - * Imposta alcune variabili utili in fase di debugging degli errori - * - * @param object $serverData Response del server già decodato dalla versione json - * @param string $serverHeader Stringa contentene gli header della response - * @param string $serverRawResponse Stringa contente la risposta raw del server - * - * @return [type] - */ - function setServerResponse(object $serverData, string $serverHeader, string $serverRawResponse, $httpCode = NULL){ - $this->serverData = $serverData; - $this->serverHeader = $serverHeader; - $this->serverRawResponse = $serverRawResponse; - $this->httpCode = $httpCode; - } - - /** - * - * Restituisce la risposta del server già decodata da json - * - * @return object - */ - function getServerResponse(){ - return $this->serverData; - } - - /** - * - * Restituisce gli header della rispopsta del server - * - * @return string - */ - function getServerHeaderResponse(){ - return $this->serverHeader; - } - - /** - * - * Restituisce la risposta in formato RAW del server - * @return string - */ - function getServerRawResponse(){ - return $this->serverRawResponse; - } - - function getHttpCode(){ - return $this->httpCode; - } +serverData = NULL; + $this->serverHeader = NULL; + $this->serverRawResponse = NULL; + $this->httpCode = NULL; + } + public function __toString() { + return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; + } + + + /** + * + * Imposta alcune variabili utili in fase di debugging degli errori + * + * @param object $serverData Response del server già decodato dalla versione json + * @param string $serverHeader Stringa contentene gli header della response + * @param string $serverRawResponse Stringa contente la risposta raw del server + * + * @return [type] + */ + function setServerResponse(object $serverData, string $serverHeader, string $serverRawResponse, $httpCode = NULL){ + $this->serverData = $serverData; + $this->serverHeader = $serverHeader; + $this->serverRawResponse = $serverRawResponse; + $this->httpCode = $httpCode; + } + + /** + * + * Restituisce la risposta del server già decodata da json + * + * @return object + */ + function getServerResponse(){ + return $this->serverData; + } + + /** + * + * Restituisce gli header della rispopsta del server + * + * @return string + */ + function getServerHeaderResponse(){ + return $this->serverHeader; + } + + /** + * + * Restituisce la risposta in formato RAW del server + * @return string + */ + function getServerRawResponse(){ + return $this->serverRawResponse; + } + + function getHttpCode(){ + return $this->httpCode; + } } \ No newline at end of file diff --git a/src/classes/exception/OpenApiPecMassivaException.php b/src/classes/exception/OpenApiPecMassivaException.php index 31d9848..7f48b0e 100644 --- a/src/classes/exception/OpenApiPecMassivaException.php +++ b/src/classes/exception/OpenApiPecMassivaException.php @@ -1,15 +1,15 @@ -data->province = NULL; $this->data->country = "Italia"; $this->data->email = NULL; + $this->data->id = NULL; + $this->data->IdRicevuta = NULL; + $this->data->tracking_code = NULL; $this->itData = new \stdClass(); @@ -38,6 +41,9 @@ function __construct($recipient = NULL){ $this->itData->provincia = NULL; $this->itData->nazione = "Italia"; $this->itData->email = NULL; + $this->itData->id = NULL; + $this->itData->IdRicevuta = NULL; + $this->itData->tracking_code = NULL; $this->validate = false; @@ -67,6 +73,8 @@ public function createFromObject($object){ $this->data->id = isset($object->id)?$object->id:NULL; $this->data->state = isset($object->state)?$object->state:NULL; + $this->data->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; + $this->data->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; @@ -86,6 +94,9 @@ public function createFromObject($object){ $this->itData->id= $this->data->id; $this->itData->state= $this->data->state; + $this->itData->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; + $this->itData->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; + } public function getObject($itNames = FALSE){ @@ -103,6 +114,11 @@ public function getAt(){ return $this->data->at; } + public function getState(){ + return $this->data->state; + } + + public function getFirstName(){ return $this->data->firstName; } @@ -138,6 +154,19 @@ public function getEmail(){ return $this->data->email; } + public function getId(){ + return $this->data->id; + } + public function getIdRicevuta(){ + return $this->data->IdRicevuta; + } + + + + public function getTrackingCode(){ + return $this->data->tracking_code; + } + public function setTitle(string $title){ $this->data->title = $title; $this->itData->titolo = $title; diff --git a/src/classes/utility/UfficioPostale/Raccomandata.php b/src/classes/utility/UfficioPostale/Raccomandata.php index 61ffce4..44ccc53 100644 --- a/src/classes/utility/UfficioPostale/Raccomandata.php +++ b/src/classes/utility/UfficioPostale/Raccomandata.php @@ -23,6 +23,22 @@ function confirm(){ } + function creaRaccomandataByData($data){ + + + $this->pricing = $data->pricing; + $this->id = $data->id; + $this->confirmed = $data->confirmed; + $this->state = $data->state; + $this->numero_pagine = $data->documento_validato->pagine; + $this->clearRecipients(); + $this->setRecipients($data->destinatari); + $this->setSender($data->mittente); + $this->colori = $data->opzioni->colori; + $this->fronteretro = $data->opzioni->fronteretro; + $this->ar = $data->opzioni->ar; + $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); + } function send(){ $object = new \stdClass();; @@ -44,13 +60,23 @@ function send(){ } } // var_dump($object);exit; + if($this->getId() == NULL){ $ret = call_user_func_array($this->connect,["raccomandate/","POST",$object]); + }else{ + $ret = call_user_func_array($this->connect,["raccomandate/".$this->getId(),"PATCH",$object]); + } + + if(!isset($ret->data[0])){ + return false; + } $this->pricing = $ret->data[0]->pricing; $this->id = $ret->data[0]->id; $this->confirmed = $ret->data[0]->confirmed; $this->state = $ret->data[0]->state; + $this->numero_pagine = $ret->data[0]->documento_validato->pagine; $this->clearRecipients(); $this->setRecipients($ret->data[0]->destinatari); + return true; //$ret= $this->connect->call($this,"raccomandate",$object,"POST"); } diff --git a/src/classes/utility/UfficioPostale/ServiziPostali.php b/src/classes/utility/UfficioPostale/ServiziPostali.php index 5dfc177..3e0c16b 100644 --- a/src/classes/utility/UfficioPostale/ServiziPostali.php +++ b/src/classes/utility/UfficioPostale/ServiziPostali.php @@ -17,6 +17,7 @@ class ServiziPostali { protected $confirmed; protected $state; protected $callback; + protected $numero_pagine; function __construct($connect){ $this->connect = $connect; @@ -36,6 +37,10 @@ function __construct($connect){ $this->callback = NULL; } + function getNumeroPagine(){ + return $this->numero_pagine; + } + function getPricing(){ return $this->pricing; } @@ -107,6 +112,10 @@ public function getSenderError(){ return $this->sender->getErrors(); } + public function getRecipients(){ + return $this->recipients; + } + public function getRecpients(){ return $this->recipients; } diff --git a/src/classes/utility/Uploader/Collection.php b/src/classes/utility/Uploader/Collection.php index 9e903f2..99bc039 100644 --- a/src/classes/utility/Uploader/Collection.php +++ b/src/classes/utility/Uploader/Collection.php @@ -38,6 +38,11 @@ function save($state = false){ if($this->getOutputSize() != NULL){ $data['output_size'] = $this->getOutputSize(); } + if($this->outputGroup != NULL){ + $data['output_group'] = $this->outputGroup; + } + + if($this->getInputTypes() != NULL){ $data['input_types'] = $this->getInputTypes(); } @@ -324,4 +329,16 @@ function getDocumento($id_documento){ $this->updateCollection(); return $ret; } + + function getDocumenti(){ + if($this->id == NULL){ + throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + } + + + $ret = call_user_func_array ($this->connect,["collections/$this->id","GET"]); + + $this->updateCollection(); + return $ret; + } } \ No newline at end of file From e728868ba53024d300f12a7e13eae4e36025b7ed Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Wed, 16 Jun 2021 14:20:37 +0200 Subject: [PATCH 21/85] Implementate ultime versioni API --- src/classes/Pec.php | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 src/classes/Pec.php diff --git a/src/classes/Pec.php b/src/classes/Pec.php deleted file mode 100644 index f88e565..0000000 --- a/src/classes/Pec.php +++ /dev/null @@ -1,31 +0,0 @@ -basePath = "https://pec.openapi.it"; - } - - function verify($pec){ - try{ - $data = $this->connect("verifica_pec/$pec", "GET"); - return $data; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - $res = $e->getServerResponse(); - var_dump($res); - if(isset($res->message) && strpos($res->message,"not available") !== false){ - return ["success"=>true,"data"=>["available" => false]]; - } - - return $res; - } - - } - -} \ No newline at end of file From 35e81c280712785ba159a4559b70acb1e93b3cf4 Mon Sep 17 00:00:00 2001 From: lorenzo paderi <> Date: Fri, 18 Jun 2021 13:10:53 +0200 Subject: [PATCH 22/85] aggiunte indicazioni sull'inizializzazione del progetto --- readme.md | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/readme.md b/readme.md index c6a0a76..4b8fef9 100644 --- a/readme.md +++ b/readme.md @@ -4,19 +4,22 @@ ### Instanza della classe -``` +```php $this->openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); ``` -Dove ```$scopes``` è un array di stringhe o di oggetti in uno dei seguenti formati: +Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: ```php $scopes=[ -"GET:ws.ufficiopostale.com/comuni", -["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] + "GET:ws.ufficiopostale.com/comuni", + ["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] ]; ``` +...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` +``` + A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: ```php @@ -49,3 +52,4 @@ La funzione consente di recuperare i dati aziendali a partire dalla partita IVA * $partitaIva: La partita IVA da cercare * $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + From 1b8cb7137931f189204da109eea365ed5a004526 Mon Sep 17 00:00:00 2001 From: lpaderiAltravia <85158884+lpaderiAltravia@users.noreply.github.com> Date: Fri, 18 Jun 2021 13:15:09 +0200 Subject: [PATCH 23/85] Update readme.md --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 4b8fef9..d0b568c 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ $scopes=[ ``` ...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` -``` + A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: From 9404c5b6d407b3fb24d8d5b7c3189fc77de66319 Mon Sep 17 00:00:00 2001 From: lorenzo paderi <> Date: Fri, 18 Jun 2021 14:48:49 +0200 Subject: [PATCH 24/85] aggiunta indicazione sull'installazione del paccetto composer --- readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/readme.md b/readme.md index 4b8fef9..8dab1aa 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,11 @@ # OpenAPI Library +## Installation + +```sh +composer require altravia/openapi +``` + ## Usage ### Instanza della classe From 08863982519796ad2f9c920afe64a278a890e5c6 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 18 Jun 2021 17:56:42 +0200 Subject: [PATCH 25/85] aggiunto gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b44d4eb --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +vendor/ +.env \ No newline at end of file From 47867f8056cc5b3eab0ab6f6928a6c4cf9060f6b Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 18 Jun 2021 17:57:49 +0200 Subject: [PATCH 26/85] dichiara le variabili di classe per la compatibilita' con i linters --- src/OpenApi.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/OpenApi.php b/src/OpenApi.php index 89a6d44..792e947 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -2,6 +2,15 @@ class OpenApi { + public \OpenApi\classes\Imprese $imprese; + public \OpenApi\classes\ufficiopostale $ufficiopostale; + public \OpenApi\classes\comuni $comuni; + public \OpenApi\classes\visengine $visengine; + public \OpenApi\classes\marcheTemporali $marcheTemporali; + public \OpenApi\classes\geocoding $geocoding; + public \OpenApi\classes\SMS $SMS; + public \OpenApi\classes\firmaDigitale $firmaDigitale; + public \OpenApi\classes\pecMassiva $pecMassiva; /** * @param array $scopes Array con gli scopes da utilizzare nel formato: ["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] oppure "GET:ws.ufficiopostale.com/comuni NOTA: il dominio NON deve mai avere lo stage From 3b347f775a10b2df34933ac6701b3d3bb8e58d60 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 18 Jun 2021 18:14:35 +0200 Subject: [PATCH 27/85] aggiunti esempi di codice --- readme.md | 49 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 41 insertions(+), 8 deletions(-) diff --git a/readme.md b/readme.md index 4911d52..e1035c0 100644 --- a/readme.md +++ b/readme.md @@ -11,34 +11,67 @@ composer require altravia/openapi ### Instanza della classe ```php - $this->openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); +require_once 'vendor/autoload.php'; + +$openapi = new \OpenApi\OpenApi($scopes, $user, $apikey, $environment); ``` Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: ```php -$scopes=[ +$scopes = [ "GET:ws.ufficiopostale.com/comuni", - ["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] + [ + "domain"=>"ws.ufficiopostale.com", + "method"=>"comuni", + "mode" =>"GET" + ] ]; ``` ...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` +OpenApi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. + +A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: -A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: ```php -$this->openapi->ufficiopostale -$this->openapi->imprese -... +// Ogni oggetto verrá creato solo se disponibile nello scope. +$openapi->ufficiopostale +$openapi->comuni +$openapi->imprese +$openapi->visengine +$openapi->marcheTemporali +$openapi->geocoding +$openapi->SMS +$openapi->firmaDigitale +$openapi->pecMassiva ``` - che possono essere usati al seguente modo: ```php $this->openapi->ufficioposale->getCitiesByCap('00132'); ``` +### Esempi + +```php +require_once 'vendor/autoload.php'; + +// Dichiaro gli scopes necessari +$scopes = [ + 'GET:comuni.openapi.it/cap', + 'GET:imprese.altravia.com/advance', +]; + +$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'production'); + +// Prendi informazioni sul cap 00132 +$cap = $openapi->comuni->getCitiesByCap('00132'); + +// Prendi informazioni su una specifica impresa +$impresa = $openapi->imprese->getByPartitaIva('12485671007'); +``` # Modulo ufficio postale From 49d25710ddb064b0b41c8094c3b7cc31e862acdb Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 18 Jun 2021 18:14:48 +0200 Subject: [PATCH 28/85] creata cartella di test --- tests/example_test.php | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/example_test.php diff --git a/tests/example_test.php b/tests/example_test.php new file mode 100644 index 0000000..9eeab7b --- /dev/null +++ b/tests/example_test.php @@ -0,0 +1,38 @@ +load(__DIR__.'/../.env'); + +$username = $_ENV['OPENAPI_USERNAME']; +$api_key = $_ENV['API_KEY']; + +// Dichiaro gli scopes necessari +$scopes = [ + "GET:ws.ufficiopostale.com/telegrammi", + "GET:imprese.altravia.com/autocomplete", + "GET:imprese.openapi.it/base", + "GET:imprese.openapi.it/advance", + "GET:imprese.openapi.it/pec", + "GET:imprese.openapi.it/autocomplete", + "GET:imprese.openapi.it/closed", + "GET:imprese.openapi.it/gruppoiva", + "GET:comuni.openapi.it/cap", + "GET:comuni.openapi.it/istat", + "GET:comuni.openapi.it/regioni", + "GET:comuni.openapi.it/province", +]; + +$openapi = new OpenApi\OpenApi($scopes, $username, $api_key, 'test'); + +// Prendi informazioni sul cap 00132 +$cap = $openapi->comuni->getCitiesByCap('00132'); +var_dump($cap); + +// Prendi informazioni su una specifica impresa +$impresa = $openapi->imprese->getByPartitaIva('12485671007'); +var_dump($impresa); + +$cerca_impresa = $openapi->imprese->getBySearch('Altravia', 'RM'); +var_dump($cerca_impresa); From 6fcf03850adc8bfe53722b29fd0419dde4086258 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 18 Jun 2021 18:18:52 +0200 Subject: [PATCH 29/85] aggiunto modulo dotenv per i test --- .gitignore | 3 ++- composer.json | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index b44d4eb..42c2c31 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ vendor/ -.env \ No newline at end of file +.env +composer.lock diff --git a/composer.json b/composer.json index 51fc60f..d85d2ee 100644 --- a/composer.json +++ b/composer.json @@ -15,5 +15,8 @@ "psr-4": { "OpenApi\\": "src" } + }, + "require-dev": { + "symfony/dotenv": "^5.3" } } From 436ce27f193711209669e586e61da69814357c07 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Mon, 21 Jun 2021 10:03:48 +0200 Subject: [PATCH 30/85] usa phpunit per i test --- composer.json | 3 ++- tests/ClientTest.php | 61 ++++++++++++++++++++++++++++++++++++++++++ tests/example_test.php | 38 -------------------------- 3 files changed, 63 insertions(+), 39 deletions(-) create mode 100644 tests/ClientTest.php delete mode 100644 tests/example_test.php diff --git a/composer.json b/composer.json index d85d2ee..6f87738 100644 --- a/composer.json +++ b/composer.json @@ -17,6 +17,7 @@ } }, "require-dev": { - "symfony/dotenv": "^5.3" + "symfony/dotenv": "^5.3", + "phpunit/phpunit": "^9.5" } } diff --git a/tests/ClientTest.php b/tests/ClientTest.php new file mode 100644 index 0000000..e87de6c --- /dev/null +++ b/tests/ClientTest.php @@ -0,0 +1,61 @@ +dotenv = new Dotenv(); + $this->dotenv->load(__DIR__.'/../.env'); + + $this->username = $_ENV['OPENAPI_USERNAME']; + $this->api_key = $_ENV['API_KEY']; + + // Dichiaro gli scopes necessari + $this->scopes = [ + "GET:ws.ufficiopostale.com/telegrammi", + "GET:imprese.altravia.com/autocomplete", + "GET:imprese.openapi.it/base", + "GET:imprese.openapi.it/advance", + "GET:imprese.openapi.it/pec", + "GET:imprese.openapi.it/autocomplete", + "GET:imprese.openapi.it/closed", + "GET:imprese.openapi.it/gruppoiva", + "GET:comuni.openapi.it/cap", + "GET:comuni.openapi.it/istat", + "GET:comuni.openapi.it/regioni", + "GET:comuni.openapi.it/province", + "POST:geocoding.realgest.it/geocode" + ]; + + $this->openapi = new OpenApi($this->scopes, $this->username, $this->api_key, 'test'); + } + + + public function testClientInstance() { + $this->assertInstanceOf('OpenApi\OpenApi', $this->openapi); + } + + public function testComuni() { + // Prendi informazioni sul cap 00132 + $cap = $this->openapi->comuni->getCitiesByCap('00132'); + $this->assertIsArray($cap); + } + + public function testGeocoding() { + // Prendi informazioni sul cap 00132 + $cap = $this->openapi->geocoding->geocode('Via Cristoforo Colombo, Roma RM'); + $this->assertIsArray($cap); + } +} \ No newline at end of file diff --git a/tests/example_test.php b/tests/example_test.php deleted file mode 100644 index 9eeab7b..0000000 --- a/tests/example_test.php +++ /dev/null @@ -1,38 +0,0 @@ -load(__DIR__.'/../.env'); - -$username = $_ENV['OPENAPI_USERNAME']; -$api_key = $_ENV['API_KEY']; - -// Dichiaro gli scopes necessari -$scopes = [ - "GET:ws.ufficiopostale.com/telegrammi", - "GET:imprese.altravia.com/autocomplete", - "GET:imprese.openapi.it/base", - "GET:imprese.openapi.it/advance", - "GET:imprese.openapi.it/pec", - "GET:imprese.openapi.it/autocomplete", - "GET:imprese.openapi.it/closed", - "GET:imprese.openapi.it/gruppoiva", - "GET:comuni.openapi.it/cap", - "GET:comuni.openapi.it/istat", - "GET:comuni.openapi.it/regioni", - "GET:comuni.openapi.it/province", -]; - -$openapi = new OpenApi\OpenApi($scopes, $username, $api_key, 'test'); - -// Prendi informazioni sul cap 00132 -$cap = $openapi->comuni->getCitiesByCap('00132'); -var_dump($cap); - -// Prendi informazioni su una specifica impresa -$impresa = $openapi->imprese->getByPartitaIva('12485671007'); -var_dump($impresa); - -$cerca_impresa = $openapi->imprese->getBySearch('Altravia', 'RM'); -var_dump($cerca_impresa); From fff010b0d22f7223e001ad12c310e3e583fdd791 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Mon, 21 Jun 2021 10:04:30 +0200 Subject: [PATCH 31/85] migliorato readme --- readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/readme.md b/readme.md index e1035c0..6effeab 100644 --- a/readme.md +++ b/readme.md @@ -66,10 +66,10 @@ $scopes = [ $openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'production'); -// Prendi informazioni sul cap 00132 +// Comuni: prendi informazioni sul cap 00132 $cap = $openapi->comuni->getCitiesByCap('00132'); -// Prendi informazioni su una specifica impresa +// Imprese: prendi informazioni su una specifica impresa $impresa = $openapi->imprese->getByPartitaIva('12485671007'); ``` From 55f86042888da713eda10395cbf1e0372d72f278 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Mon, 21 Jun 2021 10:50:35 +0200 Subject: [PATCH 32/85] aggiunto test per ufficio postale --- readme.md | 5 +++++ src/classes/UfficioPostale.php | 2 +- tests/ClientTest.php | 38 ++++++++++++++++++++++++++++++---- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/readme.md b/readme.md index 6effeab..0e333ba 100644 --- a/readme.md +++ b/readme.md @@ -71,9 +71,14 @@ $cap = $openapi->comuni->getCitiesByCap('00132'); // Imprese: prendi informazioni su una specifica impresa $impresa = $openapi->imprese->getByPartitaIva('12485671007'); + +// Ufficio Postale: ottieni informaizoni sul tracking +$track = $this->openapi->ufficiopostale->track('123456789'); ``` # Modulo ufficio postale +## Creare raccomandata + # Modulo visure diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index 6ff1dec..530eae4 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -17,7 +17,7 @@ function __construct(string $token, array $scopes, object $cache, string $prefi * Restiuisce un oggetto di tipo raccomandata * @return object */ - function createRaccomandata(){ + function createRaccomandata() { return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); diff --git a/tests/ClientTest.php b/tests/ClientTest.php index e87de6c..c7ecb2c 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -1,5 +1,7 @@ assertIsArray($cap); } - public function testGeocoding() { - // Prendi informazioni sul cap 00132 - $cap = $this->openapi->geocoding->geocode('Via Cristoforo Colombo, Roma RM'); - $this->assertIsArray($cap); + // public function testGeocoding() { + // // Prendi informazioni sul cap 00132 + // $cap = $this->openapi->geocoding->geocode('Via Cristoforo Colombo, Roma RM'); + // $this->assertIsArray($cap); + // } + + public function testUfficioPostale() { + $track = $this->openapi->ufficiopostale->track($_ENV['TRACK_TEST']); + $this->assertEquals(true, $track->success); + var_dump($track); + + $raccomandata = $this->openapi->ufficiopostale->createRaccomandata(); + var_dump($raccomandata); + + $data = new stdClass(); + $sender = new Sender([ + 'firstName' => 'John', + 'secondName' => 'Doe', + 'companyName' => 'example-spa', + ]); + + $recipient = new Recipient([ + 'firstName' => 'John', + 'secondName' => 'Doe', + 'companyName' => 'example-spa', + ]); + + $data->sender = $sender; + $data->recipient = $recipient; + + $raccomandata->creaRaccomandataByData(); } } \ No newline at end of file From 9b2a47ce894c995eb6fc7132fffb4f9db3adab76 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Mon, 21 Jun 2021 11:16:02 +0200 Subject: [PATCH 33/85] aggiunte infomrazioni sull'utilizzo di imprese --- readme.md | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/readme.md b/readme.md index 0e333ba..bebad29 100644 --- a/readme.md +++ b/readme.md @@ -83,17 +83,13 @@ $track = $this->openapi->ufficiopostale->track('123456789'); # Modulo visure # Modulo imprese - -## `getByPartitaIva` - -### Introduction - -La funzione consente di recuperare i dati aziendali a partire dalla partita IVA - -### Description - -`function getByPartitaIva(string $partitaIva, $ttl = 86400):object` - -* $partitaIva: La partita IVA da cercare -* $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta +## Utilizzo +Il modulo imprese espone i seguenti metodi: +* `getByPartitaIva` +* `getClosed` +* `getVatGroup` +* `getPec` +* `getBySearch` + +Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` From aed9cd1fe4eb26e89237a0408f53f0481c4f77f6 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Mon, 21 Jun 2021 16:33:46 +0200 Subject: [PATCH 34/85] aggiunti esempi e test per modulo SMS e firma digitale --- readme.md | 41 ++++++++++++------- tests/ClientTest.php | 97 +++++++++++++++++++++++++++++--------------- 2 files changed, 91 insertions(+), 47 deletions(-) diff --git a/readme.md b/readme.md index bebad29..3394ff4 100644 --- a/readme.md +++ b/readme.md @@ -38,15 +38,15 @@ A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: ```php // Ogni oggetto verrá creato solo se disponibile nello scope. -$openapi->ufficiopostale -$openapi->comuni -$openapi->imprese -$openapi->visengine -$openapi->marcheTemporali -$openapi->geocoding -$openapi->SMS -$openapi->firmaDigitale -$openapi->pecMassiva +$openapi->ufficiopostale; +$openapi->comuni; +$openapi->imprese; +$openapi->visengine; +$openapi->marcheTemporali; +$openapi->geocoding; +$openapi->SMS; +$openapi->firmaDigitale; +$openapi->pecMassiva; ``` che possono essere usati al seguente modo: @@ -64,7 +64,7 @@ $scopes = [ 'GET:imprese.altravia.com/advance', ]; -$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'production'); +$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'test'); // Comuni: prendi informazioni sul cap 00132 $cap = $openapi->comuni->getCitiesByCap('00132'); @@ -76,14 +76,24 @@ $impresa = $openapi->imprese->getByPartitaIva('12485671007'); $track = $this->openapi->ufficiopostale->track('123456789'); ``` -# Modulo ufficio postale -## Creare raccomandata +## Modulo ufficio postale +### Creare raccomandata -# Modulo visure +## Modulo visure +### Utilizzo +Il modulo espone i seguenti metodi: +* `sendRequest` +* `getRequestByIdVisura` +* `getRequestByData` +* `getDocument` +* `setRicerca` -# Modulo imprese -## Utilizzo +### `sendRequest($VisRequest)` + + +## Modulo imprese +### Utilizzo Il modulo imprese espone i seguenti metodi: * `getByPartitaIva` * `getClosed` @@ -93,3 +103,4 @@ Il modulo imprese espone i seguenti metodi: Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` +## Modulo SMS diff --git a/tests/ClientTest.php b/tests/ClientTest.php index c7ecb2c..1f678c1 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -2,6 +2,7 @@ use OpenApi\classes\utility\UfficioPostale\Objects\Recipient; use OpenApi\classes\utility\UfficioPostale\Objects\Sender; +use OpenApi\classes\utility\VisEngine\VisRequest; use OpenApi\OpenApi; use PHPUnit\Framework\TestCase; use Symfony\Component\Dotenv\Dotenv; @@ -26,20 +27,25 @@ public function __construct() { // Dichiaro gli scopes necessari $this->scopes = [ - "GET:ws.ufficiopostale.com/telegrammi", + "GET:ws.ufficiopostale.com/raccomandate", "GET:imprese.altravia.com/autocomplete", - "GET:imprese.openapi.it/base", - "GET:imprese.openapi.it/advance", - "GET:imprese.openapi.it/pec", - "GET:imprese.openapi.it/autocomplete", - "GET:imprese.openapi.it/closed", - "GET:imprese.openapi.it/gruppoiva", + "GET:imprese.altravia.com/base", + "GET:imprese.altravia.com/advance", + "GET:imprese.altravia.com/pec", + "GET:imprese.altravia.com/autocomplete", + "GET:imprese.altravia.com/closed", + "GET:imprese.altravia.com/gruppoiva", "GET:comuni.openapi.it/cap", "GET:comuni.openapi.it/istat", "GET:comuni.openapi.it/regioni", "GET:comuni.openapi.it/province", "GET:ws.ufficiopostale.com/tracking", - "POST:geocoding.realgest.it/geocode" + "POST:geocoding.realgest.it/geocode", + "POST:ws.messaggisms.com/messages", + "GET:ws.messaggisms.com/messages", + "PUT:ws.messaggisms.com/messages", + "GET:ws.firmadigitale.com/richiesta", + "POST:ws.firmadigitale.com/richiesta", ]; $this->openapi = new OpenApi($this->scopes, $this->username, $this->api_key, 'test'); @@ -56,36 +62,63 @@ public function testComuni() { $this->assertIsArray($cap); } + // public function testImprese() { + // $impresa = $this->openapi->imprese->getByPartitaIva('00966950230'); + // $autocomplete = $this->openapi->imprese->getBySearch('*multiservizi*', 'RM'); + // $this->assertEquals($impresa->provincia, 'RM'); + // $this->assertIsArray($autocomplete); + // } + // public function testGeocoding() { // // Prendi informazioni sul cap 00132 // $cap = $this->openapi->geocoding->geocode('Via Cristoforo Colombo, Roma RM'); // $this->assertIsArray($cap); // } - public function testUfficioPostale() { - $track = $this->openapi->ufficiopostale->track($_ENV['TRACK_TEST']); - $this->assertEquals(true, $track->success); - var_dump($track); - - $raccomandata = $this->openapi->ufficiopostale->createRaccomandata(); - var_dump($raccomandata); - - $data = new stdClass(); - $sender = new Sender([ - 'firstName' => 'John', - 'secondName' => 'Doe', - 'companyName' => 'example-spa', - ]); - - $recipient = new Recipient([ - 'firstName' => 'John', - 'secondName' => 'Doe', - 'companyName' => 'example-spa', - ]); - - $data->sender = $sender; - $data->recipient = $recipient; + // public function testUfficioPostale() { + // $track = $this->openapi->ufficiopostale->track($_ENV['TRACK_TEST']); + // $this->assertEquals(true, $track->success); + // var_dump($track); + + // $raccomandata = $this->openapi->ufficiopostale->createRaccomandata(); + // var_dump($raccomandata); + + // $data = new stdClass(); + // $sender = new Sender([ + // 'firstName' => 'John', + // 'secondName' => 'Doe', + // 'companyName' => 'example-spa', + // ]); + + // $recipient = new Recipient([ + // 'firstName' => 'John', + // 'secondName' => 'Doe', + // 'companyName' => 'example-spa', + // ]); + + // $data->sender = $sender; + // $data->recipient = $recipient; - $raccomandata->creaRaccomandataByData(); + // $raccomandata->creaRaccomandataByData($data); + // } + + // public function testSms() { + // $singleSms = $this->openapi->SMS->sendOne('prova', '3939989741', 'messaggio di prova', null, 1, null, true); + // $this->assertIsArray($singleSms); + // var_dump($singleSms); + // } + + // public function testVisura() { + // // $visura = new VisRequest('eccbc87e4b5ce2fe28308fd9f2a7baf3'); + // $response = $this->openapi->visengine->getRequestByIdVisura('eccbc87e4b5ce2fe28308fd9f2a7baf3'); + // $this->assertNotEmpty($response); + // var_dump($response); + // } + + public function testFirmaDigitale() { + $data = json_decode(file_get_contents(__DIR__.'/esempio_firma.json'), true); + $data['codice_prodotto'] = 'FIR'; + $response = $this->openapi->firmaDigitale->requestProduct($data); + $this->assertNotEmpty($response); } } \ No newline at end of file From 886d9cecc6b9ae443b2ca808cb2cb24bf4199b12 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Tue, 22 Jun 2021 10:16:25 +0200 Subject: [PATCH 35/85] fix nome dell'endpoint --- src/classes/Imprese.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/Imprese.php b/src/classes/Imprese.php index c4fa12f..172dd38 100644 --- a/src/classes/Imprese.php +++ b/src/classes/Imprese.php @@ -60,7 +60,7 @@ function getClosed(string $partitaIva, $ttr = 86400){ function getVatGroup(string $partitaIva, $ttr = 86400){ $partitaIva = trim($partitaIva); try{ - $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); + $data = $this->connect("gruppoiva/$partitaIva", "GET", [], $ttr); return $data->data; }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ From 33a12d9a77438c55b603fad86cc534a689071da6 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Tue, 22 Jun 2021 10:17:01 +0200 Subject: [PATCH 36/85] specificato il ritorno della funzione per creare raccomandate --- src/classes/UfficioPostale.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index 530eae4..4d53656 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -15,7 +15,7 @@ function __construct(string $token, array $scopes, object $cache, string $prefi /** * Restiuisce un oggetto di tipo raccomandata - * @return object + * @return \OpenApi\classes\utility\UfficioPostale\Raccomandata */ function createRaccomandata() { return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ From 5ec404c3692fe798f65574f4a88f76143f55bd94 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Tue, 22 Jun 2021 10:18:07 +0200 Subject: [PATCH 37/85] aggiunti test per comuni ed imprese --- tests/ClientTest.php | 51 ++++++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 1f678c1..d014b0e 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -39,6 +39,7 @@ public function __construct() { "GET:comuni.openapi.it/istat", "GET:comuni.openapi.it/regioni", "GET:comuni.openapi.it/province", + "GET:comuni.openapi.it/catastale", "GET:ws.ufficiopostale.com/tracking", "POST:geocoding.realgest.it/geocode", "POST:ws.messaggisms.com/messages", @@ -56,19 +57,37 @@ public function testClientInstance() { $this->assertInstanceOf('OpenApi\OpenApi', $this->openapi); } - public function testComuni() { - // Prendi informazioni sul cap 00132 - $cap = $this->openapi->comuni->getCitiesByCap('00132'); - $this->assertIsArray($cap); - } + // public function testComuni() { + // // Prendi informazioni sul cap 00132 + // $cap = $this->openapi->comuni->getCitiesByCap('00132'); + // $comune = $this->openapi->comuni->getComuneByCatasto('117'); + // $comuni = $this->openapi->comuni->getComuni('RM'); + // $regioni = $this->openapi->comuni->getRegioni(); + // $provincie = $this->openapi->comuni->getProvince(); + + // $this->assertIsArray($cap); + // $this->assertIsArray($comune); + // $this->assertIsArray($comuni); + // $this->assertIsArray($regioni); + // $this->assertIsArray($provincie); - // public function testImprese() { - // $impresa = $this->openapi->imprese->getByPartitaIva('00966950230'); - // $autocomplete = $this->openapi->imprese->getBySearch('*multiservizi*', 'RM'); - // $this->assertEquals($impresa->provincia, 'RM'); - // $this->assertIsArray($autocomplete); + // var_dump($comuni[0]->nome); // } + public function testImprese() { + $impresa = $this->openapi->imprese->getByPartitaIva('00966950230'); + $autocomplete = $this->openapi->imprese->getBySearch('*multiservizi*', 'RM'); + $closed = $this->openapi->imprese->getClosed('00966950230'); + $vat = $this->openapi->imprese->getVatGroup('00966950230'); + $Pec = $this->openapi->imprese->getPec('00966950230'); + + $this->assertEquals($impresa->provincia, 'RM'); + $this->assertIsArray($autocomplete); + $this->assertIsBool($closed->cessata); + $this->assertIsObject($vat); + $this->assertIsObject($Pec); + } + // public function testGeocoding() { // // Prendi informazioni sul cap 00132 // $cap = $this->openapi->geocoding->geocode('Via Cristoforo Colombo, Roma RM'); @@ -115,10 +134,10 @@ public function testComuni() { // var_dump($response); // } - public function testFirmaDigitale() { - $data = json_decode(file_get_contents(__DIR__.'/esempio_firma.json'), true); - $data['codice_prodotto'] = 'FIR'; - $response = $this->openapi->firmaDigitale->requestProduct($data); - $this->assertNotEmpty($response); - } + // public function testFirmaDigitale() { + // $data = json_decode(file_get_contents(__DIR__.'/esempio_firma.json'), true); + // $data['codice_prodotto'] = 'FIR'; + // $response = $this->openapi->firmaDigitale->requestProduct($data); + // $this->assertNotEmpty($response); + // } } \ No newline at end of file From 2a4dada7d2926414d92ffd11a2a85ad5d9d00df9 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Tue, 22 Jun 2021 10:47:46 +0200 Subject: [PATCH 38/85] aggiunti ritorni di funzioni --- src/classes/Imprese.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/classes/Imprese.php b/src/classes/Imprese.php index 172dd38..9076cf9 100644 --- a/src/classes/Imprese.php +++ b/src/classes/Imprese.php @@ -40,7 +40,7 @@ function getByPartitaIva(string $partitaIva, $ttr = 86400, $force = false){ } - function getClosed(string $partitaIva, $ttr = 86400){ + function getClosed(string $partitaIva, $ttr = 86400): object{ $partitaIva = trim($partitaIva); try{ $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); @@ -57,7 +57,7 @@ function getClosed(string $partitaIva, $ttr = 86400){ } } - function getVatGroup(string $partitaIva, $ttr = 86400){ + function getVatGroup(string $partitaIva, $ttr = 86400): object { $partitaIva = trim($partitaIva); try{ $data = $this->connect("gruppoiva/$partitaIva", "GET", [], $ttr); @@ -74,7 +74,7 @@ function getVatGroup(string $partitaIva, $ttr = 86400){ } } - function getPec(string $partitaIva, $ttr = 86400){ + function getPec(string $partitaIva, $ttr = 86400): object { $partitaIva = trim($partitaIva); try{ $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); From 3bc7fc1ca527551cf859f089e0ce18105f49a9c2 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Tue, 22 Jun 2021 10:48:03 +0200 Subject: [PATCH 39/85] aggiunti test ed esempi per il modulo Marche Temporali --- readme.md | 87 +++++++++++++++++++++++++++++++++++++++++--- tests/ClientTest.php | 38 +++++++++++++------ 2 files changed, 108 insertions(+), 17 deletions(-) diff --git a/readme.md b/readme.md index 3394ff4..e1ebeaf 100644 --- a/readme.md +++ b/readme.md @@ -76,11 +76,44 @@ $impresa = $openapi->imprese->getByPartitaIva('12485671007'); $track = $this->openapi->ufficiopostale->track('123456789'); ``` -## Modulo ufficio postale -### Creare raccomandata + +## Modulo comuni +Consente di prendere informazioni su comuni e provincie. -## Modulo visure +* `getCitiesByCap` +* `getComuneByCatasto` +* `getRegioni` +* `getProvince` +* `getComuni` + +### Esempi + +```php +$provincia = 'RM'; +$comuni = $this->openapi->comuni->getComuni($provincia); + +var_dump($comuni['comuni']); +/* + +["nome_provincia"]=> + string(4) "Roma" + ["sigla_provincia"]=> + string(2) "RM" + ["regione"]=> + string(5) "Lazio" + ["comuni"]=> + array(121) { + [0]=> + string(6) "Affile" + ... +*/ + + +``` + + ## Modulo imprese @@ -103,4 +136,48 @@ Il modulo imprese espone i seguenti metodi: Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` -## Modulo SMS +### Esempi +Utilizziamo `getBySearch` per cercare un'azienda il cui nome inizia con `Altrav` a Roma + +```php +$autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); + +/* + [0]=> + object(stdClass)#41 (10) { + ["piva"]=> + string(11) "12485671007" + ["cf"]=> + string(11) "12485671007" + ["denominazione"]=> + string(20) "ALTRAVIA SERVIZI SRL" + [1]=> + object(stdClass)#42 (10) { + ["id"]=> + string(24) "4242424242" + ["denominazione"]=> + string(18) "xxx Altravia Esempio 2" + ... + */ +``` + +## Modulo Marche Temporali +* `availability` +* `checkLotto` +* `purcahse` + +### Esempi + +```php +// Controlliamo la disponibilitá di una marca di inforcert o aruba +$disponibilita = $this->openapi->marcheTemporali->availability('infocert', 1); + +// Se le marche sono disponibili, acquistiamone una +if ($disponibilita->availability > 0) { + try { + $marca = $this->openapi->marcheTemporali->purcahse('infocert', 1); + } catch (\OpenApi\classes\exception\OpenApiMarcheTemporaliException $e) { + error_log(var_dump($e)); + } +} +``` \ No newline at end of file diff --git a/tests/ClientTest.php b/tests/ClientTest.php index d014b0e..9bd2d47 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -47,6 +47,12 @@ public function __construct() { "PUT:ws.messaggisms.com/messages", "GET:ws.firmadigitale.com/richiesta", "POST:ws.firmadigitale.com/richiesta", + "GET:ws.marchetemporali.com/availability", + "GET:ws.marchetemporali.com/marche", + "POST:ws.marchetemporali.com/check_lotto", + "POST:ws.marchetemporali.com/marca", + "POST:ws.marchetemporali.com/verifica", + "POST:ws.marchetemporali.com/analisi", ]; $this->openapi = new OpenApi($this->scopes, $this->username, $this->api_key, 'test'); @@ -74,18 +80,26 @@ public function testClientInstance() { // var_dump($comuni[0]->nome); // } - public function testImprese() { - $impresa = $this->openapi->imprese->getByPartitaIva('00966950230'); - $autocomplete = $this->openapi->imprese->getBySearch('*multiservizi*', 'RM'); - $closed = $this->openapi->imprese->getClosed('00966950230'); - $vat = $this->openapi->imprese->getVatGroup('00966950230'); - $Pec = $this->openapi->imprese->getPec('00966950230'); - - $this->assertEquals($impresa->provincia, 'RM'); - $this->assertIsArray($autocomplete); - $this->assertIsBool($closed->cessata); - $this->assertIsObject($vat); - $this->assertIsObject($Pec); + // public function testImprese() { + // $impresa = $this->openapi->imprese->getByPartitaIva('00966950230'); + // $autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); + // $closed = $this->openapi->imprese->getClosed('00966950230'); + // $vat = $this->openapi->imprese->getVatGroup('00966950230'); + // $Pec = $this->openapi->imprese->getPec('00966950230'); + + // $this->assertEquals($impresa->provincia, 'RM'); + // $this->assertIsArray($autocomplete); + // var_dump($autocomplete); + // $this->assertIsBool($closed->cessata); + // $this->assertIsObject($vat); + // $this->assertIsObject($Pec); + // } + + public function testMarche() { + $marca = $this->openapi->marcheTemporali->availability('infocert', 1); + $comprata = $this->openapi->marcheTemporali->purcahse('infocert', 1); + + $this->assertIsInt($marca->availability); } // public function testGeocoding() { From 00828db5be275e643bcb6ac00338c6f8988a432d Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Wed, 23 Jun 2021 16:32:09 +0200 Subject: [PATCH 40/85] aggiunti test ed esempi per il modulo SMS --- readme.md | 41 +++++++++++++++++++++++++++++++++++++++++ tests/ClientTest.php | 31 ++++++++++++++++++++----------- 2 files changed, 61 insertions(+), 11 deletions(-) diff --git a/readme.md b/readme.md index e1ebeaf..b68db00 100644 --- a/readme.md +++ b/readme.md @@ -180,4 +180,45 @@ if ($disponibilita->availability > 0) { error_log(var_dump($e)); } } +``` + +## Modulo SMS +* `getRecipients` +* `getMessage` +* `sendMore` +* `sendOne` + +### Inviare un SMS +Per inviare un SMS, per prima cosa definiamo i destinatari: + +```php +$recipient = '+39-3939989741'; +// OR +$recipients = [ + [ + 'number' => '+39-3939989741', + 'fields' => ['nome' => 'NomeDestinatario'] + ] +]; +``` + +Possiamo ora procedere ad inviare un SMS: +```php + +try { + $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, 1, null); +} catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { + throw 'Non è stato possibile recapitare il messaggio'; +} +``` + +Possiamo anche speficiare i prefissi in modo indipendente: +```php +$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, null); +``` + +O passare delle opzioni +```php +$options = ['timestamp_send' => '2021-04-20'] +$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); ``` \ No newline at end of file diff --git a/tests/ClientTest.php b/tests/ClientTest.php index 9bd2d47..e638ac6 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -37,8 +37,8 @@ public function __construct() { "GET:imprese.altravia.com/gruppoiva", "GET:comuni.openapi.it/cap", "GET:comuni.openapi.it/istat", - "GET:comuni.openapi.it/regioni", "GET:comuni.openapi.it/province", + "GET:comuni.openapi.it/regioni", "GET:comuni.openapi.it/catastale", "GET:ws.ufficiopostale.com/tracking", "POST:geocoding.realgest.it/geocode", @@ -95,12 +95,12 @@ public function testClientInstance() { // $this->assertIsObject($Pec); // } - public function testMarche() { - $marca = $this->openapi->marcheTemporali->availability('infocert', 1); - $comprata = $this->openapi->marcheTemporali->purcahse('infocert', 1); + // public function testMarche() { + // $marca = $this->openapi->marcheTemporali->availability('infocert', 1); + // $comprata = $this->openapi->marcheTemporali->purcahse('infocert', 1); - $this->assertIsInt($marca->availability); - } + // $this->assertIsInt($marca->availability); + // } // public function testGeocoding() { // // Prendi informazioni sul cap 00132 @@ -135,11 +135,20 @@ public function testMarche() { // $raccomandata->creaRaccomandataByData($data); // } - // public function testSms() { - // $singleSms = $this->openapi->SMS->sendOne('prova', '3939989741', 'messaggio di prova', null, 1, null, true); - // $this->assertIsArray($singleSms); - // var_dump($singleSms); - // } + public function testSms() { + $recipients = [ + [ + 'number' => '+39-3939989741', + 'fields' => ['nome' => 'NomeDestinatario'] + ] + ]; + $singleSms = $this->openapi->SMS->sendOne('test', '+39-3939989741', 'prova', null, 1, null, true); + + $message = $this->openapi->SMS->getMessage($singleSms->data->id); + + $this->assertEquals(true, $singleSms->success); + $this->assertEquals(true, $message['success']); + } // public function testVisura() { // // $visura = new VisRequest('eccbc87e4b5ce2fe28308fd9f2a7baf3'); From b3a888f6327ed77ef66a42380c4fa0da7e5c7d69 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Wed, 23 Jun 2021 16:35:48 +0200 Subject: [PATCH 41/85] Corrette dichiarazioni variabili mancanti --- readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index b68db00..7b157aa 100644 --- a/readme.md +++ b/readme.md @@ -206,7 +206,9 @@ Possiamo ora procedere ad inviare un SMS: ```php try { - $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, 1, null); + $priority = 1; + $options = null; + $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, $priority, $options); } catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { throw 'Non è stato possibile recapitare il messaggio'; } From cb94f145c2ddc1813d02c5925ffea5e9c5b300d5 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Thu, 24 Jun 2021 12:24:12 +0200 Subject: [PATCH 42/85] fix paramentro opzioni non passato --- src/classes/Sms.php | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/classes/Sms.php b/src/classes/Sms.php index 0a05d9d..e21b37a 100644 --- a/src/classes/Sms.php +++ b/src/classes/Sms.php @@ -75,9 +75,11 @@ function sendMore($sender, $recipients, $text, $transaction = false, $priority = $param['recipients'] = $recipients; $param['body'] = $text; $param['transaction'] = $transaction; - if($options != NULL){ - $param['priority'] = $priority; + $param['priority'] = $priority; + if(sizeof($options)){ + $param['options'] = $options; } + try{ $data = $this->connect("messages/", "POST", $param); if(isset($data->data[0]) && $transaction){ @@ -94,8 +96,10 @@ function sendMore($sender, $recipients, $text, $transaction = false, $priority = } } - - function sendOne($sender, $recipient, $text, $prefix = NULL, $priority = 1,$options = NULL, $test = false){ + /** + * @param number $priority un moltiplicatore per la priorita di invio + */ + function sendOne($sender, $recipient, $text, $prefix = NULL, $priority = 1,$options = [], $test = false){ if($prefix != NULL){ $recipient = $prefix."-".$recipient; } @@ -105,8 +109,9 @@ function sendOne($sender, $recipient, $text, $prefix = NULL, $priority = 1,$opti $param['recipients'] = $recipient; $param['body'] = $text; $param['transaction'] = FALSE; - if($options != NULL){ - $param['priority'] = $priority; + $param['priority'] = $priority; + if(sizeof($options)){ + $param['options'] = $options; } try{ From 5af6819ac999153c6fb35ea82ca19554f996d961 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Thu, 24 Jun 2021 12:25:08 +0200 Subject: [PATCH 43/85] aggiunto commento descrittivo --- src/classes/VisEngine.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index f55c496..5dcc9f1 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -154,6 +154,9 @@ function getDocument($id_visura){ return $request; } + /** + * Nel caso arrivino dei risultati di ricerca, seleziona il risultato richiesto + */ function setRicerca($id_visura, $id_ricerca, $index){ $index = str_replace("indice_","",$index); $request = $this->getRequestByIdVisura($id_visura); From fb1287fad5a4adcf17f9ba668dc82e83e37e585f Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Thu, 24 Jun 2021 12:25:32 +0200 Subject: [PATCH 44/85] rimosso file errato --- src/classes/FirrmaDigitale.php | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 src/classes/FirrmaDigitale.php diff --git a/src/classes/FirrmaDigitale.php b/src/classes/FirrmaDigitale.php deleted file mode 100644 index de518c5..0000000 --- a/src/classes/FirrmaDigitale.php +++ /dev/null @@ -1,16 +0,0 @@ -basePath = "https://ws.firmadigitale.com"; - } - - -} \ No newline at end of file From 43676a9c693d7b73539d62552d27e98017c03ff6 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 25 Jun 2021 09:57:41 +0200 Subject: [PATCH 45/85] fix type del json visura --- src/classes/utility/VisEngine/VisRequest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/utility/VisEngine/VisRequest.php b/src/classes/utility/VisEngine/VisRequest.php index 447219b..47e9d2e 100644 --- a/src/classes/utility/VisEngine/VisRequest.php +++ b/src/classes/utility/VisEngine/VisRequest.php @@ -51,7 +51,7 @@ function getNew(){ * * @return boolean Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono stati compilati (attenzione, viene effettuata la sola validazione sui required, per la validazione del formato occcorre inviare la visura) */ - function setJson(object $data){ + function setJson(array $data){ foreach($data as $k => $v){ if(!isset($this->variables[$k])){ throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); From c89420effb412a164aede3a3a824476ba501e2b1 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 25 Jun 2021 09:58:57 +0200 Subject: [PATCH 46/85] impostato ritorno di createRequest visura --- src/classes/VisEngine.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index 5dcc9f1..cae9a03 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -39,7 +39,7 @@ function getFormTool(){ * Prepara un nuovo oggetto di tipo VisRequest da utilizzare per inviare una nuova richiesta e lo restituisce * @param int $ttr Time to Release sulla richiesta dei dati della visura * - * @return object + * @return \OpenApi\classes\utility\VisEngine\VisRequest */ function createRequest($ttr = 500){ if($this->hash == NULL){ From e9b6040b87d8298986881574d82d455c3f114efd Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 25 Jun 2021 09:59:08 +0200 Subject: [PATCH 47/85] aggiunti test per visengine --- tests/ClientTest.php | 94 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/tests/ClientTest.php b/tests/ClientTest.php index e638ac6..44eb7d6 100644 --- a/tests/ClientTest.php +++ b/tests/ClientTest.php @@ -50,6 +50,16 @@ public function __construct() { "GET:ws.marchetemporali.com/availability", "GET:ws.marchetemporali.com/marche", "POST:ws.marchetemporali.com/check_lotto", + "GET:visengine2.altravia.com/fornitori", + "GET:ws.leicode.info/lei-records", + "POST:ws.leicode.info/create-lei", + "POST:ws.leicode.info/renew-lei", + "DELETE:visengine2.altravia.com/richiesta", + "GET:visengine2.altravia.com/visure", + "POST:visengine2.altravia.com/richiesta", + "PUT:visengine2.altravia.com/richiesta", + "GET:visengine2.altravia.com/richiesta", + "GET:visengine2.altravia.com/documento", "POST:ws.marchetemporali.com/marca", "POST:ws.marchetemporali.com/verifica", "POST:ws.marchetemporali.com/analisi", @@ -135,32 +145,80 @@ public function testClientInstance() { // $raccomandata->creaRaccomandataByData($data); // } - public function testSms() { - $recipients = [ - [ - 'number' => '+39-3939989741', - 'fields' => ['nome' => 'NomeDestinatario'] - ] - ]; - $singleSms = $this->openapi->SMS->sendOne('test', '+39-3939989741', 'prova', null, 1, null, true); + // public function testSms() { + // $recipients = [ + // [ + // 'number' => '+39-3939989741', + // 'fields' => ['nome' => 'NomeDestinatario'] + // ] + // ]; + // $singleSms = $this->openapi->SMS->sendOne('test', '+39-3939989741', 'prova', null, 1, null, true); - $message = $this->openapi->SMS->getMessage($singleSms->data->id); + // $message = $this->openapi->SMS->getMessage($singleSms->data->id); - $this->assertEquals(true, $singleSms->success); - $this->assertEquals(true, $message['success']); - } - - // public function testVisura() { - // // $visura = new VisRequest('eccbc87e4b5ce2fe28308fd9f2a7baf3'); - // $response = $this->openapi->visengine->getRequestByIdVisura('eccbc87e4b5ce2fe28308fd9f2a7baf3'); - // $this->assertNotEmpty($response); - // var_dump($response); + // $this->assertEquals(true, $singleSms->success); + // $this->assertEquals(true, $message['success']); // } + public function testVisura() { + $this->openapi->visengine->setHash('eccbc87e4b5ce2fe28308fd9f2a7baf3'); + $visura = $this->openapi->visengine->createRequest(); + var_dump($visura); + + $response = $this->openapi->visengine->getRequestByIdVisura('eccbc87e4b5ce2fe28308fd9f2a7baf3'); + $this->assertNotEmpty($response); + // var_dump($response); + } + // public function testFirmaDigitale() { // $data = json_decode(file_get_contents(__DIR__.'/esempio_firma.json'), true); // $data['codice_prodotto'] = 'FIR'; // $response = $this->openapi->firmaDigitale->requestProduct($data); // $this->assertNotEmpty($response); // } + // public function testcreaVisura() { + + // $this->openapi->visengine->setHash($visura->hash); + // $request = $this->openapi->visengine->createRequest(); + // $res = $request->setJson((object)$json); + // if($request->isValidJson() && !$visura->show_form){ + // $request->setState(1); + // $request->setCallbackData(site_url("callbacks/ordini/visure"),(object)["order_id"=>"".$order_id, "detail_key"=>$detail_key]); + // $request = $this->openapi->visengine->sendRequest($request); + // } + // } + + // public function callbackVisura(Request $data) { + // $data =json_decode(file_get_contents('php://input')); + // $request = $this->openapi->visengine->getRequestByData($data); + // $ret['id'] = $request->getId(); + // $ret['stato'] = $request->getStatoRichiesta(); + // $ret['stato_ricerca'] = $request->getStatoRicerca(); + // if($request->hasSearchResult()){ + // $ret['ricerche'] = $request->getSearchResult(); + // $ret['search_count'] = $request->getSearchCount(); + // $ret['has_search_result'] = TRUE; + // $ret['search_id'] = $request->getSearchId(); + // }else{ + // if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ + // $document = $this->openapi->visengine->getDocument($id_visura)->getDocument(); + // if($document != NULL && $document->file != ""){ + // $has_document = TRUE; + // //salviamo il file + // file_put_contents("writable/documenti/{$id_visura}.bin", $document->file); + // } + // } + // } + // } + + public function testcreaVisura() { + + $this->openapi->visengine->setHash('8f14e45fceea167a5a36dedd4bea2543'); + $request = $this->openapi->visengine->createRequest(); + $request->setState(1); + $request->setCallbackData('https://example.com', new stdClass(), 'POST'); + $request->setJson(['$0' => 'abcd', '$1' => '12485671007']); + $visura = $this->openapi->visengine->sendRequest($request); + + } } \ No newline at end of file From 3815404df893b8d06693f3f81eb011a6245fd2a5 Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 25 Jun 2021 09:59:25 +0200 Subject: [PATCH 48/85] migliorato readme con esempi visengine --- readme.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/readme.md b/readme.md index 7b157aa..cca18e2 100644 --- a/readme.md +++ b/readme.md @@ -223,4 +223,27 @@ O passare delle opzioni ```php $options = ['timestamp_send' => '2021-04-20'] $this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); +``` + +## Modulo Visengine +Come prima cosa, settiamo l'hash della visura che vogliamo richiedere + +```php +// https://developers.openapi.it/services/visengine +$this->openapi->visengine->setHash($visura->hash); +``` + +A questo punto, possiamo lanciare `createRequest`, che ritornerà una istanza vuota della visura che andremo a creare della struttura richiesta + +```php +$request = $this->openapi->visengine->createRequest(); +``` + +Prodediamo a completare l'oggetto, che potremmo passare a sendRequest quando pronto + +```php +$request->setJson(['$0' => 'abcd', '$1' => '12485671007']); + // url di callback, oggetto con dati aggiuntivi, metodo +$request->setCallbackData('https://example.com', new stdClass(), 'POST'); +$visura = $this->openapi->visengine->sendRequest($request); ``` \ No newline at end of file From 9f10a877577a7015c7fa51fdde5b25a565583b7d Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 25 Jun 2021 10:01:55 +0200 Subject: [PATCH 49/85] generata TOC --- readme.md | 59 +++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 17 deletions(-) diff --git a/readme.md b/readme.md index cca18e2..e96b0df 100644 --- a/readme.md +++ b/readme.md @@ -1,14 +1,39 @@ # OpenAPI Library -## Installation + +* 1. [Installation](#Installation) +* 2. [Usage](#Usage) + * 2.1. [Instanza della classe](#Instanzadellaclasse) + * 2.2. [Esempi](#Esempi) + * 2.3. [Creare raccomandata -->](#Creareraccomandata--) +* 3. [Modulo comuni](#Modulocomuni) + * 3.1. [Esempi](#Esempi-1) + * 3.2. [Utilizzo](#Utilizzo) + * 3.3. [`sendRequest($VisRequest)` -->](#sendRequestVisRequest--) +* 4. [Modulo imprese](#Moduloimprese) + * 4.1. [Utilizzo](#Utilizzo-1) + * 4.2. [Esempi](#Esempi-1) +* 5. [Modulo Marche Temporali](#ModuloMarcheTemporali) + * 5.1. [Esempi](#Esempi-1) +* 6. [Modulo SMS](#ModuloSMS) + * 6.1. [Inviare un SMS](#InviareunSMS) +* 7. [Modulo Visengine](#ModuloVisengine) + + + + +## 1. Installation ```sh composer require altravia/openapi ``` -## Usage +## 2. Usage -### Instanza della classe +### 2.1. Instanza della classe ```php require_once 'vendor/autoload.php'; @@ -53,7 +78,7 @@ che possono essere usati al seguente modo: ```php $this->openapi->ufficioposale->getCitiesByCap('00132'); ``` -### Esempi +### 2.2. Esempi ```php require_once 'vendor/autoload.php'; @@ -77,9 +102,9 @@ $track = $this->openapi->ufficiopostale->track('123456789'); ``` +### 2.3. Creare raccomandata --> -## Modulo comuni +## 3. Modulo comuni Consente di prendere informazioni su comuni e provincie. * `getCitiesByCap` @@ -88,7 +113,7 @@ Consente di prendere informazioni su comuni e provincie. * `getProvince` * `getComuni` -### Esempi +### 3.1. Esempi ```php $provincia = 'RM'; @@ -114,7 +139,7 @@ var_dump($comuni['comuni']); ``` +### 3.3. `sendRequest($VisRequest)` --> -## Modulo imprese -### Utilizzo +## 4. Modulo imprese +### 4.1. Utilizzo Il modulo imprese espone i seguenti metodi: * `getByPartitaIva` * `getClosed` @@ -136,7 +161,7 @@ Il modulo imprese espone i seguenti metodi: Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` -### Esempi +### 4.2. Esempi Utilizziamo `getBySearch` per cercare un'azienda il cui nome inizia con `Altrav` a Roma ```php @@ -161,12 +186,12 @@ $autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); */ ``` -## Modulo Marche Temporali +## 5. Modulo Marche Temporali * `availability` * `checkLotto` * `purcahse` -### Esempi +### 5.1. Esempi ```php // Controlliamo la disponibilitá di una marca di inforcert o aruba @@ -182,13 +207,13 @@ if ($disponibilita->availability > 0) { } ``` -## Modulo SMS +## 6. Modulo SMS * `getRecipients` * `getMessage` * `sendMore` * `sendOne` -### Inviare un SMS +### 6.1. Inviare un SMS Per inviare un SMS, per prima cosa definiamo i destinatari: ```php @@ -225,7 +250,7 @@ $options = ['timestamp_send' => '2021-04-20'] $this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); ``` -## Modulo Visengine +## 7. Modulo Visengine Come prima cosa, settiamo l'hash della visura che vogliamo richiedere ```php From 2bba961d462cf4ed3003c844c6ab9cf795cf631b Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Fri, 25 Jun 2021 10:04:12 +0200 Subject: [PATCH 50/85] corretta TOC --- readme.md | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/readme.md b/readme.md index e96b0df..139e3c8 100644 --- a/readme.md +++ b/readme.md @@ -5,13 +5,10 @@ * 2. [Usage](#Usage) * 2.1. [Instanza della classe](#Instanzadellaclasse) * 2.2. [Esempi](#Esempi) - * 2.3. [Creare raccomandata -->](#Creareraccomandata--) * 3. [Modulo comuni](#Modulocomuni) * 3.1. [Esempi](#Esempi-1) - * 3.2. [Utilizzo](#Utilizzo) - * 3.3. [`sendRequest($VisRequest)` -->](#sendRequestVisRequest--) * 4. [Modulo imprese](#Moduloimprese) - * 4.1. [Utilizzo](#Utilizzo-1) + * 4.1. [Utilizzo](#Utilizzo) * 4.2. [Esempi](#Esempi-1) * 5. [Modulo Marche Temporali](#ModuloMarcheTemporali) * 5.1. [Esempi](#Esempi-1) @@ -25,6 +22,7 @@ /vscode-markdown-toc-config --> + ## 1. Installation ```sh @@ -101,8 +99,6 @@ $impresa = $openapi->imprese->getByPartitaIva('12485671007'); $track = $this->openapi->ufficiopostale->track('123456789'); ``` - ## 3. Modulo comuni Consente di prendere informazioni su comuni e provincie. @@ -138,20 +134,8 @@ var_dump($comuni['comuni']); ``` - - - ## 4. Modulo imprese -### 4.1. Utilizzo +### 4.1. Utilizzo Il modulo imprese espone i seguenti metodi: * `getByPartitaIva` * `getClosed` From dfb8ef6a769c3caa17a6df341773a5ae88ab6de7 Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Tue, 29 Jun 2021 17:04:28 +0200 Subject: [PATCH 51/85] imprese openapi --- src/OpenApi.php | 3 + src/classes/ImpreseOpenapi.php | 143 +++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+) create mode 100644 src/classes/ImpreseOpenapi.php diff --git a/src/OpenApi.php b/src/OpenApi.php index 89a6d44..f5fac3a 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -88,6 +88,9 @@ private function getListaModuli(){ $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; $nomi['imprese.altravia.com'] = "imprese"; + $moduli['imprese.openapi.it'] = "\\OpenApi\\classes\\ImpreseOpenapi"; + $nomi['imprese.openapi.it'] = "imprese"; + $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; $nomi['visengine2.altravia.com'] = "visengine"; diff --git a/src/classes/ImpreseOpenapi.php b/src/classes/ImpreseOpenapi.php new file mode 100644 index 0000000..a1b7f6f --- /dev/null +++ b/src/classes/ImpreseOpenapi.php @@ -0,0 +1,143 @@ +basePath = "https://imprese.openapi.it"; + } + + /** + * + * Consente di recuperare i dati di una azienda a partire dalla partita IVA + * + * @param string $partitaIva La partita IVa da ricercare + * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + * + * @return object + */ + function getByPartitaIva(string $partitaIva, $ttr = 86400, $force = false){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("advance/$partitaIva", "GET", [], $ttr, true); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + + + } + + function getClosed(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + function getVatGroup(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + function getPec(string $partitaIva, $ttr = 86400){ + $partitaIva = trim($partitaIva); + try{ + $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + + /** + * + * Cerca un'azienda o più utilizzando vari parametri + * + * @param string $denominazione Denominazione azienda + * @param string $provincia Provincia + * @param string $partitaIva=NULL Partita IVA + * @param string $codiceFiscale=NULL Codice Fiscale + * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta + * + * @return array Lista delle aziende individuate + */ + function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ + $params=[]; + if($denominazione != NULL){ + $params['denominazione'] = trim($denominazione); + } + if($provincia != NULL){ + $params['provincia'] = $provincia; + } + if($partitaIva != NULL){ + $params['piva'] = $partitaIva; + } + if($codiceFiscale != NULL){ + $params['cf'] = $codiceFiscale; + } + + $data = $this->connect("advance/$partitaIva", "GET", $params, $ttr); + return $data->data; + } + + function autocomplete($query, $ttr = 86400){ + try{ + $query = trim($query); + $query = str_replace(" ","*",$query); + $query = urlencode("*$query*"); + $data = $this->connect("autocomplete/$query", "GET", [], $ttr); + if($data == null){ + $data = []; + }else{ + $data = $data->data; + } + return $data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + } + return []; + + } +} \ No newline at end of file From 099541b390b71a4ca621dc284f7492aa8c6ab2ac Mon Sep 17 00:00:00 2001 From: Paolo Bernardini Date: Mon, 10 Jan 2022 09:18:02 +0100 Subject: [PATCH 52/85] - Bugfixing on API Ufficiopostale Raccomandata, PecMassiva, VisEngine - API UfficioPostale: Posta Ordionaria, Posta Prioritaria, Telegramma - API Catasto --- src/OpenApi.php | 4 + src/classes/Catasto.php | 95 ++++ src/classes/ImpreseOpenapi.php | 17 + src/classes/PecMassiva.php | 152 +++--- src/classes/UfficioPostale.php | 249 +++++++--- src/classes/VisEngine.php | 6 +- .../exception/OpenApiPecMassivaException.php | 28 +- .../Objects/ErrorTranslation/errorLang.php | 23 + .../Objects/ErrorTranslation/lng/it.json | 11 + .../UfficioPostale/Objects/Recipient.php | 67 ++- .../Objects/RecipientRaccomandate.php | 81 ++++ .../utility/UfficioPostale/PostaOrdinaria.php | 92 ++++ .../UfficioPostale/PostaPrioritaria.php | 90 ++++ .../utility/UfficioPostale/Raccomandata.php | 139 ++++-- .../utility/UfficioPostale/ServiziPostali.php | 42 +- .../utility/UfficioPostale/Telegramma.php | 148 ++++++ src/classes/utility/VisRequest.php | 434 ++++++++++++++++++ 17 files changed, 1482 insertions(+), 196 deletions(-) create mode 100644 src/classes/Catasto.php create mode 100644 src/classes/utility/UfficioPostale/Objects/ErrorTranslation/errorLang.php create mode 100644 src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json create mode 100644 src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php create mode 100644 src/classes/utility/UfficioPostale/PostaOrdinaria.php create mode 100644 src/classes/utility/UfficioPostale/PostaPrioritaria.php create mode 100644 src/classes/utility/UfficioPostale/Telegramma.php create mode 100644 src/classes/utility/VisRequest.php diff --git a/src/OpenApi.php b/src/OpenApi.php index f5fac3a..f75db74 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -114,6 +114,10 @@ private function getListaModuli(){ $moduli['pec.openapi.it'] = "\\OpenApi\\classes\\Pec"; $nomi['pec.openapi.it'] = "PEC"; + + $moduli['catasto.openapi.it'] = "\\OpenApi\\classes\\Catasto"; + $nomi['catasto.openapi.it'] = "catasto"; + $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; $nomi['ws.firmadigitale.com'] = "firmaDigitale"; return array($moduli,$nomi); diff --git a/src/classes/Catasto.php b/src/classes/Catasto.php new file mode 100644 index 0000000..e07a613 --- /dev/null +++ b/src/classes/Catasto.php @@ -0,0 +1,95 @@ +basePath = "https://catasto.openapi.it"; + } + + + function ufficiCatastali($ttl = 86400){ + $data = $this->connect("territorio", "GET", [], $ttl); + return $data->data; + } + + function getComuni($provincia, $ttl = 86400){ + $data = $this->connect("territorio/$provincia", "GET", [], $ttl); + return $data->data; + } + + function elencoImmobili($tipo_catasto, $provincia,$comune,$sezione, $foglio,$particella, $callback){ + $param = [ + "tipo_catasto" => $tipo_catasto, + "provincia" => trim($provincia), + "comune" => $comune, + "sezione" => $sezione, + "foglio" => $foglio, + "particella" => $particella, + + ]; + if($callback != NULL){ + $param['callback'] = $callback; + } + $data = $this->connect("richiesta/elenco_immobili", "POST", $param); + return $data->data; + } + + function getComune($provincia, $comune, $ttl = 86400){ + $comune = urlencode($comune); + $data = $this->connect("territorio/$provincia/$comune", "GET", [], $ttl); + return $data->data; + } + function prospettoCatastale($tipo_catasto, $provincia,$comune,$sezione, $foglio,$particella,$subalterno, $callback=NULL){ + $param = [ + "tipo_catasto" => $tipo_catasto, + "provincia" => trim($provincia), + "comune" => $comune, + "sezione" => $sezione, + "foglio" => $foglio, + "particella" => $particella, + "subalterno" => $subalterno, + ]; + if($callback != NULL){ + $param['callback'] = $callback; + } + $data = $this->connect("richiesta/prospetto_catastale", "POST", $param); + return $data->data; + } + + function ricercaPersona($tipo_catasto,$cf_piva,$provincia,$callback = NULL){ + $param = [ + "tipo_catasto" => $tipo_catasto, + "cf_piva" => trim($cf_piva), + "provincia" => $provincia, + ]; + //var_dump($param);exit; + if($callback != NULL){ + $param['callback'] = $callback; + } + $data = $this->connect("richiesta/ricerca_persona", "POST", $param); + return $data->data; + } + + function ricercaNazionale($tipo_catasto,$cf_piva,$callback= NULL){ + $param = [ + "tipo_catasto" => $tipo_catasto, + "cf_piva" => trim($cf_piva) + ]; + //var_dump($param);exit; + if($callback != NULL){ + $param['callback'] = $callback; + } + $data = $this->connect("richiesta/ricerca_nazionale", "POST", $param); + return $data->data; + } + + + + +} \ No newline at end of file diff --git a/src/classes/ImpreseOpenapi.php b/src/classes/ImpreseOpenapi.php index a1b7f6f..ad799d8 100644 --- a/src/classes/ImpreseOpenapi.php +++ b/src/classes/ImpreseOpenapi.php @@ -13,6 +13,23 @@ function __construct(string $token, array $scopes, object $cache, string $prefi $this->basePath = "https://imprese.openapi.it"; } + function getFormaGiuridica($codice, $ttr=86400){ + $codice = trim($codice); + try{ + $data = $this->connect("forma_giuridica/$codice", "GET", [], $ttr); + return $data->data; + }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + + if($e->getHTTPCode() == 404){ + return null; + } + throw $e; + + + exit; + } + } + /** * * Consente di recuperare i dati di una azienda a partire dalla partita IVA diff --git a/src/classes/PecMassiva.php b/src/classes/PecMassiva.php index daafed0..dcb7f6b 100644 --- a/src/classes/PecMassiva.php +++ b/src/classes/PecMassiva.php @@ -1,77 +1,77 @@ -basePath = "https://ws.pecmassiva.com"; - $this->inizialized = FALSE; - - } - - function initialize(string $username, string $password){ - $this->username = $username; - $this->password = $password; - $this->inizialized = TRUE; - } - - function getStatus($messageId){ - if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); - } - - - try{ - $header[] = 'x-username: '.$this->username; - $header[] = 'x-password: '.$this->password; - return $this->connect("send/$messageId","GET",[],0,false,$header); - - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); - } - throw $e; - - } - } - - function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ - if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); - } - $sender = $sender ? $sender : $this->username; - - $params['username'] = $this->username; - $params['password'] = $this->password; - $params['recipient'] = $recipient; - $params['subject'] = $subject; - $params['body'] = $body; - if(count($attachments)>0){ - $params['attachments'] = $attachments; - } - $params['sender'] = $sender; - try{ - return $this->connect("send","POST",$params); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); - } - throw $e; - - } - - } - - +basePath = "https://ws.pecmassiva.com"; + $this->inizialized = FALSE; + + } + + function initialize(string $username, string $password){ + $this->username = $username; + $this->password = $password; + $this->inizialized = TRUE; + } + + function getStatus($messageId){ + if(!$this->inizialized){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + } + + + try{ + $header[] = 'x-username: '.$this->username; + $header[] = 'x-password: '.$this->password; + return $this->connect("send/$messageId","GET",[],0,false,$header); + + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if(isset($e->getServerResponse()->message_id)){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + } + throw $e; + + } + } + + function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ + if(!$this->inizialized){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + } + $sender = $sender ? $sender : $this->username; + + $params['username'] = $this->username; + $params['password'] = $this->password; + $params['recipient'] = $recipient; + $params['subject'] = $subject; + $params['body'] = $body; + if(count($attachments)>0){ + $params['attachments'] = $attachments; + } + $params['sender'] = $sender; + try{ + return $this->connect("send","POST",$params); + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + if(isset($e->getServerResponse()->message_id)){ + throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + } + throw $e; + + } + + } + + } \ No newline at end of file diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index 6ff1dec..9b31130 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -1,53 +1,198 @@ -basePath = "https://ws.ufficiopostale.com"; - } - - - /** - * Restiuisce un oggetto di tipo raccomandata - * @return object - */ - function createRaccomandata(){ - return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ - - return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); - }); - - - } - - function getRaccomandataById($id){ - $data = $this->connect("raccomandate/$id", "GET"); - - return $this->getRaccomandataByData($data->data); - } - - function getRaccomandataByData($data){ - $busta = $this->createRaccomandata(); - $busta->creaRaccomandataByData($data); - return $busta; - } - - function getPricing($type = NULL){ - return $this->connect("pricing/$type", "GET"); - } - - function track($tracking_code){ - return $this->connect("tracking/$tracking_code", "GET"); - } - - - - - +errorClass = NULL; + $this->setErrorLang('it'); + $this->basePath = "https://ws.ufficiopostale.com"; + } + + + /** + * Prende in ingresso la path di un json contenente le traduzioni degli errori + */ + function setErrorLang($errorLang){ + $this->errorClass = new \OpenApi\classes\utility\UfficioPostale\Objects\ErrorTranslation\errorLang($errorLang); + } + + function getComuniByCAP($cap){ + $data = $this->connect("comuni/$cap", "GET"); + return $data->data; + + } + + function create( $prodotto){ + if($prodotto == "raccomandata"){ + return $this->createRaccomandata(); + } + if($prodotto == "telegramma"){ + return $this->createTelegramma(); + } + if($prodotto == "posta-prioritaria"){ + return $this->createPostaPrioritaria(); + } + if($prodotto == "posta-ordinaria"){ + return $this->createPostaOrdinaria(); + } + $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); + throw $ex; + + } + /** + * Restiuisce un oggetto di tipo raccomandata + * @return object + */ + function createRaccomandata(){ + return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + + return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); + }, + + function($code, $serverResponse){ + + return $this->errorClass->getError( $code, $serverResponse); + }); + } + + function createPostaPrioritaria(){ + return new \OpenApi\classes\utility\UfficioPostale\PostaPrioritaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + + return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); + }, + + function($code, $serverResponse){ + + return $this->errorClass->getError( $code, $serverResponse); + }); + } + + function createPostaOrdinaria(){ + return new \OpenApi\classes\utility\UfficioPostale\PostaOrdinaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + + return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); + }, + + function($code, $serverResponse){ + + return $this->errorClass->getError( $code, $serverResponse); + }); + } + + function createTelegramma(){ + return new \OpenApi\classes\utility\UfficioPostale\Telegramma(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + + return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); + }, + + function($code, $serverResponse){ + + return $this->errorClass->getError( $code, $serverResponse); + }); + } + + + function track($tracking_code){ + return $this->connect("tracking/$tracking_code", "GET"); + } + + function getById($id, $prodotto){ + if($prodotto == "raccomandata"){ + return $this->getRaccomandataById($id); + } + if($prodotto == "telegramma"){ + return $this->getTelegrammaById($id); + } + if($prodotto == "posta-prioritaria"){ + return $this->getPostaPrioritariaById($id); + } + if($prodotto == "posta-ordinaria"){ + return $this->getPostaOrdinariaById($id); + } + $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); + throw $ex; + + } + + function getByData($data, $prodotto){ + if($prodotto == "raccomandata"){ + return $this->getRaccomandataByData($data); + } + if($prodotto == "telegramma"){ + return $this->getTelegrammaByData($data); + } + if($prodotto == "posta-prioritaria"){ + return $this->getTelegrammaByData($data); + } + if($prodotto == "posta-ordinaria"){ + return $this->getPostaOrdinariaByData($data); + } + $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); + throw $ex; + } + + function getRaccomandataById($id){ + $data = $this->connect("raccomandate/$id", "GET"); + return $this->getRaccomandataByData($data->data); + } + + function getRaccomandataByData($data){ + $busta = $this->createRaccomandata(); + $busta->creaRaccomandataByData($data); + return $busta; + } + + function getPostaPrioritariaById($id){ + $data = $this->connect("prioritarie/$id", "GET"); + return $this->getPostaPrioritariaByData($data->data); + } + + function getPostaPrioritariaByData($data){ + $busta = $this->createPostaPrioritaria(); + $busta->creaPostaPrioritariaByData($data); + return $busta; + } + + function getPostaOrdinariaById($id){ + $data = $this->connect("ordinarie/$id", "GET"); + return $this->getPostaOrdinariaByData($data->data); + } + + function getPostaOrdinariaByData($data){ + $busta = $this->createPostaOrdinaria(); + $busta->creaPostaOrdinariaByData($data); + return $busta; + } + + + function getTelegrammaById($id){ + $data = $this->connect("telegrammi/$id", "GET"); + + return $this->getTelegrammaByData($data->data); + } + + function getTelegrammaByData($data){ + $busta = $this->createTelegramma(); + $busta->creaTelegrammaByData($data); + return $busta; + } + function getPricing($type = NULL){ + return $this->connect("pricing/$type", "GET"); + } + + + function getDug(){ + return $this->connect("dug/", "GET"); + } + + + + + } \ No newline at end of file diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index f55c496..2869869 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -143,10 +143,14 @@ function getRequestByData($visura){ } function getDocument($id_visura){ + ini_set("memory_limit","1024M"); + $request = $this->getRequestByIdVisura($id_visura); + $documento = $this->connect("documento/{$id_visura}", "GET", [], 0); - //var_dump($documento);exit; + + if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ $request->setDocument($documento->data); diff --git a/src/classes/exception/OpenApiPecMassivaException.php b/src/classes/exception/OpenApiPecMassivaException.php index 7f48b0e..31d9848 100644 --- a/src/classes/exception/OpenApiPecMassivaException.php +++ b/src/classes/exception/OpenApiPecMassivaException.php @@ -1,15 +1,15 @@ -errors = (array)json_decode(file_get_contents($json)); + } + + function getError($code, $serverResponse){ + if(isset($this->errors[$code])){ + return $this->errors[$code]; + }else{ + if(isset($serverResponse->message)){ + return $serverResponse->message; + } + } + + return NULL; + } + +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json b/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json new file mode 100644 index 0000000..bc591a9 --- /dev/null +++ b/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json @@ -0,0 +1,11 @@ +{ + + "12080":"Il campo indirizzo è obbligatorio", + "15060":"Il campo indirizzo è obbligatorio", + "12090":"Il campo numero civico è obbligatorio", + "15070":"Il campo numero civico è obbligatorio", + "12140":"Il campo comune è obbligatorio", + "15080":"Il campo comune è obbligatorio", + "13020":"Caricare almeno un documento o un testo", + "12180":"Comune, CAP e provinca in conflitto" +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/Recipient.php b/src/classes/utility/UfficioPostale/Objects/Recipient.php index 7b7d178..8c1e0e7 100644 --- a/src/classes/utility/UfficioPostale/Objects/Recipient.php +++ b/src/classes/utility/UfficioPostale/Objects/Recipient.php @@ -1,10 +1,10 @@ errors = null; @@ -25,6 +25,8 @@ function __construct($recipient = NULL){ $this->data->id = NULL; $this->data->IdRicevuta = NULL; $this->data->tracking_code = NULL; + $this->data->post_office = NULL; + $this->data->post_office_box = NULL; $this->itData = new \stdClass(); @@ -44,7 +46,15 @@ function __construct($recipient = NULL){ $this->itData->id = NULL; $this->itData->IdRicevuta = NULL; $this->itData->tracking_code = NULL; - + $this->data->state = NULL; + $this->itData->state = NULL; + $this->itData->casella_postale = NULL; + $this->itData->ufficio_postale = NULL; + + $this->itData->stateType = 'TRANSITORIO'; + $this->data->stateType = 'TRANSITORIO'; + $this->data->stateDescription = 'Inviato da Web'; + $this->itData->stateDescription = 'Inviato da Web'; $this->validate = false; if($recipient != NULL){ @@ -57,6 +67,30 @@ public function createFromObject($object){ $object = (object)$object; } //var_dump($object);Exit; + $stateType = 'TRANSITORIO'; + $stateDescription = ''; + // var_dump($object);exit; + if(isset($object->tracking)) + { + $object->tracking = (array)$object->tracking; + if(is_array($object->tracking) && count($object->tracking)>1){ + + $lastT = $object->tracking[count($object->tracking)-1]; + + $stateType = $lastT->definitivo?'DEFINITIVO':'TRANSITORIO'; + $stateDescription = $lastT->descrizione; + + } + }else{ + if(isset($object->stateType)){ + $stateType = $object->stateType; + $stateDescription = $object->state; + } + } + $this->data->stateType = $stateType; + $this->data->stateDescription = $stateDescription; + $this->itData->stateType = $stateType; + $this->itData->stateDescription = $stateDescription; $this->data->title = isset($object->title)?$object->title:(isset($object->titolo)?$object->titolo:NULL); $this->data->at = isset($object->at)?$object->at:(isset($object->co)?$object->co:NULL); $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); @@ -75,9 +109,13 @@ public function createFromObject($object){ $this->data->state = isset($object->state)?$object->state:NULL; $this->data->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; $this->data->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; + $this->data->post_office = isset($object->post_office)?$object->post_office:(isset($object->ufficio_postale)?$object->ufficio_postale:NULL); + $this->data->post_office_box = isset($object->post_office_box)?$object->post_office_box:(isset($object->casella_postale)?$object->casella_postale:NULL); + $this->itData->ufficio_postale = $this->data->post_office; + $this->itData->casella_postale = $this->data->post_office_box; $this->itData->co = $this->data->at; $this->itData->titolo = $this->data->title; $this->itData->nome = $this->data->firstName; @@ -96,7 +134,10 @@ public function createFromObject($object){ $this->itData->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; $this->itData->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; - + if($this->itData->tracking_code == NULL && $this->itData->IdRicevuta != NULL){ + $this->itData->tracking_code = $this->itData->IdRicevuta; + $this->data->tracking_code = $this->itData->tracking_code; + } } public function getObject($itNames = FALSE){ @@ -118,7 +159,13 @@ public function getState(){ return $this->data->state; } + public function getStateType(){ + return $this->data->stateType; + } + public function getStateDescription(){ + return $this->data->stateDescription; + } public function getFirstName(){ return $this->data->firstName; } @@ -126,6 +173,10 @@ public function getSecondName(){ return $this->data->secondName; } + public function getLastName(){ + return $this->getSecondName(); + } + public function getCompanyName(){ return $this->data->companyName; } @@ -182,6 +233,10 @@ public function setFirstName(string $firstName){ $this->itData->nome = $firstName; } + public function setLastName(string $secondName){ + $this->setSecondName($secondName); + + } public function setSecondName(string $secondName){ $this->data->secondName = $secondName; $this->itData->cognome = $secondName; diff --git a/src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php b/src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php new file mode 100644 index 0000000..5ffa0f9 --- /dev/null +++ b/src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php @@ -0,0 +1,81 @@ +tracking)) + { + $object->tracking = (array)$object->tracking; + if(is_array($object->tracking) && count($object->tracking)>1){ + + $lastT = $object->tracking[count($object->tracking)-1]; + + $stateType = $lastT->definitivo?'DEFINITIVO':'TRANSITORIO'; + $stateDescription = $lastT->descrizione; + + } + }else{ + if(isset($object->stateType)){ + $stateType = $object->stateType; + $stateDescription = $object->state; + } + } + $this->data->stateType = $stateType; + $this->data->stateDescription = $stateDescription; + $this->itData->stateType = $stateType; + $this->itData->stateDescription = $stateDescription; + $this->data->title = isset($object->title)?$object->title:(isset($object->titolo)?$object->titolo:NULL); + $this->data->at = isset($object->at)?$object->at:(isset($object->co)?$object->co:NULL); + $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); + $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); + $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); + $this->data->dug = isset($object->dug)?$object->dug:NULL; + $this->data->address = isset($object->address)?$object->address:(isset($object->indirizzo)?$object->indirizzo:NULL); + $this->data->huoseNumber = isset($object->huoseNumber)?$object->huoseNumber:(isset($object->civico)?$object->civico:NULL); + $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); + $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); + $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); + $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"IT"); + $this->data->email = isset($object->email)?$object->email:NULL; + + $this->data->id = isset($object->id)?$object->id:NULL; + $this->data->state = isset($object->state)?$object->state:NULL; + $this->data->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; + $this->data->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; + $this->data->post_office = isset($object->post_office)?$object->post_office:(isset($object->ufficio_postale)?$object->ufficio_postale:NULL); + $this->data->post_office_box = isset($object->post_office_box)?$object->post_office_box:(isset($object->casella_postale)?$object->casella_postale:NULL); + + + + $this->itData->ufficio_postale = $this->data->post_office; + $this->itData->casella_postale = $this->data->post_office_box; + $this->itData->co = $this->data->at; + $this->itData->titolo = $this->data->title; + $this->itData->nome = $this->data->firstName; + $this->itData->cognome = $this->data->secondName; + $this->itData->ragione_sociale = $this->data->companyName; + $this->itData->dug = $this->data->dug; + $this->itData->indirizzo = $this->data->address; + $this->itData->civico = $this->data->huoseNumber; + $this->itData->comune = $this->data->city; + $this->itData->cap = $this->data->zip; + $this->itData->provincia = $this->data->province; + $this->itData->nazione = $this->data->country; + $this->itData->email = $this->data->email; + $this->itData->id= $this->data->id; + $this->itData->state= $this->data->state; + + $this->itData->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; + $this->itData->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; + + } +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/PostaOrdinaria.php b/src/classes/utility/UfficioPostale/PostaOrdinaria.php new file mode 100644 index 0000000..15f7a67 --- /dev/null +++ b/src/classes/utility/UfficioPostale/PostaOrdinaria.php @@ -0,0 +1,92 @@ +getId() == NULL){ + throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + } + if($this->getState() != "NEW"){ + throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + } + $param['confirmed'] = TRUE; + $ret = call_user_func_array($this->connect,["ordinarie/".$this->getId(),"PATCH",$param]); + + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + } + + function send(){ + try{ + $object = new \stdClass();; + $object->mittente = $this->sender->getObject(TRUE); + $object->destinatari = []; + foreach($this->getRecpients() as $r){ + $object->destinatari[] = $r->getObject(TRUE); + } + $object->documento =$this->documents; + $object->opzioni = new \stdClass(); + $object->opzioni->fronteretro = $this->getFronteRetro(); + $object->opzioni->colori = $this->getColori(); + $object->opzioni->autoconfirm = $this->getAutoconfirm(); + if($this->getCallback() != NULL){ + $callback = $this->getCallback(); + foreach($callback as $k => $v){ + $object->opzioni->$k = $v; + } + } + $ret = call_user_func_array($this->connect,["ordinarie/","POST",$object]); + $this->pricing = $ret->data[0]->pricing; + $this->id = $ret->data[0]->id; + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->pages = $ret->data[0]->documento_validato->pagine; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + return true; + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + $response = $e->getServerResponse(); + //var_dump($response->data->wrong_fields);exit; + if(isset($response->data->wrong_fields) && isset($response->error)){ + $error_message = $this->getError($response->error, $response); + + $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); + $e2->setErrorMessage($error_message); + $e2->setFields($response->data->wrong_fields); + throw $e2; + } + throw $e; + } + } + + + function creaPostaOrdinariaByData($data){ + if(isset($data->documento_validato) && is_object($data->documento_validato)){ + $this->valid_doc_pdf = $data->documento_validato->pdf; + $this->valid_doc_jpg = $data->documento_validato->jpg; + } + $this->pricing = $data->pricing; + $this->id = $data->id; + $this->confirmed = $data->confirmed; + $this->state = $data->state; + $this->numero_pagine = $data->documento_validato->pagine; + $this->clearRecipients(); + $this->setRecipients($data->destinatari); + $this->setSender($data->mittente); + $this->colori = $data->opzioni->colori; + $this->fronteretro = $data->opzioni->fronteretro; + $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); + + if(isset($data->IDRichiesta)){ + $this->request_id = $data->IDRichiesta; + } + + } +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/PostaPrioritaria.php b/src/classes/utility/UfficioPostale/PostaPrioritaria.php new file mode 100644 index 0000000..061a415 --- /dev/null +++ b/src/classes/utility/UfficioPostale/PostaPrioritaria.php @@ -0,0 +1,90 @@ +getId() == NULL){ + throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + } + if($this->getState() != "NEW"){ + throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + } + $param['confirmed'] = TRUE; + $ret = call_user_func_array($this->connect,["prioritarie/".$this->getId(),"PATCH",$param]); + + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + } + + function send(){ + try{ + $object = new \stdClass();; + $object->mittente = $this->sender->getObject(TRUE); + $object->destinatari = []; + foreach($this->getRecpients() as $r){ + $object->destinatari[] = $r->getObject(TRUE); + } + $object->documento =$this->documents; + $object->opzioni = new \stdClass(); + $object->opzioni->fronteretro = $this->getFronteRetro(); + $object->opzioni->colori = $this->getColori(); + $object->opzioni->autoconfirm = $this->getAutoconfirm(); + if($this->getCallback() != NULL){ + $callback = $this->getCallback(); + foreach($callback as $k => $v){ + $object->opzioni->$k = $v; + } + } + $ret = call_user_func_array($this->connect,["prioritarie/","POST",$object]); + $this->pricing = $ret->data[0]->pricing; + $this->id = $ret->data[0]->id; + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->pages = $ret->data[0]->documento_validato->pagine; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + return true; + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + $response = $e->getServerResponse(); + //var_dump($response->data->wrong_fields);exit; + if(isset($response->data->wrong_fields) && isset($response->error)){ + $error_message = $this->getError($response->error, $response); + + $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); + $e2->setErrorMessage($error_message); + $e2->setFields($response->data->wrong_fields); + throw $e2; + } + throw $e; + } + } + + + function creaPostaPrioritariaByData($data){ + if(isset($data->documento_validato) && is_object($data->documento_validato)){ + $this->valid_doc_pdf = $data->documento_validato->pdf; + $this->valid_doc_jpg = $data->documento_validato->jpg; + } + $this->pricing = $data->pricing; + $this->id = $data->id; + $this->confirmed = $data->confirmed; + $this->state = $data->state; + $this->numero_pagine = $data->documento_validato->pagine; + $this->clearRecipients(); + $this->setRecipients($data->destinatari); + $this->setSender($data->mittente); + $this->colori = $data->opzioni->colori; + $this->fronteretro = $data->opzioni->fronteretro; + $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); + if(isset($data->IDRichiesta)){ + $this->request_id = $data->IDRichiesta; + } + } +} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Raccomandata.php b/src/classes/utility/UfficioPostale/Raccomandata.php index 44ccc53..18f2ebf 100644 --- a/src/classes/utility/UfficioPostale/Raccomandata.php +++ b/src/classes/utility/UfficioPostale/Raccomandata.php @@ -2,10 +2,12 @@ namespace OpenApi\classes\utility\UfficioPostale; class Raccomandata extends ServiziPostali { - function __construct($connect){ - parent::__construct($connect); + function __construct($connect, $errorClass){ + parent::__construct($connect, $errorClass); } + + function confirm(){ if($this->getId() == NULL){ throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); @@ -22,10 +24,96 @@ function confirm(){ $this->setRecipients($ret->data[0]->destinatari); } + + /* + public function setRecipients($recipients){ + $this->clearRecipients(); + $valid = TRUE; + foreach($recipients as $key => $recipient){ + if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ + + $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); + } + if(!$recipient->validate()){ + $valid = FALSE; + } + $this->recipients[] = $recipient; + } + $this->validRecipients = $valid; + return $valid; + } + + protected function getError($code, $serverResponse){ + return call_user_func_array($this->errorFunc,[$code, $serverResponse]); + } + + public function addRecipient($recipient){ + + if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ + $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); + } + $valid = TRUE; + if(!$recipient->validate()){ + $valid = FALSE; + } + $this->recipients[] = $recipient; + $this->validRecipients = $valid; + return $valid; + }*/ + + + function send(){ + try{ + $object = new \stdClass();; + $object->mittente = $this->sender->getObject(TRUE); + $object->destinatari = []; + foreach($this->getRecpients() as $r){ + $object->destinatari[] = $r->getObject(TRUE); + } + $object->documento =$this->documents; + $object->opzioni = new \stdClass(); + $object->opzioni->fronteretro = $this->getFronteRetro(); + $object->opzioni->colori = $this->getColori(); + $object->opzioni->ar = $this->getAR(); + $object->opzioni->autoconfirm = $this->getAutoconfirm(); + if($this->getCallback() != NULL){ + $callback = $this->getCallback(); + foreach($callback as $k => $v){ + $object->opzioni->$k = $v; + } + } + $ret = call_user_func_array($this->connect,["raccomandate/","POST",$object]); + $this->pricing = $ret->data[0]->pricing; + $this->id = $ret->data[0]->id; + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->pages = $ret->data[0]->documento_validato->pagine; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + return true; + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + $response = $e->getServerResponse(); + //var_dump($response->data->wrong_fields);exit; + if(isset($response->data->wrong_fields) && isset($response->error)){ + $error_message = $this->getError($response->error, $response); + + $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); + $e2->setErrorMessage($error_message); + $e2->setFields($response->data->wrong_fields); + throw $e2; + } + throw $e; + } + } + + function creaRaccomandataByData($data){ - - + if(isset($data->documento_validato) && is_object($data->documento_validato)){ + $this->valid_doc_pdf = $data->documento_validato->pdf; + $this->valid_doc_jpg = $data->documento_validato->jpg; + } $this->pricing = $data->pricing; $this->id = $data->id; $this->confirmed = $data->confirmed; @@ -38,46 +126,9 @@ function creaRaccomandataByData($data){ $this->fronteretro = $data->opzioni->fronteretro; $this->ar = $data->opzioni->ar; $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); - } - - function send(){ - $object = new \stdClass();; - $object->mittente = $this->sender->getObject(TRUE); - $object->destinatari = []; - foreach($this->getRecpients() as $r){ - $object->destinatari[] = $r->getObject(TRUE); + if(isset($data->IDRichiesta)){ + $this->request_id = $data->IDRichiesta; } - $object->documento =$this->documents; - $object->opzioni = new \stdClass(); - $object->opzioni->fronteretro = $this->getFronteRetro(); - $object->opzioni->colori = $this->getColori(); - $object->opzioni->ar = $this->getAR(); - $object->opzioni->autoconfirm = $this->getAutoconfirm(); - if($this->getCallback() != NULL){ - $callback = $this->getCallback(); - foreach($callback as $k => $v){ - $object->opzioni->$k = $v; - } - } - // var_dump($object);exit; - if($this->getId() == NULL){ - $ret = call_user_func_array($this->connect,["raccomandate/","POST",$object]); - }else{ - $ret = call_user_func_array($this->connect,["raccomandate/".$this->getId(),"PATCH",$object]); - } - - if(!isset($ret->data[0])){ - return false; - } - $this->pricing = $ret->data[0]->pricing; - $this->id = $ret->data[0]->id; - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->numero_pagine = $ret->data[0]->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - return true; - //$ret= $this->connect->call($this,"raccomandate",$object,"POST"); - } + } \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/ServiziPostali.php b/src/classes/utility/UfficioPostale/ServiziPostali.php index 3e0c16b..a9b19a7 100644 --- a/src/classes/utility/UfficioPostale/ServiziPostali.php +++ b/src/classes/utility/UfficioPostale/ServiziPostali.php @@ -17,12 +17,19 @@ class ServiziPostali { protected $confirmed; protected $state; protected $callback; + protected $pages; + protected $request_id; protected $numero_pagine; + protected $valid_doc_pdf; + protected $valid_doc_jpg; - function __construct($connect){ + function __construct($connect, $errorFunc){ $this->connect = $connect; $this->sender = NULL; + $this->errorFunc = $errorFunc; $this->recipients = []; + $this->valid_doc_pdf = NULL; + $this->valid_doc_jpg = NULL; $this->documents = []; $this->textMessage = NULL; $this->validRecipients = FALSE; @@ -37,9 +44,34 @@ function __construct($connect){ $this->callback = NULL; } + + function setRequestId($request_id){ + $this->request_id = $request_id; + } + + function getRequestId(){ + return $this->request_id ; + } + + function getValidatedDocument($type = "pdf"){ + if($type == "pdf"){ + return $this->valid_doc_pdf; + } + if($type == "jpg"){ + return $this->valid_doc_jpg; + } + } + + function getNumeroLettere(){ + throw new \OpenApi\classes\exception\OpenApiUPException("Letter exist only for telagrammi",40016); + } + function getNumeroPagine(){ return $this->numero_pagine; } + function getPages(){ + return $this->pages; + } function getPricing(){ return $this->pricing; @@ -113,9 +145,9 @@ public function getSenderError(){ } public function getRecipients(){ - return $this->recipients; + return $this->getRecpients(); } - + //MANTENUTO PER RETROCOMPATIBILITA' public function getRecpients(){ return $this->recipients; } @@ -155,6 +187,10 @@ public function setRecipients($recipients){ return $valid; } + protected function getError($code, $serverResponse){ + return call_user_func_array($this->errorFunc,[$code, $serverResponse]); + } + public function addRecipient($recipient){ if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ diff --git a/src/classes/utility/UfficioPostale/Telegramma.php b/src/classes/utility/UfficioPostale/Telegramma.php new file mode 100644 index 0000000..1a86447 --- /dev/null +++ b/src/classes/utility/UfficioPostale/Telegramma.php @@ -0,0 +1,148 @@ +letter = NULL; + $this->ar_e = false; + $this->ar_c = false; + } + + function getNumeroLettere(){ + return $this->letter; + } + + function getNumeroParole(){ + return $this->parole; + } + function getNumeroPagine(){ + throw new \OpenApi\classes\exception\OpenApiUPException("Pages not exist for telagrammi",40015); + } + + + function confirm(){ + if($this->getId() == NULL){ + throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + } + if($this->getState() != "NEW"){ + throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + } + $param['confirmed'] = TRUE; + $ret = call_user_func_array($this->connect,["telegrammi/".$this->getId(),"PATCH",$param]); + + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + } + + + function send(){ + try{ + $object = new \stdClass();; + $object->mittente = $this->sender->getObject(TRUE); + $object->destinatari = []; + foreach($this->getRecpients() as $r){ + $object->destinatari[] = $r->getObject(TRUE); + } + $object->documento =$this->documents; + $object->opzioni = new \stdClass(); + + $object->opzioni->ar_c = is_bool($this->ar_c)?$this->ar_c:$this->ar_c->getObject(TRUE); + + $object->opzioni->ar_e = $this->ar_e; + + if($this->getCallback() != NULL){ + $callback = $this->getCallback(); + foreach($callback as $k => $v){ + $object->opzioni->$k = $v; + } + } + $ret = call_user_func_array($this->connect,["telegrammi/","POST",$object]); + $this->pricing = $ret->data[0]->pricing; + $this->id = $ret->data[0]->id; + $this->confirmed = $ret->data[0]->confirmed; + $this->state = $ret->data[0]->state; + $this->letter = $ret->data[0]->documento_validato->size; + $this->parole = $ret->data[0]->documento_validato->parole; + $this->clearRecipients(); + $this->setRecipients($ret->data[0]->destinatari); + return true; + }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + $response = $e->getServerResponse(); + if(isset($response->data->wrong_fields) && isset($response->error)){ + $error_message = $this->getError($response->error, $response); + + $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); + $e2->setErrorMessage($error_message); + $e2->setFields($response->data->wrong_fields); + throw $e2; + } + throw $e; + } + } + + function creaTelegrammaByData($data){ + if(isset($data->documento_validato) && is_object($data->documento_validato)){ + $this->valid_doc_pdf = $data->documento_validato->pdf; + $this->valid_doc_jpg = $data->documento_validato->jpg; + } + $this->pricing = $data->pricing; + $this->id = $data->id; + $this->confirmed = $data->confirmed; + $this->state = $data->state; + $this->letter = $data->documento_validato->size; + $this->parole = $data->documento_validato->parole; + $this->clearRecipients(); + $this->setRecipients($data->destinatari); + $this->setSender($data->mittente); + $this->ar_e = isset($data->opzioni->ar_e)?$data->opzioni->ar_e:FALSE; + $this->ar_c = isset($data->opzioni->ar_c)?$data->opzioni->ar_c:FALSE; + /* $this->colori = $data->opzioni->colori; + $this->fronteretro = $data->opzioni->fronteretro; + $this->ar = $data->opzioni->ar;*/ + $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); + if(isset($data->IDRichiesta)){ + $this->request_id = $data->IDRichiesta; + } + + } + + + function setRicevutaElettronica($ar_e){ + $this->ar_e = $ar_e; + } + + function getRicevutaElettronica(){ + return $this->ar_e; + } + + function setRicevutaCartacea($ar_c){ + if(is_bool(($ar_c))){ + $this->ar_c = $ar_c; + return TRUE; + }else{ + if($ar_c instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Sender){ + $this->ar_c = $ar_c; + }else{ + $this->ar_c = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($ar_c); + } + if(!$this->ar_c->validate()){ + return FALSE; + } + return TRUE; + } + + } + + function getRicevutaCartacea(){ + return $this->ar_c; + } + +} \ No newline at end of file diff --git a/src/classes/utility/VisRequest.php b/src/classes/utility/VisRequest.php new file mode 100644 index 0000000..447219b --- /dev/null +++ b/src/classes/utility/VisRequest.php @@ -0,0 +1,434 @@ + visengin",40008); + } + $this->visura = $visura; + $this->variables = []; + $this->new = TRUE; + $this->json = NULL; + $this->jsonValido = FALSE; + $this->state = 0; + $this->test = false; + $this->callback = NULL; + $this->email_target = NULL; + $this->id = NULL; + $this->statoRichiesta = NULL; + $this->ricerche = []; + $this->document = NULL; + $this->format_errror = []; + $this->opzioni = null; + foreach($visura->data->json_struttura->campi as $k => $v){ + $this->variables[$k] = FALSE; + } + } + + function setOpzioni($opzioni){ + $this->opzioni = $opzioni; + } + + function getOpzioni(){ + return $this->opzioni; + } + + function setNew(bool $new){ + return $this->new = $new; + } + + function getNew(){ + return $this->new; + } + /** + * + * Imposta il JSON per inviare una nuova visura + * + * @param array $data IL JSON della visura da inviare + * + * @return boolean Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono stati compilati (attenzione, viene effettuata la sola validazione sui required, per la validazione del formato occcorre inviare la visura) + */ + function setJson(object $data){ + foreach($data as $k => $v){ + if(!isset($this->variables[$k])){ + throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); + } + $this->variables[$k] = $v!=NULL; + } + $this->json = $data; + + $this->validaJSON(); + return $this->jsonValido; + } + + + + + + /** + * + * Restituisce il JSON della visura + * + * @return object + */ + function getJson(){ + return $this->json; + } + + /** + * Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON + * @return boolean + */ + function isValidJson(){ + return $this->jsonValido; + } + + /** + * + * Imposta i dati della callback + * + * @param string $url La url da richiamare per la callback + * @param object $data Oggetto data che verrà ripassato + * @param string $method='JSON' Metodo da usare JSON/POST + * @param string $field="visengineData" Nome del campo dove verranno passati i dati della visura + * + * @return void + */ + function setCallbackData(string $url, object $data, $method = "JSON", $field="visengineData"){ + $this->callback = (object)[ + "url" => $url, + "data" => $data, + "method" => $method, + "field" => $field + ]; + } + + + /** + * Restituisce i dati della callback + * + * @return object + */ + function getCallbackData(){ + return $this->callback; + } + + /** + * Impowsta il parametro state della visura + * @param int $stato + * + * @return void + */ + function setState($stato = 0){ + if($stato != 0 && !$this->jsonValido ){ + throw new \OpenApi\classes\exception\OpenApiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); + } + $this->state = $stato == 0 ? $stato : 1; + } + + /** + * Ritorna il parametro state + * @return int + */ + function getState(){ + return $this->state; + } + + /** + * Imposta il parametro email_target + * + * @param string $email_target + * + * @return void + */ + function setTargetEmail(string $email_target){ + $this->email_target = $email_target; + } + + /** + * Ritorna il parametro email_target + * @return string + */ + function getTargetEmail(){ + return $this->email_target; + } + + function hasSearchResult(){ + return $this->visura->data->ricerca == 1 && $this->getStatoRichiesta() == "In ricerca" && $this->getStatoRicerca() == "Ricerca evasa"; + } + + function getSearchResult(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return json_decode($this->ricerche[count($this->ricerche) - 1]->json_risultato); + } + function getSearchId(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return $this->ricerche[count($this->ricerche) - 1]->id_ricerca; + } + function getSearch(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return $this->ricerche[count($this->ricerche) - 1]; + } + + function getSearchCount(){ + return count($this->ricerche); + } + + function setDocument($document){ + $this->document = $document; + } + + function getDocument(){ + return $this->document; + } + + function getHash(){ + return $this->visura->data->hash_visura; + } + + + /** + * + * Imposta il parametro test + * + * @param bool $test + * + * @return void + */ + function setTest(bool $test){ + $this->test = $test; + } + + + /** + * Restituisce il parametro test + * @return bool + */ + function getTest(){ + return $this->test; + } + + + /** + * Controlla il JSON e ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON + * @return boolean + */ + private function validaJSON(){ + if(!$this->validaPresenzaCampi()){ + $this->format_errror = []; + $this->jsonValido = FALSE; + return; + } + $this->format_errror = []; + if(!$this->validaFormatoCampi()){ + $this->jsonValido = FALSE; + return; + } + $this->jsonValido = TRUE; + + } + + private function validaFormatoCampi(){ + $error = FALSE; +// var_dump($this->visura->data->json_struttura->campi);exit; + + //cod_comune + //cod_provincia + //codice_fiscale_persona_fisica + foreach($this->visura->data->json_struttura->campi as $key => $campo){ + if(!isset($this->json->$key) || $this->json->$key == ""){ + continue; + } + if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale_persona_fisica'){ + $val = new \OpenApi\classes\utility\Plugins\Validations(); + if(!$val->italianFiscalCode($this->json->$key)){ + $this->format_errror[$key] = 'codice_fiscale_persona_fisica'; + $error = TRUE; + } + } + + if(isset($campo->tipo) && $campo->tipo == 'partita_iva'){ + $val = new \OpenApi\classes\utility\Plugins\Validations(); + if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ + $this->format_errror[$key] = 'partita_iva'; + $error = TRUE; + } + } + + if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale'){ + $val = new \OpenApi\classes\utility\Plugins\Validations(); + if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ + $this->format_errror[$key] = 'codice_fiscale'; + $error = TRUE; + } + } + if(isset($campo->tipo) && $campo->tipo == 'cod_comune'){ + $re = '/^[a-zA-Z]{1}[0-9]{3}$/m'; + + preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); + if(count($matches) == 0){ + $this->format_errror[$key] = 'cod_comune'; + $error = TRUE; + } + } + + if(isset($campo->tipo) && $campo->tipo == 'cod_provincia'){ + $re = '/^[a-zA-Z]{2}$/m'; + + preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); + if(count($matches) == 0){ + $this->format_errror[$key] = 'cod_provincia'; + $error = TRUE; + } + } + if(isset($campo->tipo) && $campo->tipo == 'data_iso8601'){ + $d = \DateTime::createFromFormat("d-m-Y", $this->json->$key); + + if(!($d && $d->format('d-m-Y') === $this->json->$key)){ + $this->format_errror[$key] = 'data_iso8601'; + $error = TRUE; + } + } + } + return !$error; + } + + private function validaPresenzaCampi(){ + $re = '/\$(\d)+/m'; + $validazione = $this->visura->data->json_struttura->validazione; + $subst = '$this->variables[\'$0\']'; + $valida = TRUE; + $validazione = '$valida = ' .preg_replace($re, $subst, $validazione).";"; + eval($validazione); + return $valida; + } + + public function getErrors(){ + if(count($this->format_errror) != 0){ + $ret['error_type'] = "format"; + $ret['error'] = $this->format_errror; + return $ret; + } + $this->expr = []; + $validazione = $this->visura->data->json_struttura->validazione; + + list($validazione, $expr) =$this->createExpression($validazione); + + //var_dump($validazione);exit; + $errori = $this->valida($validazione, $expr); + + $ret['error_type'] = "empty_fields"; + $ret['error'] = $errori; + return $ret; + + } + + private function valida($validazione,$expr, $errori = []){ + //var_dump($this->variables); + $errori = ["type"=>"and","list"=>[]]; + $and = explode('&&',$validazione); + foreach($and as $andItem){ + $andItem = trim($andItem); + $or = explode('||',$andItem); + if(count($or) == 1){ + $orItem = $or[0]; + if(substr($orItem,0,1)=='$'){ + if(!$this->variables[$orItem]){ + $errori['list'][] = $orItem; + } + }else{ + $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); + if(count($errors)){ + + $errori['list'] = array_merge($errori['list'], $errors['list']); + + } + } + }else{ + $errore = false; + $item = array(); + $hasError = true; + foreach($or as $orItem){ + $orItem = trim($orItem); + if(substr($orItem,0,1)=='$'){ + $item[] = $orItem; + if($this->variables[$orItem]){ + + $hasError = FALSE; + } + }else{ + $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); + if(count($errors['list'])){ + $item[] = $errors; + }else{ + $hasError = FALSE; + } + } + } + + if($hasError){ + $errori['list'][] = ["type"=>"or","list"=>$item]; + } + } + } + + return $errori; + } + + private function createExpression($validazione, $expr = []){ + $preg = "/\(([$\d&| e]*?)\)/"; + preg_match($preg, $validazione, $matches, PREG_OFFSET_CAPTURE, 0); + if(isset($matches[0]) && isset($matches[1])){ + $expr[] = $matches[1][0]; + $expn = count($expr)-1; + $validazione = str_replace($matches[0],"e{$expn}",$validazione); + return $this->createExpression($validazione, $expr); + } + return array($validazione, $expr); + + } + + function getId() { + return $this->id; + } + + function setId($id) { + $this->id = $id; + } + + function getStatoRichiesta() { + return $this->statoRichiesta; + } + + function setStatoRichiesta($statoRichiesta) { + $this->statoRichiesta = $statoRichiesta; + } + + function getRicerche() { + return $this->ricerche; + } + + function setRicerche($ricerche) { + $this->ricerche = $ricerche; + } + + function getStatoRicerca(){ + if(count($this->ricerche) == NULL){ + return FALSE; + } + return $this->ricerche[count($this->ricerche) - 1]->stato_ricerca; + } + + function getValidation(){ + return $validazione = $this->visura->data->json_struttura->validazione;; + } +} \ No newline at end of file From 2e80b3efb00e73078c222d063f53d193acd88bab Mon Sep 17 00:00:00 2001 From: Lorenzo Paderi Date: Thu, 24 Feb 2022 13:03:20 +0100 Subject: [PATCH 53/85] Merge 'readme.md' from 'fix-linting' into 'master' --- readme.md | 239 +++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 218 insertions(+), 21 deletions(-) diff --git a/readme.md b/readme.md index 4911d52..139e3c8 100644 --- a/readme.md +++ b/readme.md @@ -1,61 +1,258 @@ # OpenAPI Library -## Installation + +* 1. [Installation](#Installation) +* 2. [Usage](#Usage) + * 2.1. [Instanza della classe](#Instanzadellaclasse) + * 2.2. [Esempi](#Esempi) +* 3. [Modulo comuni](#Modulocomuni) + * 3.1. [Esempi](#Esempi-1) +* 4. [Modulo imprese](#Moduloimprese) + * 4.1. [Utilizzo](#Utilizzo) + * 4.2. [Esempi](#Esempi-1) +* 5. [Modulo Marche Temporali](#ModuloMarcheTemporali) + * 5.1. [Esempi](#Esempi-1) +* 6. [Modulo SMS](#ModuloSMS) + * 6.1. [Inviare un SMS](#InviareunSMS) +* 7. [Modulo Visengine](#ModuloVisengine) + + + + + +## 1. Installation ```sh composer require altravia/openapi ``` -## Usage +## 2. Usage -### Instanza della classe +### 2.1. Instanza della classe ```php - $this->openapi = new \OpenApi\OpenApi($scopes,$user,$apikey,"test"); +require_once 'vendor/autoload.php'; + +$openapi = new \OpenApi\OpenApi($scopes, $user, $apikey, $environment); ``` Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: ```php -$scopes=[ +$scopes = [ "GET:ws.ufficiopostale.com/comuni", - ["domain"=>"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] + [ + "domain"=>"ws.ufficiopostale.com", + "method"=>"comuni", + "mode" =>"GET" + ] ]; ``` ...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` +OpenApi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. + +A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: -A questo punto, in base agli scopes indicati vengono creati i seguenti oggetto: ```php -$this->openapi->ufficiopostale -$this->openapi->imprese -... +// Ogni oggetto verrá creato solo se disponibile nello scope. +$openapi->ufficiopostale; +$openapi->comuni; +$openapi->imprese; +$openapi->visengine; +$openapi->marcheTemporali; +$openapi->geocoding; +$openapi->SMS; +$openapi->firmaDigitale; +$openapi->pecMassiva; ``` - che possono essere usati al seguente modo: ```php $this->openapi->ufficioposale->getCitiesByCap('00132'); ``` +### 2.2. Esempi + +```php +require_once 'vendor/autoload.php'; + +// Dichiaro gli scopes necessari +$scopes = [ + 'GET:comuni.openapi.it/cap', + 'GET:imprese.altravia.com/advance', +]; + +$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'test'); + +// Comuni: prendi informazioni sul cap 00132 +$cap = $openapi->comuni->getCitiesByCap('00132'); + +// Imprese: prendi informazioni su una specifica impresa +$impresa = $openapi->imprese->getByPartitaIva('12485671007'); + +// Ufficio Postale: ottieni informaizoni sul tracking +$track = $this->openapi->ufficiopostale->track('123456789'); +``` + + +## 3. Modulo comuni +Consente di prendere informazioni su comuni e provincie. + +* `getCitiesByCap` +* `getComuneByCatasto` +* `getRegioni` +* `getProvince` +* `getComuni` + +### 3.1. Esempi + +```php +$provincia = 'RM'; +$comuni = $this->openapi->comuni->getComuni($provincia); + +var_dump($comuni['comuni']); +/* + +["nome_provincia"]=> + string(4) "Roma" + ["sigla_provincia"]=> + string(2) "RM" + ["regione"]=> + string(5) "Lazio" + ["comuni"]=> + array(121) { + [0]=> + string(6) "Affile" + ... +*/ + + +``` + +## 4. Modulo imprese +### 4.1. Utilizzo +Il modulo imprese espone i seguenti metodi: +* `getByPartitaIva` +* `getClosed` +* `getVatGroup` +* `getPec` +* `getBySearch` + +Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` + +### 4.2. Esempi +Utilizziamo `getBySearch` per cercare un'azienda il cui nome inizia con `Altrav` a Roma + +```php +$autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); + +/* + [0]=> + object(stdClass)#41 (10) { + ["piva"]=> + string(11) "12485671007" + ["cf"]=> + string(11) "12485671007" + ["denominazione"]=> + string(20) "ALTRAVIA SERVIZI SRL" + [1]=> + object(stdClass)#42 (10) { + ["id"]=> + string(24) "4242424242" + ["denominazione"]=> + string(18) "xxx Altravia Esempio 2" + ... + */ +``` + +## 5. Modulo Marche Temporali +* `availability` +* `checkLotto` +* `purcahse` + +### 5.1. Esempi + +```php +// Controlliamo la disponibilitá di una marca di inforcert o aruba +$disponibilita = $this->openapi->marcheTemporali->availability('infocert', 1); + +// Se le marche sono disponibili, acquistiamone una +if ($disponibilita->availability > 0) { + try { + $marca = $this->openapi->marcheTemporali->purcahse('infocert', 1); + } catch (\OpenApi\classes\exception\OpenApiMarcheTemporaliException $e) { + error_log(var_dump($e)); + } +} +``` + +## 6. Modulo SMS +* `getRecipients` +* `getMessage` +* `sendMore` +* `sendOne` + +### 6.1. Inviare un SMS +Per inviare un SMS, per prima cosa definiamo i destinatari: + +```php +$recipient = '+39-3939989741'; +// OR +$recipients = [ + [ + 'number' => '+39-3939989741', + 'fields' => ['nome' => 'NomeDestinatario'] + ] +]; +``` -# Modulo ufficio postale +Possiamo ora procedere ad inviare un SMS: +```php -# Modulo visure +try { + $priority = 1; + $options = null; + $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, $priority, $options); +} catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { + throw 'Non è stato possibile recapitare il messaggio'; +} +``` -# Modulo imprese +Possiamo anche speficiare i prefissi in modo indipendente: +```php +$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, null); +``` -## `getByPartitaIva` +O passare delle opzioni +```php +$options = ['timestamp_send' => '2021-04-20'] +$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); +``` -### Introduction +## 7. Modulo Visengine +Come prima cosa, settiamo l'hash della visura che vogliamo richiedere -La funzione consente di recuperare i dati aziendali a partire dalla partita IVA +```php +// https://developers.openapi.it/services/visengine +$this->openapi->visengine->setHash($visura->hash); +``` -### Description +A questo punto, possiamo lanciare `createRequest`, che ritornerà una istanza vuota della visura che andremo a creare della struttura richiesta -`function getByPartitaIva(string $partitaIva, $ttl = 86400):object` +```php +$request = $this->openapi->visengine->createRequest(); +``` -* $partitaIva: La partita IVA da cercare -* $ttl: Time To Release, per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta +Prodediamo a completare l'oggetto, che potremmo passare a sendRequest quando pronto +```php +$request->setJson(['$0' => 'abcd', '$1' => '12485671007']); + // url di callback, oggetto con dati aggiuntivi, metodo +$request->setCallbackData('https://example.com', new stdClass(), 'POST'); +$visura = $this->openapi->visengine->sendRequest($request); +``` \ No newline at end of file From 28def3741e6c5fe1577b9154d4fb387da207f999 Mon Sep 17 00:00:00 2001 From: francesco Date: Mon, 13 Oct 2025 20:21:09 +0200 Subject: [PATCH 54/85] chore: init quality maintenance --- .github/REPOINFO.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .github/REPOINFO.txt diff --git a/.github/REPOINFO.txt b/.github/REPOINFO.txt new file mode 100644 index 0000000..e69de29 From d198c335e76718b42fad61e028a9805a78df2786 Mon Sep 17 00:00:00 2001 From: francesco Date: Mon, 13 Oct 2025 20:30:29 +0200 Subject: [PATCH 55/85] chore: upkeep --- .github/assets/repo-header-a3.png | Bin 0 -> 72023 bytes .github/assets/repo-header-a3.txt | 15 + readme.md => README.md | 529 +++++++++++++++--------------- 3 files changed, 287 insertions(+), 257 deletions(-) create mode 100644 .github/assets/repo-header-a3.png create mode 100644 .github/assets/repo-header-a3.txt rename readme.md => README.md (88%) diff --git a/.github/assets/repo-header-a3.png b/.github/assets/repo-header-a3.png new file mode 100644 index 0000000000000000000000000000000000000000..3db54204d56f3a78206b802f343cd5df829a19e0 GIT binary patch literal 72023 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 literal 0 HcmV?d00001 diff --git a/.github/assets/repo-header-a3.txt b/.github/assets/repo-header-a3.txt new file mode 100644 index 0000000..3ba3803 --- /dev/null +++ b/.github/assets/repo-header-a3.txt @@ -0,0 +1,15 @@ +Image Description Sheet +----------------------- + +File Name: repo-header-a3.png +Format: PNG +Dimensions: 830 x 173 pixels + +Short Description: +A banner image featuring the word "PHP" on the left, PHP code snippet in the background, +and the Openapi logo on the right. + +Purpose: +This image is intended to be used as a header/banner for documentation or repository README. +It visually associates Rust programming language with the Openapi SDK/client, +giving a professional and modern look to the project materials. diff --git a/readme.md b/README.md similarity index 88% rename from readme.md rename to README.md index 139e3c8..2b8cb6d 100644 --- a/readme.md +++ b/README.md @@ -1,258 +1,273 @@ -# OpenAPI Library - - -* 1. [Installation](#Installation) -* 2. [Usage](#Usage) - * 2.1. [Instanza della classe](#Instanzadellaclasse) - * 2.2. [Esempi](#Esempi) -* 3. [Modulo comuni](#Modulocomuni) - * 3.1. [Esempi](#Esempi-1) -* 4. [Modulo imprese](#Moduloimprese) - * 4.1. [Utilizzo](#Utilizzo) - * 4.2. [Esempi](#Esempi-1) -* 5. [Modulo Marche Temporali](#ModuloMarcheTemporali) - * 5.1. [Esempi](#Esempi-1) -* 6. [Modulo SMS](#ModuloSMS) - * 6.1. [Inviare un SMS](#InviareunSMS) -* 7. [Modulo Visengine](#ModuloVisengine) - - - - - -## 1. Installation - -```sh -composer require altravia/openapi -``` - -## 2. Usage - -### 2.1. Instanza della classe - -```php -require_once 'vendor/autoload.php'; - -$openapi = new \OpenApi\OpenApi($scopes, $user, $apikey, $environment); -``` - -Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: - -```php -$scopes = [ - "GET:ws.ufficiopostale.com/comuni", - [ - "domain"=>"ws.ufficiopostale.com", - "method"=>"comuni", - "mode" =>"GET" - ] -]; -``` - -...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` - -OpenApi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. - -A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: - - -```php -// Ogni oggetto verrá creato solo se disponibile nello scope. -$openapi->ufficiopostale; -$openapi->comuni; -$openapi->imprese; -$openapi->visengine; -$openapi->marcheTemporali; -$openapi->geocoding; -$openapi->SMS; -$openapi->firmaDigitale; -$openapi->pecMassiva; -``` -che possono essere usati al seguente modo: - -```php -$this->openapi->ufficioposale->getCitiesByCap('00132'); -``` -### 2.2. Esempi - -```php -require_once 'vendor/autoload.php'; - -// Dichiaro gli scopes necessari -$scopes = [ - 'GET:comuni.openapi.it/cap', - 'GET:imprese.altravia.com/advance', -]; - -$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'test'); - -// Comuni: prendi informazioni sul cap 00132 -$cap = $openapi->comuni->getCitiesByCap('00132'); - -// Imprese: prendi informazioni su una specifica impresa -$impresa = $openapi->imprese->getByPartitaIva('12485671007'); - -// Ufficio Postale: ottieni informaizoni sul tracking -$track = $this->openapi->ufficiopostale->track('123456789'); -``` - - -## 3. Modulo comuni -Consente di prendere informazioni su comuni e provincie. - -* `getCitiesByCap` -* `getComuneByCatasto` -* `getRegioni` -* `getProvince` -* `getComuni` - -### 3.1. Esempi - -```php -$provincia = 'RM'; -$comuni = $this->openapi->comuni->getComuni($provincia); - -var_dump($comuni['comuni']); -/* - -["nome_provincia"]=> - string(4) "Roma" - ["sigla_provincia"]=> - string(2) "RM" - ["regione"]=> - string(5) "Lazio" - ["comuni"]=> - array(121) { - [0]=> - string(6) "Affile" - ... -*/ - - -``` - -## 4. Modulo imprese -### 4.1. Utilizzo -Il modulo imprese espone i seguenti metodi: -* `getByPartitaIva` -* `getClosed` -* `getVatGroup` -* `getPec` -* `getBySearch` - -Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` - -### 4.2. Esempi -Utilizziamo `getBySearch` per cercare un'azienda il cui nome inizia con `Altrav` a Roma - -```php -$autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); - -/* - [0]=> - object(stdClass)#41 (10) { - ["piva"]=> - string(11) "12485671007" - ["cf"]=> - string(11) "12485671007" - ["denominazione"]=> - string(20) "ALTRAVIA SERVIZI SRL" - [1]=> - object(stdClass)#42 (10) { - ["id"]=> - string(24) "4242424242" - ["denominazione"]=> - string(18) "xxx Altravia Esempio 2" - ... - */ -``` - -## 5. Modulo Marche Temporali -* `availability` -* `checkLotto` -* `purcahse` - -### 5.1. Esempi - -```php -// Controlliamo la disponibilitá di una marca di inforcert o aruba -$disponibilita = $this->openapi->marcheTemporali->availability('infocert', 1); - -// Se le marche sono disponibili, acquistiamone una -if ($disponibilita->availability > 0) { - try { - $marca = $this->openapi->marcheTemporali->purcahse('infocert', 1); - } catch (\OpenApi\classes\exception\OpenApiMarcheTemporaliException $e) { - error_log(var_dump($e)); - } -} -``` - -## 6. Modulo SMS -* `getRecipients` -* `getMessage` -* `sendMore` -* `sendOne` - -### 6.1. Inviare un SMS -Per inviare un SMS, per prima cosa definiamo i destinatari: - -```php -$recipient = '+39-3939989741'; -// OR -$recipients = [ - [ - 'number' => '+39-3939989741', - 'fields' => ['nome' => 'NomeDestinatario'] - ] -]; -``` - -Possiamo ora procedere ad inviare un SMS: -```php - -try { - $priority = 1; - $options = null; - $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, $priority, $options); -} catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { - throw 'Non è stato possibile recapitare il messaggio'; -} -``` - -Possiamo anche speficiare i prefissi in modo indipendente: -```php -$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, null); -``` - -O passare delle opzioni -```php -$options = ['timestamp_send' => '2021-04-20'] -$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); -``` - -## 7. Modulo Visengine -Come prima cosa, settiamo l'hash della visura che vogliamo richiedere - -```php -// https://developers.openapi.it/services/visengine -$this->openapi->visengine->setHash($visura->hash); -``` - -A questo punto, possiamo lanciare `createRequest`, che ritornerà una istanza vuota della visura che andremo a creare della struttura richiesta - -```php -$request = $this->openapi->visengine->createRequest(); -``` - -Prodediamo a completare l'oggetto, che potremmo passare a sendRequest quando pronto - -```php -$request->setJson(['$0' => 'abcd', '$1' => '12485671007']); - // url di callback, oggetto con dati aggiuntivi, metodo -$request->setCallbackData('https://example.com', new stdClass(), 'POST'); -$visura = $this->openapi->visengine->sendRequest($request); +

+ + Openapi SDK for PHP + + +

Openapi® client for Rust

+

The perfect starting point to integrate Openapi® within your Rust project

+ +[![Build Status](https://img.shields.io/github/actions/workflow/status///rust.yml?branch=main)](https://github.com///actions) +[![Crates.io](https://img.shields.io/crates/v/.svg)](https://crates.io/crates/) +[![Docs.rs](https://img.shields.io/docsrs/)](https://docs.rs/) +[![License](https://img.shields.io/github/license//)](LICENSE) +[![Rust Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) +
+ +# OpenAPI Library + + +* 1. [Installation](#Installation) +* 2. [Usage](#Usage) + * 2.1. [Instanza della classe](#Instanzadellaclasse) + * 2.2. [Esempi](#Esempi) +* 3. [Modulo comuni](#Modulocomuni) + * 3.1. [Esempi](#Esempi-1) +* 4. [Modulo imprese](#Moduloimprese) + * 4.1. [Utilizzo](#Utilizzo) + * 4.2. [Esempi](#Esempi-1) +* 5. [Modulo Marche Temporali](#ModuloMarcheTemporali) + * 5.1. [Esempi](#Esempi-1) +* 6. [Modulo SMS](#ModuloSMS) + * 6.1. [Inviare un SMS](#InviareunSMS) +* 7. [Modulo Visengine](#ModuloVisengine) + + + + + +## 1. Installation + +```sh +composer require altravia/openapi +``` + +## 2. Usage + +### 2.1. Instanza della classe + +```php +require_once 'vendor/autoload.php'; + +$openapi = new \OpenApi\OpenApi($scopes, $user, $apikey, $environment); +``` + +Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: + +```php +$scopes = [ + "GET:ws.ufficiopostale.com/comuni", + [ + "domain"=>"ws.ufficiopostale.com", + "method"=>"comuni", + "mode" =>"GET" + ] +]; +``` + +...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` + +OpenApi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. + +A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: + + +```php +// Ogni oggetto verrá creato solo se disponibile nello scope. +$openapi->ufficiopostale; +$openapi->comuni; +$openapi->imprese; +$openapi->visengine; +$openapi->marcheTemporali; +$openapi->geocoding; +$openapi->SMS; +$openapi->firmaDigitale; +$openapi->pecMassiva; +``` +che possono essere usati al seguente modo: + +```php +$this->openapi->ufficioposale->getCitiesByCap('00132'); +``` +### 2.2. Esempi + +```php +require_once 'vendor/autoload.php'; + +// Dichiaro gli scopes necessari +$scopes = [ + 'GET:comuni.openapi.it/cap', + 'GET:imprese.altravia.com/advance', +]; + +$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'test'); + +// Comuni: prendi informazioni sul cap 00132 +$cap = $openapi->comuni->getCitiesByCap('00132'); + +// Imprese: prendi informazioni su una specifica impresa +$impresa = $openapi->imprese->getByPartitaIva('12485671007'); + +// Ufficio Postale: ottieni informaizoni sul tracking +$track = $this->openapi->ufficiopostale->track('123456789'); +``` + + +## 3. Modulo comuni +Consente di prendere informazioni su comuni e provincie. + +* `getCitiesByCap` +* `getComuneByCatasto` +* `getRegioni` +* `getProvince` +* `getComuni` + +### 3.1. Esempi + +```php +$provincia = 'RM'; +$comuni = $this->openapi->comuni->getComuni($provincia); + +var_dump($comuni['comuni']); +/* + +["nome_provincia"]=> + string(4) "Roma" + ["sigla_provincia"]=> + string(2) "RM" + ["regione"]=> + string(5) "Lazio" + ["comuni"]=> + array(121) { + [0]=> + string(6) "Affile" + ... +*/ + + +``` + +## 4. Modulo imprese +### 4.1. Utilizzo +Il modulo imprese espone i seguenti metodi: +* `getByPartitaIva` +* `getClosed` +* `getVatGroup` +* `getPec` +* `getBySearch` + +Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` + +### 4.2. Esempi +Utilizziamo `getBySearch` per cercare un'azienda il cui nome inizia con `Altrav` a Roma + +```php +$autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); + +/* + [0]=> + object(stdClass)#41 (10) { + ["piva"]=> + string(11) "12485671007" + ["cf"]=> + string(11) "12485671007" + ["denominazione"]=> + string(20) "ALTRAVIA SERVIZI SRL" + [1]=> + object(stdClass)#42 (10) { + ["id"]=> + string(24) "4242424242" + ["denominazione"]=> + string(18) "xxx Altravia Esempio 2" + ... + */ +``` + +## 5. Modulo Marche Temporali +* `availability` +* `checkLotto` +* `purcahse` + +### 5.1. Esempi + +```php +// Controlliamo la disponibilitá di una marca di inforcert o aruba +$disponibilita = $this->openapi->marcheTemporali->availability('infocert', 1); + +// Se le marche sono disponibili, acquistiamone una +if ($disponibilita->availability > 0) { + try { + $marca = $this->openapi->marcheTemporali->purcahse('infocert', 1); + } catch (\OpenApi\classes\exception\OpenApiMarcheTemporaliException $e) { + error_log(var_dump($e)); + } +} +``` + +## 6. Modulo SMS +* `getRecipients` +* `getMessage` +* `sendMore` +* `sendOne` + +### 6.1. Inviare un SMS +Per inviare un SMS, per prima cosa definiamo i destinatari: + +```php +$recipient = '+39-3939989741'; +// OR +$recipients = [ + [ + 'number' => '+39-3939989741', + 'fields' => ['nome' => 'NomeDestinatario'] + ] +]; +``` + +Possiamo ora procedere ad inviare un SMS: +```php + +try { + $priority = 1; + $options = null; + $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, $priority, $options); +} catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { + throw 'Non è stato possibile recapitare il messaggio'; +} +``` + +Possiamo anche speficiare i prefissi in modo indipendente: +```php +$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, null); +``` + +O passare delle opzioni +```php +$options = ['timestamp_send' => '2021-04-20'] +$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); +``` + +## 7. Modulo Visengine +Come prima cosa, settiamo l'hash della visura che vogliamo richiedere + +```php +// https://developers.openapi.it/services/visengine +$this->openapi->visengine->setHash($visura->hash); +``` + +A questo punto, possiamo lanciare `createRequest`, che ritornerà una istanza vuota della visura che andremo a creare della struttura richiesta + +```php +$request = $this->openapi->visengine->createRequest(); +``` + +Prodediamo a completare l'oggetto, che potremmo passare a sendRequest quando pronto + +```php +$request->setJson(['$0' => 'abcd', '$1' => '12485671007']); + // url di callback, oggetto con dati aggiuntivi, metodo +$request->setCallbackData('https://example.com', new stdClass(), 'POST'); +$visura = $this->openapi->visengine->sendRequest($request); ``` \ No newline at end of file From 1f9ced3b6097d17a9e6ac15fb6ca4f544995f426 Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 14 Oct 2025 16:00:41 +0200 Subject: [PATCH 56/85] chore: add Makefile --- .idea/.gitignore | 8 ++++++++ .idea/modules.xml | 8 ++++++++ .idea/openapi-php-sdk.iml | 12 +++++++++++ .idea/vcs.xml | 6 ++++++ Makefile | 43 +++++++++++++++++++++++++++++++++++++++ composer.json | 4 ++-- 6 files changed, 79 insertions(+), 2 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/modules.xml create mode 100644 .idea/openapi-php-sdk.iml create mode 100644 .idea/vcs.xml create mode 100644 Makefile diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..ea0548d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/openapi-php-sdk.iml b/.idea/openapi-php-sdk.iml new file mode 100644 index 0000000..24643cc --- /dev/null +++ b/.idea/openapi-php-sdk.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c457881 --- /dev/null +++ b/Makefile @@ -0,0 +1,43 @@ +#!make + +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# # +# ____ _ # +# / __ \____ ___ ____ ____ _____ (_) ® # +# / / / / __ \/ _ \/ __ \/ __ `/ __ \/ / # +# / /_/ / /_/ / __/ / / / /_/ / /_/ / / # +# \____/ .___/\___/_/ /_/\__,_/ .___/_/ # +# /_/ /_/ # +# # +# The Largest Certified API Marketplace # +# Accelerate Digital Transformation • Simplify Processes • Lead Industry # +# # +# ═══════════════════════════════════════════════════════════════════════ # +# # +# Project: openapi-rust-sdk # +# Version: 0.1.0 # +# Author: Michael Cuffaro (@maiku1008) # +# Copyright: (c) 2025 Openapi®. All rights reserved. # +# License: MIT # +# Maintainer: Francesco Bianco # +# Contact: https://openapi.com/ # +# Repository: [Repository URL] # +# Documentation: [Docs URL] # +# # +# ═══════════════════════════════════════════════════════════════════════ # +# # +# "Truth lies at the source of the stream." # +# — English Proverb # +# # +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # + + +## ==================== +## Development Commands +## ==================== + +dev-push: + @git config credential.helper 'cache --timeout=3600' + @git add . + @git commit -m "$$(read -p 'Commit message: ' msg; echo $$msg)" || true + @git push diff --git a/composer.json b/composer.json index 51fc60f..d14abfe 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "altravia/openapi", - "description": "OpenApi PHP Libraries (https://openapi.it)", + "name": "openapi/openapi-sdk", + "description": "OpenApi PHP Libraries (https://openapi.com)", "authors": [ { "name": "Altravia", From f44c43c47a8d98159ea0017846374da1be2b1f8c Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 14 Oct 2025 16:03:27 +0200 Subject: [PATCH 57/85] chore: fix ignore file --- .gitignore | 18 ++++++++++++++++++ .idea/.gitignore | 8 -------- .idea/modules.xml | 8 -------- .idea/openapi-php-sdk.iml | 12 ------------ .idea/vcs.xml | 6 ------ 5 files changed, 18 insertions(+), 34 deletions(-) create mode 100644 .gitignore delete mode 100644 .idea/.gitignore delete mode 100644 .idea/modules.xml delete mode 100644 .idea/openapi-php-sdk.iml delete mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f8f44c --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +.idea/ +.vscode/ +/vendor/ +node_modules/ +npm-debug.log +yarn-error.log +storage/*.key +.env +Homestead.yaml +Homestead.json +/.vagrant +.phpunit.result.cache +/public/build +/storage/pail +.env.backup +.env.production +.phpactor.json +auth.json diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index ea0548d..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/openapi-php-sdk.iml b/.idea/openapi-php-sdk.iml deleted file mode 100644 index 24643cc..0000000 --- a/.idea/openapi-php-sdk.iml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file From a035db9573e151aecc7345a34baeaa42aa665975 Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 14 Oct 2025 16:34:11 +0200 Subject: [PATCH 58/85] chore: init quality maintenance --- README.md | 12 ++--- composer.json | 6 +-- src/OpenApi.php | 50 +++++++++---------- src/classes/Catasto.php | 6 +-- src/classes/Comuni.php | 6 +-- src/classes/FirmaDigitale.php | 6 +-- src/classes/FirrmaDigitale.php | 6 +-- src/classes/Geocoding.php | 6 +-- src/classes/Imprese.php | 14 +++--- src/classes/ImpreseOpenapi.php | 18 +++---- src/classes/MarcheTemporali.php | 8 +-- src/classes/OpenApiBase.php | 14 +++--- src/classes/PecMassiva.php | 18 +++---- src/classes/Sms.php | 18 +++---- src/classes/UfficioPostale.php | 22 ++++---- src/classes/Uploader.php | 16 +++--- src/classes/VisEngine.php | 18 +++---- .../exception/OpenApiConnectionsException.php | 4 +- .../exception/OpenApiExceptionBase.php | 4 +- .../OpenApiMarcheTemporaliException.php | 4 +- .../exception/OpenApiPecMassivaException.php | 4 +- src/classes/exception/OpenApiSMSException.php | 4 +- .../exception/OpenApiTokenException.php | 4 +- src/classes/exception/OpenApiUPException.php | 4 +- .../exception/OpenApiUploaderException.php | 4 +- .../exception/OpenApiVisEngineException.php | 4 +- src/classes/utility/CacheSystemInterface.php | 2 +- src/classes/utility/DummyCache.php | 2 +- src/classes/utility/Plugins/FiscalCode.php | 2 +- src/classes/utility/Plugins/Validations.php | 2 +- .../Objects/ErrorTranslation/errorLang.php | 2 +- .../UfficioPostale/Objects/Recipient.php | 2 +- .../Objects/RecipientRaccomandate.php | 2 +- .../utility/UfficioPostale/Objects/Sender.php | 2 +- .../utility/UfficioPostale/PostaOrdinaria.php | 10 ++-- .../UfficioPostale/PostaPrioritaria.php | 10 ++-- .../utility/UfficioPostale/Raccomandata.php | 18 +++---- .../utility/UfficioPostale/ServiziPostali.php | 16 +++--- .../utility/UfficioPostale/Telegramma.php | 16 +++--- src/classes/utility/Uploader/Collection.php | 24 ++++----- src/classes/utility/VisEngine/VisRequest.php | 14 +++--- src/classes/utility/VisRequest.php | 14 +++--- src/classes/utility/ci4SessionStoreToken.php | 2 +- src/classes/utility/sessionStoreToken.php | 2 +- src/classes/utility/storeTokenInterface.php | 2 +- 45 files changed, 212 insertions(+), 212 deletions(-) diff --git a/README.md b/README.md index 2b8cb6d..efa4a87 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ [![Rust Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) -# OpenAPI Library +# Openapi Library * 1. [Installation](#Installation) @@ -51,7 +51,7 @@ composer require altravia/openapi ```php require_once 'vendor/autoload.php'; -$openapi = new \OpenApi\OpenApi($scopes, $user, $apikey, $environment); +$openapi = new \Openapi\Openapi($scopes, $user, $apikey, $environment); ``` Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: @@ -69,7 +69,7 @@ $scopes = [ ...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` -OpenApi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. +Openapi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: @@ -102,7 +102,7 @@ $scopes = [ 'GET:imprese.altravia.com/advance', ]; -$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'test'); +$openapi = new Openapi\Openapi($scopes, 'my_username','my_api_key', 'test'); // Comuni: prendi informazioni sul cap 00132 $cap = $openapi->comuni->getCitiesByCap('00132'); @@ -200,7 +200,7 @@ $disponibilita = $this->openapi->marcheTemporali->availability('infocert', 1); if ($disponibilita->availability > 0) { try { $marca = $this->openapi->marcheTemporali->purcahse('infocert', 1); - } catch (\OpenApi\classes\exception\OpenApiMarcheTemporaliException $e) { + } catch (\Openapi\classes\exception\OpenapiMarcheTemporaliException $e) { error_log(var_dump($e)); } } @@ -233,7 +233,7 @@ try { $priority = 1; $options = null; $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, $priority, $options); -} catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { +} catch (\Openapi\classes\exception\OpenapiConnectionsException $e) { throw 'Non è stato possibile recapitare il messaggio'; } ``` diff --git a/composer.json b/composer.json index 51fc60f..05b51a4 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { - "name": "altravia/openapi", - "description": "OpenApi PHP Libraries (https://openapi.it)", + "name": "openapi/openapi-sdk", + "description": "Openapi PHP Libraries (https://openapi.com)", "authors": [ { "name": "Altravia", @@ -13,7 +13,7 @@ }, "autoload": { "psr-4": { - "OpenApi\\": "src" + "Openapi\\": "src" } } } diff --git a/src/OpenApi.php b/src/OpenApi.php index f75db74..8c97ab0 100644 --- a/src/OpenApi.php +++ b/src/OpenApi.php @@ -1,6 +1,6 @@ -cache = new \OpenApi\classes\utility\DummyCache; + $this->cache = new \Openapi\classes\utility\DummyCache; $this->store = $store; $this->header = null; $this->rawResponse = null; @@ -68,9 +68,9 @@ function __construct(array $scopes, string $username, string $apikey, $environme } } - $this->validations = new \OpenApi\classes\utility\Plugins\Validations(); - $this->fiscalCode = new \OpenApi\classes\utility\Plugins\FiscalCode(); - // $this->ufficiopostale = new \OpenApi\classes\UfficioPostale($token->token, $domainsRealScopes[$d], $this->cache, $prefix); + $this->validations = new \Openapi\classes\utility\Plugins\Validations(); + $this->fiscalCode = new \Openapi\classes\utility\Plugins\FiscalCode(); + // $this->ufficiopostale = new \Openapi\classes\UfficioPostale($token->token, $domainsRealScopes[$d], $this->cache, $prefix); } /** @@ -82,50 +82,50 @@ function __construct(array $scopes, string $username, string $apikey, $environme private function getListaModuli(){ $moduli = []; $nomi = []; - $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; + $moduli['ws.ufficiopostale.com'] = "\\Openapi\\classes\\UfficioPostale"; $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; - $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; + $moduli['imprese.altravia.com'] = "\\Openapi\\classes\\Imprese"; $nomi['imprese.altravia.com'] = "imprese"; - $moduli['imprese.openapi.it'] = "\\OpenApi\\classes\\ImpreseOpenapi"; + $moduli['imprese.openapi.it'] = "\\Openapi\\classes\\ImpreseOpenapi"; $nomi['imprese.openapi.it'] = "imprese"; - $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; + $moduli['visengine2.altravia.com'] = "\\Openapi\\classes\\VisEngine"; $nomi['visengine2.altravia.com'] = "visengine"; - $moduli['comuni.openapi.it'] = "\\OpenApi\\classes\\Comuni"; + $moduli['comuni.openapi.it'] = "\\Openapi\\classes\\Comuni"; $nomi['comuni.openapi.it'] = "comuni"; - $moduli['ws.marchetemporali.com'] = "\\OpenApi\\classes\\MarcheTemporali"; + $moduli['ws.marchetemporali.com'] = "\\Openapi\\classes\\MarcheTemporali"; $nomi['ws.marchetemporali.com'] = "marcheTemporali"; - $moduli['geocoding.realgest.it'] = "\\OpenApi\\classes\\Geocoding"; + $moduli['geocoding.realgest.it'] = "\\Openapi\\classes\\Geocoding"; $nomi['geocoding.realgest.it'] = "geocoding"; - $moduli['uploader.altravia.com'] = "\\OpenApi\\classes\\Uploader"; + $moduli['uploader.altravia.com'] = "\\Openapi\\classes\\Uploader"; $nomi['uploader.altravia.com'] = "uploader"; - $moduli['ws.messaggisms.com'] = "\\OpenApi\\classes\\Sms"; + $moduli['ws.messaggisms.com'] = "\\Openapi\\classes\\Sms"; $nomi['ws.messaggisms.com'] = "SMS"; - $moduli['pec.openapi.it'] = "\\OpenApi\\classes\\Pec"; + $moduli['pec.openapi.it'] = "\\Openapi\\classes\\Pec"; $nomi['pec.openapi.it'] = "PEC"; - $moduli['catasto.openapi.it'] = "\\OpenApi\\classes\\Catasto"; + $moduli['catasto.openapi.it'] = "\\Openapi\\classes\\Catasto"; $nomi['catasto.openapi.it'] = "catasto"; - $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; + $moduli['ws.firmadigitale.com'] = "\\Openapi\\classes\\FirmaDigitale"; $nomi['ws.firmadigitale.com'] = "firmaDigitale"; return array($moduli,$nomi); } /** * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) + * {@see Openapi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) * * @param mixed $cacheSys Istanza della classe da usare come sistema di cache * @return void @@ -178,14 +178,14 @@ private function renewToken(){ $token = $this->connect("token/".$this->store->get()['token']->token,$param,"PUT"); if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("Renew Token: Connection Error",40001); + throw new \Openapi\classes\exception\OpenapiTokenException("Renew Token: Connection Error",40001); } if($token->success == false){ $message = "REnew Token: unknow error"; if(isset($token->message)) { $message = "REnew Token: $token->message"; } - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); + $except = new \Openapi\classes\exception\OpenapiTokenException($message,40002); $except->setServerResponse($token, $this->header, $this->rawResponse); throw $except; @@ -266,14 +266,14 @@ private function generateNewToken(){ $param = ["scopes" => $this->scopes]; $token = $this->connect("token",$param,"POST"); if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("Getting Token: Connection Error",40001); + throw new \Openapi\classes\exception\OpenapiTokenException("Getting Token: Connection Error",40001); } if($token->success == false){ $message = "Getting Token: unknow error"; if(isset($token->message)) { $message = "Getting Token: $token->message"; } - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); + $except = new \Openapi\classes\exception\OpenapiTokenException($message,40002); $except->setServerResponse($token, $this->header, $this->rawResponse); throw $except; @@ -291,7 +291,7 @@ private function generateNewToken(){ } $message = "Getting Token: invalid scopes (".implode($invalid_scopes).")"; - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40003); + $except = new \Openapi\classes\exception\OpenapiTokenException($message,40003); $except->setServerResponse($token, $this->header, $this->rawResponse); throw $except; } diff --git a/src/classes/Catasto.php b/src/classes/Catasto.php index e07a613..956494b 100644 --- a/src/classes/Catasto.php +++ b/src/classes/Catasto.php @@ -1,11 +1,11 @@ connect("advance/$partitaIva", "GET", [], $ttr, true); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; } @@ -45,7 +45,7 @@ function getClosed(string $partitaIva, $ttr = 86400){ try{ $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -62,7 +62,7 @@ function getVatGroup(string $partitaIva, $ttr = 86400){ try{ $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -79,7 +79,7 @@ function getPec(string $partitaIva, $ttr = 86400){ try{ $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; diff --git a/src/classes/ImpreseOpenapi.php b/src/classes/ImpreseOpenapi.php index ad799d8..d48b925 100644 --- a/src/classes/ImpreseOpenapi.php +++ b/src/classes/ImpreseOpenapi.php @@ -1,10 +1,10 @@ connect("forma_giuridica/$codice", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -44,7 +44,7 @@ function getByPartitaIva(string $partitaIva, $ttr = 86400, $force = false){ try{ $data = $this->connect("advance/$partitaIva", "GET", [], $ttr, true); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; } @@ -62,7 +62,7 @@ function getClosed(string $partitaIva, $ttr = 86400){ try{ $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -79,7 +79,7 @@ function getVatGroup(string $partitaIva, $ttr = 86400){ try{ $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -96,7 +96,7 @@ function getPec(string $partitaIva, $ttr = 86400){ try{ $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -151,7 +151,7 @@ function autocomplete($query, $ttr = 86400){ $data = $data->data; } return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ } return []; diff --git a/src/classes/MarcheTemporali.php b/src/classes/MarcheTemporali.php index b945083..05e4fe1 100644 --- a/src/classes/MarcheTemporali.php +++ b/src/classes/MarcheTemporali.php @@ -1,11 +1,11 @@ availability($type, $qty); //var_dump($data);exit; if($data->availability == 0){ - throw new \OpenApi\classes\exception\OpenApiMarcheTemporaliException("$qty $type time stamps is not availabile for purchase",40009); + throw new \Openapi\classes\exception\OpenapiMarcheTemporaliException("$qty $type time stamps is not availabile for purchase",40009); } //echo "marche/$type/$qty";exit; $data = $this->connect("marche/$type/$qty", "GET", []); diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php index 705bec4..778970e 100644 --- a/src/classes/OpenApiBase.php +++ b/src/classes/OpenApiBase.php @@ -1,12 +1,12 @@ scopes)){ - throw new \OpenApi\classes\exception\OpenApiConnectionsException("Scope missed: $permission",40004); + throw new \Openapi\classes\exception\OpenapiConnectionsException("Scope missed: $permission",40004); } } @@ -151,7 +151,7 @@ public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, if($data == NULL){ - throw new \OpenApi\classes\exception\OpenApiConnectionsException("Connection to $url: Connection Error",40001); + throw new \Openapi\classes\exception\OpenapiConnectionsException("Connection to $url: Connection Error",40001); } if(is_object($data) && $data->success == false){ @@ -171,7 +171,7 @@ public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, } //var_dump($this->rawResponse); - $except = new \OpenApi\classes\exception\OpenApiConnectionsException($message,40002); + $except = new \Openapi\classes\exception\OpenapiConnectionsException($message,40002); $except->setServerResponse($data, $this->header, $this->rawResponse, $httpCode); throw $except; diff --git a/src/classes/PecMassiva.php b/src/classes/PecMassiva.php index dcb7f6b..f45f017 100644 --- a/src/classes/PecMassiva.php +++ b/src/classes/PecMassiva.php @@ -1,6 +1,6 @@ inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + throw new \Openapi\classes\exception\OpenapiPecMassivaException("class must initialized calling initialize function", 40011); } @@ -37,9 +37,9 @@ function getStatus($messageId){ $header[] = 'x-password: '.$this->password; return $this->connect("send/$messageId","GET",[],0,false,$header); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + throw new \Openapi\classes\exception\OpenapiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); } throw $e; @@ -48,7 +48,7 @@ function getStatus($messageId){ function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); + throw new \Openapi\classes\exception\OpenapiPecMassivaException("class must initialized calling initialize function", 40011); } $sender = $sender ? $sender : $this->username; @@ -63,9 +63,9 @@ function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ $params['sender'] = $sender; try{ return $this->connect("send","POST",$params); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); + throw new \Openapi\classes\exception\OpenapiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); } throw $e; diff --git a/src/classes/Sms.php b/src/classes/Sms.php index 0a05d9d..26b03aa 100644 --- a/src/classes/Sms.php +++ b/src/classes/Sms.php @@ -1,10 +1,10 @@ messageId == NULL){ - throw new \OpenApi\classes\exception\OpenApiSMSException("No message id presente",40010); + throw new \Openapi\classes\exception\OpenapiSMSException("No message id presente",40010); exit; } $data = $this->addRecipeintsByMessageId($this->messageId, $recipients, $finish ); @@ -31,7 +31,7 @@ function addRecipeintsByMessageId($messageId, $recipients, $finish = false){ $data = $this->connect("messages/$messageId", "PUT", $param); return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; } @@ -44,7 +44,7 @@ function getRecipients($messageId, $number = NULL){ try{ $data = $this->connect("messages/$messageId/recipients/".$number, "GET", []); return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -58,7 +58,7 @@ function getMessage($messageId){ try{ $data = $this->connect("messages/$messageId", "GET", []); return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -84,7 +84,7 @@ function sendMore($sender, $recipients, $text, $transaction = false, $priority = $this->messageId =$data->data[0]->id; } return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; @@ -113,7 +113,7 @@ function sendOne($sender, $recipient, $text, $prefix = NULL, $priority = 1,$opti $data = $this->connect("messages/", "POST", $param); return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch (\Openapi\classes\exception\OpenapiConnectionsException $e){ if($e->getHTTPCode() == 404){ return null; } diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php index 9b31130..ce2d08d 100644 --- a/src/classes/UfficioPostale.php +++ b/src/classes/UfficioPostale.php @@ -1,11 +1,11 @@ errorClass = new \OpenApi\classes\utility\UfficioPostale\Objects\ErrorTranslation\errorLang($errorLang); + $this->errorClass = new \Openapi\classes\utility\UfficioPostale\Objects\ErrorTranslation\errorLang($errorLang); } function getComuniByCAP($cap){ @@ -41,7 +41,7 @@ function create( $prodotto){ if($prodotto == "posta-ordinaria"){ return $this->createPostaOrdinaria(); } - $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); + $ex = new \Openapi\classes\exception\OpenapiUPException("Il prodotto $prodotto non esiste",40014); throw $ex; } @@ -50,7 +50,7 @@ function create( $prodotto){ * @return object */ function createRaccomandata(){ - return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + return new \Openapi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); }, @@ -62,7 +62,7 @@ function($code, $serverResponse){ } function createPostaPrioritaria(){ - return new \OpenApi\classes\utility\UfficioPostale\PostaPrioritaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + return new \Openapi\classes\utility\UfficioPostale\PostaPrioritaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); }, @@ -74,7 +74,7 @@ function($code, $serverResponse){ } function createPostaOrdinaria(){ - return new \OpenApi\classes\utility\UfficioPostale\PostaOrdinaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + return new \Openapi\classes\utility\UfficioPostale\PostaOrdinaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); }, @@ -86,7 +86,7 @@ function($code, $serverResponse){ } function createTelegramma(){ - return new \OpenApi\classes\utility\UfficioPostale\Telegramma(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ + return new \Openapi\classes\utility\UfficioPostale\Telegramma(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); }, @@ -115,7 +115,7 @@ function getById($id, $prodotto){ if($prodotto == "posta-ordinaria"){ return $this->getPostaOrdinariaById($id); } - $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); + $ex = new \Openapi\classes\exception\OpenapiUPException("Il prodotto $prodotto non esiste",40014); throw $ex; } @@ -133,7 +133,7 @@ function getByData($data, $prodotto){ if($prodotto == "posta-ordinaria"){ return $this->getPostaOrdinariaByData($data); } - $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); + $ex = new \Openapi\classes\exception\OpenapiUPException("Il prodotto $prodotto non esiste",40014); throw $ex; } diff --git a/src/classes/Uploader.php b/src/classes/Uploader.php index 1b5d67f..43398ec 100644 --- a/src/classes/Uploader.php +++ b/src/classes/Uploader.php @@ -1,11 +1,11 @@ connect($endpoint, $method,$data); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ $message = $e->getMessage(); var_dump($message); @@ -82,7 +82,7 @@ function gateway(){ } function createCollection($outputFormat, $outputSize = null, $inputTypes = null, $inputCount = null, $public = null, $watermark = null, $watermarkPosition = NULL, $expireTimestamp = null) { - $collection = new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); + $collection = new \Openapi\classes\utility\Uploader\Collection([$this, 'connect']); $collection->setOutput($outputFormat); $collection->setOutputSize($outputSize); $collection->setInputTypes($inputTypes); @@ -96,7 +96,7 @@ function createCollection($outputFormat, $outputSize = null, $inputTypes = null, function getCollectionById($id){ $coll = $this->connect("collections/$id","GET"); - $collection = new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); + $collection = new \Openapi\classes\utility\Uploader\Collection([$this, 'connect']); if(isset($coll->data)){ $collection->parseData($coll->data); return $collection; diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php index 2869869..854880d 100644 --- a/src/classes/VisEngine.php +++ b/src/classes/VisEngine.php @@ -1,11 +1,11 @@ hash = NULL; @@ -24,7 +24,7 @@ function setHash(string $hash){ function getFormTool(){ if($this->hash == NULL){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); + throw new \Openapi\classes\exception\OpenapiVisEngineException("Visengine hash is not setted",40005); } $url = $this->basePath; $url = str_replace("https://","https://".$this->prefix,$url); @@ -43,22 +43,22 @@ function getFormTool(){ */ function createRequest($ttr = 500){ if($this->hash == NULL){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); + throw new \Openapi\classes\exception\OpenapiVisEngineException("Visengine hash is not setted",40005); } $this->visura = $this->connect("visure/$this->hash", "GET", [], $ttr); defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); - return new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); + return new \Openapi\classes\utility\VisEngine\VisRequest($this->visura); } /** * Invia una request, in base al contenuto della stessa distingue automaticamente se fare la chiamata in POST o PUT * Restituisce la richiesa comprensiva di risposta del server - * @param \OpenApi\classes\utility\VisEngine\VisRequest $request + * @param \Openapi\classes\utility\VisEngine\VisRequest $request * * @return object */ - function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { + function sendRequest(\Openapi\classes\utility\VisEngine\VisRequest $req) { @@ -127,7 +127,7 @@ function getRequestByData($visura){ $this->hash = $visura->data->hash_visura; defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); - $request = new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); + $request = new \Openapi\classes\utility\VisEngine\VisRequest($this->visura); $request->setNew(FALSE); $request->setId($visura->data->_id); $request->setStatoRichiesta($visura->data->stato_richiesta); diff --git a/src/classes/exception/OpenApiConnectionsException.php b/src/classes/exception/OpenApiConnectionsException.php index 15b5818..ac83d71 100644 --- a/src/classes/exception/OpenApiConnectionsException.php +++ b/src/classes/exception/OpenApiConnectionsException.php @@ -1,5 +1,5 @@ getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + throw new \Openapi\classes\exception\OpenapiUPException("Id not present",40011); } if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + throw new \Openapi\classes\exception\OpenapiUPException("State is not NEW",40012); } $param['confirmed'] = TRUE; $ret = call_user_func_array($this->connect,["ordinarie/".$this->getId(),"PATCH",$param]); @@ -50,13 +50,13 @@ function send(){ $this->clearRecipients(); $this->setRecipients($ret->data[0]->destinatari); return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ $response = $e->getServerResponse(); //var_dump($response->data->wrong_fields);exit; if(isset($response->data->wrong_fields) && isset($response->error)){ $error_message = $this->getError($response->error, $response); - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2 = new \Openapi\classes\exception\OpenapiUPFieldsException("Fields Error",40013); $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); $e2->setErrorMessage($error_message); $e2->setFields($response->data->wrong_fields); diff --git a/src/classes/utility/UfficioPostale/PostaPrioritaria.php b/src/classes/utility/UfficioPostale/PostaPrioritaria.php index 061a415..ce93c7f 100644 --- a/src/classes/utility/UfficioPostale/PostaPrioritaria.php +++ b/src/classes/utility/UfficioPostale/PostaPrioritaria.php @@ -1,5 +1,5 @@ getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + throw new \Openapi\classes\exception\OpenapiUPException("Id not present",40011); } if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + throw new \Openapi\classes\exception\OpenapiUPException("State is not NEW",40012); } $param['confirmed'] = TRUE; $ret = call_user_func_array($this->connect,["prioritarie/".$this->getId(),"PATCH",$param]); @@ -50,13 +50,13 @@ function send(){ $this->clearRecipients(); $this->setRecipients($ret->data[0]->destinatari); return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ $response = $e->getServerResponse(); //var_dump($response->data->wrong_fields);exit; if(isset($response->data->wrong_fields) && isset($response->error)){ $error_message = $this->getError($response->error, $response); - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2 = new \Openapi\classes\exception\OpenapiUPFieldsException("Fields Error",40013); $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); $e2->setErrorMessage($error_message); $e2->setFields($response->data->wrong_fields); diff --git a/src/classes/utility/UfficioPostale/Raccomandata.php b/src/classes/utility/UfficioPostale/Raccomandata.php index 18f2ebf..283f76f 100644 --- a/src/classes/utility/UfficioPostale/Raccomandata.php +++ b/src/classes/utility/UfficioPostale/Raccomandata.php @@ -1,5 +1,5 @@ getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + throw new \Openapi\classes\exception\OpenapiUPException("Id not present",40011); } if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + throw new \Openapi\classes\exception\OpenapiUPException("State is not NEW",40012); } $param['confirmed'] = TRUE; $ret = call_user_func_array($this->connect,["raccomandate/".$this->getId(),"PATCH",$param]); @@ -30,9 +30,9 @@ public function setRecipients($recipients){ $this->clearRecipients(); $valid = TRUE; foreach($recipients as $key => $recipient){ - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ + if(!($recipient instanceof \Openapi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); + $recipient = new \Openapi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); } if(!$recipient->validate()){ $valid = FALSE; @@ -49,8 +49,8 @@ protected function getError($code, $serverResponse){ public function addRecipient($recipient){ - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); + if(!($recipient instanceof \Openapi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ + $recipient = new \Openapi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); } $valid = TRUE; @@ -92,13 +92,13 @@ function send(){ $this->clearRecipients(); $this->setRecipients($ret->data[0]->destinatari); return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ $response = $e->getServerResponse(); //var_dump($response->data->wrong_fields);exit; if(isset($response->data->wrong_fields) && isset($response->error)){ $error_message = $this->getError($response->error, $response); - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2 = new \Openapi\classes\exception\OpenapiUPFieldsException("Fields Error",40013); $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); $e2->setErrorMessage($error_message); $e2->setFields($response->data->wrong_fields); diff --git a/src/classes/utility/UfficioPostale/ServiziPostali.php b/src/classes/utility/UfficioPostale/ServiziPostali.php index a9b19a7..34db47a 100644 --- a/src/classes/utility/UfficioPostale/ServiziPostali.php +++ b/src/classes/utility/UfficioPostale/ServiziPostali.php @@ -1,5 +1,5 @@ sender = $sender; }else{ - $this->sender = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($sender); + $this->sender = new \Openapi\classes\utility\UfficioPostale\Objects\Sender($sender); } if(!$this->sender->validate()){ // var_dump($this->sender->getErrors()); @@ -174,9 +174,9 @@ public function setRecipients($recipients){ $this->clearRecipients(); $valid = TRUE; foreach($recipients as $key => $recipient){ - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ + if(!($recipient instanceof \Openapi\classes\utility\UfficioPostale\Objects\Recipient)){ - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); + $recipient = new \Openapi\classes\utility\UfficioPostale\Objects\Recipient($recipient); } if(!$recipient->validate()){ $valid = FALSE; @@ -193,8 +193,8 @@ protected function getError($code, $serverResponse){ public function addRecipient($recipient){ - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); + if(!($recipient instanceof \Openapi\classes\utility\UfficioPostale\Objects\Recipient)){ + $recipient = new \Openapi\classes\utility\UfficioPostale\Objects\Recipient($recipient); } $valid = TRUE; diff --git a/src/classes/utility/UfficioPostale/Telegramma.php b/src/classes/utility/UfficioPostale/Telegramma.php index 1a86447..d16e3a0 100644 --- a/src/classes/utility/UfficioPostale/Telegramma.php +++ b/src/classes/utility/UfficioPostale/Telegramma.php @@ -1,5 +1,5 @@ parole; } function getNumeroPagine(){ - throw new \OpenApi\classes\exception\OpenApiUPException("Pages not exist for telagrammi",40015); + throw new \Openapi\classes\exception\OpenapiUPException("Pages not exist for telagrammi",40015); } function confirm(){ if($this->getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); + throw new \Openapi\classes\exception\OpenapiUPException("Id not present",40011); } if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); + throw new \Openapi\classes\exception\OpenapiUPException("State is not NEW",40012); } $param['confirmed'] = TRUE; $ret = call_user_func_array($this->connect,["telegrammi/".$this->getId(),"PATCH",$param]); @@ -73,12 +73,12 @@ function send(){ $this->clearRecipients(); $this->setRecipients($ret->data[0]->destinatari); return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ + }catch(\Openapi\classes\exception\OpenapiConnectionsException $e){ $response = $e->getServerResponse(); if(isset($response->data->wrong_fields) && isset($response->error)){ $error_message = $this->getError($response->error, $response); - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); + $e2 = new \Openapi\classes\exception\OpenapiUPFieldsException("Fields Error",40013); $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); $e2->setErrorMessage($error_message); $e2->setFields($response->data->wrong_fields); @@ -128,10 +128,10 @@ function setRicevutaCartacea($ar_c){ $this->ar_c = $ar_c; return TRUE; }else{ - if($ar_c instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Sender){ + if($ar_c instanceof \Openapi\classes\utility\UfficioPostale\Objects\Sender){ $this->ar_c = $ar_c; }else{ - $this->ar_c = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($ar_c); + $this->ar_c = new \Openapi\classes\utility\UfficioPostale\Objects\Sender($ar_c); } if(!$this->ar_c->validate()){ return FALSE; diff --git a/src/classes/utility/Uploader/Collection.php b/src/classes/utility/Uploader/Collection.php index 99bc039..627a9fb 100644 --- a/src/classes/utility/Uploader/Collection.php +++ b/src/classes/utility/Uploader/Collection.php @@ -1,5 +1,5 @@ getOutput() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output format not setted",40017); + throw new \Openapi\classes\exception\OpenapiUploaderException("Output format not setted",40017); } $this->state = $state; $data['output_format'] = $this->getOutput(); @@ -125,7 +125,7 @@ function getId(){ } function setOutput($output){ if($output != "image/png" && $output != "image/jpeg" && $output != "application/pdf"){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output format not valid",40013); + throw new \Openapi\classes\exception\OpenapiUploaderException("Output format not valid",40013); } if($output == "image/png" || $output == "image/jpeg") { $this->outputGroup = false; @@ -181,7 +181,7 @@ function setInputCount($ic){ } function setOutputGroup($outputGroup){ if($outputGroup && ($this->output == "image/png" || $this->output == "image/jpeg")){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output group not valid",40015); + throw new \Openapi\classes\exception\OpenapiUploaderException("Output group not valid",40015); } $this->outputGroup = $outputGroup; } @@ -212,7 +212,7 @@ function setInputTypes($types){ } foreach($types as $t){ if($t != "image/png" && $t != "image/jpeg" && $t != "application/pdf"){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Input type not valid",40016); + throw new \Openapi\classes\exception\OpenapiUploaderException("Input type not valid",40016); } } $this->inputTypes = $types; @@ -233,11 +233,11 @@ private function checkOutputSize(){ } if($this->output == "application/pdf"){ if(!in_array($this->outputSize,$this->validPdfFormats)){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output size not valid",40014); + throw new \Openapi\classes\exception\OpenapiUploaderException("Output size not valid",40014); } }else{ if(!is_array($this->outputSize) || !isset($this->outputSize[0]) || !isset($this->outputSize[1]) || !is_int($this->outputSize[0]) || !is_int($this->outputSize[1])){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output size not valid",40014); + throw new \Openapi\classes\exception\OpenapiUploaderException("Output size not valid",40014); } } } @@ -260,7 +260,7 @@ function getOutput(){ function addDocument($name, $type,$file,$crop_size = null){ if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + throw new \Openapi\classes\exception\OpenapiUploaderException("Impossible to add File",40019); } $data['name'] = $name; @@ -276,7 +276,7 @@ function addDocument($name, $type,$file,$crop_size = null){ function updateDocument($id_documento, $name = NULL,$type = NULL, $file = NULL, $crop_size = NULL){ if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + throw new \Openapi\classes\exception\OpenapiUploaderException("Impossible to add File",40019); } if($name != NULL){ $data['name'] = $name; @@ -299,7 +299,7 @@ function updateDocument($id_documento, $name = NULL,$type = NULL, $file = NULL, function deleteDocument($id_documento){ if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + throw new \Openapi\classes\exception\OpenapiUploaderException("Impossible to add File",40019); } @@ -320,7 +320,7 @@ private function updateCollection(){ function getDocumento($id_documento){ if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + throw new \Openapi\classes\exception\OpenapiUploaderException("Impossible to add File",40019); } @@ -332,7 +332,7 @@ function getDocumento($id_documento){ function getDocumenti(){ if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); + throw new \Openapi\classes\exception\OpenapiUploaderException("Impossible to add File",40019); } diff --git a/src/classes/utility/VisEngine/VisRequest.php b/src/classes/utility/VisEngine/VisRequest.php index 447219b..6e4d33c 100644 --- a/src/classes/utility/VisEngine/VisRequest.php +++ b/src/classes/utility/VisEngine/VisRequest.php @@ -1,12 +1,12 @@ visengin",40008); + throw new \Openapi\classes\exception\OpenapiVisEngineException("this class is not externally installable, but must be recovered using the appropriate methods of the class openapi-> visengin",40008); } $this->visura = $visura; $this->variables = []; @@ -54,7 +54,7 @@ function getNew(){ function setJson(object $data){ foreach($data as $k => $v){ if(!isset($this->variables[$k])){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); + throw new \Openapi\classes\exception\OpenapiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); } $this->variables[$k] = $v!=NULL; } @@ -124,7 +124,7 @@ function getCallbackData(){ */ function setState($stato = 0){ if($stato != 0 && !$this->jsonValido ){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); + throw new \Openapi\classes\exception\OpenapiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); } $this->state = $stato == 0 ? $stato : 1; } @@ -249,7 +249,7 @@ private function validaFormatoCampi(){ continue; } if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale_persona_fisica'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); + $val = new \Openapi\classes\utility\Plugins\Validations(); if(!$val->italianFiscalCode($this->json->$key)){ $this->format_errror[$key] = 'codice_fiscale_persona_fisica'; $error = TRUE; @@ -257,7 +257,7 @@ private function validaFormatoCampi(){ } if(isset($campo->tipo) && $campo->tipo == 'partita_iva'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); + $val = new \Openapi\classes\utility\Plugins\Validations(); if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ $this->format_errror[$key] = 'partita_iva'; $error = TRUE; @@ -265,7 +265,7 @@ private function validaFormatoCampi(){ } if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); + $val = new \Openapi\classes\utility\Plugins\Validations(); if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ $this->format_errror[$key] = 'codice_fiscale'; $error = TRUE; diff --git a/src/classes/utility/VisRequest.php b/src/classes/utility/VisRequest.php index 447219b..6e4d33c 100644 --- a/src/classes/utility/VisRequest.php +++ b/src/classes/utility/VisRequest.php @@ -1,12 +1,12 @@ visengin",40008); + throw new \Openapi\classes\exception\OpenapiVisEngineException("this class is not externally installable, but must be recovered using the appropriate methods of the class openapi-> visengin",40008); } $this->visura = $visura; $this->variables = []; @@ -54,7 +54,7 @@ function getNew(){ function setJson(object $data){ foreach($data as $k => $v){ if(!isset($this->variables[$k])){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); + throw new \Openapi\classes\exception\OpenapiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); } $this->variables[$k] = $v!=NULL; } @@ -124,7 +124,7 @@ function getCallbackData(){ */ function setState($stato = 0){ if($stato != 0 && !$this->jsonValido ){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); + throw new \Openapi\classes\exception\OpenapiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); } $this->state = $stato == 0 ? $stato : 1; } @@ -249,7 +249,7 @@ private function validaFormatoCampi(){ continue; } if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale_persona_fisica'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); + $val = new \Openapi\classes\utility\Plugins\Validations(); if(!$val->italianFiscalCode($this->json->$key)){ $this->format_errror[$key] = 'codice_fiscale_persona_fisica'; $error = TRUE; @@ -257,7 +257,7 @@ private function validaFormatoCampi(){ } if(isset($campo->tipo) && $campo->tipo == 'partita_iva'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); + $val = new \Openapi\classes\utility\Plugins\Validations(); if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ $this->format_errror[$key] = 'partita_iva'; $error = TRUE; @@ -265,7 +265,7 @@ private function validaFormatoCampi(){ } if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); + $val = new \Openapi\classes\utility\Plugins\Validations(); if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ $this->format_errror[$key] = 'codice_fiscale'; $error = TRUE; diff --git a/src/classes/utility/ci4SessionStoreToken.php b/src/classes/utility/ci4SessionStoreToken.php index c01d873..39558cf 100644 --- a/src/classes/utility/ci4SessionStoreToken.php +++ b/src/classes/utility/ci4SessionStoreToken.php @@ -1,5 +1,5 @@ Date: Tue, 14 Oct 2025 16:46:41 +0200 Subject: [PATCH 59/85] chore: upkeep --- .github/assets/repo-header-a3.png | Bin 72023 -> 83760 bytes composer.json | 4 ---- 2 files changed, 4 deletions(-) diff --git a/.github/assets/repo-header-a3.png b/.github/assets/repo-header-a3.png index 3db54204d56f3a78206b802f343cd5df829a19e0..88d6e2ef50384c72e238c0b9c423c8ad73c8d35c 100644 GIT binary patch literal 83760 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 z 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 literal 72023 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 diff --git a/composer.json b/composer.json index e6511b9..05b51a4 100644 --- a/composer.json +++ b/composer.json @@ -1,10 +1,6 @@ { "name": "openapi/openapi-sdk", -<<<<<<< HEAD "description": "Openapi PHP Libraries (https://openapi.com)", -======= - "description": "OpenApi PHP Libraries (https://openapi.com)", ->>>>>>> f44c43c47a8d98159ea0017846374da1be2b1f8c "authors": [ { "name": "Altravia", From 2c7567c961fdec356bf2e418d5840a6d50b27a84 Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 14 Oct 2025 16:49:53 +0200 Subject: [PATCH 60/85] chore: upkeep --- README.md | 40 +++++++++++++++++++++++++++++++++++- docs/code-of-conduct.md | 30 +++++++++++++++++++++++++++ docs/contributing.md | 45 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 1 deletion(-) create mode 100644 docs/code-of-conduct.md create mode 100644 docs/contributing.md diff --git a/README.md b/README.md index efa4a87..3862610 100644 --- a/README.md +++ b/README.md @@ -270,4 +270,42 @@ $request->setJson(['$0' => 'abcd', '$1' => '12485671007']); // url di callback, oggetto con dati aggiuntivi, metodo $request->setCallbackData('https://example.com', new stdClass(), 'POST'); $visura = $this->openapi->visengine->sendRequest($request); -``` \ No newline at end of file +``` + +## Contributing + +Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. + +See [docs/contributing.md](docs/contributing.md) for detailed instructions on how to get started. Please make sure to follow this project's [docs/code-of-conduct.md](docs/code-of-conduct.md) to help maintain a welcoming and collaborative environment. + +## Authors + +Meet the project authors: + +- Michael Cuffaro ([@maiku1008](https://www.github.com/maiku1008)) +- Openapi Team ([@openapi-it](https://github.com/openapi-it)) + +## Partners + +Meet our partners using Openapi or contributing to this SDK: + +- [Blank](https://www.blank.app/) +- [Credit Safe](https://www.creditsafe.com/) +- [Deliveroo](https://deliveroo.it/) +- [Gruppo MOL](https://molgroupitaly.it/it/) +- [Jakala](https://www.jakala.com/) +- [Octotelematics](https://www.octotelematics.com/) +- [OTOQI](https://otoqi.com/) +- [PWC](https://www.pwc.com/) +- [QOMODO S.R.L.](https://www.qomodo.me/) +- [SOUNDREEF S.P.A.](https://www.soundreef.com/) + +## License + +This project is licensed under the [MIT License](LICENSE). + +The MIT License is a permissive open-source license that allows you to freely use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, provided that the original copyright notice and this permission notice are included in all copies or substantial portions of the software. + +In short, you are free to use this SDK in your personal, academic, or commercial projects, with minimal restrictions. The project is provided "as-is", without any warranty of any kind, either expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. + +For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). diff --git a/docs/code-of-conduct.md b/docs/code-of-conduct.md new file mode 100644 index 0000000..8908ea2 --- /dev/null +++ b/docs/code-of-conduct.md @@ -0,0 +1,30 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project a harassment-free experience for everyone. + +## Our Standards + +Examples of positive behavior: + +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy toward other community members + +Examples of unacceptable behavior: + +- Harassment, intimidation, or discrimination +- Public or private insults and derogatory comments +- Publishing others’ private information without consent +- Any other conduct reasonably considered inappropriate + +## Enforcement + +Instances of unacceptable behavior may be reported by contacting the project team at ``. All complaints will be reviewed promptly and fairly. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org), version 2.1. diff --git a/docs/contributing.md b/docs/contributing.md new file mode 100644 index 0000000..dad6238 --- /dev/null +++ b/docs/contributing.md @@ -0,0 +1,45 @@ +# Contributing to Openapi SDK + +Thanks for considering contributing! 🎉 +We welcome all kinds of contributions: bug reports, feature requests, documentation improvements, and code enhancements. + +## How to Contribute + +1. **Fork the repository** and clone it locally: + ```bash + git clone https://github.com//.git + ``` + +2. **Create a branch** for your feature or fix: + ```bash + git checkout -b feature/your-feature-name + ``` + +3. **Make your changes** and commit them: + ```bash + git commit -m "Add some feature" + ``` + +4. **Push your branch** to your fork: + ```bash + git push origin feature/your-feature-name + ``` + +5. **Open a Pull Request** describing your changes. + +## Guidelines + +* Follow the existing **Rust coding style**. +* Include **tests** for new features or bug fixes when applicable. +* Keep **commit messages clear and concise**. +* Update **documentation** as needed for your changes. + +## Reporting Issues + +To report bugs or request features, please **open an issue** on GitHub including: + +* Clear description of the problem or feature. +* Steps to reproduce (if applicable). +* Relevant logs or screenshots. + +Thank you for helping improve Openapi SDK! 🚀 From 48bd426985ff140bc0c4f1cd48ec99c2638499ea Mon Sep 17 00:00:00 2001 From: francesco Date: Sat, 8 Nov 2025 09:55:10 +0100 Subject: [PATCH 61/85] refactoring files to introduce minimal version --- .gitignore | 1 + README.md | 287 ++---------- composer.json | 6 +- examples/api_calls.php | 34 ++ examples/complete_workflow.php | 75 +++ examples/token_generation.php | 29 ++ src/Cache/ArrayCache.php | 46 ++ src/Cache/CacheInterface.php | 11 + src/Client.php | 82 ++++ src/Exception.php | 39 ++ src/OauthClient.php | 91 ++++ src/OpenApi.php | 400 ---------------- src/classes/Catasto.php | 95 ---- src/classes/Comuni.php | 122 ----- src/classes/FirmaDigitale.php | 91 ---- src/classes/Geocoding.php | 28 -- src/classes/Imprese.php | 124 ----- src/classes/ImpreseOpenapi.php | 160 ------- src/classes/MarcheTemporali.php | 51 -- src/classes/OpenApiBase.php | 209 --------- src/classes/PecMassiva.php | 77 ---- src/classes/Sms.php | 130 ------ src/classes/UfficioPostale.php | 198 -------- src/classes/Uploader.php | 120 ----- src/classes/VisEngine.php | 179 -------- .../exception/OpenApiConnectionsException.php | 17 - .../exception/OpenApiExceptionBase.php | 66 --- .../OpenApiMarcheTemporaliException.php | 13 - .../exception/OpenApiPecMassivaException.php | 15 - src/classes/exception/OpenApiSMSException.php | 13 - .../exception/OpenApiTokenException.php | 16 - src/classes/exception/OpenApiUPException.php | 14 - .../exception/OpenApiUploaderException.php | 19 - .../exception/OpenApiVisEngineException.php | 16 - src/classes/utility/CacheSystemInterface.php | 8 - src/classes/utility/DummyCache.php | 23 - src/classes/utility/Plugins/FiscalCode.php | 317 ------------- src/classes/utility/Plugins/Validations.php | 122 ----- .../Objects/ErrorTranslation/errorLang.php | 23 - .../Objects/ErrorTranslation/lng/it.json | 11 - .../UfficioPostale/Objects/Recipient.php | 356 -------------- .../Objects/RecipientRaccomandate.php | 81 ---- .../utility/UfficioPostale/Objects/Sender.php | 241 ---------- .../utility/UfficioPostale/PostaOrdinaria.php | 92 ---- .../UfficioPostale/PostaPrioritaria.php | 90 ---- .../utility/UfficioPostale/Raccomandata.php | 134 ------ .../utility/UfficioPostale/ServiziPostali.php | 238 ---------- .../utility/UfficioPostale/Telegramma.php | 148 ------ src/classes/utility/Uploader/Collection.php | 344 -------------- src/classes/utility/VisEngine/VisRequest.php | 434 ------------------ src/classes/utility/VisRequest.php | 434 ------------------ src/classes/utility/ci4SessionStoreToken.php | 18 - src/classes/utility/sessionStoreToken.php | 19 - src/classes/utility/storeTokenInterface.php | 8 - tests/ApiClientTest.php | 78 ++++ tests/ArrayCacheTest.php | 61 +++ tests/ClientTest.php | 224 --------- tests/ExceptionTest.php | 35 ++ tests/OauthClientTest.php | 39 ++ 59 files changed, 668 insertions(+), 5784 deletions(-) create mode 100644 examples/api_calls.php create mode 100644 examples/complete_workflow.php create mode 100644 examples/token_generation.php create mode 100644 src/Cache/ArrayCache.php create mode 100644 src/Cache/CacheInterface.php create mode 100644 src/Client.php create mode 100644 src/Exception.php create mode 100644 src/OauthClient.php delete mode 100644 src/OpenApi.php delete mode 100644 src/classes/Catasto.php delete mode 100644 src/classes/Comuni.php delete mode 100644 src/classes/FirmaDigitale.php delete mode 100644 src/classes/Geocoding.php delete mode 100644 src/classes/Imprese.php delete mode 100644 src/classes/ImpreseOpenapi.php delete mode 100644 src/classes/MarcheTemporali.php delete mode 100644 src/classes/OpenApiBase.php delete mode 100644 src/classes/PecMassiva.php delete mode 100644 src/classes/Sms.php delete mode 100644 src/classes/UfficioPostale.php delete mode 100644 src/classes/Uploader.php delete mode 100644 src/classes/VisEngine.php delete mode 100644 src/classes/exception/OpenApiConnectionsException.php delete mode 100644 src/classes/exception/OpenApiExceptionBase.php delete mode 100644 src/classes/exception/OpenApiMarcheTemporaliException.php delete mode 100644 src/classes/exception/OpenApiPecMassivaException.php delete mode 100644 src/classes/exception/OpenApiSMSException.php delete mode 100644 src/classes/exception/OpenApiTokenException.php delete mode 100644 src/classes/exception/OpenApiUPException.php delete mode 100644 src/classes/exception/OpenApiUploaderException.php delete mode 100644 src/classes/exception/OpenApiVisEngineException.php delete mode 100644 src/classes/utility/CacheSystemInterface.php delete mode 100644 src/classes/utility/DummyCache.php delete mode 100644 src/classes/utility/Plugins/FiscalCode.php delete mode 100644 src/classes/utility/Plugins/Validations.php delete mode 100644 src/classes/utility/UfficioPostale/Objects/ErrorTranslation/errorLang.php delete mode 100644 src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json delete mode 100644 src/classes/utility/UfficioPostale/Objects/Recipient.php delete mode 100644 src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php delete mode 100644 src/classes/utility/UfficioPostale/Objects/Sender.php delete mode 100644 src/classes/utility/UfficioPostale/PostaOrdinaria.php delete mode 100644 src/classes/utility/UfficioPostale/PostaPrioritaria.php delete mode 100644 src/classes/utility/UfficioPostale/Raccomandata.php delete mode 100644 src/classes/utility/UfficioPostale/ServiziPostali.php delete mode 100644 src/classes/utility/UfficioPostale/Telegramma.php delete mode 100644 src/classes/utility/Uploader/Collection.php delete mode 100644 src/classes/utility/VisEngine/VisRequest.php delete mode 100644 src/classes/utility/VisRequest.php delete mode 100644 src/classes/utility/ci4SessionStoreToken.php delete mode 100644 src/classes/utility/sessionStoreToken.php delete mode 100644 src/classes/utility/storeTokenInterface.php create mode 100644 tests/ApiClientTest.php create mode 100644 tests/ArrayCacheTest.php delete mode 100644 tests/ClientTest.php create mode 100644 tests/ExceptionTest.php create mode 100644 tests/OauthClientTest.php diff --git a/.gitignore b/.gitignore index 3579892..fd79774 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ .idea/ .vscode/ +reference/ /vendor/ node_modules/ npm-debug.log diff --git a/README.md b/README.md index 2b8cb6d..19b810f 100644 --- a/README.md +++ b/README.md @@ -1,273 +1,72 @@ -

- - Openapi SDK for PHP - +# OpenAPI PHP SDK -

Openapi® client for Rust

-

The perfect starting point to integrate Openapi® within your Rust project

+A minimal and agnostic PHP SDK for OpenAPI, inspired by the Rust implementation. This SDK provides only the core HTTP primitives needed to interact with any OpenAPI service. -[![Build Status](https://img.shields.io/github/actions/workflow/status///rust.yml?branch=main)](https://github.com///actions) -[![Crates.io](https://img.shields.io/crates/v/.svg)](https://crates.io/crates/) -[![Docs.rs](https://img.shields.io/docsrs/)](https://docs.rs/) -[![License](https://img.shields.io/github/license//)](LICENSE) -[![Rust Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) -
+## Features -# OpenAPI Library +- **Agnostic Design**: No API-specific classes, works with any OpenAPI service +- **Minimal Dependencies**: Only requires PHP 8.0+ and cURL +- **OAuth Support**: Built-in OAuth client for token management +- **HTTP Primitives**: GET, POST, PUT, DELETE, PATCH methods +- **Clean Interface**: Similar to the Rust SDK design - -* 1. [Installation](#Installation) -* 2. [Usage](#Usage) - * 2.1. [Instanza della classe](#Instanzadellaclasse) - * 2.2. [Esempi](#Esempi) -* 3. [Modulo comuni](#Modulocomuni) - * 3.1. [Esempi](#Esempi-1) -* 4. [Modulo imprese](#Moduloimprese) - * 4.1. [Utilizzo](#Utilizzo) - * 4.2. [Esempi](#Esempi-1) -* 5. [Modulo Marche Temporali](#ModuloMarcheTemporali) - * 5.1. [Esempi](#Esempi-1) -* 6. [Modulo SMS](#ModuloSMS) - * 6.1. [Inviare un SMS](#InviareunSMS) -* 7. [Modulo Visengine](#ModuloVisengine) +## Installation - - - - -## 1. Installation - -```sh -composer require altravia/openapi -``` - -## 2. Usage - -### 2.1. Instanza della classe - -```php -require_once 'vendor/autoload.php'; - -$openapi = new \OpenApi\OpenApi($scopes, $user, $apikey, $environment); -``` - -Dove `$scopes` è un array di stringhe o di oggetti in uno dei seguenti formati: - -```php -$scopes = [ - "GET:ws.ufficiopostale.com/comuni", - [ - "domain"=>"ws.ufficiopostale.com", - "method"=>"comuni", - "mode" =>"GET" - ] -]; +```bash +composer require openapi/openapi-sdk ``` -...e `$environment` è l'ambiente sceltro tra `'test'` (default) e `'production'` - -OpenApi si occuperá di reperire automaticamente, o generare, un nuovo token quando necessario. +## Quick Start -A questo punto, in base agli scopes indicati vengono creati i seguenti oggetti: - - -```php -// Ogni oggetto verrá creato solo se disponibile nello scope. -$openapi->ufficiopostale; -$openapi->comuni; -$openapi->imprese; -$openapi->visengine; -$openapi->marcheTemporali; -$openapi->geocoding; -$openapi->SMS; -$openapi->firmaDigitale; -$openapi->pecMassiva; -``` -che possono essere usati al seguente modo: +### Token Generation ```php -$this->openapi->ufficioposale->getCitiesByCap('00132'); -``` -### 2.2. Esempi +use OpenApi\OauthClient; -```php -require_once 'vendor/autoload.php'; +$oauthClient = new OauthClient('username', 'apikey', true); // true for test environment -// Dichiaro gli scopes necessari $scopes = [ - 'GET:comuni.openapi.it/cap', - 'GET:imprese.altravia.com/advance', + 'GET:test.imprese.openapi.it/advance', + 'POST:test.postontarget.com/fields/country' ]; -$openapi = new OpenApi\OpenApi($scopes, 'my_username','my_api_key', 'test'); - -// Comuni: prendi informazioni sul cap 00132 -$cap = $openapi->comuni->getCitiesByCap('00132'); - -// Imprese: prendi informazioni su una specifica impresa -$impresa = $openapi->imprese->getByPartitaIva('12485671007'); - -// Ufficio Postale: ottieni informaizoni sul tracking -$track = $this->openapi->ufficiopostale->track('123456789'); +$result = $oauthClient->createToken($scopes, 3600); +$tokenData = json_decode($result, true); +$token = $tokenData['token']; ``` - -## 3. Modulo comuni -Consente di prendere informazioni su comuni e provincie. - -* `getCitiesByCap` -* `getComuneByCatasto` -* `getRegioni` -* `getProvince` -* `getComuni` - -### 3.1. Esempi +### Making API Calls ```php -$provincia = 'RM'; -$comuni = $this->openapi->comuni->getComuni($provincia); +use OpenApi\Client; -var_dump($comuni['comuni']); -/* +$client = new Client($token); -["nome_provincia"]=> - string(4) "Roma" - ["sigla_provincia"]=> - string(2) "RM" - ["regione"]=> - string(5) "Lazio" - ["comuni"]=> - array(121) { - [0]=> - string(6) "Affile" - ... -*/ +// GET request +$params = ['denominazione' => 'altravia', 'provincia' => 'RM']; +$response = $client->get('https://test.imprese.openapi.it/advance', $params); +// POST request +$payload = ['limit' => 10, 'query' => ['country_code' => 'IT']]; +$response = $client->post('https://test.postontarget.com/fields/country', $payload); +// Other HTTP methods +$response = $client->put($url, $payload); +$response = $client->delete($url); +$response = $client->patch($url, $payload); ``` -## 4. Modulo imprese -### 4.1. Utilizzo -Il modulo imprese espone i seguenti metodi: -* `getByPartitaIva` -* `getClosed` -* `getVatGroup` -* `getPec` -* `getBySearch` +## Architecture -Per `getBySearch` e `getByPartitaIva` è richiesto accesso allo scope `/advance` +This SDK follows a minimal approach with only essential components: -### 4.2. Esempi -Utilizziamo `getBySearch` per cercare un'azienda il cui nome inizia con `Altrav` a Roma - -```php -$autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); - -/* - [0]=> - object(stdClass)#41 (10) { - ["piva"]=> - string(11) "12485671007" - ["cf"]=> - string(11) "12485671007" - ["denominazione"]=> - string(20) "ALTRAVIA SERVIZI SRL" - [1]=> - object(stdClass)#42 (10) { - ["id"]=> - string(24) "4242424242" - ["denominazione"]=> - string(18) "xxx Altravia Esempio 2" - ... - */ -``` +- `OauthClient`: Handles OAuth authentication and token management +- `Client`: Agnostic HTTP client for API calls +- `Exception`: Error handling +- `Cache\CacheInterface`: Optional caching interface -## 5. Modulo Marche Temporali -* `availability` -* `checkLotto` -* `purcahse` +## Requirements -### 5.1. Esempi - -```php -// Controlliamo la disponibilitá di una marca di inforcert o aruba -$disponibilita = $this->openapi->marcheTemporali->availability('infocert', 1); - -// Se le marche sono disponibili, acquistiamone una -if ($disponibilita->availability > 0) { - try { - $marca = $this->openapi->marcheTemporali->purcahse('infocert', 1); - } catch (\OpenApi\classes\exception\OpenApiMarcheTemporaliException $e) { - error_log(var_dump($e)); - } -} -``` - -## 6. Modulo SMS -* `getRecipients` -* `getMessage` -* `sendMore` -* `sendOne` - -### 6.1. Inviare un SMS -Per inviare un SMS, per prima cosa definiamo i destinatari: - -```php -$recipient = '+39-3939989741'; -// OR -$recipients = [ - [ - 'number' => '+39-3939989741', - 'fields' => ['nome' => 'NomeDestinatario'] - ] -]; -``` - -Possiamo ora procedere ad inviare un SMS: -```php - -try { - $priority = 1; - $options = null; - $singleSms = $this->openapi->SMS->sendOne('Nome del mittente', $recipient, 'lorem ipsum', null, $priority, $options); -} catch (\OpenApi\classes\exception\OpenApiConnectionsException $e) { - throw 'Non è stato possibile recapitare il messaggio'; -} -``` - -Possiamo anche speficiare i prefissi in modo indipendente: -```php -$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, null); -``` - -O passare delle opzioni -```php -$options = ['timestamp_send' => '2021-04-20'] -$this->openapi->SMS->sendOne('Nome del mittente', '3939989741', 'lorem ipsum', '+42', 1, $options); -``` - -## 7. Modulo Visengine -Come prima cosa, settiamo l'hash della visura che vogliamo richiedere - -```php -// https://developers.openapi.it/services/visengine -$this->openapi->visengine->setHash($visura->hash); -``` - -A questo punto, possiamo lanciare `createRequest`, che ritornerà una istanza vuota della visura che andremo a creare della struttura richiesta - -```php -$request = $this->openapi->visengine->createRequest(); -``` - -Prodediamo a completare l'oggetto, che potremmo passare a sendRequest quando pronto - -```php -$request->setJson(['$0' => 'abcd', '$1' => '12485671007']); - // url di callback, oggetto con dati aggiuntivi, metodo -$request->setCallbackData('https://example.com', new stdClass(), 'POST'); -$visura = $this->openapi->visengine->sendRequest($request); -``` \ No newline at end of file +- PHP 8.0 or higher +- cURL extension +- JSON extension \ No newline at end of file diff --git a/composer.json b/composer.json index a5a0d18..bd8840a 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "openapi/openapi-sdk", - "description": "OpenApi PHP Libraries (https://openapi.com)", + "description": "Minimal and agnostic PHP SDK for OpenAPI (https://openapi.com)", "authors": [ { "name": "Altravia", @@ -9,7 +9,9 @@ ], "minimum-stability": "stable", "require": { - "php": ">=7.2.0" + "php": ">=8.0.0", + "ext-curl": "*", + "ext-json": "*" }, "autoload": { "psr-4": { diff --git a/examples/api_calls.php b/examples/api_calls.php new file mode 100644 index 0000000..4be6279 --- /dev/null +++ b/examples/api_calls.php @@ -0,0 +1,34 @@ +'; + $client = new Client($token); + + // GET request with parameters + $params = [ + 'denominazione' => 'altravia', + 'provincia' => 'RM', + 'codice_ateco' => '6201' + ]; + + $result = $client->get('https://test.imprese.openapi.it/advance', $params); + echo "GET API Response: " . $result . PHP_EOL; + + // POST request with payload + $payload = [ + 'limit' => 10, + 'query' => [ + 'country_code' => 'IT' + ] + ]; + + $result = $client->post('https://test.postontarget.com/fields/country', $payload); + echo "POST API Response: " . $result . PHP_EOL; + +} catch (Exception $e) { + echo "Error: " . $e->getMessage() . PHP_EOL; +} \ No newline at end of file diff --git a/examples/complete_workflow.php b/examples/complete_workflow.php new file mode 100644 index 0000000..a6389cf --- /dev/null +++ b/examples/complete_workflow.php @@ -0,0 +1,75 @@ +', '', true); + echo "✓ OAuth client created" . PHP_EOL . PHP_EOL; + + // Step 2: Generate token + echo "Step 2: Generating access token..." . PHP_EOL; + $scopes = [ + 'GET:test.imprese.openapi.it/advance', + 'POST:test.postontarget.com/fields/country' + ]; + + $tokenResult = $oauthClient->createToken($scopes, 3600); + $tokenData = json_decode($tokenResult, true); + + if (!isset($tokenData['token'])) { + throw new Exception('Failed to generate token: ' . $tokenResult); + } + + $token = $tokenData['token']; + echo "✓ Token generated: " . substr($token, 0, 20) . "..." . PHP_EOL . PHP_EOL; + + // Step 3: Create API client + echo "Step 3: Creating API client..." . PHP_EOL; + $apiClient = new Client($token); + echo "✓ API client created" . PHP_EOL . PHP_EOL; + + // Step 4: Make API calls + echo "Step 4: Making API calls..." . PHP_EOL; + + // GET request + echo " → Making GET request..." . PHP_EOL; + $getParams = [ + 'denominazione' => 'altravia', + 'provincia' => 'RM', + 'codice_ateco' => '6201' + ]; + $getResponse = $apiClient->get('https://test.imprese.openapi.it/advance', $getParams); + echo " ✓ GET response received (" . strlen($getResponse) . " bytes)" . PHP_EOL; + + // POST request + echo " → Making POST request..." . PHP_EOL; + $postPayload = [ + 'limit' => 10, + 'query' => [ + 'country_code' => 'IT' + ] + ]; + $postResponse = $apiClient->post('https://test.postontarget.com/fields/country', $postPayload); + echo " ✓ POST response received (" . strlen($postResponse) . " bytes)" . PHP_EOL . PHP_EOL; + + echo "=== Workflow completed successfully! ===" . PHP_EOL; + +} catch (Exception $e) { + echo "✗ Error: " . $e->getMessage() . PHP_EOL; + + if ($e->getHttpCode()) { + echo " HTTP Code: " . $e->getHttpCode() . PHP_EOL; + } + + if ($e->getServerResponse()) { + echo " Server Response: " . json_encode($e->getServerResponse()) . PHP_EOL; + } +} \ No newline at end of file diff --git a/examples/token_generation.php b/examples/token_generation.php new file mode 100644 index 0000000..79c08b2 --- /dev/null +++ b/examples/token_generation.php @@ -0,0 +1,29 @@ +', '', true); + + $scopes = [ + 'GET:test.imprese.openapi.it/advance', + 'POST:test.postontarget.com/fields/country' + ]; + + $ttl = 3600; + $result = $oauthClient->createToken($scopes, $ttl); + + $tokenData = json_decode($result, true); + + if (isset($tokenData['token'])) { + echo "Generated token: " . $tokenData['token'] . PHP_EOL; + echo "Token created successfully!" . PHP_EOL; + } else { + echo "Error creating token: " . $result . PHP_EOL; + } + +} catch (Exception $e) { + echo "Error: " . $e->getMessage() . PHP_EOL; +} \ No newline at end of file diff --git a/src/Cache/ArrayCache.php b/src/Cache/ArrayCache.php new file mode 100644 index 0000000..43f5486 --- /dev/null +++ b/src/Cache/ArrayCache.php @@ -0,0 +1,46 @@ +cache[$key])) { + return null; + } + + if (isset($this->expiry[$key]) && time() > $this->expiry[$key]) { + $this->delete($key); + return null; + } + + return $this->cache[$key]; + } + + public function save(string $key, mixed $value, int $ttl = 3600): bool + { + $this->cache[$key] = $value; + $this->expiry[$key] = time() + $ttl; + + return true; + } + + public function delete(string $key): bool + { + unset($this->cache[$key], $this->expiry[$key]); + + return true; + } + + public function clear(): bool + { + $this->cache = []; + $this->expiry = []; + + return true; + } +} \ No newline at end of file diff --git a/src/Cache/CacheInterface.php b/src/Cache/CacheInterface.php new file mode 100644 index 0000000..e9c253f --- /dev/null +++ b/src/Cache/CacheInterface.php @@ -0,0 +1,11 @@ +token = $token; + } + + public function request(string $method, string $url, mixed $payload = null, ?array $params = null): string + { + if ($params && $method === 'GET') { + $url .= '?' . http_build_query($params); + } + + $ch = curl_init(); + + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Authorization: Bearer ' . $this->token + ] + ]); + + if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'])) { + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); + } + + if ($params && $method !== 'GET') { + curl_setopt($ch, CURLOPT_POSTFIELDS, + is_string($params) ? $params : http_build_query($params)); + } + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = curl_error($ch); + curl_close($ch); + + if ($response === false) { + throw new Exception("cURL Error: " . $error); + } + + if ($httpCode >= 400) { + throw new Exception("HTTP Error {$httpCode}: " . $response); + } + + return $response; + } + + public function get(string $url, ?array $params = null): string + { + return $this->request('GET', $url, null, $params); + } + + public function post(string $url, mixed $payload = null): string + { + return $this->request('POST', $url, $payload); + } + + public function put(string $url, mixed $payload = null): string + { + return $this->request('PUT', $url, $payload); + } + + public function delete(string $url): string + { + return $this->request('DELETE', $url); + } + + public function patch(string $url, mixed $payload = null): string + { + return $this->request('PATCH', $url, $payload); + } +} \ No newline at end of file diff --git a/src/Exception.php b/src/Exception.php new file mode 100644 index 0000000..e154439 --- /dev/null +++ b/src/Exception.php @@ -0,0 +1,39 @@ +serverResponse = $response; + $this->headers = $headers; + $this->rawResponse = $rawResponse; + $this->httpCode = $httpCode; + } + + public function getServerResponse(): mixed + { + return $this->serverResponse; + } + + public function getHeaders(): mixed + { + return $this->headers; + } + + public function getRawResponse(): mixed + { + return $this->rawResponse; + } + + public function getHttpCode(): ?int + { + return $this->httpCode; + } +} \ No newline at end of file diff --git a/src/OauthClient.php b/src/OauthClient.php new file mode 100644 index 0000000..24ae031 --- /dev/null +++ b/src/OauthClient.php @@ -0,0 +1,91 @@ +username = $username; + $this->apikey = $apikey; + $this->url = $test ? self::TEST_OAUTH_BASE_URL : self::OAUTH_BASE_URL; + } + + public function getScopes(bool $limit = false): string + { + $params = ['limit' => $limit ? 1 : 0]; + $url = $this->url . '/scopes?' . http_build_query($params); + + return $this->request('GET', $url); + } + + public function createToken(array $scopes, int $ttl = 3600): string + { + $body = [ + 'scopes' => $scopes, + 'ttl' => $ttl + ]; + + return $this->request('POST', $this->url . '/token', $body); + } + + public function getTokens(string $scope): string + { + $params = ['scope' => $scope]; + $url = $this->url . '/token?' . http_build_query($params); + + return $this->request('GET', $url); + } + + public function deleteToken(string $id): string + { + return $this->request('DELETE', $this->url . '/token/' . $id); + } + + public function getCounters(string $period, string $date): string + { + return $this->request('GET', $this->url . '/counters/' . $period . '/' . $date); + } + + private function request(string $method, string $url, array $body = null): string + { + $ch = curl_init(); + + curl_setopt_array($ch, [ + CURLOPT_URL => $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Authorization: Basic ' . base64_encode($this->username . ':' . $this->apikey) + ] + ]); + + if ($body && in_array($method, ['POST', 'PUT'])) { + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); + } + + $response = curl_exec($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $error = curl_error($ch); + curl_close($ch); + + if ($response === false) { + throw new Exception("cURL Error: " . $error); + } + + if ($httpCode >= 400) { + throw new Exception("HTTP Error {$httpCode}: " . $response); + } + + return $response; + } +} \ No newline at end of file diff --git a/src/OpenApi.php b/src/OpenApi.php deleted file mode 100644 index a900785..0000000 --- a/src/OpenApi.php +++ /dev/null @@ -1,400 +0,0 @@ -"ws.ufficiopostale.com", "method"=>"comuni","mode"=>"GET"] oppure "GET:ws.ufficiopostale.com/comuni NOTA: il dominio NON deve mai avere lo stage - * @param string $username Username openapi - * @param string $apikey ApiKey openapi - * @param mixed $environment='test' uno tra: dev, test (default), production - */ - function __construct(array $scopes, string $username, string $apikey, $environment='test', $store = NULL){ - if($store == NULL) { - $store = new \OpenApi\classes\utility\sessionStoreToken; - } - $this->cache = new \OpenApi\classes\utility\DummyCache; - $this->store = $store; - $this->header = null; - $this->rawResponse = null; - $realScopes = []; - $domainsRealScopes = []; - $prefix = $environment=="production"?"":$environment."."; - $domains = []; - //var_dump($scopes);exit; - foreach($scopes as $s){ - if($s == NULL){ - continue; - } - if(is_array($s)){ - $domain = $s['domain']; - $realScope = $s['mode'].":".$prefix.$s['domain']."/".$s['method']; - }else{ - $realScope = str_replace(":",":{$prefix}", $s) ; - $domain = explode(":", $s)[1]; - $domain = explode("/", $domain)[0]; - } - if(!in_array($domain, $domains)){ - $domains[] = $domain; - $domainsRealScopes[$domain] = []; - } - - if(!in_array($realScope,$realScopes)){ - $realScopes[] = $realScope; - $domainsRealScopes[$domain][] = $realScope; - } - - } - - $this->username = $username; - $this->apikey = $apikey; - $this->prefix = $prefix; - $this->scopes = $realScopes; - $token = $this->getToken(); - /* - if($_SERVER['REMOTE_ADDR'] == "37.163.55.217"){ - var_dump($token);exit; - } - */ - //var_dump($token); - list($moduli,$nomi) = $this->getListaModuli(); - $this->clients = []; - foreach($domains as $d){ - if(isset($moduli[$d])){ - $modulo = $moduli[$d]; - $nome = $nomi[$d]; - $this->$nome = new $modulo($token->token, $domainsRealScopes[$d], $this->cache, $prefix); - $this->clients[] = $nome; - } - } - - $this->validations = new \OpenApi\classes\utility\Plugins\Validations(); - $this->fiscalCode = new \OpenApi\classes\utility\Plugins\FiscalCode(); - // $this->ufficiopostale = new \OpenApi\classes\UfficioPostale($token->token, $domainsRealScopes[$d], $this->cache, $prefix); - } - - /** - * - * Restituisce la lista dei moduli disponibili - * - * @return array - */ - private function getListaModuli(){ - $moduli = []; - $nomi = []; - $moduli['ws.ufficiopostale.com'] = "\\OpenApi\\classes\\UfficioPostale"; - $nomi['ws.ufficiopostale.com'] = "ufficiopostale"; - - $moduli['imprese.altravia.com'] = "\\OpenApi\\classes\\Imprese"; - $nomi['imprese.altravia.com'] = "imprese"; - - $moduli['imprese.openapi.it'] = "\\OpenApi\\classes\\ImpreseOpenapi"; - $nomi['imprese.openapi.it'] = "imprese"; - - $moduli['visengine2.altravia.com'] = "\\OpenApi\\classes\\VisEngine"; - $nomi['visengine2.altravia.com'] = "visengine"; - - - $moduli['comuni.openapi.it'] = "\\OpenApi\\classes\\Comuni"; - $nomi['comuni.openapi.it'] = "comuni"; - - - $moduli['ws.marchetemporali.com'] = "\\OpenApi\\classes\\MarcheTemporali"; - $nomi['ws.marchetemporali.com'] = "marcheTemporali"; - - - $moduli['geocoding.realgest.it'] = "\\OpenApi\\classes\\Geocoding"; - $nomi['geocoding.realgest.it'] = "geocoding"; - - $moduli['uploader.altravia.com'] = "\\OpenApi\\classes\\Uploader"; - $nomi['uploader.altravia.com'] = "uploader"; - - $moduli['ws.messaggisms.com'] = "\\OpenApi\\classes\\Sms"; - $nomi['ws.messaggisms.com'] = "SMS"; - - $moduli['pec.openapi.it'] = "\\OpenApi\\classes\\Pec"; - $nomi['pec.openapi.it'] = "PEC"; - - $moduli['catasto.openapi.it'] = "\\OpenApi\\classes\\Catasto"; - $nomi['catasto.openapi.it'] = "catasto"; - - $moduli['ws.firmadigitale.com'] = "\\OpenApi\\classes\\FirmaDigitale"; - $nomi['ws.firmadigitale.com'] = "firmaDigitale"; - return array($moduli,$nomi); - } - - /** - * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) - * - * @param mixed $cacheSys Istanza della classe da usare come sistema di cache - * @return void - */ - function setCacheSystem($cacheSys){ - $this->cache = $cacheSys; - foreach($this->clients as $c){ - $this->$c->setCacheSystem($cacheSys); - } - } - - - /** - * - * Restituisce il token attualemnte in sessione, se non presente o non più valido lo rigenera - * - * @param boolean $force=FALSE Se impostato a TRUE forza la rigenerazione del token - * @return object il token - */ - function getToken($force=FALSE){ - if(!$force && !$this->isTokenCompatible()){ - - if(!$this->mustRfreshToken()){ - return $this->store->get()['token']; - } - $this->renewToken(); - - return $this->store->get()['token']; - } - if($this->getOldToken()){ - if(!$this->mustRfreshToken()){ - return $this->store->get()['token']; - } - $this->renewToken(); - return $this->store->get()['token']; - } - return $this->generateNewToken(); - } - - - /** - * Rinnova il token in sessione - * - * @return object - */ - private function renewToken(){ - $param = ["expire" => time() + 86400, "scopes" => $this->scopes]; - //var_dump($param);exit; - - $token = $this->connect("token/".$this->store->get()['token']->token,$param,"PUT"); - - if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("Renew Token: Connection Error",40001); - } - if($token->success == false){ - $message = "REnew Token: unknow error"; - if(isset($token->message)) { - $message = "REnew Token: $token->message"; - } - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); - $except->setServerResponse($token, $this->header, $this->rawResponse); - - throw $except; - } - if(isset($token->data) && isset($token->data[0])) - { - $token = $token->data[0]; - $this->store->get()['token'] = $token; - return $token; - } - - } - - - /** - * Controlla se il token in sessione deve essere o meno rinnovato in base alla sua data di scadenza - * - * @return bool - */ - private function mustRfreshToken(){ - $token = $this->store->get()['token']; - $diff = $token->expire-date("U"); - if($diff <= 6000){ - return TRUE; - } - return FALSE; - } - - - /** - * - * Recupera la lista di token per verificare se esiste uno utilizzabile con gli scopes di interesse, - * se si lo mette in sessione e ritorna TRUE - * - * @return boolean - */ - function getOldToken(){ - $param = ["scope" => $this->scopes]; - $token = $this->connect("token",$param,"GET"); - - $finded_token = NULL; - - if($token != NULL && isset($token->data)){ - foreach($token->data AS $token){ - if($this->hasValidScopes($token)){ - $finded_token = $token; - break 1; - } - } - - if($finded_token != NULL){ - $tostore['token'] = $finded_token; - $tostore['apikey'] = $this->apikey; - $tostore['scopes'] = serialize($this->scopes); - $tostore['username'] = $this->username; - $tostore['prefix'] = $this->prefix; - $this->store->save($tostore); - return TRUE; - } - return FALSE; - } - } - - function hasValidScopes($token){ - foreach($this->scopes as $s){ - if(!in_array($s, $token->scopes)){ - return false; - } - } - return true; - } - - /** - * Genera un nuovo token - * @return object il token - */ - private function generateNewToken(){ - $param = ["scopes" => $this->scopes]; - $token = $this->connect("token",$param,"POST"); - if($token == NULL){ - throw new \OpenApi\classes\exception\OpenApiTokenException("Getting Token: Connection Error",40001); - } - if($token->success == false){ - $message = "Getting Token: unknow error"; - if(isset($token->message)) { - $message = "Getting Token: $token->message"; - } - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40002); - $except->setServerResponse($token, $this->header, $this->rawResponse); - - throw $except; - } - - $invalid_scopes = []; - foreach($this->scopes as $s){ - if(!in_array($s, $token->scopes)){ - $invalid_scopes[] = $s; - } - } - if(count($invalid_scopes)>0){ - $message = "Getting Token: unknow error"; - if(isset($token->message)) { - - } - $message = "Getting Token: invalid scopes (".implode($invalid_scopes).")"; - $except = new \OpenApi\classes\exception\OpenApiTokenException($message,40003); - $except->setServerResponse($token, $this->header, $this->rawResponse); - throw $except; - } - $tostore['token'] = $token; - $tostore['apikey'] = $this->apikey; - $tostore['scopes'] = serialize($this->scopes); - $tostore['username'] = $this->username; - $tostore['prefix'] = $this->prefix; - - $this->store->save($tostore); - - return $token; - } - - - /** - * - * Constrolla se il token in sessione è compatibile con la richiesta - * - * @return boolean - */ - private function isTokenCompatible() { - if(!$this->store->isset()|| !isset($this->store->get()['token'])){ - return TRUE; - } - if($this->store->get()['prefix'] != $this->prefix || $this->store->get()['apikey'] != $this->apikey || $this->store->get()['username'] != $this->username){ - return TRUE; - } - $sessionScopes = unserialize($this->store->get()['scopes']); - if(!is_array($sessionScopes)){ - return TRUE; - } - foreach($this->scopes as $s){ - if(!in_array($s, $sessionScopes)){ - return TRUE; - } - } - return FALSE; - } - - - /** - * Effettua una connessione al server oauth - * - * @param string $endpoint path da recuperare - * @param array $param Lista dei parametri da passare - * @param mixed $mode metodo http da usare per la chiamata - * @return object - */ - private function connect(string $endpoint, $param = [], $mode="POST"){ - - $this->header = null; - $this->rawResponse = null; - $basePath = "https://".$this->prefix."oauth.altravia.com"; - $url = $basePath."/".$endpoint; - if($mode == "GET") - { - $param = http_build_query($param); - $param = preg_replace('/(%5B)\d+(%5D=)/i', '$1$2', $param); - $url .= "?".$param; - } - - $ch = curl_init($url); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $mode); - if($mode == "POST" || $mode == "PUT") - { - curl_setopt($ch, CURLOPT_POST, TRUE); - } - if($mode != "GET") - { - $param = json_encode($param); - - curl_setopt($ch, CURLOPT_POSTFIELDS, $param); - } - - $baseauth = base64_encode($this->username.":".$this->apikey); - $headers = array( - 'Content-Type:application/json', - 'Authorization: Basic '. $baseauth - ); - curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); - - - curl_setopt($ch, CURLOPT_TIMEOUT, 30); - - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_HEADER, 1); - $response = curl_exec($ch); - $this->rawResponse = $response; - - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $this->header = substr($response, 0, $header_size); - $return = substr($response, $header_size); - curl_close($ch); - return json_decode($return); - } -} diff --git a/src/classes/Catasto.php b/src/classes/Catasto.php deleted file mode 100644 index e07a613..0000000 --- a/src/classes/Catasto.php +++ /dev/null @@ -1,95 +0,0 @@ -basePath = "https://catasto.openapi.it"; - } - - - function ufficiCatastali($ttl = 86400){ - $data = $this->connect("territorio", "GET", [], $ttl); - return $data->data; - } - - function getComuni($provincia, $ttl = 86400){ - $data = $this->connect("territorio/$provincia", "GET", [], $ttl); - return $data->data; - } - - function elencoImmobili($tipo_catasto, $provincia,$comune,$sezione, $foglio,$particella, $callback){ - $param = [ - "tipo_catasto" => $tipo_catasto, - "provincia" => trim($provincia), - "comune" => $comune, - "sezione" => $sezione, - "foglio" => $foglio, - "particella" => $particella, - - ]; - if($callback != NULL){ - $param['callback'] = $callback; - } - $data = $this->connect("richiesta/elenco_immobili", "POST", $param); - return $data->data; - } - - function getComune($provincia, $comune, $ttl = 86400){ - $comune = urlencode($comune); - $data = $this->connect("territorio/$provincia/$comune", "GET", [], $ttl); - return $data->data; - } - function prospettoCatastale($tipo_catasto, $provincia,$comune,$sezione, $foglio,$particella,$subalterno, $callback=NULL){ - $param = [ - "tipo_catasto" => $tipo_catasto, - "provincia" => trim($provincia), - "comune" => $comune, - "sezione" => $sezione, - "foglio" => $foglio, - "particella" => $particella, - "subalterno" => $subalterno, - ]; - if($callback != NULL){ - $param['callback'] = $callback; - } - $data = $this->connect("richiesta/prospetto_catastale", "POST", $param); - return $data->data; - } - - function ricercaPersona($tipo_catasto,$cf_piva,$provincia,$callback = NULL){ - $param = [ - "tipo_catasto" => $tipo_catasto, - "cf_piva" => trim($cf_piva), - "provincia" => $provincia, - ]; - //var_dump($param);exit; - if($callback != NULL){ - $param['callback'] = $callback; - } - $data = $this->connect("richiesta/ricerca_persona", "POST", $param); - return $data->data; - } - - function ricercaNazionale($tipo_catasto,$cf_piva,$callback= NULL){ - $param = [ - "tipo_catasto" => $tipo_catasto, - "cf_piva" => trim($cf_piva) - ]; - //var_dump($param);exit; - if($callback != NULL){ - $param['callback'] = $callback; - } - $data = $this->connect("richiesta/ricerca_nazionale", "POST", $param); - return $data->data; - } - - - - -} \ No newline at end of file diff --git a/src/classes/Comuni.php b/src/classes/Comuni.php deleted file mode 100644 index b9d1e50..0000000 --- a/src/classes/Comuni.php +++ /dev/null @@ -1,122 +0,0 @@ -basePath = "https://comuni.openapi.it"; - } - - - /** - * - * A partire dal CAP restistuisce un'array di oggietti di tipo comune - * - * @param string $cap Il cap da ricercare - * @param int $ttl Il tempo di chache degli oggetti ritornati, 0 per no chche - * - * @return array - */ - function getCitiesByCap(string $cap, $ttl = 86400){ - $data = $this->connect("cap/$cap", "GET", [], $ttl); - return $data->data; - } - - /** - * - * A partire dal CAP restistuisce un'array di oggietti di tipo comune - * - * @param string $cap Il cap da ricercare - * @param int $ttl Il tempo di chache degli oggetti ritornati, 0 per no chche - * - * @return array - */ - function getComuneByCatasto(string $codice_catastale, $ttl = 86400){ - $data = $this->connect("catastale/$codice_catastale", "GET", [], $ttl); - return $data->data; - } - - /** - * Restituisce la lista delle regioni italiani - * - * @return array - */ - function getRegioni($ttl = 86400){ - $data = $this->connect("regioni", "GET", [], $ttl); - $regioni = $data->data; - sort($regioni); - return $regioni; - } - - /** - * Restituisce la lsita delle province italiane (a partire dalla regione) - * @param string $regione La regione per la quale recuperare le regioni - * - * @return array - */ - function getProvince($regione = NULL, $ttl = 86400){ - if($regione == NULL){ - $data = $this->connect("province", "GET", [], $ttl); - $province = $data->data; - - $_province = []; - foreach($province as $key => $p){ - $provincia = new \stdClass(); - $provincia->nome_provincia = $p; - $provincia->sigla_provincia = $key; - $_province[] = $provincia; - } - - usort($_province,[$this, 'sortProcince']); - return $_province; - } - $regione = explode("/",$regione)[0]; - $regione = trim(\strtolower($regione)); - $regione = urlencode($regione); - - $data = $this->connect("regioni/$regione", "GET", [], $ttl); - - - $province = $data->data; - usort($province,[$this, 'sortProcince']); - return $province; - } - - - /** - * Restituisce la lista comuni a partire dalla provincia - * @param mixed $provincia provincia Es.: RM - * @param int $ttl time to reload cache - * - * @return array - */ - function getComuni($provincia, $ttl = 86400){ - - $provincia = trim(\strtolower($provincia)); - $data = $this->connect("province/$provincia", "GET", [], $ttl); - - $comuni = $data->data; - return $comuni; - - } - - private function sortComune($a, $b){ - if($a->nome == $b->nome){ - return 0; - } - return $a->nome < $b->nome ? -1 : 1; - } - - private function sortProcince($a, $b){ - if($a->nome_provincia == $b->nome_provincia){ - return 0; - } - return $a->nome_provincia < $b->nome_provincia ? -1 : 1; - } - -} \ No newline at end of file diff --git a/src/classes/FirmaDigitale.php b/src/classes/FirmaDigitale.php deleted file mode 100644 index f0ed548..0000000 --- a/src/classes/FirmaDigitale.php +++ /dev/null @@ -1,91 +0,0 @@ -basePath = "https://ws.firmadigitale.com"; - } - - - function getModule($id, $add_header = TRUE){ - - $pdf = $this->connect("richiesta/$id/modulo", "GET", [], 0, FALSE, TRUE); - if(!$add_header){ - return $pdf; - } - header("Content-type:application/pdf"); - header("Content-Disposition:attachment;filename={$id}.pdf"); - header('Content-Length: '.strlen( $pdf )); - header('Cache-Control: public, must-revalidate, max-age=0'); - header('Pragma: public'); - header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT'); - echo $pdf; - } - - - function requestProduct($data){ - $type = isset($data['tipo'])?$data['tipo']:NULL; - $codice_prodotto = isset($data['codice_prodotto'])?$data['codice_prodotto']:NULL; - $anagrafica = isset($data['anagrafica'])?$data['anagrafica']:NULL; - $spedizione = isset($data['spedizione'])?$data['spedizione']:NULL; - $urgenza = isset($data['urgenza'])?$data['urgenza']:NULL; - $assistenza = isset($data['assistenza'])?$data['assistenza']:NULL; - $callback = isset($data['callback'])?$data['callback']:NULL; - $quantita = isset($data['quantita'])?$data['quantita']:NULL; - - $params = []; - if($anagrafica != NULL){ - if($type == "lettore" || $type == "vergine"){ - $params['anagrafica_spedizione'] = $anagrafica; - }elseif($type == "spid"){ - $params['email'] = $anagrafica->email; - $params['cellulare'] = $anagrafica->cellulare; - }else{ - $params['anagrafica'] = $anagrafica; - } - - } - - if($quantita != NULL && ($type == "lettore" || $type == "vergine")){ - $params['quantita'] = $quantita; - } - - - if($spedizione != NULL && ($type == "lettore" || $type == "firma")){ - $params['spedizione'] = $spedizione; - } - - if($urgenza != NULL && ($type == "lettore" || $type == "firma")){ - $params['urgenza'] = $urgenza; - } - if($assistenza != NULL){ - $params['assistenza'] = $assistenza; - } - - if($callback != NULL){ - $params['callback'] = $callback; - } - if(isset($data['options'])){ - foreach($data['options'] as $key =>$value){ - $params[$key] = $value; - } - } -//var_dump(json_encode($params));exit; - - $ret = $this->connect("richiesta/$codice_prodotto","POST",$params); - return $ret; - } - - function addVideoRiconoscimento($id_fd){ - $param['id'] = $id_fd; - $ret = $this->connect("richiesta/VIDEORIC","POST",$param); - return $ret; - } - -} \ No newline at end of file diff --git a/src/classes/Geocoding.php b/src/classes/Geocoding.php deleted file mode 100644 index b0ec8bd..0000000 --- a/src/classes/Geocoding.php +++ /dev/null @@ -1,28 +0,0 @@ -basePath = "https://geocoding.realgest.it"; - } - - /** - * Restituisce le coordinate geografiche a partire dall'indirizzo - * @param string $address Indirizzo - * @param int $ttl Tempo in cui la risposta resta in cahce - * - * @return object - */ - function geocode(string $address, $ttl = 86400){ - $data = $this->connect("geocode", "POST", ["address" => $address], $ttl, TRUE); - - return $data; - } - -} \ No newline at end of file diff --git a/src/classes/Imprese.php b/src/classes/Imprese.php deleted file mode 100644 index 9076cf9..0000000 --- a/src/classes/Imprese.php +++ /dev/null @@ -1,124 +0,0 @@ -basePath = "https://imprese.altravia.com"; - } - - /** - * - * Consente di recuperare i dati di una azienda a partire dalla partita IVA - * - * @param string $partitaIva La partita IVa da ricercare - * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta - * - * @return object - */ - function getByPartitaIva(string $partitaIva, $ttr = 86400, $force = false){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("advance/$partitaIva", "GET", [], $ttr, true); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - - - } - - function getClosed(string $partitaIva, $ttr = 86400): object{ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - function getVatGroup(string $partitaIva, $ttr = 86400): object { - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("gruppoiva/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - function getPec(string $partitaIva, $ttr = 86400): object { - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - /** - * - * Cerca un'azienda o più utilizzando vari parametri - * - * @param string $denominazione Denominazione azienda - * @param string $provincia Provincia - * @param string $partitaIva=NULL Partita IVA - * @param string $codiceFiscale=NULL Codice Fiscale - * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta - * - * @return array Lista delle aziende individuate - */ - function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ - $params=[]; - if($denominazione != NULL){ - $params['denominazione'] = trim($denominazione); - } - if($provincia != NULL){ - $params['provincia'] = $provincia; - } - if($partitaIva != NULL){ - $params['piva'] = $partitaIva; - } - if($codiceFiscale != NULL){ - $params['cf'] = $codiceFiscale; - } - - $data = $this->connect("advance/$partitaIva", "GET", $params, $ttr); - return $data->data; - } -} \ No newline at end of file diff --git a/src/classes/ImpreseOpenapi.php b/src/classes/ImpreseOpenapi.php deleted file mode 100644 index ad799d8..0000000 --- a/src/classes/ImpreseOpenapi.php +++ /dev/null @@ -1,160 +0,0 @@ -basePath = "https://imprese.openapi.it"; - } - - function getFormaGiuridica($codice, $ttr=86400){ - $codice = trim($codice); - try{ - $data = $this->connect("forma_giuridica/$codice", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - /** - * - * Consente di recuperare i dati di una azienda a partire dalla partita IVA - * - * @param string $partitaIva La partita IVa da ricercare - * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta - * - * @return object - */ - function getByPartitaIva(string $partitaIva, $ttr = 86400, $force = false){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("advance/$partitaIva", "GET", [], $ttr, true); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - - - } - - function getClosed(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("closed/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - function getVatGroup(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("gruppoIva/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - function getPec(string $partitaIva, $ttr = 86400){ - $partitaIva = trim($partitaIva); - try{ - $data = $this->connect("pec/$partitaIva", "GET", [], $ttr); - return $data->data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - - - exit; - } - } - - /** - * - * Cerca un'azienda o più utilizzando vari parametri - * - * @param string $denominazione Denominazione azienda - * @param string $provincia Provincia - * @param string $partitaIva=NULL Partita IVA - * @param string $codiceFiscale=NULL Codice Fiscale - * @param int $ttr Time to Release: per quanti secondi la chiamata resta in cache prima di essere effettuata una seconda volta - * - * @return array Lista delle aziende individuate - */ - function getBySearch(string $denominazione, string $provincia, $partitaIva= NULL , $codiceFiscale=NULL, $ttr = 86400){ - $params=[]; - if($denominazione != NULL){ - $params['denominazione'] = trim($denominazione); - } - if($provincia != NULL){ - $params['provincia'] = $provincia; - } - if($partitaIva != NULL){ - $params['piva'] = $partitaIva; - } - if($codiceFiscale != NULL){ - $params['cf'] = $codiceFiscale; - } - - $data = $this->connect("advance/$partitaIva", "GET", $params, $ttr); - return $data->data; - } - - function autocomplete($query, $ttr = 86400){ - try{ - $query = trim($query); - $query = str_replace(" ","*",$query); - $query = urlencode("*$query*"); - $data = $this->connect("autocomplete/$query", "GET", [], $ttr); - if($data == null){ - $data = []; - }else{ - $data = $data->data; - } - return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - } - return []; - - } -} \ No newline at end of file diff --git a/src/classes/MarcheTemporali.php b/src/classes/MarcheTemporali.php deleted file mode 100644 index b945083..0000000 --- a/src/classes/MarcheTemporali.php +++ /dev/null @@ -1,51 +0,0 @@ -basePath = "https://ws.marchetemporali.com"; - } - - function availability(string $type, int $qty){ - $data = $this->connect("availability/$type/$qty", "GET", []); - return $data->data; - } - - function checkLotto($username, $password, $tipo){ - - if(substr($username,0,4) == "FAKE" && substr($password,0,4) == "FAKE"){ - $ret = new \stdClass(); - $ret->data = new \stdClass(); - $ret->data->available = 10; - $ret->data->used = 90; - $ret->message = "DESCR= Marche per $username; disponibili 10 consumate 0"; - $ret->success = TRUE; - $ret->error = NULL; - return $ret->data; - } - $data = $this->connect("check_lotto", "POST", ["username"=>$username, "password"=> $password,'type'=>$tipo]); - - return $data->data; - } - - function purcahse(string $type, int $qty){ - $data = $this->availability($type, $qty); - //var_dump($data);exit; - if($data->availability == 0){ - throw new \OpenApi\classes\exception\OpenApiMarcheTemporaliException("$qty $type time stamps is not availabile for purchase",40009); - } - //echo "marche/$type/$qty";exit; - $data = $this->connect("marche/$type/$qty", "GET", []); - //var_dump($data);exit; - return $data->data; - } - - - -} \ No newline at end of file diff --git a/src/classes/OpenApiBase.php b/src/classes/OpenApiBase.php deleted file mode 100644 index 705bec4..0000000 --- a/src/classes/OpenApiBase.php +++ /dev/null @@ -1,209 +0,0 @@ -token = $token; - $this->cache = $cache; - $this->scopes = $scopes; - $this->prefix = $prefix; - $this->basePath = null; - } - - /** - * Imposta la calsse da utilizzare sistema di cache, deve essere una classe che estende - * {@see \OpenApi\clasess\utility\DummyCache} o comunque compatibile con essa (stessi metodi) - * - * @param object $cacheSys Istanza della classe da usare come sistema di cache - * @return void - */ - function setCacheSystem(object $cacheSys){ - $this->cache = $cacheSys; - } - - - - /** - * Salva un oggetto nella cache - * @param string $key LA chiave utilizzata per salvare l'oggetto nella cache - * @param object $value L'oggetto da salvare nella cache - * @param int $ttr TEmpo in cui l'oggetto resta in cache - * - * @return void - */ - protected function setCacheObject(string $key, object $value, int $ttr){ - $ttr += rand ( 0 , 120 ); - $this->cache->save($key, $value, $ttr); - } - - /** - * - * Recupera un oggetto dalla cache se presente - * - * @param string $key LA chiave da utilizzare per recuperare l'oggetto in cache - * - * @return mixed L'oggetto o NUL se insesistente - */ - protected function getCacheObject(string $key){ - $cached = $this->cache->get($key); - if($cached){ - return $cached; - } - return false; - } - - /** - * - * Controlla se si ha lo scope necessario per poter invocare il metodo, in caso contrario scatena un'eccezione - * - * @param string $url - * - * @return void - */ - private function checkHasScope(string $url, string $type){ - $parsed = parse_url($url); - $permission = $type.":".$parsed['host']; - $path = $parsed['path']; - $path = explode("/", $path); - if(isset($path[1])){ - $permission .= "/".$path[1]; - } - if(!in_array($permission, $this->scopes)){ - throw new \OpenApi\classes\exception\OpenApiConnectionsException("Scope missed: $permission",40004); - } - - } - - /** - * @param string $endpoint Endpoint da richiamare - * @param string $type Tipo di chiamata - * @param array $param Parametri da passare alla chiamata - * @param int $ttr Tempo in cui la chiamata resta in cache (0 = no cache) - * - * @return mixed - */ - public function connect(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $addHeader = NULL){ - $url = $this->basePath; - //if($url != "https://imprese.altravia.com"){ - $url = str_replace("https://","https://".$this->prefix,$url); - $url = str_replace("http://","http://".$this->prefix,$url); - $url .= "/".$endpoint; - if(!$force){ - $this->checkHasScope($url, $type); - } - - - /* if($type == "GET" && $ttr > 0 && $ret = $this->getCacheObject($url)) { - return $ret; - }*/ - $ch = curl_init(); - if($type == "POST" || $type == "PUT") { - curl_setopt($ch, CURLOPT_POST, TRUE); - } - if($param != array()) { - if($type == "GET") { - $param = http_build_query($param); - $url .= "?".$param; - - }else{ - $param = json_encode($param); - curl_setopt($ch, CURLOPT_POSTFIELDS, $param); - } - } - curl_setopt($ch, CURLOPT_URL, $url); - curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); - curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $type); - $header = array("Authorization: Bearer ".$this->token); - if($addHeader != NULL && is_array($addHeader) && count($addHeader)>0){ - $header = array_merge($header, $addHeader); - } - - - curl_setopt($ch,CURLOPT_HTTPHEADER,$header); - curl_setopt($ch, CURLOPT_HEADER, 1); - $response = curl_exec($ch); - // var_dump($response);exit; - $this->rawResponse = $response; - $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE); - $this->header = substr($response, 0, $header_size); - //var_dump($this->header);exit; - $this->parsedHEader = $this->parseHeader($this->header); - $return = substr($response, $header_size); - $httpCode = curl_getinfo ( $ch, CURLINFO_RESPONSE_CODE );; - curl_close($ch); - //echo $return;exit; - if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { - - $data = json_decode($return); - }else if(json_decode($return) != NULL){ - $data = json_decode($return); - - }else{ - $data = $return; - } - - if($data == NULL){ - - throw new \OpenApi\classes\exception\OpenApiConnectionsException("Connection to $url: Connection Error",40001); - } - - if(is_object($data) && $data->success == false){ - - - $message = "Connection to $url: unknow error"; - if(isset($data->message)) { - if(is_string(($data->message))){ - if($dataMessage = json_decode($data->message)){ - $data = $dataMessage; - } - $message = "Connection to $url: $data->message"; - }else{ - $message = "Connection to $url error"; - } - - - } - //var_dump($this->rawResponse); - $except = new \OpenApi\classes\exception\OpenApiConnectionsException($message,40002); - $except->setServerResponse($data, $this->header, $this->rawResponse, $httpCode); - - throw $except; - } - if($type == "GET" && $ttr > 0) { - $this->setCacheObject($url, $data, $ttr); - } - return $data; - } - - protected function parseHeader($headers){ - $headers = explode("\n",$headers); - $parsedHeaders = array(); - foreach ($headers as $header) { - $header = trim($header); - - $header = explode(":",$header); - - if(count($header) < 2){ - - continue; - } - $key = $header[0]; - unset($header[0]); - $parsedHeaders[trim($key)] = trim(implode(":",$header)); - } - // exit; - - return $parsedHeaders; - } - - - - -} \ No newline at end of file diff --git a/src/classes/PecMassiva.php b/src/classes/PecMassiva.php deleted file mode 100644 index dcb7f6b..0000000 --- a/src/classes/PecMassiva.php +++ /dev/null @@ -1,77 +0,0 @@ -basePath = "https://ws.pecmassiva.com"; - $this->inizialized = FALSE; - - } - - function initialize(string $username, string $password){ - $this->username = $username; - $this->password = $password; - $this->inizialized = TRUE; - } - - function getStatus($messageId){ - if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); - } - - - try{ - $header[] = 'x-username: '.$this->username; - $header[] = 'x-password: '.$this->password; - return $this->connect("send/$messageId","GET",[],0,false,$header); - - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); - } - throw $e; - - } - } - - function send($recipient, $subject, $body, $attachments = [], $sender = NULL){ - if(!$this->inizialized){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("class must initialized calling initialize function", 40011); - } - $sender = $sender ? $sender : $this->username; - - $params['username'] = $this->username; - $params['password'] = $this->password; - $params['recipient'] = $recipient; - $params['subject'] = $subject; - $params['body'] = $body; - if(count($attachments)>0){ - $params['attachments'] = $attachments; - } - $params['sender'] = $sender; - try{ - return $this->connect("send","POST",$params); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if(isset($e->getServerResponse()->message_id)){ - throw new \OpenApi\classes\exception\OpenApiPecMassivaException("error occurred connecting to SMTP: ".$e->getServerResponse()->message_id, 40012); - } - throw $e; - - } - - } - - -} \ No newline at end of file diff --git a/src/classes/Sms.php b/src/classes/Sms.php deleted file mode 100644 index e21b37a..0000000 --- a/src/classes/Sms.php +++ /dev/null @@ -1,130 +0,0 @@ -basePath = "https://ws.messaggisms.com"; - $this->messageId = NULL; - } - - function addRecipeints($recipients, $finish = false){ - if($this->messageId == NULL){ - throw new \OpenApi\classes\exception\OpenApiSMSException("No message id presente",40010); - exit; - } - $data = $this->addRecipeintsByMessageId($this->messageId, $recipients, $finish ); - if($finish){ - $this->messageId = NULL; - } - return $data; - } - - function addRecipeintsByMessageId($messageId, $recipients, $finish = false){ - $param['recipients'] = $recipients; - $param['transaction'] = !$finish; - try{ - $data = $this->connect("messages/$messageId", "PUT", $param); - - return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - exit; - } - } - - function getRecipients($messageId, $number = NULL){ - try{ - $data = $this->connect("messages/$messageId/recipients/".$number, "GET", []); - return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - exit; - } - } - - function getMessage($messageId){ - try{ - $data = $this->connect("messages/$messageId", "GET", []); - return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - exit; - } - } - - function sendMore($sender, $recipients, $text, $transaction = false, $priority = 1,$options = NULL, $test = false){ - - $param['test'] = $test; - $param['sender'] = $sender; - $param['recipients'] = $recipients; - $param['body'] = $text; - $param['transaction'] = $transaction; - $param['priority'] = $priority; - if(sizeof($options)){ - $param['options'] = $options; - } - - try{ - $data = $this->connect("messages/", "POST", $param); - if(isset($data->data[0]) && $transaction){ - $this->messageId =$data->data[0]->id; - } - return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - exit; - } - } - - /** - * @param number $priority un moltiplicatore per la priorita di invio - */ - function sendOne($sender, $recipient, $text, $prefix = NULL, $priority = 1,$options = [], $test = false){ - if($prefix != NULL){ - $recipient = $prefix."-".$recipient; - } - - $param['test'] = $test; - $param['sender'] = $sender; - $param['recipients'] = $recipient; - $param['body'] = $text; - $param['transaction'] = FALSE; - $param['priority'] = $priority; - if(sizeof($options)){ - $param['options'] = $options; - } - - try{ - $data = $this->connect("messages/", "POST", $param); - - return $data; - }catch (\OpenApi\classes\exception\OpenApiConnectionsException $e){ - if($e->getHTTPCode() == 404){ - return null; - } - throw $e; - exit; - } - } - -} \ No newline at end of file diff --git a/src/classes/UfficioPostale.php b/src/classes/UfficioPostale.php deleted file mode 100644 index ce1649e..0000000 --- a/src/classes/UfficioPostale.php +++ /dev/null @@ -1,198 +0,0 @@ -errorClass = NULL; - $this->setErrorLang('it'); - $this->basePath = "https://ws.ufficiopostale.com"; - } - - - /** - * Prende in ingresso la path di un json contenente le traduzioni degli errori - */ - function setErrorLang($errorLang){ - $this->errorClass = new \OpenApi\classes\utility\UfficioPostale\Objects\ErrorTranslation\errorLang($errorLang); - } - - function getComuniByCAP($cap){ - $data = $this->connect("comuni/$cap", "GET"); - return $data->data; - - } - - function create( $prodotto){ - if($prodotto == "raccomandata"){ - return $this->createRaccomandata(); - } - if($prodotto == "telegramma"){ - return $this->createTelegramma(); - } - if($prodotto == "posta-prioritaria"){ - return $this->createPostaPrioritaria(); - } - if($prodotto == "posta-ordinaria"){ - return $this->createPostaOrdinaria(); - } - $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); - throw $ex; - - } - /** - * Restiuisce un oggetto di tipo raccomandata - * @return \OpenApi\classes\utility\UfficioPostale\Raccomandata - */ - function createRaccomandata() { - return new \OpenApi\classes\utility\UfficioPostale\Raccomandata(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ - - return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); - }, - - function($code, $serverResponse){ - - return $this->errorClass->getError( $code, $serverResponse); - }); - } - - function createPostaPrioritaria(){ - return new \OpenApi\classes\utility\UfficioPostale\PostaPrioritaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ - - return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); - }, - - function($code, $serverResponse){ - - return $this->errorClass->getError( $code, $serverResponse); - }); - } - - function createPostaOrdinaria(){ - return new \OpenApi\classes\utility\UfficioPostale\PostaOrdinaria(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ - - return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); - }, - - function($code, $serverResponse){ - - return $this->errorClass->getError( $code, $serverResponse); - }); - } - - function createTelegramma(){ - return new \OpenApi\classes\utility\UfficioPostale\Telegramma(function(string $endpoint, $type = "GET", $param = [], $ttr = 0, $force = false, $forceRaw = false){ - - return $this->connect( $endpoint, $type, $param , $ttr , $force, $forceRaw); - }, - - function($code, $serverResponse){ - - return $this->errorClass->getError( $code, $serverResponse); - }); - } - - - function track($tracking_code){ - return $this->connect("tracking/$tracking_code", "GET"); - } - - function getById($id, $prodotto){ - if($prodotto == "raccomandata"){ - return $this->getRaccomandataById($id); - } - if($prodotto == "telegramma"){ - return $this->getTelegrammaById($id); - } - if($prodotto == "posta-prioritaria"){ - return $this->getPostaPrioritariaById($id); - } - if($prodotto == "posta-ordinaria"){ - return $this->getPostaOrdinariaById($id); - } - $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); - throw $ex; - - } - - function getByData($data, $prodotto){ - if($prodotto == "raccomandata"){ - return $this->getRaccomandataByData($data); - } - if($prodotto == "telegramma"){ - return $this->getTelegrammaByData($data); - } - if($prodotto == "posta-prioritaria"){ - return $this->getTelegrammaByData($data); - } - if($prodotto == "posta-ordinaria"){ - return $this->getPostaOrdinariaByData($data); - } - $ex = new \OpenApi\classes\exception\OpenApiUPException("Il prodotto $prodotto non esiste",40014); - throw $ex; - } - - function getRaccomandataById($id){ - $data = $this->connect("raccomandate/$id", "GET"); - return $this->getRaccomandataByData($data->data); - } - - function getRaccomandataByData($data){ - $busta = $this->createRaccomandata(); - $busta->creaRaccomandataByData($data); - return $busta; - } - - function getPostaPrioritariaById($id){ - $data = $this->connect("prioritarie/$id", "GET"); - return $this->getPostaPrioritariaByData($data->data); - } - - function getPostaPrioritariaByData($data){ - $busta = $this->createPostaPrioritaria(); - $busta->creaPostaPrioritariaByData($data); - return $busta; - } - - function getPostaOrdinariaById($id){ - $data = $this->connect("ordinarie/$id", "GET"); - return $this->getPostaOrdinariaByData($data->data); - } - - function getPostaOrdinariaByData($data){ - $busta = $this->createPostaOrdinaria(); - $busta->creaPostaOrdinariaByData($data); - return $busta; - } - - - function getTelegrammaById($id){ - $data = $this->connect("telegrammi/$id", "GET"); - - return $this->getTelegrammaByData($data->data); - } - - function getTelegrammaByData($data){ - $busta = $this->createTelegramma(); - $busta->creaTelegrammaByData($data); - return $busta; - } - function getPricing($type = NULL){ - return $this->connect("pricing/$type", "GET"); - } - - - function getDug(){ - return $this->connect("dug/", "GET"); - } - - - - - -} \ No newline at end of file diff --git a/src/classes/Uploader.php b/src/classes/Uploader.php deleted file mode 100644 index 1b5d67f..0000000 --- a/src/classes/Uploader.php +++ /dev/null @@ -1,120 +0,0 @@ -basePath = "https://uploader.altravia.com"; - } - - function newCollection(){ - - return new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); - } - - function gateway(){ - - $endpoint = isset($_GET['endpoint'])?$_GET['endpoint']:null; - if($endpoint == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("No endpoint GET",40018); - } - //echo $endpoint;exit; - - $method = $_SERVER['REQUEST_METHOD']; - $data = null; - if($method != "GET" && $method != "DELETE"){ - $data = file_get_contents("php://input"); - $data = json_decode($data); - } - try{ - $data = $this->connect($endpoint, $method,$data); - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - - $message = $e->getMessage(); - var_dump($message); - //var_dump($e->getServerRawResponse()); - $message = explode("name (must be one of",$message); - $valid_ext = ""; - if(isset($message[1])){ - $message = substr($message[1],0,-1); - - $message = explode(",",$message); - foreach($message as $m){ - $m = trim($m); - $m = explode("/",$m); - if(isset($m[1])){ - $m = $m[1]; - if($m == "jpeg"){ - $vext[] = "jpg"; - } - $vext[] = $m; - } - - - } - - $valid_ext = ", è possibile caricare esclusivamente file con formato: ".implode(", ",$vext); - - } - $ret['success'] = FALSE; - $ret['message'] = "C'è stato un errore in fase di caricamento{$valid_ext}"; - $ret['error'] = $e->getCode(); - echo json_encode($ret); - exit; - }catch(\Exception $e){ - $ret['success'] = FALSE; - $ret['message'] = "C'è stato un errore in fase di caricamento inaspettato, riprovare, se il problema persiste contattare la nostra assistenza"; - echo json_encode($ret); - exit; - } - - header("Content-Type: ",$this->parsedHEader['Content-Type']); - if(isset($this->parsedHEader['Content-Type']) && strtolower($this->parsedHEader['Content-Type']) == "application/json") { - echo json_encode($data); - }else{ - echo $data; - } - } - - function createCollection($outputFormat, $outputSize = null, $inputTypes = null, $inputCount = null, $public = null, $watermark = null, $watermarkPosition = NULL, $expireTimestamp = null) { - $collection = new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); - $collection->setOutput($outputFormat); - $collection->setOutputSize($outputSize); - $collection->setInputTypes($inputTypes); - $collection->setInputCount($inputCount); - $collection->setPublic($public); - $collection->setWaterMark($watermark); - $collection->setWaterMarkPosition($watermarkPosition); - $collection->setExpireTimestamp($expireTimestamp); - $collection->save(); - } - - function getCollectionById($id){ - $coll = $this->connect("collections/$id","GET"); - $collection = new \OpenApi\classes\utility\Uploader\Collection([$this, 'connect']); - if(isset($coll->data)){ - $collection->parseData($coll->data); - return $collection; - } - return null; - } - - function deleteCollectionById($id){ - return $this->connect("collections/$id","DELETE"); - } - - function getCollections(){ - $collections = $this->connect("collections","GET"); - foreach($collections->data as $d){ - $d->id =$d->_id->{'$oid'}; - unset($d->_id); - } - return $collections; - } - -} \ No newline at end of file diff --git a/src/classes/VisEngine.php b/src/classes/VisEngine.php deleted file mode 100644 index 0055104..0000000 --- a/src/classes/VisEngine.php +++ /dev/null @@ -1,179 +0,0 @@ -hash = NULL; - parent::__construct($token, $scopes, $cache, $prefix); - $this->basePath = "https://visengine2.altravia.com"; - } - - /** - * Imposta l'hash della Visura da utilizzare per tutti i dati - * @param string $hash - * - */ - function setHash(string $hash){ - $this->hash = $hash; - } - - function getFormTool(){ - if($this->hash == NULL){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); - } - $url = $this->basePath; - $url = str_replace("https://","https://".$this->prefix,$url); - $url = str_replace("http://","http://".$this->prefix,$url); - $url .= "/visura/formTool/{$this->hash}.js"; - return $url; - } - - - /** - * - * Prepara un nuovo oggetto di tipo VisRequest da utilizzare per inviare una nuova richiesta e lo restituisce - * @param int $ttr Time to Release sulla richiesta dei dati della visura - * - * @return \OpenApi\classes\utility\VisEngine\VisRequest - */ - function createRequest($ttr = 500){ - if($this->hash == NULL){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine hash is not setted",40005); - } - $this->visura = $this->connect("visure/$this->hash", "GET", [], $ttr); - defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); - return new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); - } - - - /** - * Invia una request, in base al contenuto della stessa distingue automaticamente se fare la chiamata in POST o PUT - * Restituisce la richiesa comprensiva di risposta del server - * @param \OpenApi\classes\utility\VisEngine\VisRequest $request - * - * @return object - */ - function sendRequest(\OpenApi\classes\utility\VisEngine\VisRequest $req) { - - - - if($req->getNew()){ - $params = new \stdClass(); - $params->state = $req->getState(); - $params->test = $req->getTest(); - $params->hash_visura = $this->hash; - if($req->getJson() != NULL){ - $params->json_visura = $req->getJson(); - } - if($req->getCallbackData() != NULL){ - $params->callback_data = $req->getCallbackData(); - } - if($req->getTargetEmail() != NULL){ - $params->email_target = $req->getTargetEmail(); - } - $opzioni = $req->getOpzioni(); - if($opzioni != NULL){ - $params->opzioni = $opzioni; - } - $data = $this->connect("richiesta", "POST", $params); - //var_dump($data); - $req->setNew(FALSE); - $req->setId($data->data->_id); - $req->setStatoRichiesta($data->data->stato_richiesta); - if(isset($data->data->ricerche)){ - $req->setRicerche($data->data->ricerche); - } - return $req; - }else{ - - $params = new \stdClass(); - $params->state = $req->getState(); - // $params->test = $req->getTest(); - - if($req->getJson() != NULL){ - $params->json_visura = $req->getJson(); - } - - $id_visura = $req->getId(); - //echo json_encode($params);exit; - //var_dump($params);exit; - $data = $this->connect("richiesta/$id_visura", "PUT", $params); - - - $req->setNew(FALSE); - $req->setId($data->data->_id); - $req->setStatoRichiesta($data->data->stato_richiesta); - if(isset($data->data->ricerche)){ - $req->setRicerche($data->data->ricerche); - } - return $req; - } - } - - function getRequestByIdVisura($id_visura){ - $visura = $this->connect("richiesta/$id_visura", "GET"); - return $this->getRequestByData($visura); - } - - function getRequestByData($visura){ - - - $this->visura = $this->connect("visure/{$visura->data->hash_visura}", "GET", [], 0); - - $this->hash = $visura->data->hash_visura; - defined("OPENAPI_CREATING_REQUEST") OR define("OPENAPI_CREATING_REQUEST", TRUE); - $request = new \OpenApi\classes\utility\VisEngine\VisRequest($this->visura); - $request->setNew(FALSE); - $request->setId($visura->data->_id); - $request->setStatoRichiesta($visura->data->stato_richiesta); - - if(isset($visura->data->ricerche)){ - - $request->setRicerche($visura->data->ricerche); - }else{ - $request->setRicerche([]); - } - // var_dump($request);exit; - return $request; - } - - function getDocument($id_visura){ - - ini_set("memory_limit","1024M"); - - $request = $this->getRequestByIdVisura($id_visura); - - $documento = $this->connect("documento/{$id_visura}", "GET", [], 0); - - - if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ - - $request->setDocument($documento->data); - } - return $request; - } - - /** - * Nel caso arrivino dei risultati di ricerca, seleziona il risultato richiesto - */ - function setRicerca($id_visura, $id_ricerca, $index){ - $index = str_replace("indice_","",$index); - $request = $this->getRequestByIdVisura($id_visura); - $hash_visura = $request->visura->data->hash_visura; - $param = ["id_ricerca"=>$id_ricerca, "indice"=> $index]; - - $visura = $this->connect("richiesta/{$id_visura}/ricerche", "PUT", $param, 0); - - $request->setStatoRichiesta($visura->data->stato_richiesta); - return $request; - - } - -} - - diff --git a/src/classes/exception/OpenApiConnectionsException.php b/src/classes/exception/OpenApiConnectionsException.php deleted file mode 100644 index 15b5818..0000000 --- a/src/classes/exception/OpenApiConnectionsException.php +++ /dev/null @@ -1,17 +0,0 @@ -serverData = NULL; - $this->serverHeader = NULL; - $this->serverRawResponse = NULL; - $this->httpCode = NULL; - } - public function __toString() { - return __CLASS__ . ": [{$this->code}]: {$this->message}\n"; - } - - - /** - * - * Imposta alcune variabili utili in fase di debugging degli errori - * - * @param object $serverData Response del server già decodato dalla versione json - * @param string $serverHeader Stringa contentene gli header della response - * @param string $serverRawResponse Stringa contente la risposta raw del server - * - * @return [type] - */ - function setServerResponse(object $serverData, string $serverHeader, string $serverRawResponse, $httpCode = NULL){ - $this->serverData = $serverData; - $this->serverHeader = $serverHeader; - $this->serverRawResponse = $serverRawResponse; - $this->httpCode = $httpCode; - } - - /** - * - * Restituisce la risposta del server già decodata da json - * - * @return object - */ - function getServerResponse(){ - return $this->serverData; - } - - /** - * - * Restituisce gli header della rispopsta del server - * - * @return string - */ - function getServerHeaderResponse(){ - return $this->serverHeader; - } - - /** - * - * Restituisce la risposta in formato RAW del server - * @return string - */ - function getServerRawResponse(){ - return $this->serverRawResponse; - } - - function getHttpCode(){ - return $this->httpCode; - } -} \ No newline at end of file diff --git a/src/classes/exception/OpenApiMarcheTemporaliException.php b/src/classes/exception/OpenApiMarcheTemporaliException.php deleted file mode 100644 index 072c875..0000000 --- a/src/classes/exception/OpenApiMarcheTemporaliException.php +++ /dev/null @@ -1,13 +0,0 @@ - 'A', 2 => 'B', 3 => 'C', 4 => 'D', 5 => 'E', - 6 => 'H', 7 => 'L', 8 => 'M', 9 => 'P', 10 => 'R', - 11 => 'S', 12 => 'T' - ); - - - protected $_pari = array( - '0' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, - '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, - 'A' => 0, 'B' => 1, 'C' => 2, 'D' => 3, 'E' => 4, - 'F' => 5, 'G' => 6, 'H' => 7, 'I' => 8, 'J' => 9, - 'K' => 10, 'L' => 11, 'M' => 12, 'N' => 13, 'O' => 14, - 'P' => 15, 'Q' => 16, 'R' => 17, 'S' => 18, 'T' => 19, - 'U' => 20, 'V' => 21, 'W' => 22, 'X' => 23, 'Y' => 24, - 'Z' => 25 - ); - - protected $_dispari = array( - '0' => 1, '1' => 0, '2' => 5, '3' => 7, '4' => 9, - '5' => 13, '6' => 15, '7' => 17, '8' => 19, '9' => 21, - 'A' => 1, 'B' => 0, 'C' => 5, 'D' => 7, 'E' => 9, - 'F' => 13, 'G' => 15, 'H' => 17, 'I' => 19, 'J' => 21, - 'K' => 2, 'L' => 4, 'M' => 18, 'N' => 20, 'O' => 11, - 'P' => 3, 'Q' => 6, 'R' => 8, 'S' => 12, 'T' => 14, - 'U' => 16, 'V' => 10, 'W' => 22, 'X' => 25, 'Y' => 24, - 'Z' => 23 - ); - - protected $_controllo = array( - '0' => 'A', '1' => 'B', '2' => 'C', '3' => 'D', - '4' => 'E', '5' => 'F', '6' => 'G', '7' => 'H', - '8' => 'I', '9' => 'J', '10' => 'K', '11' => 'L', - '12' => 'M', '13' => 'N', '14' => 'O', '15' => 'P', - '16' => 'Q', '17' => 'R', '18' => 'S', '19' => 'T', - '20' => 'U', '21' => 'V', '22' => 'W', '23' => 'X', - '24' => 'Y', '25' => 'Z' - ); - - /** - * Stringa di errore - */ - protected $_error = null; - - /** - * Separatore per la data di nascita - */ - protected $_dateSeparator = '-'; - - - /** - * Percorso del file del database SQLite - * dei codici catastali - */ - protected $_dbCatastali = null; - - - /** - * Trasforma la stringa passata in un array di lettere - * e lo incrocia con un ulteriore array - */ - protected function _getLettere($string, array $haystack) { - $letters = array(); - foreach(str_split($string) as $needle) { - if (in_array($needle, $haystack)) { - $letters[] = $needle; - } - } - return $letters; - } - - /** - * Ritorna un array con le vocali di una data stringa - */ - protected function _getVocali($string) { - return $this->_getLettere($string, $this->_vocali); - } - - /** - * Ritorna un array con le consonanti di una data stringa - */ - protected function _getConsonanti($string) { - return $this->_getLettere($string, $this->_consonanti); - } - - /** - * Pulisce la stringa filtrando tutti i caratteri che - * non sono lettere. Lo switch $toupper se impostato a TRUE - * converte la stringa risultante in MAIUSCOLO. - */ - protected function _sanitize($string, $toupper = true) { - $result = preg_replace('/[^A-Za-z]*/', '', $string); - return ($toupper) ? strtoupper($result) : $result; - } - - /** - * Se la stringa passata a funzione e' costituita - * da meno di 3 caratteri, rimpiazza le lettere - * mancanti con la lettera X. - */ - protected function _addMissingX($string) { - $code = $string; - while(strlen($code) < 3) { - $code .= 'X'; - } - return $code; - } - - /** - * Ottiene il codice identificativo del nome - */ - protected function _calcolaNome($string) { - $nome = $this->_sanitize($string); - - // Se il nome inserito e' piu' corto di 3 lettere - // si aggiungono tante X quanti sono i caratteri - // mancanti. - if (strlen($nome) < 3) { - return $this->_addMissingX($nome); - } - - $nome_cons = $this->_getConsonanti($nome); - $code = ""; - // Se le consonanti contenute nel nome sono minori - // o uguali a 3 vengono considerate nell'ordine in cui - // compaiono. - if (count($nome_cons) <= 3) { - $code = implode('', $nome_cons); - } else { - // Se invece abbiamo almeno 4 consonanti, prendiamo - // la prima, la terza e la quarta. - for($i=0; $i<4; $i++) { - if ($i == 1) continue; - if (!empty($nome_cons[$i])) { - $code .= $nome_cons[$i]; - } - } - } - - // Se compaiono meno di 3 consonanti nel nome, si - // utilizzano le vocali, nell'ordine in cui compaiono - // nel nome. - if (strlen($code) < 3) { - $nome_voc = $this->_getVocali($nome); - while (strlen($code) < 3) { - $code .= array_shift($nome_voc); - } - } - - return $code; - } - - protected function _calcolaCognome($string) { - $cognome = $this->_sanitize($string); - $code = ""; - - // Se il cognome inserito e' piu' corto di 3 lettere - // si aggiungono tante X quanti sono i caratteri - // mancanti. - if (strlen($cognome) < 3) { - return $this->_addMissingX($cognome); - } - - $cognome_cons = $this->_getConsonanti($cognome); - - // Per il calcolo del cognome si prendono le prime - // 3 consonanti. - for ($i=0; $i<3; $i++) { - if (array_key_exists($i, $cognome_cons)) { - $code .= $cognome_cons[$i]; - } - } - - // Se le consonanti non bastano, vengono prese - // le vocali nell'ordine in cui compaiono. - if (strlen($code) < 3) { - $cognome_voc = $this->_getVocali($cognome); - while (strlen($code) < 3) { - $code .= array_shift($cognome_voc); - } - } - - return $code; - } - - /** - * Imposta il separatore di data ( default: / ) - */ - public function setDateSeparator($char) { - $this->_dateSeparator = $char; - return $this; - } - - /** - * Ritorna la parte di codice fiscale corrispondente - * alla data di nascita del soggetto (Forma: AAMGG) - */ - protected function _calcolaDataNascita($data, $sesso) { - $dn = explode($this->_dateSeparator, $data); - - $giorno = (int) @$dn[2]; - $mese = (int) @$dn[1]; - $anno = (int) @$dn[0]; - - // Le ultime due cifre dell'anno di nascita - $aa = substr($anno, -2); - - // La lettera corrispondente al mese di nascita - $mm = $this->_mesi[$mese]; - - // Il giorno viene calcolato a seconda del sesso - // del soggetto di cui si calcola il codice: - // se e' Maschio si mette il giorno reale, se e' - // Femmina viene aggiungo 40 a questo numero. - $gg = (strtoupper($sesso) == 'M') ? $giorno : ($giorno + 40); - - // Bug #1: Thanks to Luca - if (strlen($gg) < 2) $gg = '0' . $gg; - - - return $aa . $mm . $gg; - } - - - - /** - * Ritorna la cifra di controllo sulla base dei - * 15 caratteri del codice fiscale calcolati. - */ - protected function _calcolaCifraControllo($codice) { - $code = str_split($codice); - $sum = 0; - - for($i=1; $i <= count($code); $i++) { - $cifra = $code[$i-1]; - $sum += ($i % 2) ? $this->_dispari[$cifra] : $this->_pari[$cifra]; - } - - $sum %= 26; - - return $this->_controllo[$sum]; - } - - - /** - * Imposta il messaggio di errore - */ - protected function _setError($string) { - $this->_error = $string; - } - - /** - * Verifica la presenza di un errore. - * Ritorna TRUE se presente, FALSE altrimenti. - */ - public function hasError() { - return !is_null($this->_error); - } - - /** - * Ritorna la stringa di errore - */ - public function getError() { - return $this->_error; - } - - /** - * Ritorna il codice fiscale utilizzando i parametri - * passati a funzione. Se si verifica - */ - public function calculate($nome, $cognome, $data, $sesso, $codice_catastale_comune) { - $codice = $this->_calcolaCognome($cognome) . - $this->_calcolaNome($nome) . - $this->_calcolaDataNascita($data, $sesso) . - $codice_catastale_comune; - - if ($this->hasError()) { - return false; - } - - $codice .= $this->_calcolaCifraControllo($codice); - - if (strlen($codice) != 16) { - $this->_setError(self::ERR_GENERIC); - return false; - } - - return $codice; - } -} \ No newline at end of file diff --git a/src/classes/utility/Plugins/Validations.php b/src/classes/utility/Plugins/Validations.php deleted file mode 100644 index 503f87d..0000000 --- a/src/classes/utility/Plugins/Validations.php +++ /dev/null @@ -1,122 +0,0 @@ -9){ - $secondo=$secondo-9; - } - - $primo+=$secondo; - - } - if( (10-$primo%10)%10 != ord($variabile[10])-ord('0') ){ - return false; - } - - - return true; - - } -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/errorLang.php b/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/errorLang.php deleted file mode 100644 index 7e218cb..0000000 --- a/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/errorLang.php +++ /dev/null @@ -1,23 +0,0 @@ -errors = (array)json_decode(file_get_contents($json)); - } - - function getError($code, $serverResponse){ - if(isset($this->errors[$code])){ - return $this->errors[$code]; - }else{ - if(isset($serverResponse->message)){ - return $serverResponse->message; - } - } - - return NULL; - } - -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json b/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json deleted file mode 100644 index bc591a9..0000000 --- a/src/classes/utility/UfficioPostale/Objects/ErrorTranslation/lng/it.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - - "12080":"Il campo indirizzo è obbligatorio", - "15060":"Il campo indirizzo è obbligatorio", - "12090":"Il campo numero civico è obbligatorio", - "15070":"Il campo numero civico è obbligatorio", - "12140":"Il campo comune è obbligatorio", - "15080":"Il campo comune è obbligatorio", - "13020":"Caricare almeno un documento o un testo", - "12180":"Comune, CAP e provinca in conflitto" -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/Recipient.php b/src/classes/utility/UfficioPostale/Objects/Recipient.php deleted file mode 100644 index 8c1e0e7..0000000 --- a/src/classes/utility/UfficioPostale/Objects/Recipient.php +++ /dev/null @@ -1,356 +0,0 @@ -errors = null; - $this->data = new \stdClass(); - $this->data->firstName = NULL; - $this->data->secondName = NULL; - $this->data->companyName = NULL; - $this->data->at = NULL; - $this->data->title = NULL; - $this->data->dug = NULL; - $this->data->address = NULL; - $this->data->huoseNumber = NULL; - $this->data->city = NULL; - $this->data->zip = NULL; - $this->data->province = NULL; - $this->data->country = "Italia"; - $this->data->email = NULL; - $this->data->id = NULL; - $this->data->IdRicevuta = NULL; - $this->data->tracking_code = NULL; - $this->data->post_office = NULL; - $this->data->post_office_box = NULL; - - - $this->itData = new \stdClass(); - $this->itData->nome = NULL; - $this->itData->cognome = NULL; - $this->itData->ragione_sociale = NULL; - $this->itData->co = NULL; - $this->itData->titolo = NULL; - $this->itData->dug = NULL; - $this->itData->indirizzo = NULL; - $this->itData->civico = NULL; - $this->itData->comune = NULL; - $this->itData->cap = NULL; - $this->itData->provincia = NULL; - $this->itData->nazione = "Italia"; - $this->itData->email = NULL; - $this->itData->id = NULL; - $this->itData->IdRicevuta = NULL; - $this->itData->tracking_code = NULL; - $this->data->state = NULL; - $this->itData->state = NULL; - $this->itData->casella_postale = NULL; - $this->itData->ufficio_postale = NULL; - - $this->itData->stateType = 'TRANSITORIO'; - $this->data->stateType = 'TRANSITORIO'; - $this->data->stateDescription = 'Inviato da Web'; - $this->itData->stateDescription = 'Inviato da Web'; - $this->validate = false; - - if($recipient != NULL){ - $this->createFromObject($recipient); - } - } - - public function createFromObject($object){ - if(is_array($object)){ - $object = (object)$object; - } - //var_dump($object);Exit; - $stateType = 'TRANSITORIO'; - $stateDescription = ''; - // var_dump($object);exit; - if(isset($object->tracking)) - { - $object->tracking = (array)$object->tracking; - if(is_array($object->tracking) && count($object->tracking)>1){ - - $lastT = $object->tracking[count($object->tracking)-1]; - - $stateType = $lastT->definitivo?'DEFINITIVO':'TRANSITORIO'; - $stateDescription = $lastT->descrizione; - - } - }else{ - if(isset($object->stateType)){ - $stateType = $object->stateType; - $stateDescription = $object->state; - } - } - $this->data->stateType = $stateType; - $this->data->stateDescription = $stateDescription; - $this->itData->stateType = $stateType; - $this->itData->stateDescription = $stateDescription; - $this->data->title = isset($object->title)?$object->title:(isset($object->titolo)?$object->titolo:NULL); - $this->data->at = isset($object->at)?$object->at:(isset($object->co)?$object->co:NULL); - $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); - $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); - $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); - $this->data->dug = isset($object->dug)?$object->dug:NULL; - $this->data->address = isset($object->address)?$object->address:(isset($object->indirizzo)?$object->indirizzo:NULL); - $this->data->huoseNumber = isset($object->huoseNumber)?$object->huoseNumber:(isset($object->civico)?$object->civico:NULL); - $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); - $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); - $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); - $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"IT"); - $this->data->email = isset($object->email)?$object->email:NULL; - - $this->data->id = isset($object->id)?$object->id:NULL; - $this->data->state = isset($object->state)?$object->state:NULL; - $this->data->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; - $this->data->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; - $this->data->post_office = isset($object->post_office)?$object->post_office:(isset($object->ufficio_postale)?$object->ufficio_postale:NULL); - $this->data->post_office_box = isset($object->post_office_box)?$object->post_office_box:(isset($object->casella_postale)?$object->casella_postale:NULL); - - - - $this->itData->ufficio_postale = $this->data->post_office; - $this->itData->casella_postale = $this->data->post_office_box; - $this->itData->co = $this->data->at; - $this->itData->titolo = $this->data->title; - $this->itData->nome = $this->data->firstName; - $this->itData->cognome = $this->data->secondName; - $this->itData->ragione_sociale = $this->data->companyName; - $this->itData->dug = $this->data->dug; - $this->itData->indirizzo = $this->data->address; - $this->itData->civico = $this->data->huoseNumber; - $this->itData->comune = $this->data->city; - $this->itData->cap = $this->data->zip; - $this->itData->provincia = $this->data->province; - $this->itData->nazione = $this->data->country; - $this->itData->email = $this->data->email; - $this->itData->id= $this->data->id; - $this->itData->state= $this->data->state; - - $this->itData->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; - $this->itData->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; - if($this->itData->tracking_code == NULL && $this->itData->IdRicevuta != NULL){ - $this->itData->tracking_code = $this->itData->IdRicevuta; - $this->data->tracking_code = $this->itData->tracking_code; - } - } - - public function getObject($itNames = FALSE){ - if(!$itNames){ - return $this->data; - } - return $this->itData; - } - - public function getTitle(){ - return $this->data->title; - } - - public function getAt(){ - return $this->data->at; - } - - public function getState(){ - return $this->data->state; - } - - public function getStateType(){ - return $this->data->stateType; - } - - public function getStateDescription(){ - return $this->data->stateDescription; - } - public function getFirstName(){ - return $this->data->firstName; - } - public function getSecondName(){ - return $this->data->secondName; - } - - public function getLastName(){ - return $this->getSecondName(); - } - - public function getCompanyName(){ - return $this->data->companyName; - } - public function getDug(){ - return $this->data->dug; - } - public function getAddress(){ - return $this->data->address; - } - public function getHuoseNumber(){ - return $this->data->huoseNumber; - } - public function getCity(){ - return $this->data->city; - } - public function getZip(){ - return $this->data->zip; - } - public function getProvince(){ - return $this->data->province; - } - public function getCountry(){ - return $this->data->country; - } - public function getEmail(){ - return $this->data->email; - } - - public function getId(){ - return $this->data->id; - } - public function getIdRicevuta(){ - return $this->data->IdRicevuta; - } - - - - public function getTrackingCode(){ - return $this->data->tracking_code; - } - - public function setTitle(string $title){ - $this->data->title = $title; - $this->itData->titolo = $title; - } - - public function setAt(string $at){ - $this->data->at = $at; - $this->itData->co = $at; - } - - public function setFirstName(string $firstName){ - $this->data->firstName = $firstName; - $this->itData->nome = $firstName; - } - - public function setLastName(string $secondName){ - $this->setSecondName($secondName); - - } - public function setSecondName(string $secondName){ - $this->data->secondName = $secondName; - $this->itData->cognome = $secondName; - } - - public function setCompanyName(string $companyName){ - $this->data->companyName = $companyName; - $this->itData->ragione_sociale = $companyName; - } - - public function setDug(string $dug){ - $this->data->dug = $dug; - $this->itData->dug = $dug; - } - - public function setAddress(string $address){ - $this->data->address = $address; - $this->itData->indirizzo = $address; - } - public function setHuoseNumber(string $huoseNumber){ - $this->data->huoseNumber = $huoseNumber; - $this->itData->civico = $huoseNumber; - } - - public function setCity(string $city){ - $this->data->city = $city; - $this->itData->comune = $city; - } - - public function setZip(string $zip){ - $this->data->zip = $zip; - $this->itData->cap = $zip; - } - - public function setProvince(string $province){ - $this->data->province = $province; - $this->itData->privincia = $province; - } - - public function setCountry(string $country){ - $this->data->country = $country; - $this->itData->nazione = $country; - } - - public function setEmail(string $email){ - $this->data->email = $email; - $this->itData->email = $email; - } - - public function getErrors($validate = TRUE){ - if($validate){ - $this->validate(); - } - - return $this->errors; - } - - public function validate(){ - $this->errors = []; - if($this->data->zip == NULL){ - $this->errors['zip'] = (object)[ - "code"=> "required", - "text"=>"zip field is required" - ]; - } else if($this->data->country == "Italia" || $this->data->country == "Italy"){ - $re = '/^\d{5}$/'; - preg_match($re, $this->data->zip, $matches, PREG_OFFSET_CAPTURE, 0); - if(count($matches) == 0){ - $this->errors['zip'] = (object)[ - "code"=> "5_digit", - "text"=>"Italian ZIP must be 5 digits" - ]; - } - } - - if($this->data->city == NULL){ - $this->errors['city'] = (object)[ - "code"=> "required", - "text"=>"city is required" - ]; - } - - if($this->data->province == NULL){ - $this->errors['province'] = (object)[ - "code"=> "required", - "text"=>"province is required" - ]; - } - - - if($this->data->dug == NULL){ - $this->errors['dug'] = (object)[ - "code"=> "required", - "text"=>"dug is required" - ]; - } - - if($this->data->address == NULL){ - $this->errors['address'] = (object)[ - "code"=> "required", - "text"=>"address is required" - ]; - } - - if($this->data->huoseNumber == NULL){ - $this->errors['huoseNumber'] = (object)[ - "code"=> "required", - "text"=>"huose number is required" - ]; - } - - - $this->validate = count($this->errors) == 0; - return $this->validate; - } - -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php b/src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php deleted file mode 100644 index 5ffa0f9..0000000 --- a/src/classes/utility/UfficioPostale/Objects/RecipientRaccomandate.php +++ /dev/null @@ -1,81 +0,0 @@ -tracking)) - { - $object->tracking = (array)$object->tracking; - if(is_array($object->tracking) && count($object->tracking)>1){ - - $lastT = $object->tracking[count($object->tracking)-1]; - - $stateType = $lastT->definitivo?'DEFINITIVO':'TRANSITORIO'; - $stateDescription = $lastT->descrizione; - - } - }else{ - if(isset($object->stateType)){ - $stateType = $object->stateType; - $stateDescription = $object->state; - } - } - $this->data->stateType = $stateType; - $this->data->stateDescription = $stateDescription; - $this->itData->stateType = $stateType; - $this->itData->stateDescription = $stateDescription; - $this->data->title = isset($object->title)?$object->title:(isset($object->titolo)?$object->titolo:NULL); - $this->data->at = isset($object->at)?$object->at:(isset($object->co)?$object->co:NULL); - $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); - $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); - $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); - $this->data->dug = isset($object->dug)?$object->dug:NULL; - $this->data->address = isset($object->address)?$object->address:(isset($object->indirizzo)?$object->indirizzo:NULL); - $this->data->huoseNumber = isset($object->huoseNumber)?$object->huoseNumber:(isset($object->civico)?$object->civico:NULL); - $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); - $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); - $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); - $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"IT"); - $this->data->email = isset($object->email)?$object->email:NULL; - - $this->data->id = isset($object->id)?$object->id:NULL; - $this->data->state = isset($object->state)?$object->state:NULL; - $this->data->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; - $this->data->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; - $this->data->post_office = isset($object->post_office)?$object->post_office:(isset($object->ufficio_postale)?$object->ufficio_postale:NULL); - $this->data->post_office_box = isset($object->post_office_box)?$object->post_office_box:(isset($object->casella_postale)?$object->casella_postale:NULL); - - - - $this->itData->ufficio_postale = $this->data->post_office; - $this->itData->casella_postale = $this->data->post_office_box; - $this->itData->co = $this->data->at; - $this->itData->titolo = $this->data->title; - $this->itData->nome = $this->data->firstName; - $this->itData->cognome = $this->data->secondName; - $this->itData->ragione_sociale = $this->data->companyName; - $this->itData->dug = $this->data->dug; - $this->itData->indirizzo = $this->data->address; - $this->itData->civico = $this->data->huoseNumber; - $this->itData->comune = $this->data->city; - $this->itData->cap = $this->data->zip; - $this->itData->provincia = $this->data->province; - $this->itData->nazione = $this->data->country; - $this->itData->email = $this->data->email; - $this->itData->id= $this->data->id; - $this->itData->state= $this->data->state; - - $this->itData->IdRicevuta = isset($object->IdRicevuta)?$object->IdRicevuta:NULL; - $this->itData->tracking_code = isset($object->NumeroRaccomandata)?$object->NumeroRaccomandata:NULL; - - } -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Objects/Sender.php b/src/classes/utility/UfficioPostale/Objects/Sender.php deleted file mode 100644 index b93ca55..0000000 --- a/src/classes/utility/UfficioPostale/Objects/Sender.php +++ /dev/null @@ -1,241 +0,0 @@ -errors = null; - $this->data = new \stdClass(); - $this->data->firstName = NULL; - $this->data->secondName = NULL; - $this->data->companyName = NULL; - $this->data->dug = NULL; - $this->data->address = NULL; - $this->data->huoseNumber = NULL; - $this->data->city = NULL; - $this->data->zip = NULL; - $this->data->province = NULL; - $this->data->country = "IT"; - $this->data->email = NULL; - - - $this->itData = new \stdClass(); - $this->itData->nome = NULL; - $this->itData->cognome = NULL; - $this->itData->ragione_sociale = NULL; - $this->itData->dug = NULL; - $this->itData->indirizzo = NULL; - $this->itData->civico = NULL; - $this->itData->comune = NULL; - $this->itData->cap = NULL; - $this->itData->provincia = NULL; - $this->itData->nazione = "IT"; - $this->itData->email = NULL; - - $this->validate = false; - - if($sender != NULL){ - $this->createFromObject($sender); - } - } - - public function createFromObject($object){ - if(is_array($object)){ - $object = (object)$object; - } - // var_dump($object); - $this->data->firstName = isset($object->firstName)?$object->firstName:(isset($object->nome)?$object->nome:NULL); - $this->data->secondName = isset($object->secondName)?$object->secondName:(isset($object->cognome)?$object->cognome:NULL); - $this->data->companyName = isset($object->companyName)?$object->companyName:(isset($object->ragione_sociale)?$object->ragione_sociale:NULL); - $this->data->dug = isset($object->dug)?$object->dug:NULL; - $this->data->address = isset($object->address)?$object->address:(isset($object->indirizzo)?$object->indirizzo:NULL); - $this->data->huoseNumber = isset($object->huoseNumber)?$object->huoseNumber:(isset($object->civico)?$object->civico:NULL); - $this->data->city = isset($object->city)?$object->city:(isset($object->comune)?$object->comune:NULL); - $this->data->zip = isset($object->zip)?$object->zip:(isset($object->cap)?$object->cap:NULL); - $this->data->province = isset($object->province)?$object->province:(isset($object->provincia)?$object->provincia:NULL); - $this->data->country = isset($object->country)?$object->country:(isset($object->nazione)?$object->nazione:"IT"); - $this->data->email = isset($object->email)?$object->email:NULL; - // var_dump($this->data);exit; - - $this->itData->nome = $this->data->firstName; - $this->itData->cognome = $this->data->secondName; - $this->itData->ragione_sociale = $this->data->companyName; - $this->itData->dug = $this->data->dug; - $this->itData->indirizzo = $this->data->address; - $this->itData->civico = $this->data->huoseNumber; - $this->itData->comune = $this->data->city; - $this->itData->cap = $this->data->zip; - $this->itData->provincia = $this->data->province; - $this->itData->nazione = $this->data->country; - $this->itData->email = $this->data->email; - - } - - public function getObject($itNames = FALSE){ - if(!$itNames){ - return $this->data; - } - return $this->itData; - } - - - public function getFirstName(){ - return $this->data->firstName; - } - public function getSecondName(){ - return $this->data->secondName; - } - - public function getCompanyName(){ - return $this->data->companyName; - } - public function getDug(){ - return $this->data->dug; - } - public function getAddress(){ - return $this->data->address; - } - public function getHuoseNumber(){ - return $this->data->huoseNumber; - } - public function getCity(){ - return $this->data->city; - } - public function getZip(){ - return $this->data->zip; - } - public function getProvince(){ - return $this->data->province; - } - public function getCountry(){ - return $this->data->country; - } - public function getEmail(){ - return $this->data->email; - } - - public function setFirstName(string $firstName){ - $this->data->firstName = $firstName; - $this->itData->nome = $firstName; - } - - public function setSecondName(string $secondName){ - $this->data->secondName = $secondName; - $this->itData->cognome = $secondName; - } - - public function setCompanyName(string $companyName){ - $this->data->companyName = $companyName; - $this->itData->ragione_sociale = $companyName; - } - - public function setDug(string $dug){ - $this->data->dug = $dug; - $this->itData->dug = $dug; - } - - public function setAddress(string $address){ - $this->data->address = $address; - $this->itData->indirizzo = $address; - } - public function setHuoseNumber(string $huoseNumber){ - $this->data->huoseNumber = $huoseNumber; - $this->itData->civico = $huoseNumber; - } - - public function setCity(string $city){ - $this->data->city = $city; - $this->itData->comune = $city; - } - - public function setZip(string $zip){ - $this->data->zip = $zip; - $this->itData->cap = $zip; - } - - public function setProvince(string $province){ - $this->data->province = $province; - $this->itData->privincia = $province; - } - - public function setCountry(string $country){ - $this->data->country = $country; - $this->itData->nazione = $country; - } - - public function setEmail(string $email){ - $this->data->email = $email; - $this->itData->email = $email; - } - - public function getErrors($validate = TRUE){ - if($validate){ - $this->validate(); - } - - return $this->errors; - } - - public function validate(){ - $this->errors = []; - if($this->data->zip == NULL){ - $this->errors['zip'] = (object)[ - "code"=> "required", - "text"=>"zip field is required" - ]; - } else if($this->data->country == "Italia" || $this->data->country == "Italy" || $this->data->country == "IT"){ - $re = '/^\d{5}$/'; - preg_match($re, $this->data->zip, $matches, PREG_OFFSET_CAPTURE, 0); - if(count($matches) == 0){ - $this->errors['zip'] = (object)[ - "code"=> "5_digit", - "text"=>"Italian ZIP must be 5 digits" - ]; - } - } - - if($this->data->city == NULL){ - $this->errors['city'] = (object)[ - "code"=> "required", - "text"=>"city is required" - ]; - } - - if($this->data->province == NULL){ - $this->errors['province'] = (object)[ - "code"=> "required", - "text"=>"province is required" - ]; - } - - - if($this->data->dug == NULL){ - $this->errors['dug'] = (object)[ - "code"=> "required", - "text"=>"dug is required" - ]; - } - - if($this->data->address == NULL){ - $this->errors['address'] = (object)[ - "code"=> "required", - "text"=>"address is required" - ]; - } - - if($this->data->huoseNumber == NULL){ - $this->errors['huoseNumber'] = (object)[ - "code"=> "required", - "text"=>"huose number is required" - ]; - } - - - $this->validate = count($this->errors) == 0; - return $this->validate; - } - -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/PostaOrdinaria.php b/src/classes/utility/UfficioPostale/PostaOrdinaria.php deleted file mode 100644 index 15f7a67..0000000 --- a/src/classes/utility/UfficioPostale/PostaOrdinaria.php +++ /dev/null @@ -1,92 +0,0 @@ -getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); - } - if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); - } - $param['confirmed'] = TRUE; - $ret = call_user_func_array($this->connect,["ordinarie/".$this->getId(),"PATCH",$param]); - - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - } - - function send(){ - try{ - $object = new \stdClass();; - $object->mittente = $this->sender->getObject(TRUE); - $object->destinatari = []; - foreach($this->getRecpients() as $r){ - $object->destinatari[] = $r->getObject(TRUE); - } - $object->documento =$this->documents; - $object->opzioni = new \stdClass(); - $object->opzioni->fronteretro = $this->getFronteRetro(); - $object->opzioni->colori = $this->getColori(); - $object->opzioni->autoconfirm = $this->getAutoconfirm(); - if($this->getCallback() != NULL){ - $callback = $this->getCallback(); - foreach($callback as $k => $v){ - $object->opzioni->$k = $v; - } - } - $ret = call_user_func_array($this->connect,["ordinarie/","POST",$object]); - $this->pricing = $ret->data[0]->pricing; - $this->id = $ret->data[0]->id; - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->pages = $ret->data[0]->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - $response = $e->getServerResponse(); - //var_dump($response->data->wrong_fields);exit; - if(isset($response->data->wrong_fields) && isset($response->error)){ - $error_message = $this->getError($response->error, $response); - - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); - $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); - $e2->setErrorMessage($error_message); - $e2->setFields($response->data->wrong_fields); - throw $e2; - } - throw $e; - } - } - - - function creaPostaOrdinariaByData($data){ - if(isset($data->documento_validato) && is_object($data->documento_validato)){ - $this->valid_doc_pdf = $data->documento_validato->pdf; - $this->valid_doc_jpg = $data->documento_validato->jpg; - } - $this->pricing = $data->pricing; - $this->id = $data->id; - $this->confirmed = $data->confirmed; - $this->state = $data->state; - $this->numero_pagine = $data->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($data->destinatari); - $this->setSender($data->mittente); - $this->colori = $data->opzioni->colori; - $this->fronteretro = $data->opzioni->fronteretro; - $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); - - if(isset($data->IDRichiesta)){ - $this->request_id = $data->IDRichiesta; - } - - } -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/PostaPrioritaria.php b/src/classes/utility/UfficioPostale/PostaPrioritaria.php deleted file mode 100644 index 061a415..0000000 --- a/src/classes/utility/UfficioPostale/PostaPrioritaria.php +++ /dev/null @@ -1,90 +0,0 @@ -getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); - } - if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); - } - $param['confirmed'] = TRUE; - $ret = call_user_func_array($this->connect,["prioritarie/".$this->getId(),"PATCH",$param]); - - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - } - - function send(){ - try{ - $object = new \stdClass();; - $object->mittente = $this->sender->getObject(TRUE); - $object->destinatari = []; - foreach($this->getRecpients() as $r){ - $object->destinatari[] = $r->getObject(TRUE); - } - $object->documento =$this->documents; - $object->opzioni = new \stdClass(); - $object->opzioni->fronteretro = $this->getFronteRetro(); - $object->opzioni->colori = $this->getColori(); - $object->opzioni->autoconfirm = $this->getAutoconfirm(); - if($this->getCallback() != NULL){ - $callback = $this->getCallback(); - foreach($callback as $k => $v){ - $object->opzioni->$k = $v; - } - } - $ret = call_user_func_array($this->connect,["prioritarie/","POST",$object]); - $this->pricing = $ret->data[0]->pricing; - $this->id = $ret->data[0]->id; - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->pages = $ret->data[0]->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - $response = $e->getServerResponse(); - //var_dump($response->data->wrong_fields);exit; - if(isset($response->data->wrong_fields) && isset($response->error)){ - $error_message = $this->getError($response->error, $response); - - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); - $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); - $e2->setErrorMessage($error_message); - $e2->setFields($response->data->wrong_fields); - throw $e2; - } - throw $e; - } - } - - - function creaPostaPrioritariaByData($data){ - if(isset($data->documento_validato) && is_object($data->documento_validato)){ - $this->valid_doc_pdf = $data->documento_validato->pdf; - $this->valid_doc_jpg = $data->documento_validato->jpg; - } - $this->pricing = $data->pricing; - $this->id = $data->id; - $this->confirmed = $data->confirmed; - $this->state = $data->state; - $this->numero_pagine = $data->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($data->destinatari); - $this->setSender($data->mittente); - $this->colori = $data->opzioni->colori; - $this->fronteretro = $data->opzioni->fronteretro; - $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); - if(isset($data->IDRichiesta)){ - $this->request_id = $data->IDRichiesta; - } - } -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Raccomandata.php b/src/classes/utility/UfficioPostale/Raccomandata.php deleted file mode 100644 index 18f2ebf..0000000 --- a/src/classes/utility/UfficioPostale/Raccomandata.php +++ /dev/null @@ -1,134 +0,0 @@ -getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); - } - if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); - } - $param['confirmed'] = TRUE; - $ret = call_user_func_array($this->connect,["raccomandate/".$this->getId(),"PATCH",$param]); - - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - - } - - /* - public function setRecipients($recipients){ - $this->clearRecipients(); - $valid = TRUE; - foreach($recipients as $key => $recipient){ - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ - - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); - } - if(!$recipient->validate()){ - $valid = FALSE; - } - $this->recipients[] = $recipient; - } - $this->validRecipients = $valid; - return $valid; - } - - protected function getError($code, $serverResponse){ - return call_user_func_array($this->errorFunc,[$code, $serverResponse]); - } - - public function addRecipient($recipient){ - - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate)){ - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\RecipientRaccomandate($recipient); - } - - $valid = TRUE; - if(!$recipient->validate()){ - $valid = FALSE; - } - $this->recipients[] = $recipient; - $this->validRecipients = $valid; - return $valid; - }*/ - - - function send(){ - try{ - $object = new \stdClass();; - $object->mittente = $this->sender->getObject(TRUE); - $object->destinatari = []; - foreach($this->getRecpients() as $r){ - $object->destinatari[] = $r->getObject(TRUE); - } - $object->documento =$this->documents; - $object->opzioni = new \stdClass(); - $object->opzioni->fronteretro = $this->getFronteRetro(); - $object->opzioni->colori = $this->getColori(); - $object->opzioni->ar = $this->getAR(); - $object->opzioni->autoconfirm = $this->getAutoconfirm(); - if($this->getCallback() != NULL){ - $callback = $this->getCallback(); - foreach($callback as $k => $v){ - $object->opzioni->$k = $v; - } - } - $ret = call_user_func_array($this->connect,["raccomandate/","POST",$object]); - $this->pricing = $ret->data[0]->pricing; - $this->id = $ret->data[0]->id; - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->pages = $ret->data[0]->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - $response = $e->getServerResponse(); - //var_dump($response->data->wrong_fields);exit; - if(isset($response->data->wrong_fields) && isset($response->error)){ - $error_message = $this->getError($response->error, $response); - - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); - $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); - $e2->setErrorMessage($error_message); - $e2->setFields($response->data->wrong_fields); - throw $e2; - } - throw $e; - } - } - - - function creaRaccomandataByData($data){ - if(isset($data->documento_validato) && is_object($data->documento_validato)){ - $this->valid_doc_pdf = $data->documento_validato->pdf; - $this->valid_doc_jpg = $data->documento_validato->jpg; - } - $this->pricing = $data->pricing; - $this->id = $data->id; - $this->confirmed = $data->confirmed; - $this->state = $data->state; - $this->numero_pagine = $data->documento_validato->pagine; - $this->clearRecipients(); - $this->setRecipients($data->destinatari); - $this->setSender($data->mittente); - $this->colori = $data->opzioni->colori; - $this->fronteretro = $data->opzioni->fronteretro; - $this->ar = $data->opzioni->ar; - $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); - if(isset($data->IDRichiesta)){ - $this->request_id = $data->IDRichiesta; - } - } - -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/ServiziPostali.php b/src/classes/utility/UfficioPostale/ServiziPostali.php deleted file mode 100644 index a9b19a7..0000000 --- a/src/classes/utility/UfficioPostale/ServiziPostali.php +++ /dev/null @@ -1,238 +0,0 @@ -connect = $connect; - $this->sender = NULL; - $this->errorFunc = $errorFunc; - $this->recipients = []; - $this->valid_doc_pdf = NULL; - $this->valid_doc_jpg = NULL; - $this->documents = []; - $this->textMessage = NULL; - $this->validRecipients = FALSE; - $this->fronteretro = FALSE; - $this->colori = FALSE; - $this->ar = FALSE; - $this->autoconfirm = FALSE; - $this->pricing = FALSE; - $this->id = FALSE; - $this->confirmed = FALSE; - $this->state = FALSE; - $this->callback = NULL; - } - - - function setRequestId($request_id){ - $this->request_id = $request_id; - } - - function getRequestId(){ - return $this->request_id ; - } - - function getValidatedDocument($type = "pdf"){ - if($type == "pdf"){ - return $this->valid_doc_pdf; - } - if($type == "jpg"){ - return $this->valid_doc_jpg; - } - } - - function getNumeroLettere(){ - throw new \OpenApi\classes\exception\OpenApiUPException("Letter exist only for telagrammi",40016); - } - - function getNumeroPagine(){ - return $this->numero_pagine; - } - function getPages(){ - return $this->pages; - } - - function getPricing(){ - return $this->pricing; - } - - function getId(){ - return $this->id; - } - - function getConfirmed(){ - return $this->confirmed; - } - - function getState(){ - return $this->state; - } - function setAutoconfirm($autoconfirm){ - $this->autoconfirm = $autoconfirm; - } - - function getAutoconfirm(){ - return $this->autoconfirm; - } - - function setColori($colori){ - $this->colori = $colori; - } - - function getColori(){ - return $this->colori; - } - function setFronteRetro($fronteretro){ - $this->fronteretro = $fronteretro; - } - - function getFronteRetro(){ - return $this->fronteretro; - } - - function setAR($ar){ - $this->ar = $ar; - } - - function getAR(){ - return $this->ar; - } - - - public function setSender($sender){ - if($sender instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Sender){ - $this->sender = $sender; - }else{ - $this->sender = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($sender); - } - if(!$this->sender->validate()){ - // var_dump($this->sender->getErrors()); - return FALSE; - } - return TRUE; - } - - public function getSender(){ - return $this->sender; - } - - public function getSenderError(){ - if($this->sender == NULL){ - return NULL; - } - return $this->sender->getErrors(); - } - - public function getRecipients(){ - return $this->getRecpients(); - } - //MANTENUTO PER RETROCOMPATIBILITA' - public function getRecpients(){ - return $this->recipients; - } - - public function getRecpientsErrors(){ - if($this->recipients == NULL){ - return NULL; - } - if($this->validRecipients){ - return []; - } - $errors = []; - foreach($this->recipient AS $r){ - $errors[] = $r->getErrors(); - } - return $errors; - } - - public function setTextMessage($message){ - $this->textMessage = $message; - } - - public function setRecipients($recipients){ - $this->clearRecipients(); - $valid = TRUE; - foreach($recipients as $key => $recipient){ - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ - - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); - } - if(!$recipient->validate()){ - $valid = FALSE; - } - $this->recipients[] = $recipient; - } - $this->validRecipients = $valid; - return $valid; - } - - protected function getError($code, $serverResponse){ - return call_user_func_array($this->errorFunc,[$code, $serverResponse]); - } - - public function addRecipient($recipient){ - - if(!($recipient instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Recipient)){ - $recipient = new \OpenApi\classes\utility\UfficioPostale\Objects\Recipient($recipient); - } - - $valid = TRUE; - if(!$recipient->validate()){ - $valid = FALSE; - } - $this->recipients[] = $recipient; - $this->validRecipients = $valid; - return $valid; - } - - public function clearRecipients(){ - $this->recipients = []; - } - - public function setDocuments($documents){ - $this->documents = $documents; - } - - public function addDocument($document){ - $this->documents[] = $document; - } - - public function clearDocuments(){ - $this->documents = []; - } - - public function setCallback($url, $custom = NULL,$callback_field = NULL){ - $callback = new \stdClass(); - $callback->callback_url = $url; - $callback->custom = $custom; - if($callback_field != NULL){ - $callback->callback_field = $callback_field; - } - $this->callback = $callback; - } - - public function getCallback(){ - return $this->callback; - } -} \ No newline at end of file diff --git a/src/classes/utility/UfficioPostale/Telegramma.php b/src/classes/utility/UfficioPostale/Telegramma.php deleted file mode 100644 index 1a86447..0000000 --- a/src/classes/utility/UfficioPostale/Telegramma.php +++ /dev/null @@ -1,148 +0,0 @@ -letter = NULL; - $this->ar_e = false; - $this->ar_c = false; - } - - function getNumeroLettere(){ - return $this->letter; - } - - function getNumeroParole(){ - return $this->parole; - } - function getNumeroPagine(){ - throw new \OpenApi\classes\exception\OpenApiUPException("Pages not exist for telagrammi",40015); - } - - - function confirm(){ - if($this->getId() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUPException("Id not present",40011); - } - if($this->getState() != "NEW"){ - throw new \OpenApi\classes\exception\OpenApiUPException("State is not NEW",40012); - } - $param['confirmed'] = TRUE; - $ret = call_user_func_array($this->connect,["telegrammi/".$this->getId(),"PATCH",$param]); - - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - } - - - function send(){ - try{ - $object = new \stdClass();; - $object->mittente = $this->sender->getObject(TRUE); - $object->destinatari = []; - foreach($this->getRecpients() as $r){ - $object->destinatari[] = $r->getObject(TRUE); - } - $object->documento =$this->documents; - $object->opzioni = new \stdClass(); - - $object->opzioni->ar_c = is_bool($this->ar_c)?$this->ar_c:$this->ar_c->getObject(TRUE); - - $object->opzioni->ar_e = $this->ar_e; - - if($this->getCallback() != NULL){ - $callback = $this->getCallback(); - foreach($callback as $k => $v){ - $object->opzioni->$k = $v; - } - } - $ret = call_user_func_array($this->connect,["telegrammi/","POST",$object]); - $this->pricing = $ret->data[0]->pricing; - $this->id = $ret->data[0]->id; - $this->confirmed = $ret->data[0]->confirmed; - $this->state = $ret->data[0]->state; - $this->letter = $ret->data[0]->documento_validato->size; - $this->parole = $ret->data[0]->documento_validato->parole; - $this->clearRecipients(); - $this->setRecipients($ret->data[0]->destinatari); - return true; - }catch(\OpenApi\classes\exception\OpenApiConnectionsException $e){ - $response = $e->getServerResponse(); - if(isset($response->data->wrong_fields) && isset($response->error)){ - $error_message = $this->getError($response->error, $response); - - $e2 = new \OpenApi\classes\exception\OpenApiUPFieldsException("Fields Error",40013); - $e2->setServerResponse($e->getServerResponse(), $e->getServerHeaderResponse(), $e->getServerRawResponse(), $e->getHttpCode()); - $e2->setErrorMessage($error_message); - $e2->setFields($response->data->wrong_fields); - throw $e2; - } - throw $e; - } - } - - function creaTelegrammaByData($data){ - if(isset($data->documento_validato) && is_object($data->documento_validato)){ - $this->valid_doc_pdf = $data->documento_validato->pdf; - $this->valid_doc_jpg = $data->documento_validato->jpg; - } - $this->pricing = $data->pricing; - $this->id = $data->id; - $this->confirmed = $data->confirmed; - $this->state = $data->state; - $this->letter = $data->documento_validato->size; - $this->parole = $data->documento_validato->parole; - $this->clearRecipients(); - $this->setRecipients($data->destinatari); - $this->setSender($data->mittente); - $this->ar_e = isset($data->opzioni->ar_e)?$data->opzioni->ar_e:FALSE; - $this->ar_c = isset($data->opzioni->ar_c)?$data->opzioni->ar_c:FALSE; - /* $this->colori = $data->opzioni->colori; - $this->fronteretro = $data->opzioni->fronteretro; - $this->ar = $data->opzioni->ar;*/ - $this->setCallback($data->opzioni->callback_url, $data->opzioni->custom); - if(isset($data->IDRichiesta)){ - $this->request_id = $data->IDRichiesta; - } - - } - - - function setRicevutaElettronica($ar_e){ - $this->ar_e = $ar_e; - } - - function getRicevutaElettronica(){ - return $this->ar_e; - } - - function setRicevutaCartacea($ar_c){ - if(is_bool(($ar_c))){ - $this->ar_c = $ar_c; - return TRUE; - }else{ - if($ar_c instanceof \OpenApi\classes\utility\UfficioPostale\Objects\Sender){ - $this->ar_c = $ar_c; - }else{ - $this->ar_c = new \OpenApi\classes\utility\UfficioPostale\Objects\Sender($ar_c); - } - if(!$this->ar_c->validate()){ - return FALSE; - } - return TRUE; - } - - } - - function getRicevutaCartacea(){ - return $this->ar_c; - } - -} \ No newline at end of file diff --git a/src/classes/utility/Uploader/Collection.php b/src/classes/utility/Uploader/Collection.php deleted file mode 100644 index 99bc039..0000000 --- a/src/classes/utility/Uploader/Collection.php +++ /dev/null @@ -1,344 +0,0 @@ -connect = $connect; - } - - function save($state = false){ - $state = (bool)$state; - if($this->getOutput() == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output format not setted",40017); - } - $this->state = $state; - $data['output_format'] = $this->getOutput(); - if($this->getOutputSize() != NULL){ - $data['output_size'] = $this->getOutputSize(); - } - if($this->outputGroup != NULL){ - $data['output_group'] = $this->outputGroup; - } - - - if($this->getInputTypes() != NULL){ - $data['input_types'] = $this->getInputTypes(); - } - if($this->getInputCount() != NULL){ - $data['input_count'] = $this->getInputCount(); - } - $data['public'] = $this->isPublic(); - if($this->getWaterMark() != NULL){ - $data['watermark'] = $this->getWaterMark(); - $data['watermark_position'] = $this->getWaterMarkPosition(); - } - if($this->getExpireTimestamp() != NULL){ - $data['expire_timestamp'] = $this->getExpireTimestamp(); - } - $data['state'] = $state; - if($this->id == null){ - - $ret = call_user_func_array ($this->connect,["collections","POST",$data]); - $this->id = $ret->id; - return $ret->id; - }else{ - - $ret = call_user_func_array ($this->connect,["collections/$this->id","PATCH",$data]); - $this->id = $ret->id; - return $ret->id; - } - } - - function parseData($data){ - - $this->setOutput($data->output_format); - $this->setOutputSize($data->output_size); - $this->setInputTypes($data->input_types); - $this->setInputCount($data->input_count); - $this->setPublic($data->public); - $this->setWaterMark($data->watermark); - $this->setWaterMarkPosition($data->watermark_position); - $this->setExpireTimestamp($data->expire_timestamp); - $this->email = $data->email; - $this->creation_timestamp = $data->creation_timestamp; - $this->update_timestamp = $data->update_timestamp; - $this->documents_count = $data->documents_count; - $this->documents_bytes = $data->documents_bytes; - $this->documents = $data->documents; - $this->state = $data->state; - $this->id = $data->_id->{'$oid'}; - - } - - function getState(){ - return $this->state; - } - - function getDocuments(){ - $this->documents; - } - - function getDocumentBytes(){ - $this->documents_bytes; - } - - function getDocumentCount(){ - $this->documents_count; - } - - function getUpdateTimestamp(){ - $this->update_timestamp; - } - - function getCreationTimestamp(){ - $this->creation_timestamp; - } - - function getEmail(){ - $this->email; - } - - function getId(){ - return $this->id; - } - function setOutput($output){ - if($output != "image/png" && $output != "image/jpeg" && $output != "application/pdf"){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output format not valid",40013); - } - if($output == "image/png" || $output == "image/jpeg") { - $this->outputGroup = false; - $this->cropSize = null; - } - $this->output = $output; - $this->checkOutputSize(); - } - - function getOutputSize(){ - return $this->outputSize; - } - - function getInputCount(){ - return $this->inputCount; - } - - function getWaterMark(){ - return $this->watermark; - } - - function setWaterMark($watermark){ - $this->watermark = $watermark; - } - - function getWaterMarkPosition(){ - return $this->watermarkPosition; - } - - - function setWaterMarkPosition($watermarkPosition){ - $this->watermarkPosition = $watermarkPosition; - } - - function setExpireTimestamp($expireTimestamp){ - if($expireTimestamp == NULL){ - $this->expireTimestamp = NULL; - return; - } - $this->expireTimestamp = (int)$expireTimestamp; - } - - function getExpireTimestamp(){ - return $this->expireTimestamp; - } - - function setInputCount($ic){ - if($ic == NULL){ - $this->inputCount = NULL; - return; - } - $this->inputCount = (int)$ic; - } - function setOutputGroup($outputGroup){ - if($outputGroup && ($this->output == "image/png" || $this->output == "image/jpeg")){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output group not valid",40015); - } - $this->outputGroup = $outputGroup; - } - - function getOutputGroup(){ - return $this->outputGroup; - } - - function setPublic($public = true){ - $this->public = $public; - } - - function setPrivate($private = TRUE){ - $this->public = !$private; - } - - function isPublic(){ - return $this->public; - } - - function isPrivate(){ - return !$this->public; - } - - function setInputTypes($types){ - if(!is_array($types)){ - $types = [$types]; - } - foreach($types as $t){ - if($t != "image/png" && $t != "image/jpeg" && $t != "application/pdf"){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Input type not valid",40016); - } - } - $this->inputTypes = $types; - } - - function getInputTypes(){ - return $this->inputTypes; - } - - function setOutputSize($outputSize){ - $this->outputSize = $outputSize; - $this->checkOutputSize(); - } - - private function checkOutputSize(){ - if($this->output == null || $this->outputSize == NULL){ - return TRUE; - } - if($this->output == "application/pdf"){ - if(!in_array($this->outputSize,$this->validPdfFormats)){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output size not valid",40014); - } - }else{ - if(!is_array($this->outputSize) || !isset($this->outputSize[0]) || !isset($this->outputSize[1]) || !is_int($this->outputSize[0]) || !is_int($this->outputSize[1])){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Output size not valid",40014); - } - } - } - - function setOutputJpeg(){ - $this->setOutput("image/jpeg"); - } - - function setOutputPng(){ - $this->setOutput("image/png"); - } - - function setOutputPdf(){ - $this->setOutput("application/pdf"); - } - - function getOutput(){ - return $this->output; - } - - function addDocument($name, $type,$file,$crop_size = null){ - if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); - } - - $data['name'] = $name; - $data['type'] = $type; - $data['file'] = $file; - $data['crop_size'] = $crop_size; - - $ret = call_user_func_array ($this->connect,["collections/$this->id","POST",$data]); - - $this->updateCollection(); - return $ret->id; - } - - function updateDocument($id_documento, $name = NULL,$type = NULL, $file = NULL, $crop_size = NULL){ - if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); - } - if($name != NULL){ - $data['name'] = $name; - } - if($type != NULL){ - $data['type'] = $type; - } - if($file != NULL){ - $data['file'] = $file; - } - if($crop_size != NULL){ - $data['crop_size'] = $crop_size; - } - - $ret = call_user_func_array ($this->connect,["collections/$this->id/$id_documento","PATCH",$data]); - - $this->updateCollection(); - return $ret->success; - } - - function deleteDocument($id_documento){ - if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); - } - - - $ret = call_user_func_array ($this->connect,["collections/$this->id/$id_documento","DELETE"]); - - $this->updateCollection(); - return $ret->success; - } - - private function updateCollection(){ - - $coll = call_user_func_array ($this->connect,["collections/$this->id","GET"]); - if(isset($coll->data)){ - $this->parseData($coll->data); - - } - } - - function getDocumento($id_documento){ - if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); - } - - - $ret = call_user_func_array ($this->connect,["collections/$this->id/$id_documento","GET"]); - - $this->updateCollection(); - return $ret; - } - - function getDocumenti(){ - if($this->id == NULL){ - throw new \OpenApi\classes\exception\OpenApiUploaderException("Impossible to add File",40019); - } - - - $ret = call_user_func_array ($this->connect,["collections/$this->id","GET"]); - - $this->updateCollection(); - return $ret; - } -} \ No newline at end of file diff --git a/src/classes/utility/VisEngine/VisRequest.php b/src/classes/utility/VisEngine/VisRequest.php deleted file mode 100644 index 47e9d2e..0000000 --- a/src/classes/utility/VisEngine/VisRequest.php +++ /dev/null @@ -1,434 +0,0 @@ - visengin",40008); - } - $this->visura = $visura; - $this->variables = []; - $this->new = TRUE; - $this->json = NULL; - $this->jsonValido = FALSE; - $this->state = 0; - $this->test = false; - $this->callback = NULL; - $this->email_target = NULL; - $this->id = NULL; - $this->statoRichiesta = NULL; - $this->ricerche = []; - $this->document = NULL; - $this->format_errror = []; - $this->opzioni = null; - foreach($visura->data->json_struttura->campi as $k => $v){ - $this->variables[$k] = FALSE; - } - } - - function setOpzioni($opzioni){ - $this->opzioni = $opzioni; - } - - function getOpzioni(){ - return $this->opzioni; - } - - function setNew(bool $new){ - return $this->new = $new; - } - - function getNew(){ - return $this->new; - } - /** - * - * Imposta il JSON per inviare una nuova visura - * - * @param array $data IL JSON della visura da inviare - * - * @return boolean Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono stati compilati (attenzione, viene effettuata la sola validazione sui required, per la validazione del formato occcorre inviare la visura) - */ - function setJson(array $data){ - foreach($data as $k => $v){ - if(!isset($this->variables[$k])){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); - } - $this->variables[$k] = $v!=NULL; - } - $this->json = $data; - - $this->validaJSON(); - return $this->jsonValido; - } - - - - - - /** - * - * Restituisce il JSON della visura - * - * @return object - */ - function getJson(){ - return $this->json; - } - - /** - * Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON - * @return boolean - */ - function isValidJson(){ - return $this->jsonValido; - } - - /** - * - * Imposta i dati della callback - * - * @param string $url La url da richiamare per la callback - * @param object $data Oggetto data che verrà ripassato - * @param string $method='JSON' Metodo da usare JSON/POST - * @param string $field="visengineData" Nome del campo dove verranno passati i dati della visura - * - * @return void - */ - function setCallbackData(string $url, object $data, $method = "JSON", $field="visengineData"){ - $this->callback = (object)[ - "url" => $url, - "data" => $data, - "method" => $method, - "field" => $field - ]; - } - - - /** - * Restituisce i dati della callback - * - * @return object - */ - function getCallbackData(){ - return $this->callback; - } - - /** - * Impowsta il parametro state della visura - * @param int $stato - * - * @return void - */ - function setState($stato = 0){ - if($stato != 0 && !$this->jsonValido ){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); - } - $this->state = $stato == 0 ? $stato : 1; - } - - /** - * Ritorna il parametro state - * @return int - */ - function getState(){ - return $this->state; - } - - /** - * Imposta il parametro email_target - * - * @param string $email_target - * - * @return void - */ - function setTargetEmail(string $email_target){ - $this->email_target = $email_target; - } - - /** - * Ritorna il parametro email_target - * @return string - */ - function getTargetEmail(){ - return $this->email_target; - } - - function hasSearchResult(){ - return $this->visura->data->ricerca == 1 && $this->getStatoRichiesta() == "In ricerca" && $this->getStatoRicerca() == "Ricerca evasa"; - } - - function getSearchResult(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return json_decode($this->ricerche[count($this->ricerche) - 1]->json_risultato); - } - function getSearchId(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return $this->ricerche[count($this->ricerche) - 1]->id_ricerca; - } - function getSearch(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return $this->ricerche[count($this->ricerche) - 1]; - } - - function getSearchCount(){ - return count($this->ricerche); - } - - function setDocument($document){ - $this->document = $document; - } - - function getDocument(){ - return $this->document; - } - - function getHash(){ - return $this->visura->data->hash_visura; - } - - - /** - * - * Imposta il parametro test - * - * @param bool $test - * - * @return void - */ - function setTest(bool $test){ - $this->test = $test; - } - - - /** - * Restituisce il parametro test - * @return bool - */ - function getTest(){ - return $this->test; - } - - - /** - * Controlla il JSON e ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON - * @return boolean - */ - private function validaJSON(){ - if(!$this->validaPresenzaCampi()){ - $this->format_errror = []; - $this->jsonValido = FALSE; - return; - } - $this->format_errror = []; - if(!$this->validaFormatoCampi()){ - $this->jsonValido = FALSE; - return; - } - $this->jsonValido = TRUE; - - } - - private function validaFormatoCampi(){ - $error = FALSE; -// var_dump($this->visura->data->json_struttura->campi);exit; - - //cod_comune - //cod_provincia - //codice_fiscale_persona_fisica - foreach($this->visura->data->json_struttura->campi as $key => $campo){ - if(!isset($this->json->$key) || $this->json->$key == ""){ - continue; - } - if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale_persona_fisica'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); - if(!$val->italianFiscalCode($this->json->$key)){ - $this->format_errror[$key] = 'codice_fiscale_persona_fisica'; - $error = TRUE; - } - } - - if(isset($campo->tipo) && $campo->tipo == 'partita_iva'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); - if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ - $this->format_errror[$key] = 'partita_iva'; - $error = TRUE; - } - } - - if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); - if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ - $this->format_errror[$key] = 'codice_fiscale'; - $error = TRUE; - } - } - if(isset($campo->tipo) && $campo->tipo == 'cod_comune'){ - $re = '/^[a-zA-Z]{1}[0-9]{3}$/m'; - - preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); - if(count($matches) == 0){ - $this->format_errror[$key] = 'cod_comune'; - $error = TRUE; - } - } - - if(isset($campo->tipo) && $campo->tipo == 'cod_provincia'){ - $re = '/^[a-zA-Z]{2}$/m'; - - preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); - if(count($matches) == 0){ - $this->format_errror[$key] = 'cod_provincia'; - $error = TRUE; - } - } - if(isset($campo->tipo) && $campo->tipo == 'data_iso8601'){ - $d = \DateTime::createFromFormat("d-m-Y", $this->json->$key); - - if(!($d && $d->format('d-m-Y') === $this->json->$key)){ - $this->format_errror[$key] = 'data_iso8601'; - $error = TRUE; - } - } - } - return !$error; - } - - private function validaPresenzaCampi(){ - $re = '/\$(\d)+/m'; - $validazione = $this->visura->data->json_struttura->validazione; - $subst = '$this->variables[\'$0\']'; - $valida = TRUE; - $validazione = '$valida = ' .preg_replace($re, $subst, $validazione).";"; - eval($validazione); - return $valida; - } - - public function getErrors(){ - if(count($this->format_errror) != 0){ - $ret['error_type'] = "format"; - $ret['error'] = $this->format_errror; - return $ret; - } - $this->expr = []; - $validazione = $this->visura->data->json_struttura->validazione; - - list($validazione, $expr) =$this->createExpression($validazione); - - //var_dump($validazione);exit; - $errori = $this->valida($validazione, $expr); - - $ret['error_type'] = "empty_fields"; - $ret['error'] = $errori; - return $ret; - - } - - private function valida($validazione,$expr, $errori = []){ - //var_dump($this->variables); - $errori = ["type"=>"and","list"=>[]]; - $and = explode('&&',$validazione); - foreach($and as $andItem){ - $andItem = trim($andItem); - $or = explode('||',$andItem); - if(count($or) == 1){ - $orItem = $or[0]; - if(substr($orItem,0,1)=='$'){ - if(!$this->variables[$orItem]){ - $errori['list'][] = $orItem; - } - }else{ - $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); - if(count($errors)){ - - $errori['list'] = array_merge($errori['list'], $errors['list']); - - } - } - }else{ - $errore = false; - $item = array(); - $hasError = true; - foreach($or as $orItem){ - $orItem = trim($orItem); - if(substr($orItem,0,1)=='$'){ - $item[] = $orItem; - if($this->variables[$orItem]){ - - $hasError = FALSE; - } - }else{ - $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); - if(count($errors['list'])){ - $item[] = $errors; - }else{ - $hasError = FALSE; - } - } - } - - if($hasError){ - $errori['list'][] = ["type"=>"or","list"=>$item]; - } - } - } - - return $errori; - } - - private function createExpression($validazione, $expr = []){ - $preg = "/\(([$\d&| e]*?)\)/"; - preg_match($preg, $validazione, $matches, PREG_OFFSET_CAPTURE, 0); - if(isset($matches[0]) && isset($matches[1])){ - $expr[] = $matches[1][0]; - $expn = count($expr)-1; - $validazione = str_replace($matches[0],"e{$expn}",$validazione); - return $this->createExpression($validazione, $expr); - } - return array($validazione, $expr); - - } - - function getId() { - return $this->id; - } - - function setId($id) { - $this->id = $id; - } - - function getStatoRichiesta() { - return $this->statoRichiesta; - } - - function setStatoRichiesta($statoRichiesta) { - $this->statoRichiesta = $statoRichiesta; - } - - function getRicerche() { - return $this->ricerche; - } - - function setRicerche($ricerche) { - $this->ricerche = $ricerche; - } - - function getStatoRicerca(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return $this->ricerche[count($this->ricerche) - 1]->stato_ricerca; - } - - function getValidation(){ - return $validazione = $this->visura->data->json_struttura->validazione;; - } -} \ No newline at end of file diff --git a/src/classes/utility/VisRequest.php b/src/classes/utility/VisRequest.php deleted file mode 100644 index 447219b..0000000 --- a/src/classes/utility/VisRequest.php +++ /dev/null @@ -1,434 +0,0 @@ - visengin",40008); - } - $this->visura = $visura; - $this->variables = []; - $this->new = TRUE; - $this->json = NULL; - $this->jsonValido = FALSE; - $this->state = 0; - $this->test = false; - $this->callback = NULL; - $this->email_target = NULL; - $this->id = NULL; - $this->statoRichiesta = NULL; - $this->ricerche = []; - $this->document = NULL; - $this->format_errror = []; - $this->opzioni = null; - foreach($visura->data->json_struttura->campi as $k => $v){ - $this->variables[$k] = FALSE; - } - } - - function setOpzioni($opzioni){ - $this->opzioni = $opzioni; - } - - function getOpzioni(){ - return $this->opzioni; - } - - function setNew(bool $new){ - return $this->new = $new; - } - - function getNew(){ - return $this->new; - } - /** - * - * Imposta il JSON per inviare una nuova visura - * - * @param array $data IL JSON della visura da inviare - * - * @return boolean Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono stati compilati (attenzione, viene effettuata la sola validazione sui required, per la validazione del formato occcorre inviare la visura) - */ - function setJson(object $data){ - foreach($data as $k => $v){ - if(!isset($this->variables[$k])){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("Visengine you are setting $k json key, but $k key is not presente for {$this->visura->data->nome_visura}",40006); - } - $this->variables[$k] = $v!=NULL; - } - $this->json = $data; - - $this->validaJSON(); - return $this->jsonValido; - } - - - - - - /** - * - * Restituisce il JSON della visura - * - * @return object - */ - function getJson(){ - return $this->json; - } - - /** - * Ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON - * @return boolean - */ - function isValidJson(){ - return $this->jsonValido; - } - - /** - * - * Imposta i dati della callback - * - * @param string $url La url da richiamare per la callback - * @param object $data Oggetto data che verrà ripassato - * @param string $method='JSON' Metodo da usare JSON/POST - * @param string $field="visengineData" Nome del campo dove verranno passati i dati della visura - * - * @return void - */ - function setCallbackData(string $url, object $data, $method = "JSON", $field="visengineData"){ - $this->callback = (object)[ - "url" => $url, - "data" => $data, - "method" => $method, - "field" => $field - ]; - } - - - /** - * Restituisce i dati della callback - * - * @return object - */ - function getCallbackData(){ - return $this->callback; - } - - /** - * Impowsta il parametro state della visura - * @param int $stato - * - * @return void - */ - function setState($stato = 0){ - if($stato != 0 && !$this->jsonValido ){ - throw new \OpenApi\classes\exception\OpenApiVisEngineException("JSON is not valid, so is not possible set state = 1",40007); - } - $this->state = $stato == 0 ? $stato : 1; - } - - /** - * Ritorna il parametro state - * @return int - */ - function getState(){ - return $this->state; - } - - /** - * Imposta il parametro email_target - * - * @param string $email_target - * - * @return void - */ - function setTargetEmail(string $email_target){ - $this->email_target = $email_target; - } - - /** - * Ritorna il parametro email_target - * @return string - */ - function getTargetEmail(){ - return $this->email_target; - } - - function hasSearchResult(){ - return $this->visura->data->ricerca == 1 && $this->getStatoRichiesta() == "In ricerca" && $this->getStatoRicerca() == "Ricerca evasa"; - } - - function getSearchResult(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return json_decode($this->ricerche[count($this->ricerche) - 1]->json_risultato); - } - function getSearchId(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return $this->ricerche[count($this->ricerche) - 1]->id_ricerca; - } - function getSearch(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return $this->ricerche[count($this->ricerche) - 1]; - } - - function getSearchCount(){ - return count($this->ricerche); - } - - function setDocument($document){ - $this->document = $document; - } - - function getDocument(){ - return $this->document; - } - - function getHash(){ - return $this->visura->data->hash_visura; - } - - - /** - * - * Imposta il parametro test - * - * @param bool $test - * - * @return void - */ - function setTest(bool $test){ - $this->test = $test; - } - - - /** - * Restituisce il parametro test - * @return bool - */ - function getTest(){ - return $this->test; - } - - - /** - * Controlla il JSON e ritorna TRUE nel caso in cui tutti i campi richiesti per la visura sono presenti all'interno del JSON - * @return boolean - */ - private function validaJSON(){ - if(!$this->validaPresenzaCampi()){ - $this->format_errror = []; - $this->jsonValido = FALSE; - return; - } - $this->format_errror = []; - if(!$this->validaFormatoCampi()){ - $this->jsonValido = FALSE; - return; - } - $this->jsonValido = TRUE; - - } - - private function validaFormatoCampi(){ - $error = FALSE; -// var_dump($this->visura->data->json_struttura->campi);exit; - - //cod_comune - //cod_provincia - //codice_fiscale_persona_fisica - foreach($this->visura->data->json_struttura->campi as $key => $campo){ - if(!isset($this->json->$key) || $this->json->$key == ""){ - continue; - } - if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale_persona_fisica'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); - if(!$val->italianFiscalCode($this->json->$key)){ - $this->format_errror[$key] = 'codice_fiscale_persona_fisica'; - $error = TRUE; - } - } - - if(isset($campo->tipo) && $campo->tipo == 'partita_iva'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); - if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ - $this->format_errror[$key] = 'partita_iva'; - $error = TRUE; - } - } - - if(isset($campo->tipo) && $campo->tipo == 'codice_fiscale'){ - $val = new \OpenApi\classes\utility\Plugins\Validations(); - if(!$val->italianFiscalCode($this->json->$key) && !$val->italianVat($this->json->$key)){ - $this->format_errror[$key] = 'codice_fiscale'; - $error = TRUE; - } - } - if(isset($campo->tipo) && $campo->tipo == 'cod_comune'){ - $re = '/^[a-zA-Z]{1}[0-9]{3}$/m'; - - preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); - if(count($matches) == 0){ - $this->format_errror[$key] = 'cod_comune'; - $error = TRUE; - } - } - - if(isset($campo->tipo) && $campo->tipo == 'cod_provincia'){ - $re = '/^[a-zA-Z]{2}$/m'; - - preg_match_all($re, $this->json->$key, $matches, PREG_SET_ORDER, 0); - if(count($matches) == 0){ - $this->format_errror[$key] = 'cod_provincia'; - $error = TRUE; - } - } - if(isset($campo->tipo) && $campo->tipo == 'data_iso8601'){ - $d = \DateTime::createFromFormat("d-m-Y", $this->json->$key); - - if(!($d && $d->format('d-m-Y') === $this->json->$key)){ - $this->format_errror[$key] = 'data_iso8601'; - $error = TRUE; - } - } - } - return !$error; - } - - private function validaPresenzaCampi(){ - $re = '/\$(\d)+/m'; - $validazione = $this->visura->data->json_struttura->validazione; - $subst = '$this->variables[\'$0\']'; - $valida = TRUE; - $validazione = '$valida = ' .preg_replace($re, $subst, $validazione).";"; - eval($validazione); - return $valida; - } - - public function getErrors(){ - if(count($this->format_errror) != 0){ - $ret['error_type'] = "format"; - $ret['error'] = $this->format_errror; - return $ret; - } - $this->expr = []; - $validazione = $this->visura->data->json_struttura->validazione; - - list($validazione, $expr) =$this->createExpression($validazione); - - //var_dump($validazione);exit; - $errori = $this->valida($validazione, $expr); - - $ret['error_type'] = "empty_fields"; - $ret['error'] = $errori; - return $ret; - - } - - private function valida($validazione,$expr, $errori = []){ - //var_dump($this->variables); - $errori = ["type"=>"and","list"=>[]]; - $and = explode('&&',$validazione); - foreach($and as $andItem){ - $andItem = trim($andItem); - $or = explode('||',$andItem); - if(count($or) == 1){ - $orItem = $or[0]; - if(substr($orItem,0,1)=='$'){ - if(!$this->variables[$orItem]){ - $errori['list'][] = $orItem; - } - }else{ - $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); - if(count($errors)){ - - $errori['list'] = array_merge($errori['list'], $errors['list']); - - } - } - }else{ - $errore = false; - $item = array(); - $hasError = true; - foreach($or as $orItem){ - $orItem = trim($orItem); - if(substr($orItem,0,1)=='$'){ - $item[] = $orItem; - if($this->variables[$orItem]){ - - $hasError = FALSE; - } - }else{ - $errors = $this->valida($expr[str_replace("e","",$orItem)], $expr); - if(count($errors['list'])){ - $item[] = $errors; - }else{ - $hasError = FALSE; - } - } - } - - if($hasError){ - $errori['list'][] = ["type"=>"or","list"=>$item]; - } - } - } - - return $errori; - } - - private function createExpression($validazione, $expr = []){ - $preg = "/\(([$\d&| e]*?)\)/"; - preg_match($preg, $validazione, $matches, PREG_OFFSET_CAPTURE, 0); - if(isset($matches[0]) && isset($matches[1])){ - $expr[] = $matches[1][0]; - $expn = count($expr)-1; - $validazione = str_replace($matches[0],"e{$expn}",$validazione); - return $this->createExpression($validazione, $expr); - } - return array($validazione, $expr); - - } - - function getId() { - return $this->id; - } - - function setId($id) { - $this->id = $id; - } - - function getStatoRichiesta() { - return $this->statoRichiesta; - } - - function setStatoRichiesta($statoRichiesta) { - $this->statoRichiesta = $statoRichiesta; - } - - function getRicerche() { - return $this->ricerche; - } - - function setRicerche($ricerche) { - $this->ricerche = $ricerche; - } - - function getStatoRicerca(){ - if(count($this->ricerche) == NULL){ - return FALSE; - } - return $this->ricerche[count($this->ricerche) - 1]->stato_ricerca; - } - - function getValidation(){ - return $validazione = $this->visura->data->json_struttura->validazione;; - } -} \ No newline at end of file diff --git a/src/classes/utility/ci4SessionStoreToken.php b/src/classes/utility/ci4SessionStoreToken.php deleted file mode 100644 index c01d873..0000000 --- a/src/classes/utility/ci4SessionStoreToken.php +++ /dev/null @@ -1,18 +0,0 @@ -set("openapi",$data); - } - - function clear(){ - session()->remove("openapi"); - } - - function isset(){ - return session()->has("openapi"); - } -} \ No newline at end of file diff --git a/src/classes/utility/sessionStoreToken.php b/src/classes/utility/sessionStoreToken.php deleted file mode 100644 index 066bbb9..0000000 --- a/src/classes/utility/sessionStoreToken.php +++ /dev/null @@ -1,19 +0,0 @@ -testToken); + $this->assertInstanceOf(Client::class, $client); + } + + public function testGetRequest(): void + { + $this->markTestSkipped('Requires valid token for integration test'); + + $client = new Client($this->testToken); + $params = [ + 'denominazione' => 'altravia', + 'provincia' => 'RM', + 'codice_ateco' => '6201' + ]; + + $result = $client->get('https://test.imprese.openapi.it/advance', $params); + $this->assertIsString($result); + } + + public function testPostRequest(): void + { + $this->markTestSkipped('Requires valid token for integration test'); + + $client = new Client($this->testToken); + $payload = [ + 'limit' => 10, + 'query' => [ + 'country_code' => 'IT' + ] + ]; + + $result = $client->post('https://test.postontarget.com/fields/country', $payload); + $this->assertIsString($result); + } + + public function testPutRequest(): void + { + $this->markTestSkipped('Requires valid token for integration test'); + + $client = new Client($this->testToken); + $payload = ['test' => 'data']; + + $result = $client->put('https://example.com/api', $payload); + $this->assertIsString($result); + } + + public function testDeleteRequest(): void + { + $this->markTestSkipped('Requires valid token for integration test'); + + $client = new Client($this->testToken); + + $result = $client->delete('https://example.com/api/123'); + $this->assertIsString($result); + } + + public function testPatchRequest(): void + { + $this->markTestSkipped('Requires valid token for integration test'); + + $client = new Client($this->testToken); + $payload = ['update' => 'data']; + + $result = $client->patch('https://example.com/api/123', $payload); + $this->assertIsString($result); + } +} \ No newline at end of file diff --git a/tests/ArrayCacheTest.php b/tests/ArrayCacheTest.php new file mode 100644 index 0000000..9e22756 --- /dev/null +++ b/tests/ArrayCacheTest.php @@ -0,0 +1,61 @@ +cache = new ArrayCache(); + } + + public function testCacheImplementation(): void + { + $key = 'test_key'; + $value = 'test_value'; + + // Test save and get + $this->assertTrue($this->cache->save($key, $value)); + $this->assertEquals($value, $this->cache->get($key)); + + // Test delete + $this->assertTrue($this->cache->delete($key)); + $this->assertNull($this->cache->get($key)); + } + + public function testCacheExpiry(): void + { + $key = 'expiry_test'; + $value = 'expiry_value'; + + // Save with 1 second TTL + $this->cache->save($key, $value, 1); + $this->assertEquals($value, $this->cache->get($key)); + + // Wait for expiry and test + sleep(2); + $this->assertNull($this->cache->get($key)); + } + + public function testCacheClear(): void + { + $this->cache->save('key1', 'value1'); + $this->cache->save('key2', 'value2'); + + $this->assertTrue($this->cache->clear()); + $this->assertNull($this->cache->get('key1')); + $this->assertNull($this->cache->get('key2')); + } + + public function testCacheWithComplexData(): void + { + $key = 'complex_key'; + $value = ['array' => 'data', 'number' => 42, 'nested' => ['key' => 'value']]; + + $this->cache->save($key, $value); + $this->assertEquals($value, $this->cache->get($key)); + } +} \ No newline at end of file diff --git a/tests/ClientTest.php b/tests/ClientTest.php deleted file mode 100644 index 44eb7d6..0000000 --- a/tests/ClientTest.php +++ /dev/null @@ -1,224 +0,0 @@ -dotenv = new Dotenv(); - $this->dotenv->load(__DIR__.'/../.env'); - - $this->username = $_ENV['OPENAPI_USERNAME']; - $this->api_key = $_ENV['API_KEY']; - - // Dichiaro gli scopes necessari - $this->scopes = [ - "GET:ws.ufficiopostale.com/raccomandate", - "GET:imprese.altravia.com/autocomplete", - "GET:imprese.altravia.com/base", - "GET:imprese.altravia.com/advance", - "GET:imprese.altravia.com/pec", - "GET:imprese.altravia.com/autocomplete", - "GET:imprese.altravia.com/closed", - "GET:imprese.altravia.com/gruppoiva", - "GET:comuni.openapi.it/cap", - "GET:comuni.openapi.it/istat", - "GET:comuni.openapi.it/province", - "GET:comuni.openapi.it/regioni", - "GET:comuni.openapi.it/catastale", - "GET:ws.ufficiopostale.com/tracking", - "POST:geocoding.realgest.it/geocode", - "POST:ws.messaggisms.com/messages", - "GET:ws.messaggisms.com/messages", - "PUT:ws.messaggisms.com/messages", - "GET:ws.firmadigitale.com/richiesta", - "POST:ws.firmadigitale.com/richiesta", - "GET:ws.marchetemporali.com/availability", - "GET:ws.marchetemporali.com/marche", - "POST:ws.marchetemporali.com/check_lotto", - "GET:visengine2.altravia.com/fornitori", - "GET:ws.leicode.info/lei-records", - "POST:ws.leicode.info/create-lei", - "POST:ws.leicode.info/renew-lei", - "DELETE:visengine2.altravia.com/richiesta", - "GET:visengine2.altravia.com/visure", - "POST:visengine2.altravia.com/richiesta", - "PUT:visengine2.altravia.com/richiesta", - "GET:visengine2.altravia.com/richiesta", - "GET:visengine2.altravia.com/documento", - "POST:ws.marchetemporali.com/marca", - "POST:ws.marchetemporali.com/verifica", - "POST:ws.marchetemporali.com/analisi", - ]; - - $this->openapi = new OpenApi($this->scopes, $this->username, $this->api_key, 'test'); - } - - - public function testClientInstance() { - $this->assertInstanceOf('OpenApi\OpenApi', $this->openapi); - } - - // public function testComuni() { - // // Prendi informazioni sul cap 00132 - // $cap = $this->openapi->comuni->getCitiesByCap('00132'); - // $comune = $this->openapi->comuni->getComuneByCatasto('117'); - // $comuni = $this->openapi->comuni->getComuni('RM'); - // $regioni = $this->openapi->comuni->getRegioni(); - // $provincie = $this->openapi->comuni->getProvince(); - - // $this->assertIsArray($cap); - // $this->assertIsArray($comune); - // $this->assertIsArray($comuni); - // $this->assertIsArray($regioni); - // $this->assertIsArray($provincie); - - // var_dump($comuni[0]->nome); - // } - - // public function testImprese() { - // $impresa = $this->openapi->imprese->getByPartitaIva('00966950230'); - // $autocomplete = $this->openapi->imprese->getBySearch('Altrav*', 'RM'); - // $closed = $this->openapi->imprese->getClosed('00966950230'); - // $vat = $this->openapi->imprese->getVatGroup('00966950230'); - // $Pec = $this->openapi->imprese->getPec('00966950230'); - - // $this->assertEquals($impresa->provincia, 'RM'); - // $this->assertIsArray($autocomplete); - // var_dump($autocomplete); - // $this->assertIsBool($closed->cessata); - // $this->assertIsObject($vat); - // $this->assertIsObject($Pec); - // } - - // public function testMarche() { - // $marca = $this->openapi->marcheTemporali->availability('infocert', 1); - // $comprata = $this->openapi->marcheTemporali->purcahse('infocert', 1); - - // $this->assertIsInt($marca->availability); - // } - - // public function testGeocoding() { - // // Prendi informazioni sul cap 00132 - // $cap = $this->openapi->geocoding->geocode('Via Cristoforo Colombo, Roma RM'); - // $this->assertIsArray($cap); - // } - - // public function testUfficioPostale() { - // $track = $this->openapi->ufficiopostale->track($_ENV['TRACK_TEST']); - // $this->assertEquals(true, $track->success); - // var_dump($track); - - // $raccomandata = $this->openapi->ufficiopostale->createRaccomandata(); - // var_dump($raccomandata); - - // $data = new stdClass(); - // $sender = new Sender([ - // 'firstName' => 'John', - // 'secondName' => 'Doe', - // 'companyName' => 'example-spa', - // ]); - - // $recipient = new Recipient([ - // 'firstName' => 'John', - // 'secondName' => 'Doe', - // 'companyName' => 'example-spa', - // ]); - - // $data->sender = $sender; - // $data->recipient = $recipient; - - // $raccomandata->creaRaccomandataByData($data); - // } - - // public function testSms() { - // $recipients = [ - // [ - // 'number' => '+39-3939989741', - // 'fields' => ['nome' => 'NomeDestinatario'] - // ] - // ]; - // $singleSms = $this->openapi->SMS->sendOne('test', '+39-3939989741', 'prova', null, 1, null, true); - - // $message = $this->openapi->SMS->getMessage($singleSms->data->id); - - // $this->assertEquals(true, $singleSms->success); - // $this->assertEquals(true, $message['success']); - // } - - public function testVisura() { - $this->openapi->visengine->setHash('eccbc87e4b5ce2fe28308fd9f2a7baf3'); - $visura = $this->openapi->visengine->createRequest(); - var_dump($visura); - - $response = $this->openapi->visengine->getRequestByIdVisura('eccbc87e4b5ce2fe28308fd9f2a7baf3'); - $this->assertNotEmpty($response); - // var_dump($response); - } - - // public function testFirmaDigitale() { - // $data = json_decode(file_get_contents(__DIR__.'/esempio_firma.json'), true); - // $data['codice_prodotto'] = 'FIR'; - // $response = $this->openapi->firmaDigitale->requestProduct($data); - // $this->assertNotEmpty($response); - // } - // public function testcreaVisura() { - - // $this->openapi->visengine->setHash($visura->hash); - // $request = $this->openapi->visengine->createRequest(); - // $res = $request->setJson((object)$json); - // if($request->isValidJson() && !$visura->show_form){ - // $request->setState(1); - // $request->setCallbackData(site_url("callbacks/ordini/visure"),(object)["order_id"=>"".$order_id, "detail_key"=>$detail_key]); - // $request = $this->openapi->visengine->sendRequest($request); - // } - // } - - // public function callbackVisura(Request $data) { - // $data =json_decode(file_get_contents('php://input')); - // $request = $this->openapi->visengine->getRequestByData($data); - // $ret['id'] = $request->getId(); - // $ret['stato'] = $request->getStatoRichiesta(); - // $ret['stato_ricerca'] = $request->getStatoRicerca(); - // if($request->hasSearchResult()){ - // $ret['ricerche'] = $request->getSearchResult(); - // $ret['search_count'] = $request->getSearchCount(); - // $ret['has_search_result'] = TRUE; - // $ret['search_id'] = $request->getSearchId(); - // }else{ - // if($request->getStatoRichiesta() == "Dati disponibili" || $request->getStatoRichiesta() == "Visura evasa"){ - // $document = $this->openapi->visengine->getDocument($id_visura)->getDocument(); - // if($document != NULL && $document->file != ""){ - // $has_document = TRUE; - // //salviamo il file - // file_put_contents("writable/documenti/{$id_visura}.bin", $document->file); - // } - // } - // } - // } - - public function testcreaVisura() { - - $this->openapi->visengine->setHash('8f14e45fceea167a5a36dedd4bea2543'); - $request = $this->openapi->visengine->createRequest(); - $request->setState(1); - $request->setCallbackData('https://example.com', new stdClass(), 'POST'); - $request->setJson(['$0' => 'abcd', '$1' => '12485671007']); - $visura = $this->openapi->visengine->sendRequest($request); - - } -} \ No newline at end of file diff --git a/tests/ExceptionTest.php b/tests/ExceptionTest.php new file mode 100644 index 0000000..daa4438 --- /dev/null +++ b/tests/ExceptionTest.php @@ -0,0 +1,35 @@ +assertEquals($message, $exception->getMessage()); + $this->assertEquals($code, $exception->getCode()); + } + + public function testSetServerResponse(): void + { + $exception = new Exception('Test message'); + + $response = ['error' => 'Server error']; + $headers = 'Content-Type: application/json'; + $rawResponse = '{"error":"Server error"}'; + $httpCode = 500; + + $exception->setServerResponse($response, $headers, $rawResponse, $httpCode); + + $this->assertEquals($response, $exception->getServerResponse()); + $this->assertEquals($headers, $exception->getHeaders()); + $this->assertEquals($rawResponse, $exception->getRawResponse()); + $this->assertEquals($httpCode, $exception->getHttpCode()); + } +} \ No newline at end of file diff --git a/tests/OauthClientTest.php b/tests/OauthClientTest.php new file mode 100644 index 0000000..4488619 --- /dev/null +++ b/tests/OauthClientTest.php @@ -0,0 +1,39 @@ +username, $this->apikey, true); + $this->assertInstanceOf(OauthClient::class, $client); + } + + public function testOauthClientProductionMode(): void + { + $client = new OauthClient($this->username, $this->apikey, false); + $this->assertInstanceOf(OauthClient::class, $client); + } + + public function testCreateTokenWithScopes(): void + { + $this->markTestSkipped('Requires valid credentials for integration test'); + + $client = new OauthClient($this->username, $this->apikey, true); + $scopes = [ + 'GET:test.imprese.openapi.it/advance', + 'POST:test.postontarget.com/fields/country' + ]; + + $result = $client->createToken($scopes, 3600); + $this->assertIsString($result); + + $data = json_decode($result, true); + $this->assertIsArray($data); + } +} \ No newline at end of file From c34d57dcd55125d67a3991b32e88cf15def71f24 Mon Sep 17 00:00:00 2001 From: francesco Date: Sat, 8 Nov 2025 10:03:05 +0100 Subject: [PATCH 62/85] review with cloud --- CLAUDE.md | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..b2e5f0c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,80 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Development Commands + +### Testing +```bash +# Run PHPUnit tests +./vendor/bin/phpunit tests/ + +# Run specific test file +./vendor/bin/phpunit tests/ApiClientTest.php + +# Note: Most integration tests are skipped by default as they require valid API tokens +``` + +### Dependencies +```bash +# Install Composer dependencies +composer install + +# Install dev dependencies +composer install --dev +``` + +### Git Workflow +```bash +# Quick development push (defined in Makefile) +make dev-push +``` + +## Architecture Overview + +This is a minimal, agnostic PHP SDK for OpenAPI services with only essential HTTP primitives. The architecture follows a clean, simple design inspired by the Rust implementation found in `reference/openapi-rust-sdk/`. + +### Core Components + +- **`OauthClient`** (`src/OauthClient.php`): Handles OAuth authentication and token management + - Uses Basic Auth with username/apikey for authentication + - Supports both production (`oauth.openapi.it`) and test (`test.oauth.openapi.it`) environments + - Methods: `getScopes()`, `createToken()`, `getTokens()`, `deleteToken()`, `getCounters()` + +- **`Client`** (`src/Client.php`): Agnostic HTTP client for making API calls + - Uses Bearer token authentication + - Supports GET, POST, PUT, DELETE, PATCH methods + - Handles URL parameter encoding for GET requests + - JSON payload encoding for POST/PUT/PATCH requests + - 30-second timeout for all requests + +- **`Exception`** (`src/Exception.php`): Custom exception handling for HTTP and cURL errors + +- **Cache System** (`src/Cache/`): Optional caching interface with array-based implementation + - `CacheInterface`: Contract for cache implementations + - `ArrayCache`: In-memory cache implementation + +### Key Design Principles + +1. **Agnostic**: No API-specific classes - works with any OpenAPI service +2. **Minimal**: Only core HTTP primitives, minimal dependencies (PHP 8.0+, cURL, JSON) +3. **Clean Interface**: Simple method signatures following REST conventions +4. **Environment Flexibility**: Built-in test/production environment switching + +### Examples Usage Patterns + +The `examples/` directory contains practical usage demonstrations: +- Token generation with OAuth client +- API calls with different HTTP methods +- Complete workflow integration + +### PSR-4 Autoloading + +The project uses PSR-4 autoloading with `OpenApi\` namespace mapped to `src/` directory. + +## Requirements + +- PHP 8.0+ +- cURL extension +- JSON extension +- PHPUnit 9.5+ for testing \ No newline at end of file From 5027f0a3dcafb2707c0954400d18a44d6ef6af98 Mon Sep 17 00:00:00 2001 From: francesco Date: Sat, 8 Nov 2025 10:13:00 +0100 Subject: [PATCH 63/85] minor fix --- .github/pull_request_template.md | 48 ++++++++++++++++++++++++++++++++ CLAUDE.md | 4 +++ 2 files changed, 52 insertions(+) create mode 100644 .github/pull_request_template.md diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..3eed199 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,48 @@ +## 📋 Description + +Brief description of the changes made in this PR. + +## ✨ Type of Change + +- [ ] 🐛 Bug fix (fixes an issue) +- [ ] ✨ New feature (adds functionality) +- [ ] 🔧 Refactoring (code restructuring without functional changes) +- [ ] 📚 Documentation (updates to documentation) +- [ ] 🧪 Tests (adding or modifying tests) +- [ ] 🔒 Security (security-related fixes) +- [ ] ⚡ Performance (performance improvements) +- [ ] 🎨 Style (formatting changes, no logic changes) + +## 🔍 Main Changes + +- +- +- + +## 🧪 Testing + +- [ ] I have tested the changes locally +- [ ] I have added/updated unit tests +- [ ] All tests pass (`./vendor/bin/phpunit`) +- [ ] I have verified PHP 8.0+ compatibility + +## 📝 Additional Notes + +Any additional information, considerations, or important context for reviewers. + +## 🔗 Related Issue + +Closes #[issue_number] (if applicable) + +## 📸 Screenshots (if applicable) + +If changes affect the interface or visible behavior, include screenshots. + +## ✅ Checklist + +- [ ] My code follows the project conventions +- [ ] I have performed a self-review of my code +- [ ] I have commented complex code where necessary +- [ ] Documentation has been updated (if needed) +- [ ] I have not introduced breaking changes (or documented them) +- [ ] I have verified no sensitive information is in the code \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index b2e5f0c..7853ab4 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,6 +2,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +## Language Policy + +**IMPORTANT:** The primary language for this codebase is English. All code, comments, documentation, commit messages, PR descriptions, and communications should be in English. + ## Development Commands ### Testing From f0e38286f327477ca3c4280749d05f72ea02e262 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 9 Nov 2025 15:03:56 +0000 Subject: [PATCH 64/85] Add minimal English comments and TODOs for error message improvements - Added class-level and method-level documentation to all files in src/ - Introduced TODO comments for graceful error message improvements in Client and OauthClient - Added TODO in Exception class to utilize setServerResponse method for structured error context - All comments follow PHPDoc standards and are concise - Error TODOs suggest specific improvements: connection context, structured error details, and auth-specific hints --- src/Cache/ArrayCache.php | 24 +++++++++++++-- src/Cache/CacheInterface.php | 22 ++++++++++++++ src/Client.php | 42 ++++++++++++++++++++++++-- src/Exception.php | 25 ++++++++++++++++ src/OauthClient.php | 58 ++++++++++++++++++++++++++++++++---- 5 files changed, 160 insertions(+), 11 deletions(-) diff --git a/src/Cache/ArrayCache.php b/src/Cache/ArrayCache.php index 43f5486..c52170e 100644 --- a/src/Cache/ArrayCache.php +++ b/src/Cache/ArrayCache.php @@ -2,17 +2,26 @@ namespace OpenApi\Cache; +/** + * In-memory cache implementation + * Data is stored in PHP arrays and cleared at end of script execution + */ class ArrayCache implements CacheInterface { private array $cache = []; private array $expiry = []; + /** + * Retrieve value from cache + * Returns null if key doesn't exist or has expired + */ public function get(string $key): mixed { if (!isset($this->cache[$key])) { return null; } + // Check if expired if (isset($this->expiry[$key]) && time() > $this->expiry[$key]) { $this->delete($key); return null; @@ -21,26 +30,35 @@ public function get(string $key): mixed return $this->cache[$key]; } + /** + * Save value to cache with expiration + */ public function save(string $key, mixed $value, int $ttl = 3600): bool { $this->cache[$key] = $value; $this->expiry[$key] = time() + $ttl; - + return true; } + /** + * Delete value from cache + */ public function delete(string $key): bool { unset($this->cache[$key], $this->expiry[$key]); - + return true; } + /** + * Clear all cached values + */ public function clear(): bool { $this->cache = []; $this->expiry = []; - + return true; } } \ No newline at end of file diff --git a/src/Cache/CacheInterface.php b/src/Cache/CacheInterface.php index e9c253f..e1172d6 100644 --- a/src/Cache/CacheInterface.php +++ b/src/Cache/CacheInterface.php @@ -2,10 +2,32 @@ namespace OpenApi\Cache; +/** + * Cache interface for SDK implementations + */ interface CacheInterface { + /** + * Retrieve value from cache + */ public function get(string $key): mixed; + + /** + * Save value to cache with TTL + * + * @param string $key Cache key + * @param mixed $value Value to store + * @param int $ttl Time-to-live in seconds (default: 3600) + */ public function save(string $key, mixed $value, int $ttl = 3600): bool; + + /** + * Delete value from cache + */ public function delete(string $key): bool; + + /** + * Clear all cached values + */ public function clear(): bool; } \ No newline at end of file diff --git a/src/Client.php b/src/Client.php index c3edf21..6f7a80f 100644 --- a/src/Client.php +++ b/src/Client.php @@ -2,23 +2,40 @@ namespace OpenApi; -class Client +/** + * Generic HTTP client for OpenAPI services + * Handles REST operations with Bearer token authentication + */ +class Client { private string $token; + /** + * Initialize client with Bearer token + */ public function __construct(string $token) { $this->token = $token; } + /** + * Execute HTTP request + * + * @param string $method HTTP method (GET, POST, PUT, DELETE, PATCH) + * @param string $url Target URL + * @param mixed $payload Request body (for POST/PUT/PATCH) + * @param array|null $params Query parameters (for GET) or form data (for other methods) + * @return string Response body + */ public function request(string $method, string $url, mixed $payload = null, ?array $params = null): string { + // Append query parameters for GET requests if ($params && $method === 'GET') { $url .= '?' . http_build_query($params); } $ch = curl_init(); - + curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, @@ -30,12 +47,14 @@ public function request(string $method, string $url, mixed $payload = null, ?arr ] ]); + // Add JSON payload for POST/PUT/PATCH requests if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'])) { curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); } + // Add form data for non-GET requests if ($params && $method !== 'GET') { - curl_setopt($ch, CURLOPT_POSTFIELDS, + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($params) ? $params : http_build_query($params)); } @@ -44,10 +63,12 @@ public function request(string $method, string $url, mixed $payload = null, ?arr $error = curl_error($ch); curl_close($ch); + // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) if ($response === false) { throw new Exception("cURL Error: " . $error); } + // TODO: Parse response body and provide structured error details (error code, message, request ID) if ($httpCode >= 400) { throw new Exception("HTTP Error {$httpCode}: " . $response); } @@ -55,26 +76,41 @@ public function request(string $method, string $url, mixed $payload = null, ?arr return $response; } + /** + * Perform GET request + */ public function get(string $url, ?array $params = null): string { return $this->request('GET', $url, null, $params); } + /** + * Perform POST request + */ public function post(string $url, mixed $payload = null): string { return $this->request('POST', $url, $payload); } + /** + * Perform PUT request + */ public function put(string $url, mixed $payload = null): string { return $this->request('PUT', $url, $payload); } + /** + * Perform DELETE request + */ public function delete(string $url): string { return $this->request('DELETE', $url); } + /** + * Perform PATCH request + */ public function patch(string $url, mixed $payload = null): string { return $this->request('PATCH', $url, $payload); diff --git a/src/Exception.php b/src/Exception.php index e154439..74650d1 100644 --- a/src/Exception.php +++ b/src/Exception.php @@ -2,6 +2,10 @@ namespace OpenApi; +/** + * Custom exception for OpenAPI SDK + * Stores HTTP response details for better error handling + */ class Exception extends \Exception { private mixed $serverResponse = null; @@ -9,6 +13,15 @@ class Exception extends \Exception private mixed $rawResponse = null; private ?int $httpCode = null; + /** + * Store server response details + * TODO: Utilize this method in Client and OauthClient to provide structured error context + * + * @param mixed $response Parsed server response + * @param mixed $headers Response headers + * @param mixed $rawResponse Raw response body + * @param int|null $httpCode HTTP status code + */ public function setServerResponse(mixed $response, mixed $headers = null, mixed $rawResponse = null, ?int $httpCode = null): void { $this->serverResponse = $response; @@ -17,21 +30,33 @@ public function setServerResponse(mixed $response, mixed $headers = null, mixed $this->httpCode = $httpCode; } + /** + * Get parsed server response + */ public function getServerResponse(): mixed { return $this->serverResponse; } + /** + * Get response headers + */ public function getHeaders(): mixed { return $this->headers; } + /** + * Get raw response body + */ public function getRawResponse(): mixed { return $this->rawResponse; } + /** + * Get HTTP status code + */ public function getHttpCode(): ?int { return $this->httpCode; diff --git a/src/OauthClient.php b/src/OauthClient.php index 24ae031..387a9c1 100644 --- a/src/OauthClient.php +++ b/src/OauthClient.php @@ -2,7 +2,11 @@ namespace OpenApi; -class OauthClient +/** + * OAuth client for OpenAPI authentication + * Handles token management using Basic Auth (username:apikey) + */ +class OauthClient { private string $url; private string $username; @@ -11,6 +15,13 @@ class OauthClient const OAUTH_BASE_URL = 'https://oauth.openapi.it'; const TEST_OAUTH_BASE_URL = 'https://test.oauth.openapi.it'; + /** + * Initialize OAuth client + * + * @param string $username API username + * @param string $apikey API key + * @param bool $test Use test environment if true + */ public function __construct(string $username, string $apikey, bool $test = false) { $this->username = $username; @@ -18,46 +29,81 @@ public function __construct(string $username, string $apikey, bool $test = false $this->url = $test ? self::TEST_OAUTH_BASE_URL : self::OAUTH_BASE_URL; } + /** + * Retrieve available scopes + * + * @param bool $limit Limit results if true + * @return string JSON response with scopes + */ public function getScopes(bool $limit = false): string { $params = ['limit' => $limit ? 1 : 0]; $url = $this->url . '/scopes?' . http_build_query($params); - + return $this->request('GET', $url); } + /** + * Create new access token + * + * @param array $scopes List of requested scopes + * @param int $ttl Token time-to-live in seconds (default: 3600) + * @return string JSON response with token details + */ public function createToken(array $scopes, int $ttl = 3600): string { $body = [ 'scopes' => $scopes, 'ttl' => $ttl ]; - + return $this->request('POST', $this->url . '/token', $body); } + /** + * Get tokens for specific scope + * + * @param string $scope Scope filter + * @return string JSON response with matching tokens + */ public function getTokens(string $scope): string { $params = ['scope' => $scope]; $url = $this->url . '/token?' . http_build_query($params); - + return $this->request('GET', $url); } + /** + * Delete token by ID + * + * @param string $id Token ID to delete + * @return string JSON response + */ public function deleteToken(string $id): string { return $this->request('DELETE', $this->url . '/token/' . $id); } + /** + * Get usage counters + * + * @param string $period Time period (e.g., 'daily', 'monthly') + * @param string $date Date in format YYYY-MM-DD + * @return string JSON response with counter data + */ public function getCounters(string $period, string $date): string { return $this->request('GET', $this->url . '/counters/' . $period . '/' . $date); } + /** + * Execute HTTP request with Basic Auth + */ private function request(string $method, string $url, array $body = null): string { $ch = curl_init(); - + curl_setopt_array($ch, [ CURLOPT_URL => $url, CURLOPT_RETURNTRANSFER => true, @@ -78,10 +124,12 @@ private function request(string $method, string $url, array $body = null): strin $error = curl_error($ch); curl_close($ch); + // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) if ($response === false) { throw new Exception("cURL Error: " . $error); } + // TODO: Parse response body and provide structured error details with auth-specific hints (invalid credentials, expired key, etc.) if ($httpCode >= 400) { throw new Exception("HTTP Error {$httpCode}: " . $response); } From 604bf98cc6952be852256a8552cc7c571f7ec48e Mon Sep 17 00:00:00 2001 From: francesco Date: Sun, 9 Nov 2025 16:25:37 +0100 Subject: [PATCH 65/85] chore: init quality maintenance --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3862610..53a4a92 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,14 @@ Openapi SDK for PHP -

Openapi® client for Rust

-

The perfect starting point to integrate Openapi® within your Rust project

+

Openapi® client for PHP

+

The perfect starting point to integrate Openapi® within your PHP project

-[![Build Status](https://img.shields.io/github/actions/workflow/status///rust.yml?branch=main)](https://github.com///actions) +[![Build Status](https://img.shields.io/github/actions/workflow/status///php.yml?branch=main)](https://github.com///actions) [![Crates.io](https://img.shields.io/crates/v/.svg)](https://crates.io/crates/) [![Docs.rs](https://img.shields.io/docsrs/)](https://docs.rs/) [![License](https://img.shields.io/github/license//)](LICENSE) -[![Rust Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) +[![PHP Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) # Openapi Library From 806dcbce9249162c6561d727557f126b488bc364 Mon Sep 17 00:00:00 2001 From: francesco Date: Sun, 9 Nov 2025 16:34:29 +0100 Subject: [PATCH 66/85] fix readme --- README.md | 99 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 96 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 19b810f..38be1cd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,25 @@ -# OpenAPI PHP SDK +
+ + Openapi SDK for PHP + -A minimal and agnostic PHP SDK for OpenAPI, inspired by the Rust implementation. This SDK provides only the core HTTP primitives needed to interact with any OpenAPI service. +

Openapi® client for PHP

+

The perfect starting point to integrate Openapi® within your PHP project

+ + [![Build Status](https://img.shields.io/github/actions/workflow/status///rust.yml?branch=main)](https://github.com///actions) + [![Crates.io](https://img.shields.io/crates/v/.svg)](https://crates.io/crates/) + [![Docs.rs](https://img.shields.io/docsrs/)](https://docs.rs/) + [![License](https://img.shields.io/github/license//)](LICENSE) + [![Rust Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) +
+ +## Overview + +A minimal and agnostic PHP SDK for Openapi, inspired by a clean client implementation. This SDK provides only the core HTTP primitives needed to interact with any Openapi service. + +## Pre-requisites + +Before using the Openapi Rust Client, you will need an account at [Openapi](https://console.openapi.com/) and an API key to the sandbox and/or production environment ## Features @@ -10,6 +29,18 @@ A minimal and agnostic PHP SDK for OpenAPI, inspired by the Rust implementation. - **HTTP Primitives**: GET, POST, PUT, DELETE, PATCH methods - **Clean Interface**: Similar to the Rust SDK design +## What you can do + +With the Openapi Rust Client, you can easily interact with a variety of services in the Openapi Marketplace. For example, you can: + +- 📩 **Send SMS messages** with delivery reports and custom sender IDs +- 💸 **Process bills and payments** in real time via API +- 🧾 **Send electronic invoices** securely to the Italian Revenue Agency +- 📄 **Generate PDFs** from HTML content, including JavaScript rendering +- ✉️ **Manage certified emails** and legal communications via Italian Legalmail + +For a complete list of all available services, check out the [Openapi Marketplace](https://console.openapi.com/) 🌐 + ## Installation ```bash @@ -69,4 +100,66 @@ This SDK follows a minimal approach with only essential components: - PHP 8.0 or higher - cURL extension -- JSON extension \ No newline at end of file +- JSON extension + +## Examples + +You can find complete examples in the `examples/` directory: + +- `examples/token_generation.rs` - Token generation example +- `examples/api_calls.rs` - API calls example + +Run examples with: + +```bash +cargo run --example token_generation +cargo run --example api_calls +``` + +## Testing + +Run tests with: + +```bash +cargo test +``` + + +## Contributing + +Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. + +See [docs/contributing.md](docs/contributing.md) for detailed instructions on how to get started. Please make sure to follow this project's [docs/code-of-conduct.md](docs/code-of-conduct.md) to help maintain a welcoming and collaborative environment. + +## Authors + +Meet the project authors: + +- L. Paderi ([@lpaderiAltravia](https://www.github.com/lpaderiAltravia)) +- Openapi Team ([@openapi-it](https://github.com/openapi-it)) + +## Partners + +Meet our partners using Openapi or contributing to this SDK: + +- [Blank](https://www.blank.app/) +- [Credit Safe](https://www.creditsafe.com/) +- [Deliveroo](https://deliveroo.it/) +- [Gruppo MOL](https://molgroupitaly.it/it/) +- [Jakala](https://www.jakala.com/) +- [Octotelematics](https://www.octotelematics.com/) +- [OTOQI](https://otoqi.com/) +- [PWC](https://www.pwc.com/) +- [QOMODO S.R.L.](https://www.qomodo.me/) +- [SOUNDREEF S.P.A.](https://www.soundreef.com/) + +## License + +This project is licensed under the [MIT License](LICENSE). + +The MIT License is a permissive open-source license that allows you to freely use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the software, provided that the original copyright notice and this permission notice are included in all copies or substantial portions of the software. + +In short, you are free to use this SDK in your personal, academic, or commercial projects, with minimal restrictions. The project is provided "as-is", without any warranty of any kind, either expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. + +For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). + From 2bfceb372facd9e20ab6fad51170479d0d06d1d3 Mon Sep 17 00:00:00 2001 From: francesco Date: Sun, 9 Nov 2025 16:39:14 +0100 Subject: [PATCH 67/85] fix readme badges and credits --- README.md | 26 ++++++++++++++++---------- composer.json | 7 +++++++ 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 38be1cd..3edf9eb 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,11 @@

Openapi® client for PHP

The perfect starting point to integrate Openapi® within your PHP project

- [![Build Status](https://img.shields.io/github/actions/workflow/status///rust.yml?branch=main)](https://github.com///actions) - [![Crates.io](https://img.shields.io/crates/v/.svg)](https://crates.io/crates/) - [![Docs.rs](https://img.shields.io/docsrs/)](https://docs.rs/) - [![License](https://img.shields.io/github/license//)](LICENSE) - [![Rust Version](https://img.shields.io/badge/rust-1.80+-orange.svg)](https://www.rust-lang.org/) + [![Build Status](https://img.shields.io/github/actions/workflow/status/openapi/openapi-php-sdk/ci.yml?branch=main)](https://github.com/openapi/openapi-php-sdk/actions) + [![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) + [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) + [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk)](LICENSE) + [![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) ## Overview @@ -106,14 +106,16 @@ This SDK follows a minimal approach with only essential components: You can find complete examples in the `examples/` directory: -- `examples/token_generation.rs` - Token generation example -- `examples/api_calls.rs` - API calls example +- `examples/token_generation.php` - OAuth token generation example +- `examples/api_calls.php` - HTTP API calls example +- `examples/complete_workflow.php` - End-to-end workflow example Run examples with: ```bash -cargo run --example token_generation -cargo run --example api_calls +composer run example:token +composer run example:api +composer run example:complete ``` ## Testing @@ -121,7 +123,11 @@ cargo run --example api_calls Run tests with: ```bash -cargo test +# Run all tests +composer run test + +# Run unit tests specifically +composer run test:unit ``` diff --git a/composer.json b/composer.json index bd8840a..d8399bf 100644 --- a/composer.json +++ b/composer.json @@ -21,5 +21,12 @@ "require-dev": { "symfony/dotenv": "^5.3", "phpunit/phpunit": "^9.5" + }, + "scripts": { + "test": "phpunit tests/", + "test:unit": "phpunit tests/ --testsuite=unit", + "example:token": "php examples/token_generation.php", + "example:api": "php examples/api_calls.php", + "example:complete": "php examples/complete_workflow.php" } } From 429c0f8a7a9a69ae148798835ab9ae92550b54bb Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 16:43:32 +0100 Subject: [PATCH 68/85] Uncomment test suite execution in PHP workflow --- .github/workflows/php.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/php.yml diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml new file mode 100644 index 0000000..e092b91 --- /dev/null +++ b/.github/workflows/php.yml @@ -0,0 +1,36 @@ +name: PHP Composer + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Validate composer.json and composer.lock + run: composer validate --strict + + - name: Cache Composer packages + id: composer-cache + uses: actions/cache@v3 + with: + path: vendor + key: ${{ runner.os }}-php-${{ hashFiles('**/composer.lock') }} + restore-keys: | + ${{ runner.os }}-php- + + - name: Install dependencies + run: composer install --prefer-dist --no-progress + + - name: Run test suite + run: composer run-script test From 33872daa3d1e765144e07bd1e76ea1271f969129 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 16:44:22 +0100 Subject: [PATCH 69/85] Update client reference from Rust to PHP --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3edf9eb..d27caa0 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ A minimal and agnostic PHP SDK for Openapi, inspired by a clean client implement ## Pre-requisites -Before using the Openapi Rust Client, you will need an account at [Openapi](https://console.openapi.com/) and an API key to the sandbox and/or production environment +Before using the Openapi PHP Client, you will need an account at [Openapi](https://console.openapi.com/) and an API key to the sandbox and/or production environment ## Features From 06ceef1365b960c2db8e69b6b72e8271a49605d1 Mon Sep 17 00:00:00 2001 From: francesco Date: Sun, 9 Nov 2025 16:44:49 +0100 Subject: [PATCH 70/85] add license --- LICENSE | 21 +++++++++++++++++++++ composer.json | 1 + 2 files changed, 22 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e275050 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Openapi® & Altravia + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/composer.json b/composer.json index d8399bf..2662d3e 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,7 @@ { "name": "openapi/openapi-sdk", "description": "Minimal and agnostic PHP SDK for OpenAPI (https://openapi.com)", + "license": "MIT", "authors": [ { "name": "Altravia", From b5b6bca813b9bf62652ccaf9296492f7951e5af6 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 16:47:47 +0100 Subject: [PATCH 71/85] Update build status badge in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d27caa0..353997b 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

Openapi® client for PHP

The perfect starting point to integrate Openapi® within your PHP project

- [![Build Status](https://img.shields.io/github/actions/workflow/status/openapi/openapi-php-sdk/ci.yml?branch=main)](https://github.com/openapi/openapi-php-sdk/actions) + [![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) [![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk)](LICENSE) From 1e36bfff147189ad677a964dcc5a6f5f300dab3b Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 16:48:15 +0100 Subject: [PATCH 72/85] Rename workflow from 'PHP Composer' to 'build' --- .github/workflows/php.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index e092b91..cc2c3d7 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -1,4 +1,4 @@ -name: PHP Composer +name: build on: push: From 7d1a26f6e5a6e7bbdfe23fd8230734d089e09bc9 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 16:48:30 +0100 Subject: [PATCH 73/85] Fix formatting issues in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 353997b..1a6303c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

Openapi® client for PHP

The perfect starting point to integrate Openapi® within your PHP project

- [![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) + [![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) [![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk)](LICENSE) From 1deb9ab5b3d2fa797154c7adae23ea930ff46249 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 17:01:31 +0100 Subject: [PATCH 74/85] Add installation command for Openapi PHP Client Added installation instructions for Openapi PHP Client. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1a6303c..96f67bc 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,8 @@ For a complete list of all available services, check out the [Openapi Marketplac ## Installation +You can add the Openapi PHP Client to your project with the following command: + ```bash composer require openapi/openapi-sdk ``` From 5ee8360059b8354d1d9731d9750364be412b3612 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Sun, 9 Nov 2025 17:21:02 +0100 Subject: [PATCH 75/85] Update license badge URL in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 96f67bc..a60160f 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) [![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) - [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk)](LICENSE) + [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) From a6d3063d6a1c2b8b641dd767452876a49840d3f2 Mon Sep 17 00:00:00 2001 From: Simone Desantis <138789490+SimoneOpenapi@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:14:58 +0100 Subject: [PATCH 76/85] Update coding style reference from Rust to PHP --- docs/contributing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/contributing.md b/docs/contributing.md index dad6238..c638d0a 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -29,7 +29,7 @@ We welcome all kinds of contributions: bug reports, feature requests, documentat ## Guidelines -* Follow the existing **Rust coding style**. +* Follow the existing **Php coding style**. * Include **tests** for new features or bug fixes when applicable. * Keep **commit messages clear and concise**. * Update **documentation** as needed for your changes. From f3023f7321bf446d92b4e03940ae59797a61ddc6 Mon Sep 17 00:00:00 2001 From: Simone Desantis <138789490+SimoneOpenapi@users.noreply.github.com> Date: Wed, 3 Dec 2025 10:16:47 +0100 Subject: [PATCH 77/85] Update client reference from Rust to PHP --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a60160f..fe0be2c 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ Before using the Openapi PHP Client, you will need an account at [Openapi](https ## What you can do -With the Openapi Rust Client, you can easily interact with a variety of services in the Openapi Marketplace. For example, you can: +With the Openapi PHP Client, you can easily interact with a variety of services in the Openapi Marketplace. For example, you can: - 📩 **Send SMS messages** with delivery reports and custom sender IDs - 💸 **Process bills and payments** in real time via API From a49d178bb4b46b0a00d334a4976c5da06eb5e212 Mon Sep 17 00:00:00 2001 From: Simone Desantis <138789490+SimoneOpenapi@users.noreply.github.com> Date: Thu, 4 Dec 2025 17:45:22 +0100 Subject: [PATCH 78/85] Update API request parameters in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fe0be2c..cf0ee79 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,8 @@ use OpenApi\Client; $client = new Client($token); // GET request -$params = ['denominazione' => 'altravia', 'provincia' => 'RM']; -$response = $client->get('https://test.imprese.openapi.it/advance', $params); +$params = ['denominazione' => 'Stellantis', 'provincia' => 'TO']; +$response = $client->get('https://test.company.openapi.com/IT-advanced', $params); // POST request $payload = ['limit' => 10, 'query' => ['country_code' => 'IT']]; From 1371804cdec30c218f21fc2d39b18db7e2326b6d Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 9 Dec 2025 18:15:43 +0100 Subject: [PATCH 79/85] Updated at mar 9 dic 2025, 18:15:43, CET --- Makefile | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index c457881..5a0c8a0 100644 --- a/Makefile +++ b/Makefile @@ -21,8 +21,8 @@ # License: MIT # # Maintainer: Francesco Bianco # # Contact: https://openapi.com/ # -# Repository: [Repository URL] # -# Documentation: [Docs URL] # +# Repository: https://github.com/openapi/openapi-php-sdk/ # +# Documentation: https://console.openapi.com/ # # # # ═══════════════════════════════════════════════════════════════════════ # # # @@ -31,6 +31,11 @@ # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +## ========= +## Variables +## ========= + +VERSION := 1.2.1 ## ==================== ## Development Commands @@ -41,3 +46,18 @@ dev-push: @git add . @git commit -m "$$(read -p 'Commit message: ' msg; echo $$msg)" || true @git push + +## ================ +## Release Commands +## ================ + +push: + @git add . + @git commit -am "Updated at $$(date)" || true + @git push + +release: push + @git add . + @git commit -m "Update PHP SDK to version ${VERSION}" || echo "No changes to commit" + @git tag -fa "v${VERSION}" -m "${VERSION}" + @git push origin --tags -f From 91c3ffb1dd12452dceb6393d91ee675bd7b639be Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 9 Dec 2025 18:16:07 +0100 Subject: [PATCH 80/85] Updated at mar 9 dic 2025, 18:16:07, CET --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 5a0c8a0..cbce29f 100644 --- a/Makefile +++ b/Makefile @@ -59,5 +59,5 @@ push: release: push @git add . @git commit -m "Update PHP SDK to version ${VERSION}" || echo "No changes to commit" - @git tag -fa "v${VERSION}" -m "${VERSION}" + @git tag -fa "${VERSION}" -m "${VERSION}" @git push origin --tags -f From 488d01d3651fe6860945c2ef5e38c212ac52b64e Mon Sep 17 00:00:00 2001 From: francesco Date: Tue, 9 Dec 2025 18:33:27 +0100 Subject: [PATCH 81/85] Updated at mar 9 dic 2025, 18:33:27, CET --- composer.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 2662d3e..5e513da 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "name": "openapi/openapi-sdk", - "description": "Minimal and agnostic PHP SDK for OpenAPI (https://openapi.com)", + "description": "Minimal and agnostic PHP SDK for Openapi® (https://openapi.com)", "license": "MIT", "authors": [ { @@ -14,15 +14,15 @@ "ext-curl": "*", "ext-json": "*" }, + "require-dev": { + "symfony/dotenv": "^5.3", + "phpunit/phpunit": "^9.5" + }, "autoload": { "psr-4": { "OpenApi\\": "src" } }, - "require-dev": { - "symfony/dotenv": "^5.3", - "phpunit/phpunit": "^9.5" - }, "scripts": { "test": "phpunit tests/", "test:unit": "phpunit tests/ --testsuite=unit", From be1c8486278b679a7dcd9b39a3bc075878d827f0 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Wed, 18 Mar 2026 10:34:19 +0100 Subject: [PATCH 82/85] Update README with commitments to open source Added a section about commitments to open source and Linux Foundation membership. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index cf0ee79..05754f3 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) [![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +
+[![Linux Foundation Member](https://img.shields.io/badge/Linux%20Foundation-Silver%20Member-003778?logo=linux-foundation&logoColor=white)](https://www.linuxfoundation.org/about/members) ## Overview @@ -161,6 +163,13 @@ Meet our partners using Openapi or contributing to this SDK: - [QOMODO S.R.L.](https://www.qomodo.me/) - [SOUNDREEF S.P.A.](https://www.soundreef.com/) +## Our Commitments + +We believe in open source and we act on that belief. We became Silver Members +of the Linux Foundation because we wanted to formally support the ecosystem +we build on every day. Open standards, open collaboration, and open governance +are part of how we work and how we think about software. + ## License This project is licensed under the [MIT License](LICENSE). From 317c4ed66265529613b7aa8cc85c89ad9bbd9301 Mon Sep 17 00:00:00 2001 From: "Francesco Bianco (yafb)" Date: Wed, 18 Mar 2026 15:03:49 +0100 Subject: [PATCH 83/85] Add LICENSE file --- LICENSE | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/LICENSE b/LICENSE index e275050..9f074c6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Openapi® & Altravia +Copyright (c) 2026 Openapi® Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. From eb624428f5a0bf8f48b06050dbb579acd9c7e7e7 Mon Sep 17 00:00:00 2001 From: francesco Date: Wed, 18 Mar 2026 16:03:51 +0100 Subject: [PATCH 84/85] docs(contributing): improve contributing guide clarity and completeness Co-Authored-By: Claude Sonnet 4.6 --- docs/contributing.md | 48 ++++++++++++++++++++++++++------------------ 1 file changed, 29 insertions(+), 19 deletions(-) diff --git a/docs/contributing.md b/docs/contributing.md index c638d0a..707911d 100644 --- a/docs/contributing.md +++ b/docs/contributing.md @@ -1,45 +1,55 @@ -# Contributing to Openapi SDK +# Contributing to Openapi PHP SDK -Thanks for considering contributing! 🎉 -We welcome all kinds of contributions: bug reports, feature requests, documentation improvements, and code enhancements. +Thanks for considering contributing! We welcome all kinds of contributions: bug reports, feature requests, documentation improvements, and code enhancements. ## How to Contribute 1. **Fork the repository** and clone it locally: ```bash - git clone https://github.com//.git + git clone https://github.com/openapi/openapi-php-sdk.git ``` -2. **Create a branch** for your feature or fix: +2. **Install dependencies:** + ```bash + composer install + ``` + +3. **Create a branch** for your feature or fix: ```bash git checkout -b feature/your-feature-name ``` - -3. **Make your changes** and commit them: + +4. **Make your changes** and run the tests: + ```bash + ./vendor/bin/phpunit tests/ + ``` + +5. **Commit your changes:** ```bash git commit -m "Add some feature" ``` - -4. **Push your branch** to your fork: + +6. **Push your branch** to your fork: ```bash git push origin feature/your-feature-name ``` - -5. **Open a Pull Request** describing your changes. + +7. **Open a Pull Request** describing your changes. ## Guidelines -* Follow the existing **Php coding style**. -* Include **tests** for new features or bug fixes when applicable. -* Keep **commit messages clear and concise**. -* Update **documentation** as needed for your changes. +- Follow the existing **PHP coding style** (PHP 8.0+). +- Include **tests** for new features or bug fixes when applicable. +- Keep **commit messages clear and concise**. +- Write all code, comments, and documentation in **English**. +- Update **documentation** as needed for your changes. ## Reporting Issues To report bugs or request features, please **open an issue** on GitHub including: -* Clear description of the problem or feature. -* Steps to reproduce (if applicable). -* Relevant logs or screenshots. +- A clear description of the problem or feature. +- Steps to reproduce (if applicable). +- Relevant logs or error output. -Thank you for helping improve Openapi SDK! 🚀 +Thank you for helping improve the OpenAPI PHP SDK! From 44e28e5fac65b60501be143aa12cf2fd122aef23 Mon Sep 17 00:00:00 2001 From: Mario Ugurcu Date: Sat, 28 Mar 2026 13:16:34 +0100 Subject: [PATCH 85/85] feat: support custom HTTP client injection Allow passing a pre-configured HTTP client (e.g. Guzzle) to the Client. This enables reuse of middleware stacks (e.g. Laravel retry/cache) instead of forcing the internal cURL transport. --- README.md | 89 +++++++++++++++++++---- composer.json | 5 +- src/Client.php | 72 ++++-------------- src/Interfaces/HttpTransportInterface.php | 13 ++++ src/Transports/CurlTransport.php | 68 +++++++++++++++++ tests/ClientTest.php | 47 ++++++++++++ tests/Transports/FakeTransport.php | 29 ++++++++ 7 files changed, 252 insertions(+), 71 deletions(-) create mode 100644 src/Interfaces/HttpTransportInterface.php create mode 100644 src/Transports/CurlTransport.php create mode 100644 tests/ClientTest.php create mode 100644 tests/Transports/FakeTransport.php diff --git a/README.md b/README.md index 05754f3..b2f7a9f 100644 --- a/README.md +++ b/README.md @@ -6,13 +6,14 @@

Openapi® client for PHP

The perfect starting point to integrate Openapi® within your PHP project

- [![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) - [![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) - [![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) - [![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) - [![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) -
+[![Build Status](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml/badge.svg)](https://github.com/openapi/openapi-php-sdk/actions/workflows/php.yml) +[![Packagist Version](https://img.shields.io/packagist/v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![PHP Version](https://img.shields.io/packagist/php-v/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +[![License](https://img.shields.io/github/license/openapi/openapi-php-sdk?v=2)](LICENSE) +[![Downloads](https://img.shields.io/packagist/dt/openapi/openapi-sdk)](https://packagist.org/packages/openapi/openapi-sdk) +
[![Linux Foundation Member](https://img.shields.io/badge/Linux%20Foundation-Silver%20Member-003778?logo=linux-foundation&logoColor=white)](https://www.linuxfoundation.org/about/members) + ## Overview @@ -27,7 +28,7 @@ Before using the Openapi PHP Client, you will need an account at [Openapi](https - **Agnostic Design**: No API-specific classes, works with any OpenAPI service - **Minimal Dependencies**: Only requires PHP 8.0+ and cURL -- **OAuth Support**: Built-in OAuth client for token management +- **OAuth Support**: Built-in OAuth client for token management - **HTTP Primitives**: GET, POST, PUT, DELETE, PATCH methods - **Clean Interface**: Similar to the Rust SDK design @@ -81,7 +82,7 @@ $client = new Client($token); $params = ['denominazione' => 'Stellantis', 'provincia' => 'TO']; $response = $client->get('https://test.company.openapi.com/IT-advanced', $params); -// POST request +// POST request $payload = ['limit' => 10, 'query' => ['country_code' => 'IT']]; $response = $client->post('https://test.postontarget.com/fields/country', $payload); @@ -91,6 +92,70 @@ $response = $client->delete($url); $response = $client->patch($url, $payload); ``` +## Custom HTTP Clients (Guzzle, Laravel, etc.) + +By default, the SDK uses an internal cURL-based transport. +However, you can now inject your own HTTP client, allowing full control over the request pipeline. + +This is especially useful in frameworks like Laravel, where you may want to reuse an existing HTTP client with middleware such as retry, caching, logging, or tracing. + +Using a custom HTTP client (e.g. Guzzle) + +You can pass any PSR-18 compatible client (such as Guzzle) directly to the SDK: + +```php +use OpenApi\Client; +use GuzzleHttp\Client as GuzzleClient; + +$guzzle = new GuzzleClient([ + 'timeout' => 10, + // You can configure middleware, retry logic, caching, etc. here +]); + +$client = new Client($token, $guzzle); + +$response = $client->get('https://test.company.openapi.com/IT-advanced', [ + 'denominazione' => 'Stellantis', +]); +``` + +### Why this matters + +When using the default transport, requests are executed via cURL and bypass any framework-level HTTP configuration. + +By injecting your own client, you can: + +- ✅ Reuse your existing HTTP middleware stack (e.g. Laravel retry/cache) +- ✅ Centralize logging, tracing, and observability +- ✅ Apply custom headers, timeouts, or authentication strategies +- ✅ Maintain consistency with your application's HTTP layer + +### Custom Transport Interface + +If needed, you can also implement your own transport by using the provided interface: + +```php +use OpenApi\Interfaces\HttpTransportInterface; + +class MyTransport implements HttpTransportInterface +{ + public function request( + string $method, + string $url, + mixed $payload = null, + ?array $params = null + ): string { + // Your custom implementation + } +} +``` + +And inject it: + +```php +$client = new Client($token, new MyTransport()); +``` + ## Architecture This SDK follows a minimal approach with only essential components: @@ -134,7 +199,6 @@ composer run test composer run test:unit ``` - ## Contributing Contributions are always welcome! Whether you want to report bugs, suggest new features, improve documentation, or contribute code, your help is appreciated. @@ -165,9 +229,9 @@ Meet our partners using Openapi or contributing to this SDK: ## Our Commitments -We believe in open source and we act on that belief. We became Silver Members -of the Linux Foundation because we wanted to formally support the ecosystem -we build on every day. Open standards, open collaboration, and open governance +We believe in open source and we act on that belief. We became Silver Members +of the Linux Foundation because we wanted to formally support the ecosystem +we build on every day. Open standards, open collaboration, and open governance are part of how we work and how we think about software. ## License @@ -179,4 +243,3 @@ The MIT License is a permissive open-source license that allows you to freely us In short, you are free to use this SDK in your personal, academic, or commercial projects, with minimal restrictions. The project is provided "as-is", without any warranty of any kind, either expressed or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose, and non-infringement. For more details, see the full license text at the [MIT License page](https://choosealicense.com/licenses/mit/). - diff --git a/composer.json b/composer.json index 5e513da..7d9b539 100644 --- a/composer.json +++ b/composer.json @@ -1,5 +1,5 @@ { - "name": "openapi/openapi-sdk", + "name": "seraphim/openapi-sdk", "description": "Minimal and agnostic PHP SDK for Openapi® (https://openapi.com)", "license": "MIT", "authors": [ @@ -12,7 +12,8 @@ "require": { "php": ">=8.0.0", "ext-curl": "*", - "ext-json": "*" + "ext-json": "*", + "psr/http-client": "^1.0" }, "require-dev": { "symfony/dotenv": "^5.3", diff --git a/src/Client.php b/src/Client.php index 6f7a80f..370202b 100644 --- a/src/Client.php +++ b/src/Client.php @@ -2,6 +2,11 @@ namespace OpenApi; +use OpenApi\Interfaces\HttpTransportInterface; +use OpenApi\Transports\CurlTransport; +use Psr\Http\Client\ClientInterface as PsrClientInterface;; + + /** * Generic HTTP client for OpenAPI services * Handles REST operations with Bearer token authentication @@ -10,70 +15,25 @@ class Client { private string $token; + private HttpTransportInterface|PsrClientInterface $transport; + /** * Initialize client with Bearer token */ - public function __construct(string $token) + public function __construct(string $token, HttpTransportInterface|PsrClientInterface|null $transport = null) { $this->token = $token; + $this->transport = $transport ?? new CurlTransport($token); } - /** - * Execute HTTP request - * - * @param string $method HTTP method (GET, POST, PUT, DELETE, PATCH) - * @param string $url Target URL - * @param mixed $payload Request body (for POST/PUT/PATCH) - * @param array|null $params Query parameters (for GET) or form data (for other methods) - * @return string Response body - */ - public function request(string $method, string $url, mixed $payload = null, ?array $params = null): string - { - // Append query parameters for GET requests - if ($params && $method === 'GET') { - $url .= '?' . http_build_query($params); - } - - $ch = curl_init(); - - curl_setopt_array($ch, [ - CURLOPT_URL => $url, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_CUSTOMREQUEST => $method, - CURLOPT_TIMEOUT => 30, - CURLOPT_HTTPHEADER => [ - 'Content-Type: application/json', - 'Authorization: Bearer ' . $this->token - ] - ]); - - // Add JSON payload for POST/PUT/PATCH requests - if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'])) { - curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); - } - - // Add form data for non-GET requests - if ($params && $method !== 'GET') { - curl_setopt($ch, CURLOPT_POSTFIELDS, - is_string($params) ? $params : http_build_query($params)); - } - - $response = curl_exec($ch); - $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); - $error = curl_error($ch); - curl_close($ch); - - // TODO: Provide more graceful error message with connection context (timeout, DNS, SSL, etc.) - if ($response === false) { - throw new Exception("cURL Error: " . $error); - } - - // TODO: Parse response body and provide structured error details (error code, message, request ID) - if ($httpCode >= 400) { - throw new Exception("HTTP Error {$httpCode}: " . $response); - } - return $response; + public function request( + string $method, + string $url, + mixed $payload = null, + ?array $params = null + ): string { + return $this->transport->request($method, $url, $payload, $params); } /** diff --git a/src/Interfaces/HttpTransportInterface.php b/src/Interfaces/HttpTransportInterface.php new file mode 100644 index 0000000..03dcdc3 --- /dev/null +++ b/src/Interfaces/HttpTransportInterface.php @@ -0,0 +1,13 @@ + $url, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_CUSTOMREQUEST => $method, + CURLOPT_TIMEOUT => 30, + CURLOPT_HTTPHEADER => [ + 'Content-Type: application/json', + 'Authorization: Bearer ' . $this->token, + ], + ]); + + if ($payload && in_array($method, ['POST', 'PUT', 'PATCH'], true)) { + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($payload) ? $payload : json_encode($payload)); + } + + if ($params && $method !== 'GET' && !$payload) { + curl_setopt($ch, CURLOPT_POSTFIELDS, is_string($params) ? $params : http_build_query($params)); + } + + $response = curl_exec($ch); + $error = curl_error($ch); + $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); + $ch = null; + + if ($response === false) { + throw new \RuntimeException('cURL error: ' . $error); + } + + if ($httpCode >= 400) { + throw new \RuntimeException("HTTP error {$httpCode}: {$response}"); + } + + return $response; + } +} \ No newline at end of file diff --git a/tests/ClientTest.php b/tests/ClientTest.php new file mode 100644 index 0000000..6819695 --- /dev/null +++ b/tests/ClientTest.php @@ -0,0 +1,47 @@ +request( + 'POST', + 'https://example.com/api/users', + ['name' => 'John'], + ['page' => 1] + ); + + $this->assertSame('fake-response', $response); + + $this->assertSame('POST', $transport->lastMethod); + $this->assertSame('https://example.com/api/users', $transport->lastUrl); + $this->assertSame(['name' => 'John'], $transport->lastPayload); + $this->assertSame(['page' => 1], $transport->lastParams); + $this->assertSame(1, $transport->callCount); + } + + public function test_it_calls_transport_once_per_request(): void + { + $transport = new FakeTransport(); + $client = new Client('test-token', $transport); + + $client->request('GET', 'https://example.com/one'); + $client->request('GET', 'https://example.com/two'); + + $this->assertSame(2, $transport->callCount); + $this->assertSame('https://example.com/two', $transport->lastUrl); + } +} + diff --git a/tests/Transports/FakeTransport.php b/tests/Transports/FakeTransport.php new file mode 100644 index 0000000..ce67e21 --- /dev/null +++ b/tests/Transports/FakeTransport.php @@ -0,0 +1,29 @@ +callCount++; + $this->lastMethod = $method; + $this->lastUrl = $url; + $this->lastPayload = $payload; + $this->lastParams = $params; + + return 'fake-response'; + } +} \ No newline at end of file