<?php
namespace RestClient\Service;
* Cliente abstrato de acesso ao webservice REST
* Este cliente é responsável por gerar o token para uso
* com os demais clientes.
* @author Rodrigo Teixeira Andreotti <ro.andriotti@gmail.com>
abstract class AbstractClient
private $tokenUrl;
private $clientId;
private $secret;
private $serviceUrl;
private $resourceId;
private $tenantId;
private $apiKey;
private $cache;
* Recebe em seu construtor uma instância da
* aplicação rodando e uma do handler de cache
* @param \Core\Application $app
* @param \Core\Cache\Cache $cache
public function __construct(\Core\Application $app, \Core\Cache\Cache $cache)
$this->tokenUrl = $app->getConfig('api_token_url');
$this->clientId = $app->getConfig('api_clientId');
$this->secret = $app->getConfig('api_secret');
$this->serviceUrl = $app->getConfig('api_service_url');
$this->tenantId = $app->getConfig('api_tenantId');
$this->apiKey = $app->getConfig('api_key');
$this->resourceId = $app->getConfig('api_resourceId');
$this->cache = $cache;
$this->loadToken();
* Verifica se existe um token válido em cache,
* caso haja o carrega, se não gera um novo token no webservice,
* o salva em cache e o retorna para uso pelo serviço.
* @uses AbstractClient::requestToken()
* @return string Token gerado / armazenado
private function loadToken()
$cache = $this->cache;
$token = $cache->readCache('api_token');
if (!$token) {
$tokenData = $this->requestToken();
$cache->saveCache('api_token', $tokenData->access_token, 45); // <-- Converte o tempo do token para minutos
$token = $tokenData->access_token;
return $token;
* Requisita ao webservice o token de acesso
* @return \stdClass Contém o json decodificado com as informações do token
private function requestToken()
$ch = curl_init($this->tokenUrl . $this->tenantId . '/oauth2/token');
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, array(
'grant_type' => 'client_credentials',
'resource' => $this->resourceId,
'client_id' => $this->clientId,
'client_secret' => $this->secret
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = json_decode(curl_exec($ch));
curl_close($ch);
return $data;
* Realiza a consulta ao webserice
* @uses AbstractClient::buildUrlParams()
* @param string $method Método REST que será consultado
* @param array $params Paramentros adicionais que serão chamados
* @return \stdClass Retorno do json decodificado
protected function callService($method, $params = null)
$ch = curl_init($this->serviceUrl . $method . ($params ? $this->buildUrlParams($params) : ''));
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_FRESH_CONNECT, TRUE);
// Linhas abaixo necessárias para usar o cUrl com windows sem certificado
//curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
//curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt_array($ch, array(
CURLOPT_HTTPGET => TRUE,
CURLOPT_RETURNTRANSFER => 1,
CURLOPT_HTTPHEADER => array(
'Authorization: Bearer ' . $this->loadToken(),
'X-Api-Key: ' . $this->apiKey,
$response = curl_exec($ch);
$httpCode = intval(curl_getinfo($ch, CURLINFO_HTTP_CODE));
if ($httpCode != 200) {
return $httpCode;
$data = json_decode($response);
curl_close($ch);
return $data;
* Constrói os parâmetros em formato de URL
* @param array $params
* @return string Parametros de URL formatados
private function buildUrlParams($params)
$urlParams = '';
if (count($params)) {
$urlParams .= '?';
$i = 0;
foreach ($params as $key => $param) {
$urlParams .= (($i == 0) ? '' : '&');
$urlParams .= $key . '=' . $param;
$i++;
return $urlParams;
}
由于我正在使用自己的缓存解决方案,所以我的类如下所示:
<?php
namespace Core\Cache;
* Sistema de cache
* @author Rodrigo Teixeira Andreotti <ro.andriotti@gmail.com>
class Cache
* @var integer Tempo para o cache em minutos
private $time = 60;
* @var string Local onde o cache será salvo
private $local;
* Inicializa a classe e define o local onde o cache será armazenado
* @uses Cache::setLocal()
* @param string $local
public function __construct($local)
$this->setLocal($local);
* Define o local onde o cache será salvo
* @param string $local
* @return $this
private function setLocal($local)
if (!file_exists($local)){
trigger_error('Diretório de cache não encontrado', E_USER_ERROR);
} elseif(!is_dir($local)) {
trigger_error('Caminho para diretório de cache não aponta para um diretório', E_USER_ERROR);
} elseif(!is_writable($local)){
trigger_error('Diretório de cache inacessível', E_USER_ERROR);
} else {
$this->local = $local;
return $this;
* Gera o local onde o arquivo será salvo
* @param string $key
* @return string
private function generateFileLocation($key)
return $this->local . DIRECTORY_SEPARATOR . sha1($key) . '.tmp';
* Cria o arquivo de cache
* @uses Cache::generateFileLocation()
* @param string $key
* @param mixed $content
* @return boolean
private function generateCacheFile($key, $content)
$file = $this->generateFileLocation($key);
return file_put_contents($file, $content) || trigger_error('Não foi possível criar o arquivo de cache', E_USER_ERROR);
* Salva um valor em cache
* @uses Cache::generateCacheFiles
* @param string $key
* @param mixed $content
* @param integer $time Tempo em minutos
* @return boolean
public function saveCache($key, $content, $time = null)
$time = strtotime(($time ? $time : $this->time) . ' minutes');
$content = serialize(array(
'expira' => $time,
'content' => $content
return $this->generateCacheFile($key, $content);
* Recupera um valor salvo no cache
* @uses Cache::generateFileLocation()
* @param string $key
* @return mixed Valor do cache salvo ou null
public function readCache($key)
$file = $this->generateFileLocation($key);
if (is_file($file) && is_readable($file)) {
$cache = unserialize(file_get_contents($file));
if ($cache['expira'] > time()) {
return $cache['content'];
} else {
unlink($file);
return null;
}