class类和trait类
class类和trait类
重写垃圾七牛的BucketManager类
<?php
namespace app\common\library;
class ApiResponseFormat
{
use \app\common\library\traits\Singleton;
protected $codeValueSuccessDefault = 1;
protected $codeValueErrorDefault = 0;
protected $codeValue = null;
protected $dataValue = null;
protected $msgValue = '';
protected $codeKeyName = 'code';
protected $dataKeyName = 'data';
protected $msgKeyName = 'msg';
protected $msgPrefix = '';
/**
* @param string $codeKeyName
* @return $this
*/
public function setCodeKeyName(string $codeKeyName)
{
$this->codeKeyName = $codeKeyName;
return $this;
}
/**
* @param string $dataKeyName
* @return $this
*/
public function setDataKeyName(string $dataKeyName)
{
$this->dataKeyName = $dataKeyName;
return $this;
}
/**
* @param string $msgKeyName
* @return $this
*/
public function setMsgKeyName(string $msgKeyName)
{
$this->msgKeyName = $msgKeyName;
return $this;
}
/**
* @param int $codeValue
* @return $this
*/
public function setCodeValue($codeValue)
{
$this->codeValue = $codeValue;
return $this;
}
/**
* @param int $codeValue
* @return $this
*/
public function setCodeErrorValue($codeValue)
{
$this->codeValue = $codeValue??$this->getCodeValueErrorDefault();
return $this;
}
/**
* @param null $dataValue
* @return $this
*/
public function setDataValue($dataValue)
{
$this->dataValue = $dataValue;
return $this;
}
/**
* @param string $msgValue
* @return $this
*/
public function setMsgValue(string $msgValue)
{
$this->msgValue = $msgValue;
return $this;
}
public function getArr()
{
return [
$this->codeKeyName => $this->codeValue??$this->codeValueSuccessDefault,
$this->dataKeyName => $this->dataValue,
$this->msgKeyName => $this->msgPrefix . $this->msgValue,
];
}
/**
* @return string
*/
public function getMsgKeyName(): string
{
return $this->msgKeyName;
}
/**
* @param int $codeValueSuccessDefault
* @return $this
*/
public function setCodeValueSuccessDefault(int $codeValueSuccessDefault)
{
$this->codeValueSuccessDefault = $codeValueSuccessDefault;
return $this;
}
/**
* @return int
*/
public function getCodeValueSuccessDefault()
{
return $this->codeValueSuccessDefault;
}
/**
* @param string $msgPrefix
* @return $this
*/
public function setMsgPrefix(string $msgPrefix)
{
$this->msgPrefix = $msgPrefix;
return $this;
}
/**
* @return int
*/
public function getCodeValueErrorDefault()
{
return $this->codeValueErrorDefault;
}
/**
* @param int $codeValueErrorDefault
* @return $this
*/
public function setCodeValueErrorDefault(int $codeValueErrorDefault)
{
$this->codeValueErrorDefault = $codeValueErrorDefault;
return $this;
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2018-12-26
* Time: 16:59
*/
namespace App\Repositories\Common\QiNiu;
use Qiniu\Auth;
use Qiniu\Config;
use Qiniu\Http\Client;
use Qiniu\Http\Error;
/**
* 通过赋值的方式重写BucketManager
*
* 七牛SDK不行
*/
class BucketManager
{
/**
* @var \Qiniu\Storage\BucketManager
*/
protected $bucketManager;
/**
* @var Config
*/
protected $config;
/**
* @var Auth
*/
protected $auth;
/**
* 设置回调相关的参数
*
* @var array
*/
protected $callbackData = [];
protected $authorizationType = 'QBox';
/**
* fetch并制定数据
*
* 返回:
* array [
"id" => "eyJ6b25lIjoiejAiLCJxdWV1ZSI6IlNJU1lQSFVTLUpPQlMtVjMiLCJwYXJ0X2lkIjoyMiwib2Zmc2V0IjoyNjkzMTgxfQ=="
"wait" => 12
]
*
* @param $url
* @param $bucket
* @param $key
* @return bool|mixed
*/
public function fetchV2($url, $bucket, $key)
{
$path = '/sisyphus/fetch';
$ak = $this->getAuth()->getAccessKey();
$ioHost = $this->getConfig()->getIovipHost($ak, $bucket);
$apiHost = $this->getConfig()->getApiHost($ak, $bucket);
// $apiHost = str_replace('api.', 'api-z0.', $apiHost);
$path = $apiHost . $path;
$callbackData = [];
foreach ($this->getCallbackData() as $callbackName => $callbackDatum) { // 转为小写
$callbackData[strtolower($callbackName)] = $callbackDatum;
}
$body = array_filter(array_merge([
'url' => $url,
'host' => parse_url($ioHost, PHP_URL_HOST),
'bucket' => $bucket,
'key' => $key,
], $callbackData)); // 将callback合并
list($response, $error) = $this->postV2($path, $body);
if ($error) {
return false;
}
return $response;
}
/**
* 获取fetch的状态
*
* @param $fetchId
* @return bool|mixed
*/
public function fetchV2Status($fetchId)
{
$path = "/sisyphus/fetch?id={$fetchId}";
$ak = $this->getAuth()->getAccessKey();
$apiHost = Config::UC_HOST;
// $apiHost = str_replace('api.', 'api-z0.', $apiHost);
$path = $apiHost . $path;
list($response, $error) = $this->getV2($path);
if ($error) {
return false;
}
return $response;
}
/**
* @param $url
* @return array
*/
public function getV2($url)
{
$headers = $this->auth->authorizationV2($url, 'GET');
$ret = Client::get($url, $headers);
if (!$ret->ok()) {
return array(null, new Error($url, $ret));
}
return array($ret->json(), null);
}
/**
* 公开post方法
*
* @see \Qiniu\Storage\BucketManager::post
* @param $url
* @param $body
* @return array
*/
public function post($url, $body)
{
$headers = $this->getAuth()->authorization($url, $body, 'application/x-www-form-urlencoded');
$ret = Client::post($url, $body, $headers);
if (!$ret->ok()) {
return array(null, new Error($url, $ret));
}
$r = ($ret->body === null) ? array() : $ret->json();
return array($r, null);
}
/**
* post请求,使用最新v2七牛协议
*
* @param $url
* @param array $body
* @return array
*/
public function postV2($url, $body)
{
$bodyJson = json_encode($body);
$headers = $this->getAuth()->authorizationV2($url, 'POST', $bodyJson, 'application/json');
$ret = Client::post($url, $bodyJson, $headers + ['Content-Type' => 'application/json']);
if (!$ret->ok()) {
return array(null, new Error($url, $ret));
}
$r = ($ret->body === null) ? array() : $ret->json();
return array($r, null);
}
/**
* 获取Authorization的header
* 可指定上传策略
*
* @param $bucket
* @param null $key 为null的时候只能新增(若已存在同名资源(且文件内容/etag不一致),上传会失败;若已存在资源的内容/etag一致,则上传会返回成功。),
* 存在值的时候按(表示只允许用户上传指定 key 的文件。在这种格式下文件默认允许修改,若已存在同名资源则会被覆盖。如果只希望上传指定 key 的文件,并且不允许修改,那么可以将下面的 insertOnly 属性值设为 1。)
* @param int $expires
* @param null|array $policy 指定哪些字段
* @return array
*/
public function getAuthUploadToken($bucket, $key = null, $policy = null, $expires = 3600)
{
// $strictPolicy是是否类型检测
$authorization = $this->authorizationType . ' ' . $this->getAuth()->uploadToken($bucket, $key, $expires, $this->handlePolicy($policy), true);
return array('Authorization' => $authorization);
}
/**
* 获取Authorization的header
* 可指定上传策略
*
* @param $urlString
* @param $body
* @param null|string $contentType 当为application/x-www-form-urlencoded时body才有用
* @return array
*/
public function getAuthorization($urlString, $body, $contentType = null)
{
// $strictPolicy是是否类型检测
$authorization = $this->authorizationType . ' ' . $this->getAuth()->signRequest($urlString, $body, $contentType);
return array('Authorization' => $authorization);
}
/**
* 处理policy
*
* @param $policy
* @return array
*/
protected function handlePolicy($policy)
{
if (is_array($policy)) {
$policy = array_merge($policy, $this->getCallbackData());
}
return $policy;
}
/**
* 调用七牛的BucketManager类库的公有方法
*
* @param $name
* @param $arguments
* @return mixed
*/
public function __call($name, $arguments)
{
return $this->getBucketManager()->{$name}(...$arguments);
}
/**
* 获取七牛的BucketManager,会初始化
*
* @return \Qiniu\Storage\BucketManager
*/
public function getBucketManager()
{
if (is_null($this->bucketManager)){
$this->bucketManager = new \Qiniu\Storage\BucketManager($this->getAuth(), $this->getConfig());
}
return $this->bucketManager;
}
/**
* @param mixed $bucketManager
* @return $this
*/
public function setBucketManager($bucketManager)
{
$this->bucketManager = $bucketManager;
return $this;
}
/**
* 获取七牛config类库
*
* @return Config
*/
public function getConfig()
{
return $this->config??($this->config = new Config());
}
/**
* @param mixed $config
* @return $this
*/
public function setConfig($config)
{
$this->config = $config;
return $this;
}
/**
* @return Auth
*/
public function getAuth()
{
return $this->auth;
}
/**
* @param mixed $auth
* @return $this
*/
public function setAuth($auth)
{
$this->auth = $auth;
return $this;
}
/**
* 设置callback的相关数据
*
* @param $url
* @param null $body
* @param null $bodyType
* @param null $host
* @return $this
*/
public function setCallbackData($url, $body, $bodyType = null, $host = null)
{
$callbackData = [
'callbackUrl' => $url,
'callbackBody' => $body, // 指定url,必须指定body
];
if (isset($bodyType)) {
$callbackData['callbackBodyType'] = $bodyType;
}
if (isset($host)) {
$callbackData['callbackHost'] = $host;
}
$this->callbackData = $callbackData;
return $this;
}
/**
* @return array
*/
public function getCallbackData()
{
return $this->callbackData;
}
public function setAuthorizationType(string $authorizationType)
{
$this->authorizationType = $authorizationType;
return $this;
}
/**
* v2版本的头
*
* @return BucketManager
*/
public function setAuthorizationTypeQiNiu()
{
return $this->setAuthorizationType('Qiniu');
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2018/9/28
* Time: 上午10:26
*/
namespace App\Repositories\Common;
use App\Repositories\Common\Traits\Singleton;
/**
* 缓存多个单一的key
*
* @since 2018/9/28
* @package App\Repositories\Common
*/
abstract class CacheMultiAbstract
{
use Singleton;
abstract protected function setCachePro($key, $value, $minutes);
abstract protected function getCachePro($key);
/**
* @param string $prefix 缓存key的前缀
* @param int $timeout 过期时间
* @param array $data 需要处理的数据,key用于缓存的key
* @param callable $func 处理没有cache的数据
* @param bool $emptyDefault 缓存get返回的不存在的key时的值
* @return array
*/
public function cacheMulti($prefix, $timeout, array $data, callable $func, $emptyDefault = null)
{
if (empty($data)) {
return [];
}
$cacheData = $result = [];
foreach ($data as $key => $item) {
$tempData = $this->getCachePro("${prefix}:${key}");
if ($tempData === $emptyDefault){
$cacheData[$key] = $item;
}else{
$result[$key] = $tempData;
}
}
if (!empty($cacheData)) {
$cacheData = $func($cacheData);
if (!empty($cacheData)) {
foreach ($cacheData as $key => $cacheDatum) {
$this->setCachePro("${prefix}:${key}", $cacheDatum, $timeout);
}
}
$result = array_merge($result, $cacheData);
}
return $result;
}
}
<?php
/**
* User: aozhuochao
* Date: 2020/11/2
*/
namespace app\modules\core;
/**
* 扩展facade的方法
* 实现门面代理的类的方法被中间件原理修改
*/
class FacadeExpand extends \think\Facade
{
protected static $config = [
'method' => [], // \app\class::method => function(){}
'class_expand' => [],
];
protected static $loadDataBool = false;
protected static function loadData()
{
if (static::$loadDataBool){
return;
}
foreach (scanDirFile(dirname(__DIR__), 'facade_expand.php') as $file) {
$arr = include $file;
foreach (static::$config as $key => &$item) {
if (empty($arr[$key]) || !is_array($arr[$key])) {
continue;
}
if ($key === 'method') { // 方法
foreach ($arr[$key] as $localKey => $arrItem) {
$callbackArr = explode('::', $localKey);
$class = !empty($callbackArr[0])?$callbackArr[0]:'';
$method = !empty($callbackArr[1])?$callbackArr[1]:'';
if (empty($class) || empty($method)) {
continue;
}
$class = ltrim($class, '\\');
if (!isset($item[$class])) {
$item[$class] = [];
}
if (!isset($item[$class][$method])) {
$item[$class][$method] = [];
}
array_push($item[$class][$method], $arrItem);
}
}else if($key === 'class_expand'){ // 类扩展
foreach ($arr[$key] as $originClass => $expandClass) {
if (!isset($item[$originClass])) {
$item[$originClass] = [];
}
array_push($item[$originClass], $expandClass);
}
}
}
}
static::$loadDataBool = true;
}
// 调用实际类的方法
public static function __callStatic($method, $params)
{
static::loadData();
$className = get_class(static::createFacade());
$bool = true;
$data = null;
$methodBool = !empty(static::$config['method'][$className]) && !empty(static::$config['method'][$className][$method]);
if ($methodBool) {
foreach (static::$config['method'][$className][$method] as $arr) {
// before
$beforeCallback = !empty($arr[0]) ? $arr[0] : (!empty($arr['before']) ? $arr['before'] : false);
if (!empty($beforeCallback) && is_callable($beforeCallback)) {
$tempBool = call_user_func($beforeCallback, $params);
$bool = isset($tempBool) ? $tempBool : $bool;
}
}
}
if ($bool) {
$keyNum = count(static::$config['class_expand'][$className]);
$currentKeyNum = 0;
$next = function ($params) use ($method, $className, &$next, &$currentKeyNum, $keyNum) {
if ($keyNum === $currentKeyNum) {
return parent::__callStatic($method, $params);
}
++$currentKeyNum;
if (empty(static::$config['class_expand'][$className])) { // 没有被设置
return $next($params);
}
/** @var \app\modules\core\FacadeExpandClassInterface $expandClass */
$expandClass = static::$config['class_expand'][$className][$currentKeyNum - 1];
if (
!isset(class_implements($expandClass)[\app\modules\core\FacadeExpandClassInterface::class])
) {
return $next($params);
}
if (!method_exists($expandClass, $method) || !method_exists($expandClass, 'newClass')){
return $next($params);
}
$expandClassObject = $expandClass::newClass();
return $expandClassObject->$method($next, $params);
};
$data = $next($params);
}
if ($methodBool) {
foreach (static::$config['method'][$className][$method] as $arr) {
// after
$beforeCallback = !empty($arr[1])?$arr[1]:(!empty($arr['after'])?$arr['after']:false);
if (!empty($beforeCallback) && is_callable($beforeCallback)) {
$bool = true; // 使用返回的结果
$tempData = call_user_func($beforeCallback, $params, $data, $bool);
$data = isset($tempData) && $bool ? $tempData : $data;
}
}
return $data;
}
return $data;
}
}
<?php
/**
* User: aozhuochao
* Date: 2020/12/9
*/
namespace app\helpers\traits;
abstract class FactoryNamespaceBase
{
/**
* 父类
*
* @var object
*/
protected $parentClass;
public function __construct($parentClass = null)
{
$this->parentClass = $parentClass;
}
public function getParentClass()
{
return $this->parentClass;
}
}
<?php
/**
* Created by PhpStorm.
* User: aozhuochao
* Date: 2020-02-24
* Time: 16:43
*/
namespace app\helpers\traits;
/**
* 工厂trait,命名空间版
*
* todo 看下是否可改为非静态
*
* 例子:
static::pushRootNamespaceOnCurrent('grids');
static::setFactorySuffix('grid');
static::setFactoryConstructArg('*', [$this]);
static::setSaveCallType(1);
static::setFactoryDefault('test');
*/
trait FactoryNamespaceStaticTrait
{
/**
* 根命名空间
*
* @var array
*/
protected static $rootNamespaceList = [];
/**
* 类别名
*
* @var array
*/
protected static $classAliasArr = [];
/**
* 工厂子类的构造函数的参数
*
* 如:static::setFactoryConstructArg('*', [$this]);
*
* @var array
*/
protected static $factoryConstructArg = [];
/**
* 全局后缀
*
* @var string
*/
protected static $factorySuffix = '';
/**
* 全局工厂默认子类
*
* @var string
*/
protected static $factoryDefaultName = '';
/**
* 保存的call的数据
*
* @var array|object[]
*/
protected static $saveCallArr = [];
/**
* 保存call的类型
*
* @var int
*/
protected static $saveCallType;
/**
* 自动单例
* 如果有后缀instance,则会又多一个
*
* @var bool
*/
protected static $autoInstance = false;
/**
* @param $rootNamespace
*/
public static function pushRootNamespace($rootNamespace)
{
/** @noinspection PhpUndefinedFieldInspection */
static::$rootNamespaceList[] = $rootNamespace;
}
/**
* 设置相对当前类的相对命名空间
*
* @param string $rootNamespace
* @param null|string $currentClass
* @param string $classSuffix
*/
public static function pushRootNamespaceOnCurrent($rootNamespace = '', $currentClass = null, $classSuffix = '')
{
$tempRootNamespace = ltrim($rootNamespace, '\\');
$staticClassName = '\\' . (isset($currentClass) ? $currentClass : static::class);
if ($pos = strrpos($staticClassName, '\\')){
$staticClassName = substr($staticClassName, 0, $pos + 1);
}
$staticClassName = rtrim($staticClassName, '\\');
/** @noinspection PhpUndefinedFieldInspection */
static::$rootNamespaceList[] = [
'rootNamespace' => $rootNamespace,
'classNamespace' => $tempRootNamespace ? $staticClassName . '\\' . $tempRootNamespace : $staticClassName,
'classSuffix' => $classSuffix
];
}
/**
* @param $name
* @param array $factoryConstructArg
*/
public static function setFactoryConstructArg($name, array $factoryConstructArg)
{
static::$factoryConstructArg[$name] = $factoryConstructArg;
}
/**
* 1、每个都保存
* 2、基于根名
* 3、基于方法名 + 实例化时第一个参数,同名覆盖
*
* @param $type
* @param string $method 特定方法名
*/
public static function setSaveCallType($type, $method = '*')
{
static::$saveCallType[$method] = $type;
}
/**
* 获取存储的数据
*
* @param null $key
* @param object[] $saveCallArr
* @return array
*/
public static function getSaveCall($key = null)
{
$saveArr = static::$saveCallArr;
if (!isset($key)) { // null返回所有
return $saveArr;
}else if (!isset($saveArr[$key])){ // 不存在就返回空数组
return [];
}
return $saveArr[$key];
}
/**
* @param string $factorySuffix
*/
public static function setFactorySuffix(string $factorySuffix)
{
static::$factorySuffix = $factorySuffix;
}
/**
* @param string $factoryDefaultName
*/
public static function setFactoryDefaultName(string $factoryDefaultName)
{
static::$factoryDefaultName = $factoryDefaultName;
}
/**
* @param bool $autoInstance
*/
public static function setAutoInstance(bool $autoInstance = true): void
{
self::$autoInstance = $autoInstance;
}
/**
* 设置替换的别名
*
* @param $alias
* @param string|object $class
*/
public static function setClassAlias($alias, $class): void
{
self::$classAliasArr['\\' . ltrim($alias, '\\')] = $class;
}
/**
* 循环处理配置
*
* @param $name
* @param $arguments
* @return \Generator
*/
protected static function factoryCallEachYieldPro($name, $arguments)
{
foreach (static::$rootNamespaceList as $itemNamespaceArr) {
$factoryDefaultAgentBool = false;
agent:;
$classNamespace = $itemNamespaceArr['classNamespace'] . '\\' . ucfirst($name);
// 处理后缀
$classNamespace .= ucfirst(
!empty($itemNamespaceArr['classSuffix']) ? $itemNamespaceArr['classSuffix'] :
(static::$factorySuffix?:'')
);
if(isset(static::$classAliasArr[$classNamespace])){
if (is_object(static::$classAliasArr[$classNamespace])) { // 指定实例化的类
yield [
1,
static::$classAliasArr[$classNamespace]
];
}else{ // 指定类别名
$classNamespace = static::$classAliasArr[$classNamespace];
}
}
if (!class_exists($classNamespace)) {
if (empty(static::$factoryDefaultName) || $factoryDefaultAgentBool){ // 当前空间不存在
continue;
}
// 默认工厂子类
array_unshift($arguments, $name); // 将$name作为第一个参数
$name = static::$factoryDefaultName;
$factoryDefaultAgentBool = true;
goto agent;
}
yield [
2,
$name, $arguments,
$itemNamespaceArr,
$classNamespace,
];
break;
}
}
/**
* 1、子类可以有handle公有方法实现实例化后传参
* 2、调用的方法带有Instance则为单例
* 3、不存在的时候就返回false
*
* @param $name
* @param $arguments
* @return bool|object
*/
public static function __callStatic($name, $arguments)
{
$result = false;
$instanceBool = static::$autoInstance;
$oldName = $name;
// 处理存储方式
$saveCallType = isset(static::$saveCallType[$name]) ? static::$saveCallType[$name] :
(isset(static::$saveCallType['*']) ? static::$saveCallType['*'] : false);
$saveArr = static::getSaveCall(null); // 存储的数据
if ($instanceBool || strrpos($name, 'Instance') !== false) { // 单例
$instanceBool = true;
$name = str_replace('Instance', '', $name);
// 获取已保存的
foreach ($saveArr as $itemObjectKey => $itemObject) {
if ($saveCallType === 1){
if ($oldName === $itemObjectKey) {
return $itemObject;
}
}else if($saveCallType === 2){ // 基于根名
foreach ($itemObject as $itemKey => $item) {
if ($itemKey === $oldName) {
return $item;
}
}
}else if($saveCallType === 3){ // 基于方法名 + 实例化时第一个参数,同名覆盖
if ($itemObjectKey === $oldName) { // 相同方法名
foreach ($itemObject as $itemKey => $item) {
$tempFirst = $arguments ? current($arguments) : 0;
$tempFirst = is_bool($tempFirst) ? ($tempFirst ? 'true' : 'false') : $tempFirst;
if ($itemKey === $tempFirst) {
return $item;
}
}
}
}
}
}else if(
$saveCallType === 3 && isset($saveArr[$oldName]) && isset($saveArr[$oldName][current($arguments)])
){ // 基于实例化时第一个参数,同名覆盖,自带单例
return $saveArr[$oldName][current($arguments)];
}
foreach (static::factoryCallEachYieldPro($name, $arguments) as list($type, $name, $arguments, $itemNamespaceArr, $classNamespace)) {
if ($type == 1){ // 直接return的
return $name;
}
$args = isset(static::$factoryConstructArg[$name]) ? static::$factoryConstructArg[$name] : [];
$args = array_merge(isset(static::$factoryConstructArg['*']) ? static::$factoryConstructArg['*'] : [], $args);
if (method_exists($classNamespace, 'handle')) {
/** @var object $object */
$object = new $classNamespace(...$args);
$result = $object->handle(...$arguments);
}else{
/** @var object $object */
$object = new $classNamespace(...array_merge($args, $arguments));
$result = $object;
}
if ($saveCallType === 1){ // 每个都保存
if ($instanceBool){ // 单例
$saveArr[$oldName] = $result; // 单例的有key名
}else{
$saveArr[] = $result; // 非单例则是数字key
}
}else if($saveCallType === 2){ // 基于根名
if ($instanceBool){ // 单例
$saveArr[$itemNamespaceArr['rootNamespace']][$oldName] = $result;
}else{
$saveArr[$itemNamespaceArr['rootNamespace']][] = $result;
}
}else if($saveCallType === 3){ // 基于方法名 + 实例化时第一个参数,同名覆盖
// 第一个参数是false的时候存储的key为0
$tempFirst = $arguments ? current($arguments) : 0;
$tempFirst = is_bool($tempFirst) ? ($tempFirst ? 'true' : 'false') : $tempFirst;
$saveArr[$oldName][$tempFirst] = $result; // 后缀是否Instance,会导致不同
}
break;
}
return $result;
}
}
<?php
/**
* Created by PhpStorm.
* User: aozhuochao
* Date: 2020-02-24
* Time: 16:43
*/
namespace app\helpers\traits;
/**
* 工厂trait,命名空间版
* 不自带静态调用
*
* 例子:
$this->pushRootNamespaceOnCurrent('grids');
$this->setFactorySuffix('grid');
$this->setFactoryConstructArg('*', [$this]);
$this->setSaveCallType(1);
$this->setFactoryDefault('test');
*/
trait FactoryNamespaceTrait
{
/**
* 根命名空间
*
* @var array
*/
protected $rootNamespaceList = [];
/**
* 类别名
*
* @var array
*/
protected static $classAliasStaticArr = [];
/**
* 工厂子类的构造函数的参数
*
* 如:$this->setFactoryConstructArg('*', [$this]);
*
* @var array
*/
protected $factoryConstructArg = [];
/**
* 全局后缀
*
* @var string
*/
protected $factorySuffix = '';
/**
* 全局工厂默认子类
*
* @var string
*/
protected $factoryDefaultName = '';
/**
* 保存的call的数据
*
* @var array|object[]
*/
protected $saveCallArr = [];
/**
* 保存call的类型
*
* @var int
*/
protected $saveCallType;
/**
* 自动单例
* 如果有后缀instance,则会又多一个
*
* @var bool
*/
protected $autoInstance = false;
/**
* @param $rootNamespace
*/
public function pushRootNamespace($rootNamespace)
{
/** @noinspection PhpUndefinedFieldInspection */
$this->rootNamespaceList[] = $rootNamespace;
}
/**
* 设置相对当前类的相对命名空间
*
* @param string $rootNamespace
* @param null|string $currentClass
* @param string $classSuffix
*/
public function pushRootNamespaceOnCurrent($rootNamespace = '', $currentClass = null, $classSuffix = '')
{
$tempRootNamespace = ltrim($rootNamespace, '\\');
$staticClassName = '\\' . (isset($currentClass) ? $currentClass : static::class);
if ($pos = strrpos($staticClassName, '\\')){
$staticClassName = substr($staticClassName, 0, $pos + 1);
}
$staticClassName = rtrim($staticClassName, '\\');
/** @noinspection PhpUndefinedFieldInspection */
$this->rootNamespaceList[] = [
'rootNamespace' => $rootNamespace,
'classNamespace' => $tempRootNamespace ? $staticClassName . '\\' . $tempRootNamespace : $staticClassName,
'classSuffix' => $classSuffix
];
}
/**
* @param $name
* @param array $factoryConstructArg
*/
public function setFactoryConstructArg($name, array $factoryConstructArg)
{
$this->factoryConstructArg[$name] = $factoryConstructArg;
}
/**
* 1、每个都保存
* 2、基于根名
* 3、基于方法名 + 实例化时第一个参数,同名覆盖
*
* @param $type
* @param string $method 特定方法名
*/
public function setSaveCallType($type, $method = '*')
{
$this->saveCallType[$method] = $type;
}
/**
* 获取存储的数据
*
* @param null $key
* @return array
*/
protected function getSaveCall($key = null)
{
$saveArr = $this->saveCallArr;
if (!isset($key)) { // null返回所有
return $saveArr;
}else if (!isset($saveArr[$key])){ // 不存在就返回空数组
return [];
}
return $saveArr[$key];
}
/**
* @param string $factorySuffix
*/
public function setFactorySuffix(string $factorySuffix)
{
$this->factorySuffix = $factorySuffix;
}
/**
* @param string $factoryDefaultName
*/
public function setFactoryDefaultName(string $factoryDefaultName)
{
$this->factoryDefaultName = $factoryDefaultName;
}
/**
* @param bool $autoInstance
*/
public function setAutoInstance(bool $autoInstance = true)
{
$this->autoInstance = $autoInstance;
}
/**
* 设置替换的别名
*
* @param $alias
* @param string|object $class
*/
public static function setClassAliasStatic($alias, $class)
{
static::$classAliasStaticArr['\\' . ltrim($alias, '\\')] = $class;
}
/**
* 循环处理配置
*
* @param $name
* @param $arguments
* @return \Generator
*/
protected function factoryCallEachYieldPro($name, $arguments)
{
foreach ($this->rootNamespaceList as $itemNamespaceArr) {
$factoryDefaultAgentBool = false;
agent:;
$classNamespace = $itemNamespaceArr['classNamespace'] . '\\' . ucfirst($name);
// 处理后缀
$classNamespace .= ucfirst(
!empty($itemNamespaceArr['classSuffix']) ? $itemNamespaceArr['classSuffix'] :
($this->factorySuffix?:'')
);
if(isset(static::$classAliasStaticArr[$classNamespace])){
if (is_object(static::$classAliasStaticArr[$classNamespace])) { // 指定实例化的类
yield [
1,
static::$classAliasStaticArr[$classNamespace]
];
}else{ // 指定类别名
$classNamespace = static::$classAliasStaticArr[$classNamespace];
}
}
if (!class_exists($classNamespace)) {
if (empty($this->factoryDefaultName) || $factoryDefaultAgentBool){ // 当前空间不存在
continue;
}
// 默认工厂子类
array_unshift($arguments, $name); // 将$name作为第一个参数
$name = $this->factoryDefaultName;
$factoryDefaultAgentBool = true;
goto agent;
}
yield [
2,
$name, $arguments,
$itemNamespaceArr,
$classNamespace,
];
break;
}
}
/**
* 1、子类可以有handle公有方法实现实例化后传参
* 2、调用的方法带有Instance则为单例
* 3、不存在的时候就返回false
*
* @param $name
* @param $arguments
* @return bool|object
*/
public function __call($name, $arguments)
{
$result = false;
$instanceBool = $this->autoInstance;
$oldName = $name;
// 处理存储方式
$saveCallType = isset($this->saveCallType[$name]) ? $this->saveCallType[$name] :
(isset($this->saveCallType['*']) ? $this->saveCallType['*'] : false);
$saveArr = $this->getSaveCall(null); // 存储的数据
if ($instanceBool || strrpos($name, 'Instance') !== false) { // 单例
$instanceBool = true;
$name = str_replace('Instance', '', $name);
// 获取已保存的
foreach ($saveArr as $itemObjectKey => $itemObject) {
if ($saveCallType === 1){
if ($oldName === $itemObjectKey) {
return $itemObject;
}
}else if($saveCallType === 2){ // 基于根名
foreach ($itemObject as $itemKey => $item) {
if ($itemKey === $oldName) {
return $item;
}
}
}else if($saveCallType === 3){ // 基于方法名 + 实例化时第一个参数,同名覆盖
if ($itemObjectKey === $oldName) { // 相同方法名
foreach ($itemObject as $itemKey => $item) {
$tempFirst = $arguments ? current($arguments) : 0;
$tempFirst = is_bool($tempFirst) ? ($tempFirst ? 'true' : 'false') : $tempFirst;
if ($itemKey === $tempFirst) {
return $item;
}
}
}
}
}
}else if(
$saveCallType === 3 && isset($saveArr[$oldName]) && isset($saveArr[$oldName][current($arguments)])
){ // 基于实例化时第一个参数,同名覆盖,自带单例
return $saveArr[$oldName][current($arguments)];
}
foreach ($this->factoryCallEachYieldPro($name, $arguments) as list($type, $name, $arguments, $itemNamespaceArr, $classNamespace)) {
if ($type == 1){ // 直接return的
return $name;
}
$args = isset($this->factoryConstructArg[$name]) ? $this->factoryConstructArg[$name] : [];
$args = array_merge(isset($this->factoryConstructArg['*']) ? $this->factoryConstructArg['*'] : [], $args);
if (method_exists($classNamespace, 'handle')) {
/** @var object $object */
$object = new $classNamespace(...$args);
$result = $object->handle(...$arguments);
}else{
/** @var object $object */
$object = new $classNamespace(...array_merge($args, $arguments));
$result = $object;
}
if ($saveCallType === 1){ // 每个都保存
if ($instanceBool){ // 单例
$this->saveCallArr[$oldName] = $result; // 单例的有key名
}else{
$this->saveCallArr[] = $result; // 非单例则是数字key
}
}else if($saveCallType === 2){ // 基于根名
if ($instanceBool){ // 单例
$this->saveCallArr[$itemNamespaceArr['rootNamespace']][$oldName] = $result;
}else{
$this->saveCallArr[$itemNamespaceArr['rootNamespace']][] = $result;
}
}else if($saveCallType === 3){ // 基于方法名 + 实例化时第一个参数,同名覆盖
// 第一个参数是false的时候存储的key为0
$tempFirst = $arguments ? current($arguments) : 0;
$tempFirst = is_bool($tempFirst) ? ($tempFirst ? 'true' : 'false') : $tempFirst;
$this->saveCallArr[$oldName][$tempFirst] = $result; // 后缀是否Instance,会导致不同
}
break;
}
return $result;
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2018-12-15
* Time: 16:24
*/
namespace App\Repositories\Common;
/**
* 方法中间件
*
* Class FuncMiddleware
* @package App\Repositories\Common
*/
class FuncMiddleware
{
use Traits\Singleton;
/**
*
* @var array
*/
protected $map = [];
/**
* 调用
*
* FuncMiddleware::instance()->call('updateByIdTrait.create', function ($data)use($modelClass, $id){
* //@ var Model $modelData
* return $modelClass->create($data);
* }, $data);
*
* @param $name
* @param $func
* @param mixed ...$content
* @return mixed
*/
public function call($name, $func, ...$content)
{
$data = new \ArrayIterator(array_get($this->map, $name) ?? []);
$handle = function (...$content)use(&$data, $func, &$handle){
$cFunc = $data->current();
$data->next();
if (!is_callable($cFunc) || $data->valid()){
return $func(...$content);
}
return $cFunc($handle, ...$content);
};
return $handle(...$content);
}
/**
* 设置同名的中间件
*
* @param $name
* @param $func
* @return $this
*/
public function setCall($name, $func)
{
if (!isset($this->map[$name])) {
$this->map[$name] = [];
}
$this->map[$name][] = $func;
return $this;
}
}
<?php
namespace app\common\model\traits\common;
class GetClassSave
{
/**
* @var \think\model
*/
protected $model;
protected $fieldEmptyUpdate = []; // 字段空的时候更新
protected $dataEmptyUpdate = []; // 整个数据空的时候更新
protected $save = []; // 需要保存的数据
protected $where = []; // 普通where条件
protected $updateWhere = []; // 更新时才执行的where条件
protected $diffUpdateBool = false; // 有差异才更新
/**
* GetSaveClass constructor.
*/
public function __construct($model)
{
$this->model = $model;
}
public function saveDiff($where = [], $save = [])
{
return $this->setDiffUpdateBool(true)->save();
}
/**
* 新增或更新
*
* @param array $where
* @param array $save
* @return mixed
*/
public function save($where = [], $save = [])
{
$where = array_merge($this->where, $where);
$save = array_merge($this->save, $save);
$class = get_class($this->model);
$model = new $class;
if (!empty($where)) {
$data = $model->where($where)->find();
}
if (empty($data)) { // 创建
foreach ($this->fieldEmptyUpdate as $field => $item) {
$save[$field] = $this->getTrueValue($item);
}
foreach ($this->dataEmptyUpdate as $field => $item) {
$save[$field] = $this->getTrueValue($item);
}
$save = array_merge($where, $save);
if (method_exists($model, 'getPk')) {
unset($save[$model->getPk()]);
}
$modelData = $model->create($save);
}else{ // 更新
if ($this->diffUpdateBool) {
foreach ($save as $field => $item) {
if (!array_key_exists($field, $data)) {
continue;
}
if ($data[$field] === $item) { // 去除无差异的
unset($save[$field]);
}
}
}
foreach ($this->fieldEmptyUpdate as $field => $item) {
if (empty($data[$field])) { // 覆盖掉
$save[$field] = $this->getTrueValue($item, $data);
}
}
if ($save) {
$modelData = $model->where(array_merge($where, $this->updateWhere))->update($save);
}else{
$modelData = $data;
}
}
return $modelData;
}
/**
* @param array $fieldEmptyUpdate
* @return $this
*/
public function setFieldEmptyUpdate(array $fieldEmptyUpdate)
{
$this->fieldEmptyUpdate = $fieldEmptyUpdate;
return $this;
}
/**
* @param array $dataEmptyUpdate
* @return $this
*/
public function setDataEmptyUpdate(array $dataEmptyUpdate)
{
$this->dataEmptyUpdate = $dataEmptyUpdate;
return $this;
}
/**
* @param array $updateWhere
* @return $this
*/
public function setUpdateWhere(array $updateWhere)
{
$this->updateWhere = $updateWhere;
return $this;
}
/**
* @param array $where
* @return $this
*/
public function setWhere(array $where)
{
$this->where = $where;
return $this;
}
/**
* @param array $save
* @return $this
*/
public function setSave(array $save)
{
$this->save = $save;
return $this;
}
/**
* @param bool $diffUpdateBool
* @return $this
*/
public function setDiffUpdateBool(bool $diffUpdateBool)
{
$this->diffUpdateBool = $diffUpdateBool;
return $this;
}
protected function getTrueValue($value, $data = null)
{
if (is_callable($value)) {
return call_user_func($value, $data);
}
return $value;
}
}
/**
* 获取修改和新增同时判断的类
*/
trait GetClassSaveTrait
{
public function getCLassSave()
{
return new GetClassSave($this);
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2018/4/12
* Time: 下午8:24
*/
namespace App\Repositories\Common;
/**
* MaxJoin
*
* @since 2018/4/13
* @package App\Repositories\Common
*/
class MaxJoin
{
const MAX_GET_LIMIT = 1000;
/**
* 返回数据的第几页
*
* @var int
*/
protected $page;
/**
* 返回数据个数
*
* @var int
*/
protected $limit;
/**
* 最大获取量
*
* @var int
*/
protected $maxGet;
/**
* 默认空的返回值
*
* @var mixed
*/
protected $defaultReturn = [];
/**
* 先一次获取所有uid($mainFunc),
* 再将uid分页返回($fromFunc)
*
*
$data = (new MaxJoin())->setForPage($page, 20)->get(function ($maxGet) use ($uid) {
return GuessInvites::instance()->getCacheLimitList($uid, $maxGet);
}, 'uid', [$this,'getLastBonusTopPro']);
*
* MaxJoin constructor.
* @param int $page
* @param int $limit
* @param int $maxGet
*/
public function __construct($page = 1, $limit = 20, $maxGet = self::MAX_GET_LIMIT)
{
$this->page = $page;
$this->limit = $limit;
$this->maxGet = $maxGet;
}
/**
* 解决有限大小的分页数据,让其分表查询
* 将$mainFunc返回的数据通过指定的key($onKey)传参给$fromFunc并返回最终数据
*
* @param callable $mainFunc 一次获取的数据
* @param string $onKey
* @param callable $fromFunc 根据分页和$onKey获取数据
* @return array
*/
public function get(callable $mainFunc, $onKey, callable $fromFunc)
{
$mainData = $mainFunc($this->maxGet);
$onData = [];
foreach ($mainData as $item) {
if (isset($item[$onKey])) {
$onData[] = $item[$onKey];
}
}
if (!empty($onData)) {
return $fromFunc($onData, $this->page, $this->limit);
}
return [];
}
public function setForPage($page, $limit = null)
{
if (!empty($page)) {
$this->page = $page;
}
if (!empty($limit)) {
$this->limit = $limit;
}
return $this;
}
/**
* @param int $maxGet
* @return $this
*/
public function setMaxGet($maxGet)
{
$this->maxGet = $maxGet;
return $this;
}
/**
* @param mixed $defaultReturn
* @return $this
*/
public function setDefaultReturn($defaultReturn)
{
$this->defaultReturn = $defaultReturn;
return $this;
}
}
<?php
namespace app\common\library\traits;
class NextNotThrow{
/**
* @var NextNotThrowTrait
*/
protected $that;
protected $errorFunc;
protected $errorReturnString;
public function __construct($that, $errorFunc, $errorReturnString = false)
{
$this->that = $that;
$this->errorFunc = $errorFunc;
$this->errorReturnString = $errorReturnString;
}
public function __call($name, $args)
{
$this->that->setNextNotThrowException(null);
try{
return call_user_func_array([$this->that, $name], $args);
}catch (\Exception | \Throwable $exception){
writeLogs([
'NextNotThrow',
'args' => [$name, $args],
'$exception' => get_sys_human_debug_backtrace($exception),
], 'NextNotThrow--' . basename(str_replace('\\', '/', get_class($this->that))));
$this->that->setNextNotThrowException($exception);
if (is_callable($this->errorFunc)) {
return call_user_func($this->errorFunc, $exception);
}else if ($this->errorReturnString){
return $exception->getMessage();
}
}
return $this->that;
}
}
/**
*
* 使用示例
* @example
$payClass = \app\common\pay\PayFactory::makeByPayment($payment);
$weiXinOrderData = $payClass->nextNotThrow()->findOrder(
$order->out_trade_no
);
if ($payClass->getNextNotThrowException()) {
}
*
*
*/
trait NextNotThrowTrait
{
protected $nextNotThrowException;
/**
* 报错就返回当前对象
*
* @param callable|null $errorFunc
* @return $this|NextNotThrow
*/
public function nextNotThrow(callable $errorFunc = null)
{
return new NextNotThrow($this, $errorFunc);
}
/**
* 报错就返回错误字符串
*
* @param callable|null $errorFunc
* @return $this|NextNotThrow
*/
public function nextNotThrowReturnString(callable $errorFunc = null)
{
return new NextNotThrow($this, $errorFunc, true);
}
/**
* @param mixed $nextNotThrowException
* @return $this
*/
public function setNextNotThrowException($nextNotThrowException)
{
$this->nextNotThrowException = $nextNotThrowException;
return $this;
}
/**
* @return \Exception
*/
public function getNextNotThrowException()
{
return $this->nextNotThrowException;
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2019-01-09
* Time: 14:25
*/
namespace App\Repositories\Common;
/**
* 代理实例化的类
*
* 如果当前类存在方法或属性就直接使用
*/
class ProxyInstanceClass
{
/**
* @var []object
*/
protected $classes = [];
public function __construct(...$classes)
{
$this->classes = $classes;
}
/**
* Dynamically handle calls to the class.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \Exception
*/
public function __call($method, $parameters)
{
foreach ($this->classes as $class) {
if (method_exists($class, $method)) {
// 可通过spl实现调用下一个方法
return call_user_func_array([$class, $method], $parameters);
}
}
throw new \Exception("ProxyInstanceClass代理了不存在的方法{$method}");
}
public function __get($name)
{
foreach ($this->classes as $class) {
if (property_exists($class, $name)) {
return $class->{$name};
}
}
return null;
}
public function __set($name, $value)
{
foreach ($this->classes as $class) {
if (property_exists($class, $name)) {
$class->{$name} = $value;
}
}
}
}
<?php
/**
* User: aozhuochao
* Date: 2020/3/4
*/
namespace app\modules\api_docking;
use app\helpers\traits\Singleton;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\Exception\RequestException;
use Throwable;
class RequestApiLog
{
use Singleton;
protected $host = '';
/**
* 不同环境的地址,key根据env来
*
* @var array
*/
protected $hostArr = [];
/**
* 当前环境
* production 生产环境
* test 测试环境
*
* @var string
*/
protected $env = '';
/**
* 设置公共header
*
* @var array
*/
protected $commonHeaders = [];
/**
* 什么项目接口
* 不同子类
*
* @var int
*/
protected $type = 1;
/**
* 保存日志的方式
* 如:TPModel
*
* @var string
*/
protected $saveLogType = '';
/**
* 保存额外数据
*
* @var array
*/
protected $onceHandleSaveValueArr = [];
/**
* 保存日志数据的insert时的id
*
* @var int|null
*/
private $saveLogInsertId = null;
/**
* 调试用数据
*
* @var array
*/
protected $debugData = [];
/**
* 最后一个请求返回的结果
*
* @var array
*/
protected $lastResult = [];
/**
* VanKeRepository constructor.
*/
public function __construct()
{
$this->host = !empty($this->hostArr[$this->env]) ? $this->hostArr[$this->env] : '';
}
/**
* 设置保存额外数据的回调函数
*
* @example
$this->setOnceOfHandleSaveValue('token', 'json.body.appAccessToken', function ($createData, $json){
return $this->isSuccess($json);
});
*
* @param string $key 要保存的key
* @param string|callable $func save_value_json要保存的值
* @param int|string|callable $status save_value_status的值
* @return $this
*/
public function setOnceOfHandleSaveValue($key, $func, $status = 1)
{
$this->onceHandleSaveValueArr[] = [$key, $func, $status];
return $this;
}
/**
* 获取最后保存的save_value_json的值
* false就是数据不存在
*
* @param $saveKey
* @param null $status
* @param null $gtCreatedTime 限制创建时间
* @return mixed
*/
public function getLastSaveValue($saveKey, $status = null, $gtCreatedTime = null)
{
return $this->execBySaveLogType('getLastSaveValueOf', [$saveKey, $status, $gtCreatedTime]);
}
/**
* 检测去重,回调时使用
* 返回true则代表没有,false则有多次
*
* @param $path
* @param $name
* @param $json
* @param $save_key
* @param $checkSaveValue
* @return bool
*/
public function checkSaveOnce($path, $name, $json, $save_key, $checkSaveValue)
{
return $this->execBySaveLogType('checkSaveOnceOf', [$path, $name, $json, $save_key, $checkSaveValue]);
}
/**
* 上一个保存的日志的status改为2
*
* @param int $status
* @return $this
*/
public function failLog($status = 2)
{
return $this->execBySaveLogType('failLogOf', [$status]);
}
/**
* 用匿名函数的方式实现订单去重判断
*
* @param callable $func
* @param mixed $json 回调所有数据
* @param mixed $uniqueValue 检测这个值是否重复
* @param string $name 当前回调名称
* @param string $path api_log的path
* @param string $saveKeyPrefix save_key字段的前缀,会拼接$uniqueValue
* @return mixed|null
*/
public function checkNotifyUnique($func, $json, $uniqueValue, $name = '回调', $path = 'notify', $saveKeyPrefix = 'notify-')
{
return $this->execBySaveLogType('checkNotifyUniqueOf', func_get_args());
}
/**
* @return array
*/
public function getLastResult()
{
return $this->lastResult;
}
/**
* @return int
*/
public function getSaveLogInsertId()
{
$this->saveLogOfTPModelCreate([], true);
return $this->saveLogInsertId;
}
/**
* @param mixed $debugData
* @return $this
*/
public function setDebugData($debugData)
{
$this->debugData = $debugData;
return $this;
}
public function setDebugDataByPath($path, $debugData)
{
$this->debugData[$path] = $debugData;
return $this;
}
/**
* @param array $commonHeaders
* @return $this
*/
public function setCommonHeaders(array $commonHeaders)
{
$this->commonHeaders = $commonHeaders;
return $this;
}
public function removeCommonHeader($key)
{
unset($this->commonHeaders[$key]);
return $this;
}
public function setCommonHeader($key, $value)
{
$this->commonHeaders[$key] = $value;
return $this;
}
/**
* @return array
*/
public function getCommonHeaders()
{
return $this->commonHeaders;
}
public function setHeaderForm($charset = 'utf-8')
{
$this->setCommonHeader('Content-Type', "application/x-www-form-urlencoded; charset={$charset}");
return $this;
}
public function setHeaderAuthorization($token, $tokenType = 'Bearer')
{
$this->setCommonHeader('Authorization', "{$tokenType} {$token}");
return $this;
}
/**
* 建表语句
*
* @example
class ApiLogModel extends BaseModel
{
protected $name = 'api_log';
protected $autoWriteTimestamp = true;
protected $json = ['json', 'save_value_json'];
}
*
* @see 留意表前缀
* @return string
*/
private function apiLogTableSql()
{
return <<<SQL
CREATE TABLE `api_log` (
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`type` varchar(32) NOT NULL DEFAULT '' COMMENT '种类',
`path` varchar(255) NOT NULL DEFAULT '' COMMENT '地址',
`name` varchar(255) NOT NULL DEFAULT '' COMMENT '接口意义',
`diff_time` decimal(11,4) unsigned NOT NULL DEFAULT '0' COMMENT '花费时间',
`json` json DEFAULT NULL COMMENT '数据',
`save_key` varchar(255) NOT NULL DEFAULT '' COMMENT '需要额外存储的数据的key',
`save_value_json` json COMMENT '需要额外存储的数据',
`save_value_status` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '需要额外存储的数据的有效期,1是有效,2为无效',
`created_time` datetime DEFAULT NULL,
`updated_time` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='~~api日志';
SQL;
}
protected function handleSaveValue($createData)
{
if (!empty($this->onceHandleSaveValueArr)) {
foreach ($this->onceHandleSaveValueArr as $key => list($saveKey, $item, $status)) {
$createData['save_key'] = $saveKey;
$temp = $createData;
if (is_string($item) || is_string($status)) { // 字符串模式下, 转为json
$temp['json']['body'] = !empty($createData['json']) && !empty($createData['json']['body']) ? (@json_decode($createData['json']['body'], true) ?: []) : [];
}
if (is_string($item)) { // 字符串
$createData['save_value_json'] = json_encode($this->getDataByKey($temp, $item) ?: '');
}else if(is_callable($item)){
$createData['save_value_json'] = json_encode(call_user_func($item, $createData, $temp['json']['body']) ?: '');
}
if (is_scalar($status)) { // 字符串
$createData['save_value_status'] = $this->getDataByKey($temp, $status)?:$status;
}else if(is_callable($status)){
$createData['save_value_status'] = call_user_func($status, $createData, $temp['json']['body']);
}
unset($this->onceHandleSaveValueArr[$key]);
}
}
return $createData;
}
protected function getDataByKeyOfTPModel($data, $key)
{
return \think\helper\Arr::get($data, $key);
}
protected function getDataByKey($data, $key)
{
return $this->execBySaveLogType('getDataByKeyOf', [$data, $key]);
}
protected function failLogOfTPModel($status = 2)
{
$model = new ApiLogModel();
$model->update(['save_value_status' => $status], [$model->getPk() => $this->getSaveLogInsertId()]);
return $this;
}
protected function saveLogOfTPModelCreate($createData, $force = false)
{
static $func = null,
$createDataExecBoolArr = [];
$tp6Bool = class_exists(\think\facade\Event::class);
if (is_null($func)){
$func = (function ($saveExecBool = false)use($createData, $tp6Bool, $force, &$func, &$createDataExecBoolArr){
if ($tp6Bool) {
/** @var mixed $createData */
$tempKey = md5(json_encode($createData));
if (!empty($createDataExecBoolArr[$tempKey])) { // 已经执行过
$func = null;
return;
}
if ($saveExecBool){ // 记录当前执行过
$createDataExecBoolArr[$tempKey] = 1;
}
}
$model = ApiLogModel::create($createData);
if ($tp6Bool && !$force) { // 有些时候不提交
\think\facade\Db::commit();
}
$this->saveLogInsertId = $model['id']??0;
$func = null;
})->bindTo($this);
}
if ($force) {
if (is_null($this->saveLogInsertId) && is_callable($func)) { // 执行最后一个
$func(true);
$func = null;
}
return;
}
// 保存
if ($tp6Bool) {
\think\facade\Event::listen('HttpEnd', clone $func);
}else{
$func();
}
$func = null;
return;
}
protected function checkSaveOnceOfTPModel($path, $name, $json, $save_key, $checkSaveValue)
{
$bool = true;
if (ApiLogModel::where('path', $path)->where('type', $this->type)
->where('save_key', $save_key)->where('save_value_status', 1)
->where('save_value_json', $checkSaveValue)->value('id')) { // 存在
$bool = false;
}
$this->setOnceOfHandleSaveValue($save_key, function () use ($checkSaveValue) {
return $checkSaveValue;
}, $bool ? 1 : 2);
$this->saveLog($path, $name, $json);
$this->getSaveLogInsertId();
return $bool;
}
protected function checkNotifyUniqueOfTPModel($func, $json, $uniqueValue, $name = '回调', $path = 'notify', $saveKeyPrefix = 'notify-')
{
$save_key = $saveKeyPrefix . $uniqueValue;
$result = false;
$time = microtime(true);
try{
$bool = 1;
if (ApiLogModel::where('path', $path)->where('type', $this->type)
->where('save_key', $save_key)->where('save_value_status', 1)
->where('save_value_json', $uniqueValue)->value('id')) { // 存在
$bool = 2;
}
if ($bool === 1){ // 首次
$this->setOnceOfHandleSaveValue($save_key, function () use ($uniqueValue) {
return $uniqueValue;
}, 1);
$this->saveLog($path, $name, ['body' => $json], microtime(true) - $time, true);
$bool = 3;
// 执行业务代码
$result = call_user_func($func, $json);
if ($result !== true) { // 回调出错
$this->failLog();
}
}
}catch (Exception $exception){
$bool = 2;
}catch (Throwable $exception){
$bool = 2;
}
if ($bool === 2){ // 没有成功
\think\facade\Log::error('回调重复执行: ' . $name . var_export(['json' => $json, 'path' => $path], true));
$this->setOnceOfHandleSaveValue($save_key, function () use ($uniqueValue) {
return $uniqueValue;
}, 2);
$this->saveLog($path, $name, ['body' => $json], microtime(true) - $time, true);
}
return $result;
}
/**
* TP获取最后保存的save_value_json
*
* @param $saveKey
* @param null $status
* @param null $gtCreatedTime
* @return mixed
* @throws \think\db\exception\DataNotFoundException
* @throws \think\db\exception\DbException
* @throws \think\db\exception\ModelNotFoundException
*/
protected function getLastSaveValueOfTPModel($saveKey, $status = null, $gtCreatedTime = null)
{
$query = ApiLogModel::where('type', $this->type)->where('save_key', $saveKey)
->order('id', 'desc')->limit(1);
if (isset($status)) {
$query = $query->where('save_value_status', $status);
}
if (isset($gtCreatedTime)) {
$query = $query->where('created_time', '>', $gtCreatedTime);
}
$data = $query->field('save_value_json')->find();
return $data ? $data['save_value_json'] : false;
}
/**
* TP的保存请求日志的方式
*
* @param $path
* @param $name
* @param $json
* @param int $diffTime
* @param bool $forceSave 强制保存
*/
protected function saveLogOfTPModel($path, $name, $json, $diffTime = 0, $forceSave = false)
{
$createData = [
'type' => $this->type,
'path' => $path,
'name' => $name,
'diff_time' => empty($diffTime) && !empty($json['diffTime']) ? $json['diffTime'] : $diffTime,
'json' => $json,
'created_time' => date('Y-m-d H:i:s'),
'updated_time' => date('Y-m-d H:i:s'),
];
$createData = $this->handleSaveValue($createData);
unset($createData['json']['response']);
// 保存
$this->saveLogOfTPModelCreate($createData, $forceSave);
}
protected function saveLog($path, $name, $json, $diffTime = 0, $forceSave = false)
{
$this->execBySaveLogType('saveLogOf', [$path, $name, $json, $diffTime, $forceSave]);
}
/**
* 根据定义的类型,执行特定类型的方法
* 最好后面有个Of
*
* @param $prefix
* @param $args
* @return mixed|null
*/
protected function execBySaveLogType($prefix, $args)
{
if (empty($this->saveLogType)) {
return null;
}
if (is_string($this->saveLogType)){
if (method_exists($this, $prefix . $this->saveLogType)){
return $this->{$prefix . $this->saveLogType}(...$args);
}
}
}
/**
* 发送数据返回json数据
*
* @param $name
* @param $method
* @param $path
* @param array $query
* @param array $moreOption
* @return mixed
*/
protected function sendOfJson($name, $method, $path, $query = [], $moreOption = [])
{
$result = $this->send($name, $method, $path, $query, $moreOption);
if (!empty($result['body']) && is_string($result['body'])) {
$result['body'] = json_decode($result['body'], true);
}
return $result['body'];
}
protected function send($name, $method, $path, $query = [], $moreOption = [])
{
// 清除数据
$this->saveLogInsertId = null;
// 正式代码
$startTime = microtime(true);
$error = $response = null;
if (empty($this->host) && empty($this->debugData)) { // 没有环境
$result = [
'query' => '',
'body' => '',
'response' => $response,
'diffTime' => 0,
'http_error' => $error,
];
return $result;
}else if (!empty($this->debugData) && !empty($this->debugData[$path])){
$body = $this->debugData[$path];
goto result;
}
$client = new Client();
try{
$tempMethod = strtolower($method);
if ($tempMethod === 'post') {
$options = [
'form_params' => $query
];
} else if ($tempMethod === 'post-json'){ // 发送json格式的请求,并且是post
$method = 'post';
$options = [
'json' => $query
];
}else {
$options = [
'query' => $query
];
}
if (isset($moreOption['body'])) { // 指定了body就不要传其他参数
unset($options['form_params'], $options['json']);
}
if (!empty($this->getCommonHeaders())) {
$options['headers'] = $this->getCommonHeaders();
}
$options = array_merge($options, $moreOption);
$response = $client->request(
$method,
$this->host . $path,
$options
);
}catch (RequestException $exception){
$error = $exception;
} catch (GuzzleException $exception) {
$error = $exception;
}
$body = !isset($error) ? $response->getBody()->getContents() : '';
result:
$diffTime = microtime(true) - $startTime;
$this->lastResult = $result = [
'query' => isset($options)?$options:[],
'body' => $body,
'response' => $response, // @see \GuzzleHttp\Psr7\Response
'diffTime' => $diffTime,
'http_error' => $error,
];
$this->saveLog($path, $name, $result);
return $result;
}
}
<?php
/**
* Created by PhpStorm.
* User: code
* Date: 2019-01-09
* Time: 15:44
*/
namespace App\Repositories\Common\Traits;
/**
* 方法中途 保存错误信息
*/
trait SetErrorTrait
{
protected $errorMsgTrait = '';
/**
* 设置错误文案
*
* @param string $errorMsgTrait
* @return $this
*/
public function setErrorMsgTrait(string $errorMsgTrait)
{
$this->errorMsgTrait = $errorMsgTrait;
return $this;
}
/**
* 获取错误文案
*
* @return string
*/
public function getErrorMsgTrait(): string
{
return $this->errorMsgTrait;
}
/**
* 是否报错
*
* @return bool
*/
public function hasErrorMsgTrait()
{
return !empty($this->getErrorMsgTrait());
}
}
<?php
/**
* User: aozhuochao
*/
namespace App\Repositories\Common\Traits;
/**
* 单例类
*/
trait Singleton
{
protected static $instance = null;
/**
* 单例
*
* @param array $args
* @return static
*/
public static function instance(...$args)
{
$key = md5(var_export(['class' => static::class, 'args' => $args], true));
if (!isset(self::$instance[$key])){
self::$instance[$key] = new static(...$args);
}
return self::$instance[$key];
}
/**
* 实例化对象
*
* @param array ...$args
* @return static
*/
public static function instanceNew(...$args)
{
return new static(...$args);
}
/**
* 设置默认实例化对象
*
* @param $object
* @return mixed
*/
public static function instanceSetDefault($object)
{
$key = md5(var_export(['class' => static::class, 'args' => []], true));
return self::$instance[$key] = $object;
}
/**
* 默认实例化对象
*
* @param array $args
* @return mixed
*/
public static function instanceDefault(...$args)
{
return static::instanceSetDefault(static::instance(...$args));
}
/**
* 实例化对象通过传入的对象进行保存
*
* @param object $callObject 保存单例的对象
* @param mixed ...$args
* @return static
*/
public static function instanceThis($callObject, ...$args)
{
$key = md5(var_export(['class' => static::class, 'args' => $args], true));
if (!property_exists($callObject, $key)) {
$instance = static::instanceNew(...$args);
$callObject->$key = $instance;
}
return $callObject->$key;
}
}
<?php
namespace App\Libs;
class Sms extends \Overtrue\EasySms\EasySms
{
use \App\Libs\Traits\Singleton;
protected $templateMap = [
];
/**
* Sms constructor.
*/
public function __construct(array $config = [])
{
$config = [
// HTTP 请求的超时时间(秒)
'timeout' => 5.0,
// 默认发送配置
'default' => [
// 网关调用策略,默认:顺序调用
'strategy' => \Overtrue\EasySms\Strategies\OrderStrategy::class,
// 默认可用的发送网关
'gateways' => [
'aliyun',
],
],
// 可用的网关配置
'gateways' => [
'errorlog' => [
'file' => app()->storagePath() . "/logs/easy-sms-".date('Ym').".log",
],
'aliyun' => [
'access_key_id' => env('ALIYUN_SMS_AK', ''),
'access_key_secret' => env('ALIYUN_SMS_AS', ''),
'sign_name' => env('ALIYUN_SMS_SIGN_NAME', ''), // 短信签名
],
//...
],
];
parent::__construct($config);
}
/**
* 根据定义的模板id发送短信
* 成功时返回true,失败返回错误文案
*
* @param $mobile
* @param $template_id
* @param array $data
* @return bool|string
* @throws \Overtrue\EasySms\Exceptions\InvalidArgumentException
*/
public static function sendByTemplateId($mobile, $template_id, $data = [])
{
try{
static::instance()->send($mobile, [
'content' => sprintf(static::instance()->getTemplateMap()[$template_id], $data),
'template' => $template_id,
'data' => $data,
]);
}catch (\Overtrue\EasySms\Exceptions\NoGatewayAvailableException $exception){
/** @var \Overtrue\EasySms\Exceptions\NoGatewayAvailableException $exception */
/** @var \Overtrue\EasySms\Exceptions\GatewayErrorException $last */
$last = $exception->getLastException();
return $last->getMessage();
}
return true;
}
/**
* @return array
*/
public function getTemplateMap(): array
{
return $this->templateMap;
}
}
<?php
namespace App\Repositories\Common;
/**
* [
* 'status' => [
* 2 => [
* 'title' => '关闭',
* '任意名1' => '<span class="red">{{title}}</span>',
* '任意名2' => function($val, $map){return $val;},
*
* ],
* ]
* ]
*
* @package helper
*/
class Tinyint
{
use Traits\Singleton;
/**
* 值对应的文案
*/
const TITLE = 'title';
/**
* 值对应数组的key
*/
const VALUE = 'value';
/**
* 唯一key,可以通过反向查找到value
*/
const KEY = 'key';
/**
* 值的下一个状态
*/
const NEXT = 'next';
protected $map = [];
/**
* 当前操作的field
*
* @var string
*/
protected $field = '';
/**
* 获取多个数据
*
* @example 一维数组key和value模式
* $model->getTinyint('cate_type')->getManyList([
* 'key' => Tinyint::VALUE,
* 'value' => Tinyint::TITLE,
* ])
*
* @example 二维数组模式
* $model->getTinyint('time_type')->getManyList([
* ['action' => Tinyint::VALUE, 'keyName' => 'key'],
* ['action' => Tinyint::TITLE, 'keyName' => 'value'],
* ])
*
* @example return 返回格式
* [
* {
* "key": 1,
* "value": "不推送"
* },
* {
* "key": 2,
* "value": "准时推送"
* }
* ]
*
* @param array $manyData
* @return array
*/
public function getManyList(array $manyData)
{
$result = [];
foreach ($this->getFieldMap() as $value => $fieldMap) {
$temp = [];
foreach ($manyData as $key => $manyDatum) {
if (is_scalar($manyDatum)){ // 一维数组
if ((int)$key === $key){ // 索引数组
$getAction=$manyDatum;
$getKeyName=null;
}else{ // 非索引
$getAction = $manyDatum;
$getKeyName =$key;
}
}else{ // 二维数组,指定返回的key名
$getAction = $manyDatum['action']; // 获取哪个action
$getKeyName = $manyDatum['keyName']; // 改名
}
$temp[$getKeyName ?? $getAction] = $this->get($value, '', $getAction);
}
$result[] = $temp;
}
return $result;
}
protected function handleActionValue($actionValue)
{
return $actionValue;
}
///////////////////上面是新的,不在通过参数传递field和map//////////////////////////////
/**
* 设置文案,可改变action改变场景
*
* @param string $field 字段名
* @param int $value 字段名对应的值
* @param mixed $data $action参数对应的值
* @param string $action 场景
* @return $this
*/
public function set($value, $data, $action = self::TITLE, $field = '')
{
$field = $this->getField($field);
if (isset($this->map[$field])) {
if (isset($this->map[$field][$value])) {
$this->map[$field][$value][$action] = $data;
}else{
$this->map[$field][$value] = [$action => $data];
}
}else{
$this->map[$field] = [
$value => [$action => $data],
];
}
return $this;
}
/**
* 获取设置的文案
*
* @param int $value 字段名对应的值
* @param string $default 最终为空时的默认值
* @param string $action 场景
* @param string $field 字段名
* @param null|array $map
* @return string
*/
public function get($value, $default = '', $action = self::TITLE, $field = '', $map = null)
{
$field = $this->getField($field);
$map = $this->getMap($map);
$result = null;
$bool = $this->existsValue($value, $field);
if ($bool && isset($map[$field][$value][$action])){
$result = $map[$field][$value][$action];
$data = $map[$field];
if (is_callable($result)) {
$result = $result($value, $data);
}else if (is_string($action) && is_string($result)){ // 可通过{{}}来获取到其他值
$result = preg_replace_callback('/{{([^_]+)}}/', function ($matches)use($value, $data){
return $this->replaceCallbackByGet($matches, $value, $data);
}, $result);
}
}else if ($bool && $action === self::VALUE){ // 获取值
$result = $value;
}
return isset($result) ? $result : $default;
}
/**
* 根据action 获取actionValue列表
*
* @param string $action
* @param string $key 指定返回值的key的值,默认为value
* @param string $field
* @param null $map
* @return array
*/
public function getList($action = self::TITLE, $key = self::VALUE, $field = '', $map = null)
{
$field = $this->getField($field);
$map = $this->getMap($map);
$result = [];
if (isset($map[$field]) && is_array($map[$field])){
foreach ($map[$field] as $value => $item) {
if (isset($item[$action])) {
$result[$this->get($value, '', $key, $field, $map)] = $this->get($value, '', $action, $field, $map);
}else if ($action === self::VALUE){ // 获取值
if (empty($key)){
$result[] = $value;
}else{
$result[$this->get($value, '', $key, $field, $map)] = $value;
}
}
}
}
return $result;
}
/**
* 获取所有value的列表
*
* @param string $field
* @param null $map
* @return array
*/
public function getValues($field = '', $map = null)
{
return $this->getList(self::VALUE, null, $field, $map);
}
/**
* 根据action 获取actionValue为true的列表,返回value
*
* @param string $action
* @param $field
* @param null $map
* @return array
*/
public function getListByActionValueTrue($action, $field = '', $map = null)
{
$field = $this->getField($field);
$map = $this->getMap($map);
$result = [];
if (isset($map[$field]) && is_array($map[$field])){
foreach ($map[$field] as $value => $item) {
if (isset($item[$action]) && $item[$action] === true) {
$result[] = $value;
}
}
}
return $result;
}
/**
* 不使用set,每次指定map
*
* @param array $data 对应$this->map
* @param array ...$args
* @return string
*/
public function getTemp(array $data, ...$args)
{
array_push($args, $data);
return call_user_func_array([$this, 'get'], $args);
}
/**
* get中的preg_replace_callback
*
* @param $matches
* @param $value
* @param $data
* @return string
*/
protected function replaceCallbackByGet($matches, $value, $data)
{
if (isset($data[$value][$matches[1]])) {
return $data[$value][$matches[1]];
}
return '';
}
public function setMap($map, $value = null)
{
if (is_null($value) && is_array($map)) {
$this->map = $map;
}else if(isset($value) && is_string($map)){
$this->map[$map] = $value;
}
return $this;
}
/**
* 获取值
*
* @param string $field
* @param null|array $map
* @return array|mixed
*/
public function getFieldMap($field = '', $map = null)
{
$map = $this->getMap($map);
$field = $this->getField($field);
return isset($map[$field]) ? $map[$field] : [];
}
public function getMap($map)
{
return $map ?: $this->map;
}
/**
* 检测field是否存在
*
* @param $field
* @return bool
*/
public function existsField($field)
{
if (empty($field)) {
return false;
}
return isset($this->map[$field]);
}
/**
* 检测值是否存在
*
* @param $field
* @param $value
* @return bool
*/
public function existsValue($value, $field = '')
{
$field = $this->getField($field);
return $this->existsField($field) && isset($this->map[$field][$value]);
}
/**
* 检测action里是否存在actionValue
*
* @param mixed $actionValue
* @param string $action
* @param string $field
* @param null $map
* @return bool
*/
public function existsActionValue($actionValue, $action, $field = '', $map = null)
{
$fieldData = $this->getFieldMap($this->getField($field), $this->getMap($map));
if (is_array($fieldData)){
foreach ($fieldData as $item) {
if (isset($item[$action]) && $item[$action] == $actionValue) {
return true;
}
}
}
return false;
}
/**
* 检测指定action是否被设置
*
* @param $field
* @param $action
* @return bool
*/
public function existsSetAction($action, $field = '')
{
$map = $this->getFieldMap($this->getField($field));
if (is_array($map)){
foreach ($map as $item) {
if (is_array($item) && isset($item[$action])) {
return true;
}
}
}
return false;
}
/**
* 判定对应action是否为true
*
* @param $field
* @param $value
* @param $action
* @return bool
*/
public function ifActionTrue($value, $action, $field = '')
{
$field = $this->getField($field);
return $this->existsValue($value, $field) && isset($this->map[$field][$value][$action]) && $this->map[$field][$value][$action] === true;
}
/**
* 获取$value里的$action的值,作为下一个值的$nextAction
*
* @param string $field
* @param string $value
* @param string $action 当前action
* @param string $nextAction 下一个值的action
* @param array $flipArr 临时指定 值的映射关系,如:[1 => 2, 2 => 1]
* @return string
*/
public function getNextValueByValue($value, $action = self::NEXT, $nextAction = self::VALUE, $field = '', $flipArr = [])
{
$field = $this->getField($field);
$result = '';
if (!empty($flipArr) && isset($flipArr[$value])){ // 指定映射关系
$result = $this->get($flipArr[$value], $result, $nextAction, $field);
}else if ($this->existsValue($value, $field)) {
$result = $this->get($this->get($value, $result, $action, $field), $result, $nextAction, $field);
}
return $result;
}
/**
* 根据action和actionValue获取 值(map下的key)
*
* @param $field
* @param $action
* @param $actionValue
* @return bool|int|string
*/
public function getValueByActionValue($actionValue, $action = self::KEY, $field = '')
{
$field = $this->getField($field);
if ($this->existsField($field)) {
$map = $this->getFieldMap($field);
foreach ($map as $value => $item) {
if (isset($item[$action]) && $item[$action] == $actionValue) {
return $value;
}
}
}
return false;
}
/**
* 获取action和actionValue为true的value
*
* @param $action
* @param string $field
* @return bool|int|string
*/
public function getValueByActionTrue($action, $field = '')
{
return $this->getValueByActionValue(true, $action, $field);
}
/**
* @param string $field
* @return string
*/
public function getField($field = '')
{
return !empty($field) ? $field : $this->field;
}
/**
* @param string $field
* @return $this
*/
public function setField($field)
{
$this->field = $field;
return $this;
}
}
<?php
namespace App\Repositories\Common\Traits;
use App\Repositories\Common\Tinyint;
/**
* 封装Tinyint,提供便捷方法
*
* @property-read array $tinyintConfig
*/
trait TinyintTrait
{
// protected $tinyintConfig = [];
/**
* @param string $field
* @return Tinyint
*/
public function getTinyint($field = '')
{
return Tinyint::instance([__CLASS__, $field])->setMap($this->tinyintConfig)->setField($field);
}
}
<?php
/**
* User: aozhuochao
* Date: 2020/7/28
*/
namespace app\helpers\traits;
/**
* laravel的bootTraits
*
* Trait bootTraits
* @package app\helpers\traits
*/
trait bootTraits
{
/**
* Boot all of the bootable traits on the model.
*
* @return void
*/
protected function bootObjectTraits()
{
$class = $this;
foreach (class_uses_recursive($class) as $trait) {
if (method_exists($this, $method = 'boot'.basename(str_replace('\\', '/', $trait)))) {
call_user_func([$this, $method]);
}
}
}
}
<?php
/**
* User: aozhuochao
* Date: 2020/3/11
*/
namespace app\helpers\traits;
/**
* @method callChildren($name, ...$arguments)
* @method callChildrenSelfSave($name, $parentClass, ...$arguments)
*/
trait callChildrenTrait
{
protected $callSave = [];
public function __call($name, $arguments)
{
static $num = 0;
++$num;
if (method_exists($this, 'callChildren')) {
return call_user_func_array([$this, 'callChildren'], array_merge([$name], $arguments));
}else if (method_exists($this, 'callChildrenSelfSave')) {
return $this->callSave[$name . '-' . $num] = call_user_func_array([clone $this, 'callChildrenSelfSave'], array_merge([$name, $this], $arguments));
}
}
}
<?php
/**
* User: aozhuochao
* Date: 2020/3/11
*/
namespace app\helpers\traits;
/**
* @method callChildren($name, ...$arguments)
* @method callChildrenSelfSave($name, $parentClass, ...$arguments)
*/
trait cloneSelfTrait
{
/**
* @var static[]
*/
protected $callSave = [];
protected $callArr = [
'name' => '',
'parentClass' => null,
'arguments' => [],
];
public function __call($name, $arguments)
{
static $num = 0;
++$num;
return $this->callSave[$name . '-' . $num] = (clone $this)->setCallArr($num, $name, $this, $arguments);
}
/**
* @param $num
* @param string $callName
* @param $parentClass
* @param $arguments
* @return $this
*/
public function setCallArr($num, $callName, $parentClass, $arguments)
{
$this->callArr = [
'num' => $num,
'name' => $callName,
'parentClass' => $parentClass,
'arguments' => $arguments,
];
return $this;
}
/**
* 获取this,父类也获取自己的
*
* @return $this
*/
public function getParentThis()
{
return empty($this->getCallName()) ? $this : $this->callArr['parentClass'];
}
public function getCallName()
{
return $this->callArr['name'];
}
public function getCallArguments()
{
return $this->callArr['arguments'];
}
}
<?php
namespace system\helper;
/**
* static缓存
* 存在实例化open,过的,remember才走缓存
*/
class CacheStaticConditional
{
protected static $instance;
protected static $cache = [];
public static function open()
{
return static::$instance = new static;
}
/**
* 开启就存储$func的结果
* 否则直接调用$func
*
* @param $cacheKey
* @param $func
* @param $dataArr
* @return mixed
*/
public static function remember($cacheKey, $func, $dataArr = [])
{
if (isset(static::$instance)) {
$key = static::handleRememberCacheKey($cacheKey, $dataArr);
return static::$cache[$key]?? (static::$cache[$key] = call_user_func_array($func, $dataArr));
}
return call_user_func_array($func, $dataArr);
}
/**
* 根据缓存调用方法
* 没缓存就不调用
*
* @param $cacheKey
* @param $func
* @param $default
* @return mixed|null
*/
public static function call($cacheKey, $func, $default = null)
{
if (is_null(static::$instance)) {
return $default;
}
if (isset(static::$cache[$cacheKey])) {
return call_user_func($func, static::$cache[$cacheKey]);
}
return $default;
}
public static function handleRememberCacheKey($cacheKey, $dataArr = [])
{
$moreKey = $dataArr ? md5(serialize($dataArr)) : '';
return $cacheKey . $moreKey;
}
}
<?php
namespace system\helper;
/**
* 将异常通过return返回
*/
class ThrowReturnException extends \RuntimeException
{
protected $data;
/**
* @param $data
* @noinspection PhpMissingParentConstructorInspection
*/
public function __construct($data)
{
$this->data = $data;
}
public static function throw($data)
{
throw new static($data);
}
public static function run($func, $arr = [])
{
try{
return call_user_func_array($func, $arr);
}catch (ThrowReturnException $exception){
return $exception->getData();
}
}
/**
* @return mixed
*/
public function getData()
{
return $this->data;
}
}
<?php
namespace system\engine;
/**
* 代理重试,根据异常来
*/
class ProxyCallRetryException
{
protected $exceptionFunc;
protected $proxyObject;
protected $retry = 2;
public function __construct($proxyObject, $exceptionFunc, $retry = 2)
{
$this->exceptionFunc = $exceptionFunc;
$this->proxyObject = $proxyObject;
$this->retry = $retry;
}
public function __call($name, $arguments)
{
for ($a = 0; $a <= $this->retry; ++$a){
try {
return call_user_func_array([$this->proxyObject, $name], $arguments);
}catch (\Exception | \Throwable $exception){
if (!call_user_func($this->exceptionFunc, $exception, $this->proxyObject, $name, $arguments)) { // 返回false就中断
break;
}
}
}
return null;
}
}
<?php
namespace App\Tools;
/**
* 列表里详情的下一个数据
*/
class PageDetailNext
{
/**
* 详情获取下一个和上一个的id
*
* @see handleQueryOnNext($currentId, $requestArr, $action, $page, $setPageNextByIdLimit)
*
* @param int|string $currentId 可以整数或者字符串
* @param callable $listFunc 每次加载一页
* @param $uniKey
* @param $redisPrefix
* @return array|int[]
*/
public static function getFuncId($currentId, $listFunc, $uniKey, $redisPrefix = 'page:next:')
{
$lastId = $nextId = 0;
$inc = static::getInc(0, $uniKey, $redisPrefix);
if (empty($inc)) { // 直接打开详情的
return [
'last' => $lastId,
'next' => $nextId
];
}
$requestArr = \Illuminate\Support\Facades\Redis::get($redisPrefix . 'request:' . $inc . ':' . $uniKey)?:[];
$requestArr = is_string($requestArr)?json_decode($requestArr, true):$requestArr;
$setPageNextByIdLimit = 15;
if (!empty($requestArr['setPageNextByIdLimit'])) {
$setPageNextByIdLimit = $requestArr['setPageNextByIdLimit'];
}
$key = md5(json_encode($requestArr) . '--' . $inc . '--' . $uniKey);
$pageKey = \Illuminate\Support\Facades\Redis::hGet($redisPrefix . 'hash:id:' . $key, $currentId);
if (empty($pageKey)) { // 直接打开详情的
return [
'last' => $lastId,
'next' => $nextId
];
}
$redisHashKey = $redisPrefix . 'hash:key:' . $key;
$pageKeyLength = strlen($pageKey);
$pageKeyLastThreeLimit = intval(substr($pageKey, -3)); // 获取后三位
$pageKeyPrefixPage = substr($pageKey, 0, $pageKeyLength - 3); // 获取前面部分
// $pageKeyArr = explode('_', $pageKey);
$pageKeyArr = [$pageKeyPrefixPage, $pageKeyLastThreeLimit];
$nextId = static::getNextId($redisHashKey, $pageKeyArr, $setPageNextByIdLimit);
if (is_array($nextId)) {
call_user_func($listFunc, $currentId, $requestArr, ...$nextId);
$nextId = static::getNextId($redisHashKey, $pageKeyArr, $setPageNextByIdLimit);
if (is_array($nextId)) {
$nextId = 0;
}
}
// 上一个
$lastId = static::getLastId($redisHashKey, $pageKeyArr, $setPageNextByIdLimit);
if (is_array($lastId)) {
call_user_func($listFunc, $currentId, $requestArr, ...$lastId);
$lastId = static::getLastId($redisHashKey, $pageKeyArr, $setPageNextByIdLimit);
if (is_array($lastId)) {
$lastId = 0;
}
}
return [
'last' => $lastId,
'next' => $nextId
];
}
/**
* 存储列表里详情的下一个数据
*
*
* @param int[]|string[] $ids 整数或者字符串
* @param int $limit 分页数量
* @param $uniKey
* @param $redisPrefix
* @return int|string
*/
public static function setPageNextById($ids, $page, $limit, $uniKey, $redisPrefix = 'page:next:', $moreRequestArr = [], $requestParamBool = true)
{
if (empty_a($ids)) {
return '';
}
$arr = $requestParamBool?request()->input():[];
$page = max(intval($page), 1);
unset($arr['page']);
$arr['setPageNextByIdLimit'] = $limit;
$arr = array_merge($arr, $moreRequestArr);
ksort($arr);
$arrJson = json_encode($arr);
$inc = static::getInc($page, $uniKey, $redisPrefix);
$key = md5($arrJson . '--' . $inc . '--' . $uniKey);
if ($page == 1) {
// \Illuminate\Support\Facades\Redis::del($fullKey . ':request');
\Illuminate\Support\Facades\Redis::set($redisPrefix . 'request:' . $inc . ':' . $uniKey, $arrJson, 86400 * 2);
}
$mArr = $mArrId = [];
foreach ($ids as $idKey => $id) {
$zKey = $page. str_pad($idKey, 3, '0', STR_PAD_LEFT);
$mArr[$zKey] = $id;
$mArrId[$id] = $zKey;
\Illuminate\Support\Facades\Redis::zRem($redisPrefix . 'hash:key:' . $key, $zKey);
\Illuminate\Support\Facades\Redis::zAdd($redisPrefix . 'hash:key:' . $key, $zKey, $id);
}
if (!empty($mArr)) {
\Illuminate\Support\Facades\Redis::hMSet($redisPrefix . 'hash:id:' . $key, $mArrId);
\Illuminate\Support\Facades\Redis::expire($redisPrefix . 'hash:key:' . $key, 86400 * 2);
\Illuminate\Support\Facades\Redis::expire($redisPrefix . 'hash:id:' . $key, 86400 * 2);
}
return $inc;
}
protected static function getInc($page, $uniKey, $redisPrefix = 'page:next:')
{
if ($page == 1) {
$inc = \Illuminate\Support\Facades\Redis::incr($redisPrefix . 'inc:' . $uniKey);
\Illuminate\Support\Facades\Redis::expire($redisPrefix . 'inc:' . $uniKey, 86400 * 2);
}else{
$inc = \Illuminate\Support\Facades\Redis::get($redisPrefix . 'inc:' . $uniKey);
}
return $inc;
}
protected static function getNextId($redisHashKey, $pageKeyArr, $setPageNextByIdLimit)
{
if ($pageKeyArr[1] >= $setPageNextByIdLimit) { // 第二页
$page = ($pageKeyArr[0] + 1);
$hashKey = $page . ('000');
$resultPage = $page;
} else { // 当前页+1
$page = ($pageKeyArr[0]);
$hashKey = $page . (str_pad(($pageKeyArr[1] + 1), 3, '0', STR_PAD_LEFT));
$resultPage = $page + 1;
}
$nextId = \Illuminate\Support\Facades\Redis::zRangeByScore($redisHashKey, $hashKey, '11111111' . '111', ['LIMIT' => [0, 1]]);
if (empty($nextId)) { // 已有的没有,就查询
return ['next', $resultPage, $setPageNextByIdLimit];
}
return current($nextId);
}
protected static function getLastId($redisHashKey, $pageKeyArr, $setPageNextByIdLimit)
{
if ($pageKeyArr[0] == 1 && empty($pageKeyArr[1])) { // 第一页第一个
return 0;
}
if (empty($pageKeyArr[1])) { // 第一个
$page = ($pageKeyArr[0] - 1);
$hashKey = $page . (str_pad($setPageNextByIdLimit, 3, '0', STR_PAD_LEFT));
$resultPage = $page;
}else{ // 当前页-1
$page = ($pageKeyArr[0]);
$resultPage = $page - 1;
$hashKey = $page . (str_pad(($pageKeyArr[1] - 1), 3, '0', STR_PAD_LEFT));
}
$lastId = \Illuminate\Support\Facades\Redis::zRevRangeByScore($redisHashKey, $hashKey, 0, ['LIMIT' => [0, 1]]);
if (empty($lastId)) { // 已有的没有,就查询
if ($resultPage < 2) { // 没有了
return 0;
}
return ['last', $resultPage, $setPageNextByIdLimit];
}
return current($lastId);
}
}
<?php
namespace app\utils;
/**
* 代理返回null
*/
class ProxyNull
{
public function __call($name, $arguments)
{
return null;
}
public static function __callStatic($name, $arguments)
{
return null;
}
}
<?php
// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK ]
// +----------------------------------------------------------------------
// | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: yunwuxin <448901948@qq.com>
// +----------------------------------------------------------------------
namespace think;
use Closure;
use Exception;
use Throwable;
class Pipeline
{
protected $passable;
protected $pipes = [];
protected $exceptionHandler;
/**
* 初始数据
* @param $passable
* @return $this
*/
public function send($passable)
{
$this->passable = $passable;
return $this;
}
/**
* 调用栈
* @param $pipes
* @return $this
*/
public function through($pipes)
{
$this->pipes = is_array($pipes) ? $pipes : func_get_args();
return $this;
}
/**
* 执行
* @param Closure $destination
* @return mixed
*/
public function then(Closure $destination)
{
$pipeline = array_reduce(
array_reverse($this->pipes),
$this->carry(),
function ($passable) use ($destination) {
try {
return $destination($passable);
} catch (Throwable | Exception $e) {
return $this->handleException($passable, $e);
}
}
);
return $pipeline($this->passable);
}
/**
* 设置异常处理器
* @param callable $handler
* @return $this
*/
public function whenException($handler)
{
$this->exceptionHandler = $handler;
return $this;
}
protected function carry()
{
return function ($stack, $pipe) {
return function ($passable) use ($stack, $pipe) {
try {
return $pipe($passable, $stack);
} catch (Throwable | Exception $e) {
return $this->handleException($passable, $e);
}
};
};
}
/**
* 异常处理
* @param $passable
* @param $e
* @return mixed
*/
protected function handleException($passable, Throwable $e)
{
if ($this->exceptionHandler) {
return call_user_func($this->exceptionHandler, $passable, $e);
}
throw $e;
}
}
<?php
namespace App\Tools\Response;
class JsonFormat
{
public static function format($code, $info, $data)
{
return compact('code', 'info', 'data');
}
public static function success($data = null)
{
return static::format(static::getCodeSuccess(), static::getCodeSuccessInfo(), $data);
}
public static function error($code = null, $info = null, $data = null)
{
return static::format($code??static::getCodeError(), $info??static::getCodeErrorInfo(), $data);
}
public static function errorMsg($info = null, $code = null, $data = null)
{
return static::format($code??static::getCodeError(), $info??static::getCodeErrorInfo(), $data);
}
public static function getCodeError()
{
return 400;
}
public static function getCodeErrorInfo()
{
return '错误';
}
public static function getCodeSuccess()
{
return 200;
}
public static function getCodeSuccessInfo()
{
return '成功';
}
}
<?php
namespace app\services\promotion;
use app\model\Promotion;
use app\services\PromotionService;
use think\Collection;
use think\helper\Arr;
use think\helper\Str;
class EnvFilter
{
public static function compare(array $env, array $condition, $comparators = null): bool
{
$compare = $comparators ? : self::comparators();
foreach ($condition as $rule) {
list($field, $operate, $value) = $rule;
$dataValue = Arr::get($env, $field);
$compareFunc = $compare[$operate] ?? function ($v1, $v2) { return false;};
if (is_null($dataValue) || !$compareFunc($dataValue, $value)) {
return false;
}
}
return true;
}
public static function comparators(): array
{
return [
"=" => function($v1, $v2) { return $v1 == $v2;},
"!=" => function($v1, $v2) { return $v1 != $v2;},
">" => function ($v1, $v2) { return $v1 != $v2 && max($v1, $v2) == $v1;},
">=" => function ($v1, $v2) { return max($v1, $v2) == $v1;},
"<" => function ($v1, $v2) { return $v1 != $v2 && max($v1, $v2) == $v2;},
"<=" => function ($v1, $v2) { return max($v1, $v2) == $v2;},
"in" => function ($v1, $v2) { return in_array($v1, explode(",", $v2));},
"not in" => function ($v1, $v2) { return !in_array($v1, explode(",", $v2));},
"^=" => function ($v1, $v2) { return Str::startsWith($v1, $v2);},
"=$" => function ($v1, $v2) { return Str::endsWith($v1, $v2);},
"contains" => function ($v1, $v2) { return Str::contains($v1, $v2);},
"not contains" => function ($v1, $v2) { return !Str::contains($v1, $v2);},
"regex" => function ($v1, $v2) { return preg_match($v2, $v1);},
"before_time" => function ($v1, $v2) { return ($v1t = strtotime($v1)) && ($v2t = strtotime(sprintf("-%s", $v2))) && $v1t >= $v2t;},
"after_time" => function ($v1, $v2) { return ($v1t = strtotime($v1)) && ($v2t = strtotime(sprintf("+%s", $v2))) && $v1t <= $v2t;},
"before_out_time" => function ($v1, $v2) { return ($v1t = strtotime($v1)) && ($v2t = strtotime(sprintf("-%s", $v2))) && $v1t < $v2t;},
"after_out_time" => function ($v1, $v2) { return ($v1t = strtotime($v1)) && ($v2t = strtotime(sprintf("+%s", $v2))) && $v1t > $v2t;},
];
}
}
<?php
class DiffRunTime
{
public static $arr = [];
public static function start($key)
{
if (!isset(static::$arr[$key])) {
static::$arr[$key] = [];
}
static::$arr[$key]['start'] = microtime(true);
}
public static function end($key){
if (!isset(static::$arr[$key])) {
static::$arr[$key] = [];
}
static::$arr[$key]['end'] = microtime(true);
if (isset(static::$arr[$key]['start'])) {
// $executionTime = ($endTime - $startTime) * 1000; // Convert to milliseconds
static::$arr[$key]['diff'] = static::$arr[$key]['end'] - static::$arr[$key]['start'];
}else{
static::$arr[$key]['diff'] = false;
}
}
public static function getArr()
{
return self::$arr;
}
}
<?php
Class ClassMagicProxy{
protected $that = null;
protected $arr = [];
protected $map = [];
public static function new($that, $map, $arr)
{
return (new static())->setArr($arr)->setMap($map)->setThat($that);
}
public function setArr($arr)
{
$this->arr = $arr;
return $this;
}
public function setMap($arr)
{
$this->map = $arr;
return $this;
}
public function setThat($that)
{
$this->that = $that;
return $this;
}
public function __get(string $name)
{
return call_user_func([$this->that, $this->map['__get']??'get'], $name, $this->arr);
}
public function __call(string $name, array $arguments)
{
return call_user_func([$this->that, $this->map['__call']??'call'], $name, $arguments, $this->arr);
}
// public static function __callStatic(string $name, array $arguments)
// {
// return call_user_func([$this->that, '__callStatic'], $name, $arguments, $this->arr);
// }
}