367 lines
12 KiB
PHP
367 lines
12 KiB
PHP
<?php
|
|
namespace dominion\api;
|
|
|
|
use Yii;
|
|
use yii\console\Exception;
|
|
use linslin\yii2\curl;
|
|
|
|
class GraphQL
|
|
{
|
|
private $url;
|
|
private $authUrl;
|
|
private $refreshUrl;
|
|
private $login;
|
|
private $pass;
|
|
private $query = '';
|
|
private $variables = [];
|
|
private static $jwt;
|
|
|
|
private static $jwtKeyCache = 'jwt';
|
|
private static $jwtRefreshKeyCache = 'refresh-token';
|
|
|
|
function __construct($key = 'apiGraphQL')
|
|
{
|
|
$this->getConfig($key);
|
|
}
|
|
|
|
private function getConfig($key = 'apiGraphQL')
|
|
{
|
|
if(empty(Yii::$app->params[$key])){
|
|
throw new Exception('Отсутствует конфигурация для rest-сервиса');
|
|
}
|
|
if(!isset(Yii::$app->params[$key]['url'])){
|
|
throw Exception('Отсутствует конфигурация для "url"');
|
|
}
|
|
if(!isset(Yii::$app->params[$key]['authUrl'])){
|
|
throw new Exception('Отсутствует конфигурация для "authUrl"');
|
|
}
|
|
if(!isset(Yii::$app->params[$key]['refreshUrl'])){
|
|
throw new Exception('Отсутствует конфигурация для "refreshUrl"');
|
|
}
|
|
if(!isset(Yii::$app->params[$key]['login'])){
|
|
throw new Exception('Отсутствует конфигурация для "login"');
|
|
}
|
|
if(!isset(Yii::$app->params[$key]['pass'])){
|
|
throw new Exception('Отсутствует конфигурация для "pass"');
|
|
}
|
|
$this->url = Yii::$app->params[$key]['url'];
|
|
$this->authUrl = Yii::$app->params[$key]['authUrl'];
|
|
$this->refreshUrl = Yii::$app->params[$key]['refreshUrl'];
|
|
$this->login = Yii::$app->params[$key]['login'];
|
|
$this->pass = Yii::$app->params[$key]['pass'];
|
|
|
|
self::$jwtKeyCache = 'jwt'.$key;
|
|
self::$jwtRefreshKeyCache = 'refresh-token'.$key;
|
|
|
|
}
|
|
|
|
public function setQuery($str, $settings = '')
|
|
{
|
|
$this->query = "query {$settings} {" . $str . "}";
|
|
}
|
|
|
|
public function setMutation($str, $settings = '')
|
|
{
|
|
$this->query = "mutation {$settings} {" . $str . "}";
|
|
}
|
|
|
|
public function setVariables($array)
|
|
{
|
|
$this->variables = $array;
|
|
}
|
|
|
|
public function setMutationVariables($str, $array = [])
|
|
{
|
|
$arSettings = [];
|
|
$variables = [];
|
|
foreach ($array as $key =>$value)
|
|
{
|
|
$arSettings[] = "\${$key}: {$value['type']}";
|
|
$type = str_replace('!', '', trim($value['type']));
|
|
$variables[$key] = null;
|
|
if(mb_substr(trim($value['type']), -1) == '!' || $value['value'] !== null)
|
|
{
|
|
switch (mb_strtolower($type)){
|
|
case 'int':
|
|
$variables[$key] = (int)$value['value'];
|
|
break;
|
|
case 'boolean':
|
|
$variables[$key] = (bool)$value['value'];
|
|
break;
|
|
case 'string':
|
|
$variables[$key] = (string)$value['value'];
|
|
break;
|
|
case '[int]':
|
|
$variables[$key] = self::intValue($value['value']);
|
|
break;
|
|
case '[string]':
|
|
$variables[$key] = self::stringValue($value['value']);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$settingsStr = 'settings(' . implode(', ', $arSettings) .')';
|
|
$this->setMutation($str, $settingsStr);
|
|
$this->setVariables($variables);
|
|
}
|
|
|
|
public function getValue($attribute = null)
|
|
{
|
|
try
|
|
{
|
|
$value = $this->sendRequest();
|
|
}
|
|
catch (\Exception $ex)
|
|
{
|
|
$value = $this->sendRequest();
|
|
}
|
|
$output = isset($value['data']) ? $value['data'] : [];
|
|
if(!empty($attribute))
|
|
{
|
|
$output = isset($output[$attribute]) ? $output[$attribute] : [];
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
public function refreshToken()
|
|
{
|
|
try
|
|
{
|
|
if(($refreshToken = Yii::$app->cache->get(self::$jwtRefreshKeyCache)) !== false)
|
|
{
|
|
$curl = new curl\Curl();
|
|
$curl->setHeader('Content-Type', 'application/json; charset=UTF-8');
|
|
$curl->setHeader('cookie', $refreshToken);
|
|
$result = $curl->post($this->refreshUrl,false);
|
|
if(isset($result["token"]))
|
|
{
|
|
self::$jwt = $result["token"];
|
|
Yii::$app->cache->set(self::$jwtKeyCache, self::$jwt, self::getJwtExtDelta());
|
|
}
|
|
}
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
throw new Exception($e->getMessage() . "\n". "url:\n " . $this->refreshUrl);
|
|
}
|
|
}
|
|
|
|
public function login($update = false)
|
|
{
|
|
try
|
|
{
|
|
if($update || (self::$jwt = Yii::$app->cache->get(self::$jwtKeyCache)) == false)
|
|
{
|
|
$curl = new curl\Curl();
|
|
$curl->setHeader('Content-Type', 'application/json; charset=UTF-8');
|
|
$curl->setRequestBody(json_encode(['login' => $this->login, 'pass' => $this->pass]));
|
|
|
|
$result = $curl->post($this->authUrl,false);
|
|
if(isset($result["token"]))
|
|
{
|
|
self::$jwt = $result["token"];
|
|
Yii::$app->cache->set(self::$jwtKeyCache, self::$jwt, self::getJwtExtDelta());
|
|
preg_match_all('/^\s*([^;]*)/mi', $curl->responseHeaders["Set-Cookie"], $matches);
|
|
$cookies = array();
|
|
foreach($matches[1] as $item) {
|
|
parse_str($item, $cookie);
|
|
$cookies = array_merge($cookies, $cookie);
|
|
}
|
|
if(isset($cookies["refresh-token"]))
|
|
{
|
|
Yii::$app->cache->set(self::$jwtRefreshKeyCache, 'refresh-token='.$cookies["refresh-token"], 3600*24*100);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new Exception('Нет токена');
|
|
}
|
|
}
|
|
}
|
|
catch (Exception $e)
|
|
{
|
|
throw new Exception($e->getMessage() . "\n". "url:\n " . $this->authUrl);
|
|
}
|
|
return self::$jwt;
|
|
}
|
|
|
|
public static function getJwtParam($key, $default = false)
|
|
{
|
|
$output = $default;
|
|
self::$jwt = self::$jwt ? self::$jwt: Yii::$app->cache->get(self::$jwtKeyCache);
|
|
if(self::$jwt)
|
|
{
|
|
$params = explode('.', self::$jwt);
|
|
if(isset($params[1]))
|
|
{
|
|
$value = json_decode(base64_decode($params[1]), true);
|
|
$output = isset($value[$key]) ? $value[$key] : $output;
|
|
}
|
|
}
|
|
return $output;
|
|
}
|
|
|
|
public static function getJwtExtDelta()
|
|
{
|
|
$jwtExp = self::getJwtParam('exp');
|
|
return $jwtExp - time() - 30;
|
|
}
|
|
|
|
public function getJwt()
|
|
{
|
|
self::$jwt = self::$jwt ? self::$jwt: Yii::$app->cache->get(self::$jwtKeyCache);
|
|
if(self::$jwt)
|
|
{
|
|
if(self::getJwtExtDelta() <= 0)
|
|
{
|
|
self::$jwt = null;
|
|
}
|
|
}
|
|
if(!self::$jwt)
|
|
{
|
|
$this->refreshToken();
|
|
}
|
|
if(self::$jwt)
|
|
{
|
|
$role = self::getJwtParam('role', 'anon');
|
|
if($role == 'anon')
|
|
{
|
|
$this->login(true);
|
|
}
|
|
}
|
|
if(!self::$jwt)
|
|
{
|
|
$this->login();
|
|
}
|
|
return self::$jwt;
|
|
}
|
|
|
|
|
|
private function sendRequest()
|
|
{
|
|
$curl = new curl\Curl();
|
|
$curl->setHeader('Content-Type', 'application/json; charset=UTF-8');
|
|
$curl->setHeader('Authorization', 'Bearer ' . $this->getJwt());
|
|
$body = json_encode([
|
|
'query' => $this->query,
|
|
'variables' => $this->variables,
|
|
]);
|
|
if(isset(\Yii::$app->params['CURL_TIMEOUT']) && \Yii::$app->params['CURL_TIMEOUT'] > 0)
|
|
{
|
|
$curl->setOption(CURLOPT_TIMEOUT, \Yii::$app->params['CURL_TIMEOUT']);
|
|
}
|
|
$curl->setRequestBody($body);
|
|
$response = $curl->post($this->url,false);
|
|
if(isset($response['errors']))
|
|
{
|
|
throw new Exception('graphql error ' . json_encode($response) . "Тело:\n " . $body);
|
|
}
|
|
$errorMessage = ($curl->responseCode != 200) ? ("\n". print_r($response, true) . "Тело:\n " . $body) : '';
|
|
switch ($curl->responseCode) {
|
|
case 'timeout':
|
|
throw new Exception('Network timeout'.$errorMessage);
|
|
break;
|
|
case 200:
|
|
return $response;
|
|
break;
|
|
case 404:
|
|
throw new Exception('404. Page not found'.$errorMessage);
|
|
break;
|
|
case 403:
|
|
throw new Exception('403. Access deny'.$errorMessage);
|
|
break;
|
|
case 401:
|
|
throw new Exception('401. Autorization required'.$errorMessage);
|
|
break;
|
|
case 400:
|
|
throw new Exception('400. Bad request'.$errorMessage);
|
|
break;
|
|
case 500:
|
|
throw new Exception('500. Internal server error'.$errorMessage);
|
|
break;
|
|
case 503:
|
|
throw new Exception('503. Service unavailable'.$errorMessage);
|
|
break;
|
|
case 502:
|
|
throw new Exception('502. Bad gateway'.$errorMessage);
|
|
break;
|
|
}
|
|
}
|
|
|
|
public function setQueryPaginction($object, $select, $filter = [], $page = null, $perPage = null, $wrapper = 'data')
|
|
{
|
|
$page = $page === null ? (isset($_GET['page']) ? $_GET['page'] : 1) : $page;
|
|
$perPage = $perPage === null ? \Yii::$app->user->identity->countPage : $perPage;
|
|
$filterStr = empty($filter) ? '' : ('(' . implode(', ', $filter) . ')');
|
|
$this->setQuery(" {$object}(page:{$page}, perPage:{$perPage}) { {$wrapper} {$filterStr} { {$select} }, totalCount }");
|
|
}
|
|
|
|
public function setSortFilters($filter, $params, $default = 'id_desc', $field = 'sort')
|
|
{
|
|
$sort = $default;
|
|
if (isset($params[$field]))
|
|
{
|
|
$sort = (mb_substr($params[$field], 0, 1) == '-') ? (mb_substr($params[$field], 1).'_desc') : ( $params[$field].'_asc');
|
|
}
|
|
$filter[] = "sort: \"{$sort}\"";
|
|
return $filter;
|
|
}
|
|
|
|
public function setFilterModel($type, $filter, $model, $fields)
|
|
{
|
|
foreach ($fields as $key)
|
|
{
|
|
if(!empty($model->{$key}) || $model->{$key} === true || $model->{$key} === false || $model->{$key} === "0" || $model->{$key} === 0 )
|
|
{
|
|
switch ($type){
|
|
case "string":
|
|
$filter[] = "{$key}: \"{$model->$key}\"";
|
|
break;
|
|
case "number":
|
|
$value = (float)$model->$key;
|
|
$filter[] = "{$key}: {$value}";
|
|
break;
|
|
case "bool":
|
|
$value = $model->$key ? 'true' : 'false';
|
|
$filter[] = "{$key}: {$value}";
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
return $filter;
|
|
}
|
|
|
|
public function setFilterString($filter, $model, $fields)
|
|
{
|
|
return $this->setFilterModel('string', $filter, $model, $fields);
|
|
}
|
|
public function setFilterNumber($filter, $model, $fields)
|
|
{
|
|
return $this->setFilterModel('number', $filter, $model, $fields);
|
|
}
|
|
public function setFilterBool($filter, $model, $fields)
|
|
{
|
|
return $this->setFilterModel('bool', $filter, $model, $fields);
|
|
}
|
|
|
|
public static function intValue($array)
|
|
{
|
|
$output = [];
|
|
foreach($array as $id)
|
|
{
|
|
$output[] = (int)$id;
|
|
}
|
|
return $output;
|
|
}
|
|
public static function stringValue($array)
|
|
{
|
|
$output = [];
|
|
foreach($array as $id)
|
|
{
|
|
$output[] = (string)$id;
|
|
}
|
|
return $output;
|
|
}
|
|
}
|