Hris.php 7.38 KB
<?php
/**
 * Hris.php
 * HRIS 系统接口服务
 * @author Deepseath
 * @version $Id$
 */
namespace deepseath\hris;

use Symfony\Component\Cache\Adapter\FilesystemAdapter;

class Hris
{
    /**
     * 缓存池
     * @var object
     */
    protected $_cache = null;

    /**
     * HRIS 系统原始 token
     * @var string
     */
    protected $_originToken = '';

    /**
     * token 过期时间,单位:秒
     * @var int
     */
    protected $_tokenExpire = 7200;

    /**
     * HRIS 接口服务根 URL
     * @var string
     */
    protected $_baseUrl = '';

    /**
     * 库版本号
     * @var string
     */
    protected $_libVersion = '1.0';

    /**
     * HTTP 请求对象
     * @var object
     */
    protected $_http = null;

    /**
     * 调试模式
     * @var boolean
     */
    protected $_debug = false;

    /**
     * 配置信息
     * @var array
     */
    public $config = [];

    /**
     * 单点实例
     * @param array $options
     * @return \deepseath\hris\Hris
     */
    public static function &instance(array $options)
    {
        static $instance = null;
        if (empty($instance)) {
            $instance = new self($options);
        }
        return $instance;
    }

    private function __construct(array $options = [])
    {
        $this->_cache = new FilesystemAdapter('hris', 86400, null);
        if (function_exists('config')) {
            $config = config('hris');
            if (empty($options)) {
                $options = $config;
            } else {
                $options = array_merge($config, $options);
            }
            unset($config);
        }
        $this->config = $options;
        if (empty($options['originToken'])) {
            throw new \Exception('原始 TOKEN 未定义', 9001);
        }
        if (!empty($options['baseUrl'])) {
            $this->_baseUrl = $options['baseUrl'];
        }
        if (isset($options['debug'])) {
            $this->_debug = $options['debug'];
        }

        $this->_originToken= $options['originToken'];
        $this->_http = \Yurun\Util\HttpRequest::newSession();
    }

    /**
     * 获取 token 信息
     * @param $force bool 是否强制获取更新 token
     * @return array
     * <pre>
     * + access_token   String  Y   令牌
     * + token_type     String  Y   令牌类型
     * + expires_in     String  Y   token有效时间,时间单位秒
     * + scope          String  Y   授权作用域
     * </pre>
     */
    public function getTokenInfo(bool $force = false) : array
    {
        $token = $this->_cache->getItem('token');
        if ($token->isHit() && $force === false) {
            return $token->get();
        }

        // 初始化 token 信息
        $newTokenInfo = [];
        // 构造 token 获取接口地址
        $url = $this->_baseUrl . 'tokenFlush';
        $params = [
            'token' => $this->_originToken
        ];
        // 请求接口
        $headers = [
            'Authorization' => $this->_originToken,
            'Content-Type' => 'application/json;charset=utf-8'
        ];
        $this->_http->headers($headers);
        $this->log($url, 'Get Token');
        $this->log($params, 'Request');
        $this->log($headers, 'Header');
        $response = $this->_http->post($url, $params, 'json');
        $newTokenInfo = $response->json(true);
        $this->log($newTokenInfo, 'Result');
        if (empty($newTokenInfo) || !isset($newTokenInfo['code'])) {
            throw new \Exception('request hris token error' . var_export($newTokenInfo, true) . '|' . $url . var_export($params, true), 9001);
        }
        if ($newTokenInfo['code'] != 200) {
            throw new \Exception('HRIS TOKEN GET ERROR:' . $newTokenInfo['msg'] . ':' . $newTokenInfo['code']);
        }

        $newTokenInfo['_datetime'] = date('Y-m-d H:i:s');
        // 将本次获取的 token 值写入到缓存
        $token->set($newTokenInfo);
        if (isset($newTokenInfo['expires_in'])) {
            $expire = $newTokenInfo['expires_in'];
        } else {
            $expire = $this->_tokenExpire;
        }
        $token->expiresAfter($expire - 10);
        $this->log($token->get(), 'Save Token');
        $this->_cache->save($token);

        return $newTokenInfo;
    }

    /**
     * 接口 API POST
     * @param string $path  接口基于版本目录的路径
     * @param array $data   请求的数据
     * @param bool $flushToken  是否强制刷新 token
     * @throws \Exception
     * @return array|string
     */
    public function apiRequest($method, $path, $data, $flushToken = false)
    {
        static $tryCount;
        if ($tryCount === null || $flushToken === false) {
            $tryCount = 1;
        } else {
            $tryCount++;
        }
        if ($tryCount > 3) {
            throw new \Exception('hris SDK Error: Get token error, retry maximum number.');
        }
        $headers = [
            'Content-Type' => 'application/json;charset=utf-8',
            'Authorization' => $this->getTokenInfo($flushToken)['data']['token']
        ];
        $this->_http->headers($headers);
        $url = $this->_baseUrl . $path;
        $method = strtolower($method);

        $this->log($url, 'Url');
        $this->log($method, 'Method');
        $this->log($headers, 'Header');
        $this->log($data, 'Request');
        if ($method == 'post') {
            $dataString = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            $response = $this->_http->post($url, $dataString, 'json');
        } elseif ($method == 'get') {
            $response = $this->_http->get($url, $data);
        }
        $body = $response->body();
        $this->log($response->getStatusCode(), 'StatusCode');
        $this->log($body, 'Body');
        $result = $response->json(true);
        $this->log($result, 'Result');
        if (!isset($result['code']) || $result['code'] != 200) {
            if (isset($result['code']) && ($result['code'] == '3001')) {
                // token 无效,尝试重新刷新 token
                $this->log($tryCount, 'Try count');
                return $this->apiRequest($method, $path, $data, true);
            }
            if (isset($result['msg']) && isset($result['code'])) {
                throw new \Exception(json_encode([
                    'url' => $url,
                    'title' => 'hris SDK request error',
                    'msg' => $result['msg'],
                    'code' => $result['code'],
                    'request' => $data,
                    'result' => $result,
                ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), $result['code']);
            } else {
                throw new \Exception(json_encode([
                    'url' => $url,
                    'title' => 'hris SDK response error',
                    'msg' => $result,
                    'result' => $result,
                    'response' => $body,
                ], JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 90001);
            }
        }


        return isset($result['data']) ? $result['data'] : [];
    }

    /**
     * 打印调试日志
     * @param mixed $info
     */
    public function log($info, $title = '', $level = 'hris')
    {
        if ($this->_debug) {
            $info = is_scalar($info) ? $info : json_encode($info, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
            $title = $title ? "[{$title}]" : '';
            \think\facade\Log::write($title . $info, 'hris');
        }
    }
}