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