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;
 | 
						|
    }
 | 
						|
}
 |