efps-version
elf 2 years ago
commit 6beac12c64

@ -0,0 +1,21 @@
APP_NAME=service
APP_ENV=dev
DB_DRIVER=mysql
DB_HOST=
DB_PORT=3306
DB_DATABASE=
DB_USERNAME=root
DB_PASSWORD=
DB_CHARSET=utf8mb4
DB_COLLATION=utf8mb4_unicode_ci
DB_PREFIX=
REDIS_HOST=172.17.0.2
REDIS_AUTH=(null)
REDIS_PORT=6379
REDIS_DB=0
LOG_PATH=/data/project/service/runtime/logs
LANHUO_URL=https://c.uaeee.com

13
.gitignore vendored

@ -0,0 +1,13 @@
.buildpath
.settings/
.project
*.patch
.idea/
.git/
runtime/
vendor/
.phpintel/
.env
.DS_Store
.phpunit*
*.cache

@ -0,0 +1,57 @@
# usermod -aG docker gitlab-runner
stages:
- build
- deploy
variables:
PROJECT_NAME: hyperf
REGISTRY_URL: registry-docker.org
build_test_docker:
stage: build
before_script:
# - git submodule sync --recursive
# - git submodule update --init --recursive
script:
- docker build . -t $PROJECT_NAME
- docker tag $PROJECT_NAME $REGISTRY_URL/$PROJECT_NAME:test
- docker push $REGISTRY_URL/$PROJECT_NAME:test
only:
- test
tags:
- builder
deploy_test_docker:
stage: deploy
script:
- docker stack deploy -c deploy.test.yml --with-registry-auth $PROJECT_NAME
only:
- test
tags:
- test
build_docker:
stage: build
before_script:
# - git submodule sync --recursive
# - git submodule update --init --recursive
script:
- docker build . -t $PROJECT_NAME
- docker tag $PROJECT_NAME $REGISTRY_URL/$PROJECT_NAME:$CI_COMMIT_REF_NAME
- docker tag $PROJECT_NAME $REGISTRY_URL/$PROJECT_NAME:latest
- docker push $REGISTRY_URL/$PROJECT_NAME:$CI_COMMIT_REF_NAME
- docker push $REGISTRY_URL/$PROJECT_NAME:latest
only:
- tags
tags:
- builder
deploy_docker:
stage: deploy
script:
- echo SUCCESS
only:
- tags
tags:
- builder

@ -0,0 +1,91 @@
<?php
$header = <<<'EOF'
This file is part of Hyperf.
@link https://www.hyperf.io
@document https://hyperf.wiki
@contact group@hyperf.io
@license https://github.com/hyperf/hyperf/blob/master/LICENSE
EOF;
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR2' => true,
'@Symfony' => true,
'@DoctrineAnnotation' => true,
'@PhpCsFixer' => true,
'header_comment' => [
'comment_type' => 'PHPDoc',
'header' => $header,
'separate' => 'none',
'location' => 'after_declare_strict',
],
'array_syntax' => [
'syntax' => 'short'
],
'list_syntax' => [
'syntax' => 'short'
],
'concat_space' => [
'spacing' => 'one'
],
'blank_line_before_statement' => [
'statements' => [
'declare',
],
],
'general_phpdoc_annotation_remove' => [
'annotations' => [
'author'
],
],
'ordered_imports' => [
'imports_order' => [
'class', 'function', 'const',
],
'sort_algorithm' => 'alpha',
],
'single_line_comment_style' => [
'comment_types' => [
],
],
'yoda_style' => [
'always_move_variable' => false,
'equal' => false,
'identical' => false,
],
'phpdoc_align' => [
'align' => 'left',
],
'multiline_whitespace_before_semicolons' => [
'strategy' => 'no_multi_line',
],
'constant_case' => [
'case' => 'lower',
],
'class_attributes_separation' => true,
'combine_consecutive_unsets' => true,
'declare_strict_types' => true,
'linebreak_after_opening_tag' => true,
'lowercase_static_reference' => true,
'no_useless_else' => true,
'no_unused_imports' => true,
'not_operator_with_successor_space' => true,
'not_operator_with_space' => false,
'ordered_class_elements' => true,
'php_unit_strict' => false,
'phpdoc_separation' => false,
'single_quote' => true,
'standardize_not_equals' => true,
'multiline_comment_opening_closing' => true,
])
->setFinder(
PhpCsFixer\Finder::create()
->exclude('public')
->exclude('runtime')
->exclude('vendor')
->in(__DIR__)
)
->setUsingCache(false);

@ -0,0 +1,11 @@
<?php
namespace PHPSTORM_META {
// Reflect
override(\Psr\Container\ContainerInterface::get(0), map('@'));
override(\Hyperf\Utils\Context::get(0), map('@'));
override(\make(0), map('@'));
override(\di(0), map('@'));
}

@ -0,0 +1,54 @@
# Default Dockerfile
#
# @link https://www.hyperf.io
# @document https://hyperf.wiki
# @contact group@hyperf.io
# @license https://github.com/hyperf/hyperf/blob/master/LICENSE
FROM hyperf/hyperf:8.0-alpine-v3.12-swoole
LABEL maintainer="Hyperf Developers <group@hyperf.io>" version="1.0" license="MIT" app.name="Hyperf"
##
# ---------- env settings ----------
##
# --build-arg timezone=Asia/Shanghai
ARG timezone
ENV TIMEZONE=${timezone:-"Asia/Shanghai"} \
APP_ENV=prod \
SCAN_CACHEABLE=(true)
# update
RUN set -ex \
# show php version and extensions
&& php -v \
&& php -m \
&& php --ri swoole \
# ---------- some config ----------
&& cd /etc/php8 \
# - config PHP
&& { \
echo "upload_max_filesize=128M"; \
echo "post_max_size=128M"; \
echo "memory_limit=1G"; \
echo "date.timezone=${TIMEZONE}"; \
} | tee conf.d/99_overrides.ini \
# - config timezone
&& ln -sf /usr/share/zoneinfo/${TIMEZONE} /etc/localtime \
&& echo "${TIMEZONE}" > /etc/timezone \
# ---------- clear works ----------
&& rm -rf /var/cache/apk/* /tmp/* /usr/share/man \
&& echo -e "\033[42;37m Build Completed :).\033[0m\n"
WORKDIR /opt/www
# Composer Cache
# COPY ./composer.* /opt/www/
# RUN composer install --no-dev --no-scripts
COPY . /opt/www
RUN composer install --no-dev -o && php bin/hyperf.php
EXPOSE 9501
ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]

@ -0,0 +1,36 @@
# Introduction
This is a skeleton application using the Hyperf framework. This application is meant to be used as a starting place for those looking to get their feet wet with Hyperf Framework.
# Requirements
Hyperf has some requirements for the system environment, it can only run under Linux and Mac environment, but due to the development of Docker virtualization technology, Docker for Windows can also be used as the running environment under Windows.
The various versions of Dockerfile have been prepared for you in the [hyperf/hyperf-docker](https://github.com/hyperf/hyperf-docker) project, or directly based on the already built [hyperf/hyperf](https://hub.docker.com/r/hyperf/hyperf) Image to run.
When you don't want to use Docker as the basis for your running environment, you need to make sure that your operating environment meets the following requirements:
- PHP >= 7.3
- Swoole PHP extension >= 4.5and Disabled `Short Name`
- OpenSSL PHP extension
- JSON PHP extension
- PDO PHP extension If you need to use MySQL Client
- Redis PHP extension If you need to use Redis Client
- Protobuf PHP extension If you need to use gRPC Server of Client
# Installation using Composer
The easiest way to create a new Hyperf project is to use Composer. If you don't have it already installed, then please install as per the documentation.
To create your new Hyperf project:
$ composer create-project hyperf/hyperf-skeleton path/to/install
Once installed, you can run the server immediately using the command below.
$ cd path/to/install
$ php bin/hyperf.php start
This will start the cli-server on port `9501`, and bind it to all network interfaces. You can then visit the site at `http://localhost:9501/`
which will bring up Hyperf default home page.

@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
namespace App\Command;
use App\Helper\Signer;
use App\Service\AppService;
use App\Service\MerchantService;
use Hyperf\Command\Command as HyperfCommand;
use Hyperf\Command\Annotation\Command;
use Hyperf\Contract\ContainerInterface;
/**
* @Command
*/
class JinlingCommand extends HyperfCommand
{
/**
* @var ContainerInterface
*/
protected $container;
protected $admin;
public function __construct(ContainerInterface $container)
{
$this->container = $container;
parent::__construct('jinling');
}
public function configure()
{
parent::configure();
$this->setDescription('廖金灵测试');
}
public function handle()
{
$this->buildPayPrams();
return;
/**
* @var MerchantService
*/
$merchantService = $this->container->make(MerchantService::class);
/**
* @var AppService
*/
$appService = $this->container->make(AppService::class);
$merchant = $merchantService->createMerchant([
'username' => 'elf',
'password' => '123456',
'email' => '360197197@qq.com',
'mobile' => '18760419185',
'ip' => '127.0.0.1'
]);
$appService->createApp($merchant);
}
public function buildPayPrams() {
$params = [
'app_id' => '202304270000004',
'timestamp' => time(),
'nonce_str' => 'lSHKbuFngCXHN8Ue1s8QHAAzPvOL3u9O',
];
$data = [
'order_name' => '测试订单',
'currency' => 'CNY',
'amount' => '20',
'notify_url' => 'http://www.baidu.com',
'redirect_url' => 'http://www.google.com',
'out_order_no' => '1122',
'direct_pay' => 0,
'show_pc_pay_url' => 0,
];
$params['data'] = json_encode($data);
$sign = Signer::sign($params, 'lSHKbuFngCXHN8Ue1s8QHAAzPvOL3u9O');
$params['sign'] = $sign;
var_dump(json_encode($params));
}
}

@ -0,0 +1,69 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Constants;
use Hyperf\Constants\AbstractConstants;
use Hyperf\Constants\Annotation\Constants;
#[Constants]
class ResultCode extends AbstractConstants
{
/**
* @Message("成功")
*/
const SUCCESS = 1000;
/**
* @Message("错误")
*/
const DEFAULT_ERROR = 2000;
/**
* @Message("Server Error")
*/
const SERVER_ERROR = 2001;
/**
* @Message("message.param_error")
*/
const SYSTEM_INVALID = 2002;
/**
* @Message("Params %s is invalid.")
*/
const PARAMS_INVALID = 2003;
/**
* @Message("message.record_not_exist")
*/
const RECORD_NOT_FOUND = 2004;
/**
* @Message("message.not_logged")
*/
const UNAUTHORIZED = 2005;
/**
* @Message("无权限")
*/
const FORBIDDEN = 2006;
/**
* @Message("message.too_frequent")
*/
const TOO_FREQUENT = 2007;
/**
* @Message("Not Found")
*/
const NOT_FOUND = 2008;
}

@ -0,0 +1,31 @@
<?php
namespace App\Contract;
interface SmsSender {
/**
* 发送短信验证码
*
* @param string $mobile 手机号
* @param string $code 验证码
* @param int $activeMinute 验证码有效期
*/
public function sendCode($mobile, $code, $activeMinute = 0);
/**
* 发送短信
*
* @param string $mobile 手机号
* @param string $content 短信内容
*/
public function send($mobile, $content);
/**
* 批量发送短信
*
* @param array $mobiles 手机号
* @param string $content 短信内容
*/
public function sendBatch(array $mobiles, $content);
}

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Controller\Payment;
use App\Constants\ResultCode;
use App\Helper\Result;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Container\ContainerInterface;
abstract class AbstractController
{
/**
* @Inject
* @var ContainerInterface
*/
protected ContainerInterface $container;
/**
* @Inject
* @var RequestInterface
*/
protected RequestInterface $request;
/**
* @Inject
* @var ResponseInterface
*/
protected ResponseInterface $response;
protected function success(array $data = [], string $message = '成功'): Result
{
return new Result(ResultCode::SUCCESS, $message, $data);
}
}

@ -0,0 +1,24 @@
<?php
declare(strict_types=1);
namespace App\Controller\Payment;
use Hyperf\HttpServer\Contract\RequestInterface;
use App\Service\PaymentService;
class NotifyController extends AbstractController
{
private PaymentService $paymentService;
public function __construct(PaymentService $paymentService)
{
$this->paymentService = $paymentService;
}
public function index(RequestInterface $request)
{
$params = $request->all();
return $this->paymentService->notify($params);
}
}

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Controller\Payment;
use App\Model\Order;
use Hyperf\HttpServer\Contract\ResponseInterface;
use Psr\Http\Message\ResponseInterface as Psr7ResponseInterface;
use Hyperf\HttpServer\Contract\RequestInterface;
class PageController extends AbstractController
{
public function index(RequestInterface $request, ResponseInterface $response): Psr7ResponseInterface
{
$orderNo = $request->input('order_no', '');
if (!$orderNo) {
return '订单号错误';
}
$order = Order::where('order_no', $orderNo)->first();
if (!$order) {
return '订单号错误';
}
return $response->redirect($order->redirect_url);
}
}

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
namespace App\Controller\Payment;
use App\Request\JsapiPayRequest;
use Hyperf\HttpServer\Contract\RequestInterface;
use App\Service\PaymentService;
class PayController extends AbstractController
{
private PaymentService $paymentService;
public function __construct(PaymentService $paymentService)
{
$this->paymentService = $paymentService;
}
public function jsapi(RequestInterface $request)
{
$form = new JsapiPayRequest($request->all());
$order = $this->paymentService->jsapiPay($form->getApp(), $form->getData());
return $this->success([
'pay_url' => $order->pay_url,
'order_no' => $order->order_no,
]);
}
}

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace App\Exception;
use App\Constants\ResultCode;
use Hyperf\Server\Exception\ServerException;
use Throwable;
abstract class BasicException extends ServerException
{
protected $code = ResultCode::DEFAULT_ERROR;
public function __construct(string $message = null, Throwable $previous = null)
{
if (is_null($message)) {
$message = ResultCode::getMessage($this->code);
}
parent::__construct($message, $this->code, $previous);
}
}

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Exception;
use App\Constants\ResultCode;
use Throwable;
class BusinessException extends BasicException
{
}

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace App\Exception\Handler;
use App\Constants\ResultCode;
use App\Exception\BasicException;
use App\Helper\Result;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\ExceptionHandler\ExceptionHandler;
use Hyperf\HttpMessage\Stream\SwooleStream;
use Psr\Http\Message\ResponseInterface;
use Throwable;
use Hyperf\Database\Model\ModelNotFoundException;
class AppExceptionHandler extends ExceptionHandler
{
/**
* @var StdoutLoggerInterface
*/
protected $logger;
public function __construct(StdoutLoggerInterface $logger)
{
$this->logger = $logger;
}
public function handle(Throwable $throwable, ResponseInterface $response)
{
$data = [];
$code = ResultCode::SERVER_ERROR;
$message = '';
$httpCode = 200;
if ($throwable instanceof BasicException) {
$this->stopPropagation();
$code = $throwable->getCode();
$message = $throwable->getMessage();
} elseif ($throwable instanceof ModelNotFoundException) {
$this->stopPropagation();
$code = ResultCode::RECORD_NOT_FOUND;
$message = ResultCode::getMessage($code);
} else {
if (config('app_env') == 'dev') {
$message = $throwable->getMessage();
$data = [
'line' => $throwable->getLine(),
'file' => $throwable->getFile(),
];
} else {
$message = ResultCode::getMessage($code);
}
$this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
$this->logger->error($throwable->getTraceAsString());
}
$result = new Result($code, $message, $data);
return $response
->withAddedHeader('content-type', 'application/json; charset=utf-8')
->withStatus($httpCode)
->withBody(new SwooleStream(strval($result)));
}
public function isValid(Throwable $throwable): bool
{
return true;
}
}

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Exception;
use App\Constants\ResultCode;
use Throwable;
class ValidationException extends BasicException
{
protected $code = ResultCode::PARAMS_INVALID;
}

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Factory;
use App\Helper\SmsSender\JhSmsSender;
use App\Helper\SmsSender\XgSmsSender;
use App\Helper\SmsSender\ZwSmsSender;
use Psr\Container\ContainerInterface;
use App\Model\Tool;
class SmsSenderFactory
{
protected $senders = [
'sms_set' => XgSmsSender::class,
'zhongwang' => ZwSmsSender::class,
'juhedata' => JhSmsSender::class,
];
public function __invoke(ContainerInterface $container)
{
$tool = Tool::getActiveByGroup('sms');
if (!$tool) {
return null;
}
$senderClass = $this->getSenderClass($tool);
if ($senderClass) {
return make($senderClass, compact('tool'));
}
return null;
}
protected function getSenderClass(Tool $tool)
{
return $this->senders[$tool->name] ?? null;
}
}

@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use Hyperf\Di\Annotation\AnnotationCollector;
class Annotation
{
/**
* 只支持系统默认收集器
*/
public static function getMethodsByAnnotationAndClass(string $annotation, string $class): array
{
$items = AnnotationCollector::getMethodsByAnnotation($annotation);
$methods = [];
foreach ($items as $item) {
if ($item['class'] == $class) {
$methods[] = $item;
}
}
return $methods;
}
/**
* 只支持系统默认收集器
*/
public static function getPropertiesByAnnotationAndClass(string $annotation, string $class): array
{
$items = AnnotationCollector::getPropertiesByAnnotation($annotation);
$properties = [];
foreach ($items as $item) {
if ($item['class'] == $class) {
$properties[] = $item;
}
}
return $properties;
}
}

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use App\Exception\BusinessException;
use Hyperf\Utils\ApplicationContext;
/**
* 缓存辅助类
* @method static mixed get(string $key, mixed $default = null)
* @method static bool set(string $key, mixed $value, null|int|\DateInterval $ttl = null)
* @method static bool delete(string $key)
* @method static bool clear()
* @method static bool deleteMultiple(iterable $keys)
* @method static iterable getMultiple(iterable $keys, mixed $default = null)
* @method static bool setMultiple(iterable $values, null|int|\DateInterval $ttl = null)
* @method static bool has(string $key)
*/
class Cache
{
private static $instance;
private static $cacheKeys = [
];
public static function getKey($name, array $params = []): string
{
$cacheKey = self::$cacheKeys[$name] ?? null;
if (is_null($cacheKey)) {
throw new BusinessException('缓存不存在');
}
foreach ($params as $key => $value) {
$cacheKey = str_replace('{' . $key . '}', $value, $cacheKey);
}
return $cacheKey;
}
public static function getInstance()
{
if (is_null(self::$instance)) {
self::$instance = ApplicationContext::getContainer()->get(\Psr\SimpleCache\CacheInterface::class);
}
return self::$instance;
}
public static function __callStatic($method, $args)
{
return call_user_func_array([self::getInstance(), $method], $args);
}
}

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Router\Router;
if (!function_exists('loadRoutes')) {
/**
* 加载路由.
*/
function loadRoutes($path)
{
$files = scandir($path);
foreach ($files as $file) {
if ($file == '.' || $file == '..') {
continue;
}
$filePath = $path . '/' . $file;
if (is_dir($filePath)) {
$prefix = '/' . $file;
$options = [];
if (file_exists($filePath . '/_init.php')) {
$config = require($filePath . '/_init.php');
$prefix = $config['prefix'] ?? $prefix;
$options = $config['options'] ?? $options;
}
Router::addGroup($prefix, function () use ($filePath) {
loadRoutes($filePath);
}, $options);
} elseif (is_file($filePath)) {
if ($file == '_init.php') {
continue;
}
require_once $filePath;
}
}
}
}
if (!function_exists('getClientIp')) {
function getClientIp(RequestInterface $request)
{
$headers = $request->getHeaders();
if(isset($headers['x-forwarded-for'][0]) && !empty($headers['x-forwarded-for'][0])) {
$ips = explode(',', $headers['x-forwarded-for'][0]);
return trim($ips[0]);
} elseif (isset($headers['x-real-ip'][0]) && !empty($headers['x-real-ip'][0])) {
return $headers['x-real-ip'][0];
}
$serverParams = $request->getServerParams();
return $serverParams['remote_addr'] ?? '';
}
}
if (!function_exists('getRoutePrefix')) {
function getRoutePrefix()
{
return env('ROUTE_PREFIX', '/newSns');
}
}

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\ApplicationContext;
class Log
{
public static function get(string $name = 'app')
{
return ApplicationContext::getContainer()->get(LoggerFactory::class)->get($name);
}
public static function __callStatic($method, $args)
{
$name = 'app';
if (isset($args[2])) {
$name = $args[2];
unset($args[2]);
}
return call_user_func_array([self::get($name), $method], $args);
}
}

@ -0,0 +1,224 @@
<?php
declare(strict_types=1);
namespace App\Helper\Macro;
use App\Helper\Str;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Relations;
class WhereHasIn
{
/**
* @var Builder
*/
protected $builder;
/**
* @var string
*/
protected $relation;
/**
* @var string
*/
protected $nextRelation;
/**
* @var \Closure
*/
protected $callback;
/**
* @var string
*/
protected $method = 'whereIn';
public function __construct(Builder $builder, $relation, $callback)
{
$this->builder = $builder;
$this->relation = $relation;
$this->callback = $callback;
}
/**
* @return Builder
*
* @throws \Exception
*/
public function execute()
{
if (! $this->relation) {
return $this->builder;
}
return $this->where(
$this->formatRelation()
);
}
/**
* @param Relations\Relation $relation
*
* @return Builder
*
* @throws \Exception
*/
protected function where($relation)
{
if ($relation instanceof Relations\MorphTo) {
throw new \Exception('Please use whereHasMorphIn() for MorphTo relationships.');
}
$relationQuery = $this->getRelationQuery($relation);
$method = $this->method;
if (
$relation instanceof Relations\MorphOne
|| $relation instanceof Relations\MorphMany
) {
return $this->builder->{$method}(
$relation->getQualifiedParentKeyName(),
$this->withRelationQueryCallback(
$relationQuery
->select($relation->getQualifiedForeignKeyName())
->whereColumn($relation->getQualifiedParentKeyName(), $relation->getQualifiedForeignKeyName())
->where($relation->getQualifiedMorphType(), $relation->getMorphClass())
)
);
}
if ($relation instanceof Relations\MorphToMany) {
return $this->builder->{$method}(
$relation->getQualifiedParentKeyName(),
$this->withRelationQueryCallback(
$relationQuery
->select($relation->getQualifiedForeignPivotKeyName())
->whereColumn($relation->getQualifiedParentKeyName(), $relation->getQualifiedForeignPivotKeyName())
->where($relation->getTable().'.'.$relation->getMorphType(), $relation->getMorphClass())
)
);
}
// BelongsTo
if ($relation instanceof Relations\BelongsTo) {
return $this->builder->{$method}(
$this->getRelationQualifiedForeignKeyName($relation),
$this->withRelationQueryCallback(
$relationQuery
->select($relation->getQualifiedOwnerKeyName())
->whereColumn($this->getRelationQualifiedForeignKeyName($relation), $relation->getQualifiedOwnerKeyName())
)
);
}
if (
$relation instanceof Relations\HasOne
|| $relation instanceof Relations\HasMany
) {
return $this->builder->{$method}(
$relation->getQualifiedParentKeyName(),
$this->withRelationQueryCallback(
$relationQuery
->select($relation->getQualifiedForeignKeyName())
->whereColumn($relation->getQualifiedParentKeyName(), $relation->getQualifiedForeignKeyName())
)
);
}
// BelongsToMany
if ($relation instanceof Relations\BelongsToMany) {
return $this->builder->{$method}(
$relation->getQualifiedParentKeyName(),
$this->withRelationQueryCallback(
$relationQuery
->select($relation->getQualifiedForeignPivotKeyName())
->whereColumn($relation->getQualifiedParentKeyName(), $relation->getQualifiedForeignPivotKeyName())
)
);
}
if (
$relation instanceof Relations\HasOneThrough
|| $relation instanceof Relations\HasManyThrough
) {
return $this->builder->{$method}(
$relation->getQualifiedLocalKeyName(),
$this->withRelationQueryCallback(
$relationQuery
->select($relation->getQualifiedFirstKeyName())
->whereColumn($relation->getQualifiedLocalKeyName(), $relation->getQualifiedFirstKeyName())
)
);
}
throw new \Exception(sprintf('%s does not support "whereHasIn".', get_class($relation)));
}
/**
* @param Relations\Relation $relation
*
* @return Builder
*/
protected function getRelationQuery($relation)
{
$q = $relation->getQuery();
if ($this->builder->getModel()->getConnectionName() !== $q->getModel()->getConnectionName()) {
$databaseName = $this->getRelationDatabaseName($q);
$table = $q->getModel()->getTable();
if (! Str::contains($table, ["`$databaseName`.", "{$databaseName}."])) {
$q->from("{$databaseName}.{$table}");
}
}
return $q;
}
protected function getRelationDatabaseName($q)
{
return config('database.connections.'.$q->getModel()->getConnectionName().'.database');
}
protected function getRelationQualifiedForeignKeyName($relation)
{
if (method_exists($relation, 'getQualifiedForeignKeyName')) {
return $relation->getQualifiedForeignKeyName();
}
return $relation->getQualifiedForeignKey();
}
/**
* @return Relations\Relation
*/
protected function formatRelation()
{
if (is_object($this->relation)) {
$relation = $this->relation;
} else {
$relationNames = explode('.', $this->relation);
$this->nextRelation = implode('.', array_slice($relationNames, 1));
$method = $relationNames[0];
$relation = Relations\Relation::noConstraints(function () use ($method) {
return $this->builder->getModel()->$method();
});
}
return $relation;
}
/**
* @param Builder $relation
*
* @return Builder
*/
protected function withRelationQueryCallback($relationQuery)
{
return call_user_func($this->callback, $this->nextRelation, $relationQuery);
}
}

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
namespace App\Helper\Macro;
use Hyperf\Database\Model\Relations\Relation;
class WhereHasMorphIn
{
public static function make()
{
return function ($relation, $types, $callback = null, $boolean = 'and') {
$relation = $this->getRelationWithoutConstraints($relation);
$types = (array) $types;
if ($types === ['*']) {
$types = $this->model->newModelQuery()->distinct()->pluck($relation->getMorphType())->all();
foreach ($types as &$type) {
$type = Relation::getMorphedModel($type) ?? $type;
}
}
return $this->where(function ($query) use ($relation, $callback, $types) {
foreach ($types as $type) {
$query->orWhere(function ($query) use ($relation, $callback, $type) {
$belongsTo = $this->getBelongsToRelation($relation, $type);
if ($callback) {
$callback = function ($query) use ($callback, $type) {
return $callback($query, $type);
};
}
$query->where($relation->getRelated()->getTable().'.'.$relation->getMorphType(), '=', (new $type)->getMorphClass())
->whereHasIn($belongsTo, $callback);
});
}
}, null, null, $boolean);
};
}
}

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
namespace App\Helper\Macro;
class WhereHasNotIn extends WhereHasIn
{
/**
* @var string
*/
protected $method = 'whereNotIn';
}

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use App\Exception\BusinessException;
use Hyperf\Database\Model\Relations\Relation;
class Morph
{
/**
* 只支持多态关联实体的关联键为id
*
* @param int $morphId
* @param string $morphType
* @return void
*/
public static function getMorph(int $morphId, string $morphType)
{
$class = self::getMorphClass($morphType);
if (is_null($class)) {
throw new BusinessException('Morph type error!');
}
return $class::where('id', $morphId)->first();
}
public static function getMorphClass(string $morphType): ?string
{
return Relation::$morphMap[$morphType] ?? null;
}
/**
* 验证评论类型是否存在
*
* @param string $morphType
* @return void
* @throws BusinessException
*/
public static function checkMorphType(string $morphType)
{
if (is_null(self::getMorphClass($morphType))) {
throw new BusinessException('Morph type error!');
}
}
public static function instanceOf(string $morphType, $instance): bool
{
return get_class($instance) === self::getMorphClass($morphType);
}
public static function getMorphTypeOfInstance(object $instance): string
{
return self::getMorphType(get_class($instance));
}
public static function getMorphType(string $class): string
{
$morphMap = Relation::$morphMap;
$morphMap = array_flip($morphMap);
return $morphMap[$class] ?? '';
}
}

@ -0,0 +1,73 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay;
use App\Helper\OmiPay\Request\AbstractRequest;
use App\Helper\StringHelper;
use App\Helper\TimeHelper;
use Exception;
use GuzzleHttp\Client;
use Hyperf\Guzzle\CoroutineHandler;
use GuzzleHttp\HandlerStack;
abstract class AbstractApi
{
protected static $client;
protected static function getCommonParams() {
$params = [
'm_number' => Config::get('app_id'),
'timestamp' => TimeHelper::getMillisecond(),
'nonce_str' => StringHelper::getRandomString(32),
];
$params['sign'] = Signer::sign($params);
return $params;
}
public static function request(AbstractRequest $request) {
$params = self::getCommonParams();
$params = array_merge($params, $request->getParams());
try {
$response = self::getClient()->post($request->getUrl(), [
'query' => $params
]);
$body = (string)$response->getBody();
$result = json_decode($body, true);
if (empty($result)) {
$result = [
'return_code' => 'FAIL',
'error_code' => 'RESPONSE_ERROR',
'error_msg' => '返回数据异常',
];
}
return new Result($result);
} catch (Exception $e) {
return new Result([
'return_code' => 'FAIL',
'error_code' => 'NETWORK_ERROR',
'error_msg' => '网络错误',
]);
}
}
protected static function getClient(): Client {
if (!self::$client) {
self::$client = new Client([
'base_uri' => Config::get('base_url'),
'handler' => HandlerStack::create(new CoroutineHandler()),
'headers' => [
'Content-Type' => 'application/json',
],
'timeout' => 5,
'swoole' => [
'timeout' => 10,
'socket_buffer_size' => 1024 * 1024 * 2,
],
]);
}
return self::$client;
}
}

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay;
use App\Helper\OmiPay\Request\GetExchangeRateRequest;
use App\Helper\OmiPay\Request\MakeJSAPIOrderRequest;
use App\Helper\OmiPay\Request\QueryRefundRequest;
use App\Helper\OmiPay\Request\RefundRequest;
class Api extends AbstractApi
{
public static function getExchangeRate($currency, $baseCurrency, $platform = 'WECHATPAY', $language = 'CHS') {
$request = new GetExchangeRateRequest();
$request->setCurrency($currency);
$request->setBaseCurrency($baseCurrency);
$request->setPlatform($platform);
$request->setLanguage($language);
return self::request($request);
}
public static function makeJSAPIOrder($orderName, $outOrderNo, $currency, $amount, $notifyUrl, $redirectUrl) {
$request = new MakeJSAPIOrderRequest();
$request->setOrderName($orderName);
$request->setCurrency($currency);
$request->setOutOrderNo($outOrderNo);
$request->setAmount($amount);
$request->setNotifyUrl($notifyUrl);
$request->setRedirectUrl($redirectUrl);
$request->setDirectPay(0);
$request->setShowPcPayUrl(0);
return self::request($request);
}
public static function refund($orderNo, $outRefundNo, $amount) {
$request = new RefundRequest();
$request->setOrderNo($orderNo);
$request->setOutRefundNo($outRefundNo);
$request->setAmount($amount);
return self::request($request);
}
public static function queryRefund($refundNo) {
$request = new QueryRefundRequest();
$request->setRefundNo($refundNo);
return self::request($request);
}
}

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay;
use App\Helper\StringHelper;
use App\Helper\TimeHelper;
class Config
{
private static $params = [
'app_id' => '30042195760',
'secret_key' => 'cea6f34bea8640dea91fd8b7a926a9a5',
'base_url' => 'https://www.omipay.com.cn',
];
public static function get($key) {
return self::$params[$key] ?: null;
}
}

@ -0,0 +1,34 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay\Request;
use App\Helper\OmiPay\Config;
abstract class AbstractRequest
{
protected $uri;
protected $method;
protected $_params = [];
public function getUrl() {
return Config::get('base_url') . $this->uri;
}
public function getParams() {
return $this->_params;
}
public function __get($name)
{
return $this->_params[$name];
}
public function __set($name, $value)
{
$this->_params[$name] = $value;
}
}

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay\Request;
class GetExchangeRateRequest extends AbstractRequest
{
protected $uri = '/omipay/api/v2/GetExchangeRate';
public function setCurrency($currency) {
$this->currency = $currency;
}
public function setBaseCurrency($baseCurrency) {
$this->base_currency = $baseCurrency;
}
public function setPlatform($platform) {
$this->platform = $platform;
}
public function setLanguage($language) {
$this->language = $language;
}
}

@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay\Request;
class MakeJSAPIOrderRequest extends AbstractRequest
{
protected $uri = '/omipay/api/v2/MakeJSAPIOrder';
public function setOrderName($orderName) {
$this->order_name = $orderName;
}
public function setOutOrderNo($outOrderNo) {
$this->out_order_no = $outOrderNo;
}
public function setCurrency($currency) {
$this->currency = $currency;
}
public function setAmount($amount) {
$this->amount = $amount;
}
public function setNotifyUrl($notifyUrl) {
$this->notify_url = $notifyUrl;
}
public function setRedirectUrl($redirectUrl) {
$this->redirect_url = $redirectUrl;
}
public function setDirectPay($directPay) {
$this->direct_pay = $directPay;
}
public function setShowPcPayUrl($showPcPayUrl) {
$this->show_pc_pay_url = $showPcPayUrl;
}
public function setONumber($oNumber) {
$this->o_number = $oNumber;
}
public function setPosNo($posNo) {
$this->pos_no = $posNo;
}
}

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay\Request;
class QueryOrderRequest extends AbstractRequest
{
protected $uri = '/omipay/api/v2/QueryOrder';
public function setOrderNo($orderNo) {
$this->order_no = $orderNo;
}
}

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay\Request;
class QueryRefundRequest extends AbstractRequest
{
protected $uri = '/omipay/api/v2/QueryRefund';
public function setRefundNo($refundNo) {
$this->refund_no = $refundNo;
}
}

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay\Request;
class RefundRequest extends AbstractRequest
{
protected $uri = '/omipay/api/v2/Refund';
public function setOrderNo($orderNo) {
$this->order_no = $orderNo;
}
public function setOutRefundNo($outRefundNo) {
$this->out_refund_no = $outRefundNo;
}
public function setAmount($amount) {
$this->amount = $amount;
}
}

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay;
class Result
{
private $data;
public function __construct($data)
{
$this->data = $data;
}
public function isSuccess() {
return $this->data['return_code'] == 'SUCCESS';
}
public function get($key) {
return $this->data[$key] ?? null;
}
}

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Helper\OmiPay;
class Signer
{
public static function sign($params) {
$signString = $params['m_number'] . '&'
. $params['timestamp'] . '&'
. $params['nonce_str'] . '&'
. Config::get('secret_key');
return strtoupper(md5($signString));
}
public static function verify($params) {
$sign = $params['sign'] ?? '';
return $sign == self::sign($params);
}
}

@ -0,0 +1,57 @@
<?php
declare(strict_types=1);
namespace App\Helper;
class Param
{
public const EMPTY_VALUES = ['', null];
public const ZERO_VALUES = [0, '0', '', null];
/**
* params是否存在key键若key对应的值存在于emptyValues中则也认为不存在
*/
public static function has(array $params, $key, array $emptyValues = self::EMPTY_VALUES): bool
{
if (isset($params[$key])) {
foreach ($emptyValues as $value) {
if ($params[$key] === $value) {
return false;
}
}
return true;
}
return false;
}
public static function require(array $params, array $requireKeys): array
{
$requireParams = [];
foreach ($requireKeys as $key) {
$requireParams[$key] = $params[$key] ?? null;
}
return $requireParams;
}
public static function default(array $params, array $defaults): array
{
foreach ($defaults as $key => $value) {
if (!isset($params[$key])) {
$params[$key] = $value;
}
}
return $params;
}
public static function remove(array $params, array $removeKeys): array
{
foreach ($removeKeys as $key) {
if (isset($params[$key])) {
unset($params[$key]);
}
}
return $params;
}
}

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use Hyperf\AsyncQueue\Driver\DriverFactory;
use Hyperf\Utils\ApplicationContext;
class Queue
{
private static $factory;
private static function getFactory()
{
if (is_null(self::$factory)) {
self::$factory = ApplicationContext::getContainer()->get(DriverFactory::class);
}
return self::$factory;
}
public static function push($jobClass, $params, int $delay = 0): bool
{
$job = new $jobClass($params);
return self::getFactory()->get($job->getQueueName())->push($job, $delay);
}
}

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use Hyperf\Redis\RedisFactory;
use Hyperf\Redis\RedisProxy;
use Hyperf\Utils\ApplicationContext;
/**
* Redis辅助类
*/
class Redis
{
/**
* @var RedisFactory
*/
private static $factory;
private static function getFactory(): RedisFactory
{
if (is_null(self::$factory)) {
self::$factory = ApplicationContext::getContainer()->get(RedisFactory::class);
}
return self::$factory;
}
public static function getInstance($poolName = 'default'): RedisProxy
{
return self::getFactory()->get($poolName);
}
public static function __callStatic($method, $args)
{
return call_user_func_array([self::getInstance(), $method], $args);
}
}

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace App\Helper;
class RedisKey
{
public static function getGenerateAppIdKey($timestamp) {
return 'gennerate_app_id:' . date('Ymd', $timestamp);
}
public static function getGenerateOrderNoKey($timestamp) {
return 'gennerate_order_no:' . date('YmdHi', $timestamp);
}
}

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace App\Helper;
use App\Constants\ResultCode;
use Hyperf\Utils\Contracts\Arrayable;
class Result implements Arrayable
{
private $code;
private $message;
private $data = [];
public function __construct(int $code = ResultCode::SUCCESS, string $message = '', array $data = [])
{
$this->code = $code;
$this->message = empty($message) ? ResultCode::getMessage($code) : $message;
$this->data = $data;
}
public function getCode(): int
{
return $this->code;
}
public function setCode(int $code)
{
return $this->code = $code;
}
public function getMessage(): string
{
return $this->message;
}
public function setMessage(string $message)
{
return $this->message = empty($message) ? ResultCode::getMessage($this->code) : $message;
}
public function getData(): array
{
return $this->data;
}
public function setData(array $data)
{
return $this->data = $data;
}
public function toArray(): array
{
return [
'code' => $this->code,
'message' => $this->message,
'data' => new \ArrayObject($this->data),
];
}
public function __toString()
{
return json_encode($this->toArray(), JSON_UNESCAPED_UNICODE);
}
}

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
namespace App\Helper;
class Signer
{
public static function sign($params, $secretKey) {
$signString = $params['app_id'] . '&'
. $params['timestamp'] . '&'
. $params['nonce_str'] . '&'
. $params['data'] . '&'
. $secretKey;
return md5($signString);
}
public static function verify($params, $secretKey) {
$sign = self::sign($params, $secretKey);
return $sign == $params['sign'];
}
}

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
namespace App\Helper;
class StringHelper
{
public static function getRandomString($length, $withSpecialChar = false)
{
$chars = array(
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k',
'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '0', '1', '2',
'3', '4', '5', '6', '7', '8', '9'
);
if($withSpecialChar){
$chars = array_merge($chars, array(
'!', '@', '#', '$', '?', '|', '{', '/', ':', ';',
'%', '^', '&', '*', '(', ')', '-', '_', '[', ']',
'}', '<', '>', '~', '+', '=', ',', '.'
));
}
$charsLen = count($chars) - 1;
shuffle($chars);
$password = '';
for($i=0; $i<$length; $i++){
$password .= $chars[mt_rand(0, $charsLen)];
}
return $password;
}
}

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Helper;
class TimeHelper
{
public static function getMillisecond(){
return (intval(round(microtime(true) * 1000)));
}
}

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace App\Job;
use App\Service\UserService;
class AfterLoginJob extends Job
{
public function handle()
{
/**
* @var UserService $userService
*/
$userService = make(UserService::class);
$userService->afterLogin($this->params);
}
}

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Job;
use App\Service\UserService;
class AfterRegisterJob extends Job
{
public function handle()
{
$userId = $this->params['user_id'] ?? '';
/**
* @var UserService $userService
*/
$userService = make(UserService::class);
$userService->afterRegister($userId);
}
}

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace App\Job;
use App\Service\PlayerRoleService;
class AfterSaveRoleJob extends Job
{
public function handle()
{
/**
* @var PlayerRoleService $playerRoleService
*/
$playerRoleService = make(PlayerRoleService::class);
$playerRoleService->save($this->params);
}
}

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Job;
use App\Service\SpendService;
class AfterSpendJob extends Job
{
public function handle()
{
$payOrderNumber = $this->params['pay_order_number'] ?? '';
/**
* @var SpendService $spendService
*/
$spendService = make(SpendService::class);
$spendService->afterSpend($payOrderNumber);
}
}

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace App\Job;
use Hyperf\AsyncQueue\Job as BaseJob;
class Job extends BaseJob
{
/**
* @var array
*/
public $params;
protected $queueName = 'default';
public function __construct(array $params)
{
$this->params = $this->prepare($params);
}
protected function prepare(array $params): array
{
return $params;
}
public function handle()
{
}
protected function getJobName()
{
return get_called_class();
}
public function getQueueName()
{
return $this->queueName;
}
}

@ -0,0 +1,53 @@
<?php
declare(strict_types=1);
namespace App\Job;
use App\Exception\BusinessException;
use App\Service\SmsService;
class SmsJob extends Job
{
public $params;
protected $queueName = 'sms';
public function __construct($params)
{
$this->params = $params;
}
public function handle()
{
$mobile = $this->params['mobile'] ?? null;
$options = $this->params['options'] ?? [];
$type = $options['type'] ?? '';
if (!$mobile) {
throw new BusinessException('缺少手机号');
}
if (!$type) {
throw new BusinessException('缺少类型');
}
/**
* @var SmsService $smsService
*/
$smsService = make(SmsService::class);
if ($type == 'content') {
$content = $options['content'] ?? '';
$smsService->send($mobile, $content);
} elseif ($type == 'code') {
$clientIp = $options['client_ip'] ?? '';
$smsService->sendCode($mobile, ['client_ip' => $clientIp]);
} elseif ($type == 'batch') {
if (!is_array($mobile)) {
$mobile = [$mobile];
}
$content = $options['content'] ?? '';
$smsService->sendBatch($mobile, $content);
} else {
throw new BusinessException('类型错误');
}
}
}

@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Listener;
use Hyperf\Database\Events\QueryExecuted;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Logger\LoggerFactory;
use Hyperf\Utils\Arr;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Psr\Log\LoggerInterface;
/**
* @Listener
*/
class DbQueryExecutedListener implements ListenerInterface
{
/**
* @var LoggerInterface
*/
private $logger;
public function __construct(ContainerInterface $container)
{
$this->logger = $container->get(LoggerFactory::class)->get('sql');
}
public function listen(): array
{
return [
QueryExecuted::class,
];
}
/**
* @param QueryExecuted $event
*/
public function process(object $event)
{
if ($event instanceof QueryExecuted) {
$sql = $event->sql;
if (! Arr::isAssoc($event->bindings)) {
foreach ($event->bindings as $key => $value) {
$sql = Str::replaceFirst('?', "'{$value}'", $sql);
}
}
$this->logger->info(sprintf('[%s] %s', $event->time, $sql));
}
}
}

@ -0,0 +1,85 @@
<?php
declare(strict_types=1);
namespace App\Listener;
use App\Helper\Macro\WhereHasIn;
use App\Helper\Macro\WhereHasMorphIn;
use App\Helper\Macro\WhereHasNotIn;
use Hyperf\Database\Model\Builder;
use Hyperf\Database\Model\Relations\Relation;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\Framework\Event\BootApplication;
/**
* @Listener
*/
class ModelPrepareListener implements ListenerInterface
{
public function listen(): array
{
return [
BootApplication::class,
];
}
public function process(object $event)
{
$this->morphMapRelation();
$this->macroWhereHasIn();
}
private function morphMapRelation()
{
Relation::morphMap([
]);
}
private function macroWhereHasIn()
{
Builder::macro('whereHasIn', function ($relationName, $callable = null) {
return (new WhereHasIn($this, $relationName, function ($nextRelation, $builder) use ($callable) {
if ($nextRelation) {
return $builder->whereHasIn($nextRelation, $callable);
}
if ($callable) {
return $builder->callScope($callable);
}
return $builder;
}))->execute();
});
Builder::macro('orWhereHasIn', function ($relationName, $callable = null) {
return $this->orWhere(function ($query) use ($relationName, $callable) {
return $query->whereHasIn($relationName, $callable);
});
});
Builder::macro('whereHasNotIn', function ($relationName, $callable = null) {
return (new WhereHasNotIn($this, $relationName, function ($nextRelation, $builder) use ($callable) {
if ($nextRelation) {
return $builder->whereHasNotIn($nextRelation, $callable);
}
if ($callable) {
return $builder->callScope($callable);
}
return $builder;
}))->execute();
});
Builder::macro('orWhereHasNotIn', function ($relationName, $callable = null) {
return $this->orWhere(function ($query) use ($relationName, $callable) {
return $query->whereHasNotIn($relationName, $callable);
});
});
Builder::macro('whereHasMorphIn', WhereHasMorphIn::make());
Builder::macro('orWhereHasMorphIn', function ($relation, $types, $callback = null) {
return $this->whereHasMorphIn($relation, $types, $callback, 'or');
});
}
}

@ -0,0 +1,83 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Listener;
use Hyperf\AsyncQueue\AnnotationJob;
use Hyperf\AsyncQueue\Event\AfterHandle;
use Hyperf\AsyncQueue\Event\BeforeHandle;
use Hyperf\AsyncQueue\Event\Event;
use Hyperf\AsyncQueue\Event\FailedHandle;
use Hyperf\AsyncQueue\Event\RetryHandle;
use Hyperf\Event\Annotation\Listener;
use Hyperf\Event\Contract\ListenerInterface;
use Hyperf\ExceptionHandler\Formatter\FormatterInterface;
use Hyperf\Logger\LoggerFactory;
/**
* @Listener
*/
class QueueHandleListener implements ListenerInterface
{
/**
* @var \Psr\Log\LoggerInterface
*/
protected $logger;
/**
* @var FormatterInterface
*/
protected $formatter;
public function __construct(LoggerFactory $loggerFactory, FormatterInterface $formatter)
{
$this->logger = $loggerFactory->get('queue');
$this->formatter = $formatter;
}
public function listen(): array
{
return [
AfterHandle::class,
BeforeHandle::class,
FailedHandle::class,
RetryHandle::class,
];
}
public function process(object $event)
{
if ($event instanceof Event && $event->message->job()) {
$job = $event->message->job();
$jobClass = get_class($job);
if ($job instanceof AnnotationJob) {
$jobClass = sprintf('Job[%s@%s]', $job->class, $job->method);
}
$date = date('Y-m-d H:i:s');
switch (true) {
case $event instanceof BeforeHandle:
$this->logger->info(sprintf('[%s] Processing %s.', $date, $jobClass));
break;
case $event instanceof AfterHandle:
$this->logger->info(sprintf('[%s] Processed %s.', $date, $jobClass));
break;
case $event instanceof FailedHandle:
$this->logger->error(sprintf('[%s] Failed %s.', $date, $jobClass));
$this->logger->error($this->formatter->format($event->getThrowable()));
break;
case $event instanceof RetryHandle:
$this->logger->warning(sprintf('[%s] Retried %s.', $date, $jobClass));
break;
}
}
}
}

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Model;
class App extends Model
{
public const STATUS_ACTIVE = 1;
protected $table = 'apps';
}

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
namespace App\Model;
class Merchant extends Model
{
public const STATUS_ACTIVE = 1;
protected $table = 'merchants';
}

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace App\Model;
use Hyperf\DbConnection\Model\Model as BaseModel;
abstract class Model extends BaseModel
{
public static function alias($alias = null)
{
$name = with(new static)->getTable();
if ($alias) {
$name .= ' as ' . $alias;
}
return $name;
}
public static function fromAlias($alias)
{
return static::from(static::alias($alias));
}
public function getRawAttribute($key)
{
if (! $key) {
return null;
}
return $this->attributes[$key] ?? null;
}
}

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
namespace App\Model;
class Order extends Model
{
public const STATUS_PREPARE = 1;
public const STATUS_WAIT_PAY = 2;
public const STATUS_PAYED = 6;
public const STATUS_FAILED = 9;
protected $table = 'orders';
}

@ -0,0 +1,22 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
namespace App\Process;
use Hyperf\AsyncQueue\Process\ConsumerProcess;
use Hyperf\Process\Annotation\Process;
/**
* @Process
*/
class AsyncQueueConsumer extends ConsumerProcess
{
}

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
namespace App\Process;
use Hyperf\AsyncQueue\Process\ConsumerProcess;
use Hyperf\Process\Annotation\Process;
/**
* @Process()
*/
class SmsQueueConsumer extends ConsumerProcess
{
/**
* @var string
*/
protected $queue = 'sms';
}

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
namespace App\Repository;
use App\Model\Promote;
class PromoteRepository
{
public function getLevelPromotesById($id, $columns = ['*']) {
$promote = Promote::query()->where('id', $id)->first(Promote::$levelColumns);
$levelIds = [];
foreach (Promote::$levelColumns as $column) {
if ($promote->{$column} > 0) {
$levelIds[] = $promote->{$column};
}
}
return Promote::query()->whereIn('id', $levelIds)->get($columns);
}
}

@ -0,0 +1,55 @@
<?php
declare(strict_types=1);
namespace App\Request;
use App\Exception\BusinessException;
use App\Helper\Signer;
use App\Model\App;
class ApiRequest extends Request
{
protected App $app;
public function __construct(array $params = [])
{
$this->checkApp($params['app_id'] ?? null);
$this->checkSign($params);
$data = json_decode($params['data'], true);
foreach ($this->defaults() as $key => $value) {
if (isset($data[$key])) {
if (empty($value) && empty($data[$key])) {
$data[$key] = $value;
}
} else {
$data[$key] = $value;
}
}
$this->_data = $data;
}
protected function checkSign($params) {
/* if ($params['timestamp'] < time() - 600) {
throw new BusinessException('请求已过期');
} */
if (!Signer::verify($params, $this->app->app_key)) {
throw new BusinessException('验签错误');
}
}
protected function checkApp($appId) {
if (is_null($appId)) {
throw new BusinessException('[app_id]错误');
}
$app = App::query()->where('app_id', $appId)->first();
if (is_null($app)) {
throw new BusinessException('APP错误');
}
$this->app = $app;
}
public function getApp() {
return $this->app;
}
}

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace App\Request;
use Hyperf\Validation\Rule;
class JsapiPayRequest extends ApiRequest
{
public function rules(): array
{
return [
'order_name' => ['required', 'max:64'],
'out_order_no' => ['required', 'max:32'],
'amount' => ['required', Rule::in([5,10,20,30,50,80,98,198,298,398,498,598,698,798,898,998])],
'currency' => ['required', Rule::in(['CNY'])],
'show_pc_pay_url' => ['integer', Rule::in([1, 2])],
'direct_pay' => ['integer', Rule::in([1, 2])],
'notify_url' => ['required', 'url'],
'redirect_url' => ['required', 'url'],
'o_number' => ['max:32'],
'pos_no' => ['max:32'],
];
}
}

@ -0,0 +1,212 @@
<?php
declare(strict_types=1);
namespace App\Request;
use App\Annotation\Validation\After;
use App\Exception\BusinessException;
use App\Exception\ValidationException;
use App\Helper\Annotation;
use Hyperf\Contract\ValidatorInterface;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Utils\Contracts\MessageBag;
use Hyperf\Validation\Contract\ValidatorFactoryInterface;
class Request
{
/**
* @Inject()
* @var ValidatorFactoryInterface
*/
protected ValidatorFactoryInterface $validationFactory;
protected $_data = [];
protected $scene;
protected $isCheckScene;
protected $scenes = [];
/**
* @var ValidatorInterface $validator
*/
protected $validator;
/**
* @param array $data 表单数据
*/
public function __construct(array $data = [])
{
foreach ($this->defaults() as $key => $value) {
if (isset($data[$key])) {
if (empty($value) && empty($data[$key])) {
$data[$key] = $value;
}
} else {
$data[$key] = $value;
}
}
$this->_data = $data;
}
/**
* 设置表单参数默认值,暂不支持多维数组
* @return array
*/
public function defaults(): array
{
return [];
}
public function rules(): array
{
return [];
}
public function messages(): array
{
return [];
}
public function attributes(): array
{
return [];
}
protected function before()
{
}
protected final function handleBefore()
{
$this->before();
$this->checkScene();
}
protected function getRules()
{
$rules = $this->rules();
$scene = $this->getScene();
if ($scene && isset($this->scenes[$scene]) && is_array($this->scenes[$scene])) {
$newRules = [];
foreach ($this->scenes[$scene] as $field) {
if (array_key_exists($field, $rules)) {
$newRules[$field] = $rules[$field];
}
}
return $newRules;
}
return $rules;
}
public final function validate($throwException = true)
{
$this->handleBefore();
$this->validator = $this->validationFactory->make($this->_data, $this->getRules(), $this->messages(), $this->attributes());
$this->handleAfter();
$fails = $this->validator->fails();
if ($throwException && $fails) {
throw new ValidationException($this->getErrorMessage());
}
return !$fails;
}
protected function after()
{
}
protected final function handleAfter()
{
$this->validator->after(function ($validator) {
$items = Annotation::getMethodsByAnnotationAndClass(After::class, static::class);
foreach ($items as $item) {
if (empty($item['annotation']->scenes) || in_array($this->scene, $item['annotation']->scenes)) {
$this->{$item['method']}();
}
}
});
$this->after();
}
public function addError($field, $message)
{
$this->validator->errors()->add($field, $message);
}
public function errors(): MessageBag
{
return $this->validator->errors();
}
public function getErrorMessage($isAll = false): string
{
if ($this->errors()->count() > 0) {
$messages = $this->errors()->all();
return $isAll ? implode('', $messages) : $messages[0];
}
return '';
}
public final function getData()
{
return $this->_data;
}
public final function getSceneData()
{
$scene = $this->getScene();
if ($scene && isset($this->scenes[$scene]) && is_array($this->scenes[$scene])) {
$newData = [];
foreach ($this->scenes[$scene] as $field) {
if (array_key_exists($field, $this->_data)) {
$newData[$field] = $this->_data[$field];
}
}
return $newData;
}
return $this->_data;
}
/**
* @param string $scene 场景名称
* @param bool $isCheckScene 是否检查场景是否存在
*/
public final function setScene(string $scene, bool $isCheckScene = true): void
{
$this->scene = $scene;
$this->isCheckScene = $isCheckScene;
}
protected final function checkScene()
{
if ($this->getScene() && $this->isCheckScene && !isset($this->scenes[$this->scene])) {
throw new BusinessException('Scene undefined!');
}
}
public final function getScene()
{
return $this->scene;
}
public function __get($key)
{
return isset($this->_data[$key]) ? $this->_data[$key] : null;
}
public function __set($key, $value)
{
$this->_data[$key] = $value;
}
public function __isset($key)
{
return $this->__get($key);
}
}

@ -0,0 +1,24 @@
<?php
namespace App\Scopes;
trait CommonPromoteScopes
{
/**
* 查询属于某个推广员的玩家
* @param $query
* @param $promote 推广员
* @param $containSubPromotes 是否包含所有下级
*/
public function scopeOfPromote($query, $promote, $containSubPromotes = true)
{
if ($containSubPromotes) {
$query->whereHas('promote', function ($query) use ($promote) {
$query->ofParent($promote)->orWhere('promote_id', $promote->id);
});
} else {
$query->where('promote_id', $promote->id);
}
return $query;
}
}

@ -0,0 +1,35 @@
<?php
namespace App\Scopes;
use App\Helper\Time;
trait CommonTimeScopes
{
public function scopeRangeTime($query, $column, $timeRange, $withTime = true)
{
if (!$timeRange) {
return $query;
}
$timeRange = Time::dateTimeRange($timeRange, $withTime);
return $query->whereBetween($column, [strtotime($timeRange[0]), strtotime($timeRange[1])]);
}
public function scopeOfMonth($query, $column, $month, $withTime = true)
{
if (!$month) {
return $query;
}
$firstDate = $month . '-01';
$lastDate = Time::getMonthLastDate($month);
$timeRange = Time::dateTimeRange([$firstDate, $lastDate], $withTime);
return $query->whereBetween($column, [strtotime($timeRange[0]), strtotime($timeRange[1])]);
}
public function scopeTimeOverlay($query, $rangeColumns, $timeRange)
{
return $query->whereNot(function ($q) use ($rangeColumns, $timeRange) {
$q->where($rangeColumns[1], '<', $timeRange[0])->orWhere($rangeColumns[0], '<', $timeRange[1]);
});
}
}

@ -0,0 +1,19 @@
<?php
namespace App\Scopes;
trait GameScopes
{
public function scopeOfConditions($query, $params)
{
if (!empty($params['relation_game_id'])) {
$query->where('relation_game_id', $params['relation_game_id']);
}
if (!empty($params['base_game_id'])) {
$query->where('base_game_id', $params['base_game_id']);
}
if (!empty($params['sdk_version'])) {
$query->where('sdk_version', $params['sdk_version']);
}
}
}

@ -0,0 +1,53 @@
<?php
namespace App\Scopes;
trait PlayerRoleScopes
{
public function scopeOfConditions($query, $params)
{
if (!empty($params['server_id'])) {
$query->where('server_id', $params['server_id']);
}
if (!empty($params['sdk_version'])) {
$query->where('sdk_version', $params['sdk_version']);
}
if (!empty($params['game_id'])) {
$query->where('game_id', $params['game_id']);
}
if (!empty($params['role_name'])) {
$query->where('role_name', $params['role_name']);
}
if (!empty($params['server_name'])) {
$query->where('server_name', $params['server_name']);
}
if (!empty($params['user_account'])) {
$query->where('user_account', $params['user_account']);
}
if (!empty($params['role_id'])) {
$query->where('role_id', $params['role_id']);
}
}
public function scopeRangeRoleLevel($query, ?array $roleLevelRange)
{
if (is_null($roleLevelRange)) {
return $query;
}
$min = $roleLevelRange[0] ?? null;
$min == '' ? null : $min;
$max = $roleLevelRange[1] ?? null;
$max == '' ? null : $max;
if (!is_null($min)) {
$query->where('role_level', '>=', $min);
}
if (!is_null($max)) {
$query->where('role_level', '<=', $max);
}
return $query;
}
}

@ -0,0 +1,8 @@
<?php
namespace App\Scopes;
trait PlayerScopes
{
}

@ -0,0 +1,39 @@
<?php
namespace App\Scopes;
trait PromoteScopes
{
public function scopeOfConditions($query, $params)
{
if (!empty($params['level'])) {
$query->where('level', $params['level']);
}
if (!empty($params['parent_id'])) {
$query->where('parent_id', $params['parent_id']);
}
if (!empty($params['account'])) {
$query->where('account', 'like', '%' . $params['account'] . '%');
}
if (!empty($params['mobile'])) {
$query->where('mobile_phone', 'like', '%' . $params['mobile'] . '%');
}
if (!empty($params['idcard'])) {
$query->where('idcard', 'like', '%' . $params['idcard'] . '%');
}
if (!empty($params['realname'])) {
$query->where('real_name', 'like', '%' . $params['realname'] . '%');
}
if (isset($params['status']) && $params['status'] != -1) {
$query->where('status', $params['status']);
}
}
/**
* 查找子推广账号
*/
public function scopeOfParent($query, $promote)
{
return $query->where('chain', 'like', $promote->chain . $promote->id . '/%');
}
}

@ -0,0 +1,49 @@
<?php
namespace App\Scopes;
use App\Model\Promote;
trait SpendScopes
{
public function scopeOfConditions($query, $params)
{
if (!empty($params['server_id'])) {
$query->where('server_id', $params['server_id']);
}
if (!empty($params['server_name'])) {
$query->where('server_name', $params['server_name']);
}
if (!empty($params['game_id'])) {
$query->where('game_id', $params['game_id']);
}
if (!empty($params['game_name'])) {
$query->where('game_name', $params['game_name']);
}
if (isset($params['pay_status']) && $params['pay_status'] != -1) {
$query->where('pay_status', $params['pay_status']);
}
if (isset($params['pay_way']) && $params['pay_way'] != -99) {
$query->where('pay_way', $params['pay_way']);
}
if (!empty($params['pay_order_number'])) {
$query->where('pay_order_number', $params['pay_order_number']);
}
if (!empty($params['user_account'])) {
$query->where('user_account', $params['user_account']);
}
if (!empty($params['role_name'])) {
$query->where('game_player_name', $params['game_player_name']);
}
return $query;
}
public function scopeSettleOrder($query, string $tableAlias = null)
{
$column = 'is_check';
if ($tableAlias) {
$column = $tableAlias . '.' . $column;
}
return $query->where($column, 1);
}
}

@ -0,0 +1,17 @@
<?php
namespace App\Scopes;
trait UserScopes
{
public function scopeOfConditions($query, $params)
{
if (!empty($params['account'])) {
$query->where('account', $params['account']);
}
if (!empty($params['id'])) {
$query->where('id', $params['id']);
}
return $query;
}
}

@ -0,0 +1,9 @@
<?php
declare(strict_types=1);
namespace App\Service;
abstract class AbstractService
{
}

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace App\Service;
use App\Helper\Redis;
use App\Helper\RedisKey;
use App\Helper\StringHelper;
use App\Model\App;
use App\Model\Merchant;
class AppService extends AbstractService
{
public function createApp(Merchant $merchant) {
$app = new App();
$app->merchant_id = $merchant->id;
$app->app_id = $this->generateAppId();
$app->app_key = StringHelper::getRandomString(32);
$app->status = App::STATUS_ACTIVE;
$app->save();
return $app;
}
private function generateAppId() {
$now = time();
$key = RedisKey::getGenerateAppIdKey($now);
$expireAt = strtotime(date('Y-m-d 23:59:59', $now)) + 1;
$incrId = Redis::incr($key);
$incrId = '' . $incrId;
Redis::expireAt($key, $expireAt);
$padLength = 8 - strlen($incrId);
$incrId = str_pad($incrId, $padLength, '0', STR_PAD_LEFT);
return date('Ymd', $now) . $incrId;
}
}

@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace App\Service;
use App\Model\Merchant;
class MerchantService extends AbstractService
{
public function createMerchant($params) {
$merchant = new Merchant();
$merchant->username = $params['username'];
$merchant->password = $params['password'];
$merchant->email = $params['email'] ?: '';
$merchant->mobile = $params['mobile'] ?: '';
$merchant->register_at = date('Y-m-d H:i:s');
$merchant->register_ip = $params['ip'] ?: '';
$merchant->status = Merchant::STATUS_ACTIVE;
$merchant->save();
return $merchant;
}
}

@ -0,0 +1,97 @@
<?php
declare(strict_types=1);
namespace App\Service;
use App\Exception\BusinessException;
use App\Helper\OmiPay\Api;
use App\Helper\OmiPay\Result;
use App\Helper\OmiPay\Signer;
use App\Helper\Redis;
use App\Helper\RedisKey;
use App\Model\App;
use App\Model\Order;
class PaymentService extends AbstractService
{
public function createOrder(App $app, array $params) {
$order = new Order();
$order->merchant_id = $app->merchant_id;
$order->app_id = $app->app_id;
$order->order_no = $this->generateOrderNo();
$order->out_order_no = $params['out_order_no'];
$order->amount = $params['amount'];
$order->currency = $params['currency'];
$order->redirect_url = $params['redirect_url'];
$order->notify_url = $params['notify_url'];
$order->direct_pay = $params['direct_pay'] ?? 0;
$order->show_pc_pay_url = $params['show_pc_pay_url'] ?? 0;
$order->o_number = $params['o_number'] ?? '';
$order->pos_no = $params['pos_no'] ?? '';
$order->status = Order::STATUS_PREPARE;
$order->save();
return $order;
}
private function generateOrderNo() {
$now = time();
$key = RedisKey::getGenerateOrderNoKey($now);
$incrId = Redis::incr($key);
$incrId = '' . $incrId;
Redis::expire($key, 5*60);
$padLength = 6 - strlen($incrId);
$incrId = str_pad($incrId, $padLength, '0', STR_PAD_LEFT);
return date('YmdHis', $now) . $incrId;
}
public function updateOrderResult(Order $order, Result $result) {
if ($result->isSuccess()) {
$order->pay_order_no = $result->get('order_no');
$order->pay_url = $result->get('pay_url');
$order->status = Order::STATUS_WAIT_PAY;
} else {
$order->error_code = $result->get('error_code');
$order->error_msg = $result->get('error_msg');
$order->status = Order::STATUS_FAILED;
}
$order->save();
}
public function jsapiPay(App $app, array $params) {
$order = Order::where('app_id', $app->app_id)->where('out_order_no', $params['out_order_no'])->first();
if ($order) {
throw new BusinessException('订单重复');
}
$order = $this->createOrder($app, $params);
$result = Api::makeJSAPIOrder(
$order->order_name,
$order->order_no,
$order->currency,
$order->amount,
'http://146.70.113.165:9501/payment/notify',
'http://146.70.113.165:9501/payment/page?order_no=' . $order->order_no
);
$this->updateOrderResult($order, $result);
return $order;
}
public function notify($params) {
if (Signer::verify($params)) {
return 'SIGN FAIL';
}
if ($params['return_code'] != 'SUCCESS') {
return 'STATUS FAIL';
}
$order = Order::where('order_no', $params['out_order_no'])->where('status', Order::STATUS_WAIT_PAY)->first();
$order->status = Order::STATUS_PAYED;
$order->payed_at = date('Y-m-d');
$order->exchange_rate = $params['exchange_rate'];
$order->cny_amount = $params['cny_amount'];
$order->save();
if ($order->save()) {
return 'SUCCESS';
}
return 'UPDATE FAIL';
}
}

@ -0,0 +1,24 @@
#!/usr/bin/env php
<?php
ini_set('display_errors', 'on');
ini_set('display_startup_errors', 'on');
ini_set('memory_limit', '1G');
error_reporting(E_ALL);
date_default_timezone_set('Asia/Shanghai');
! defined('BASE_PATH') && define('BASE_PATH', dirname(__DIR__, 1));
! defined('SWOOLE_HOOK_FLAGS') && define('SWOOLE_HOOK_FLAGS', SWOOLE_HOOK_ALL);
require BASE_PATH . '/vendor/autoload.php';
// Self-called anonymous function that creates its own scope and keep the global namespace clean.
(function () {
Hyperf\Di\ClassLoader::init();
/** @var Psr\Container\ContainerInterface $container */
$container = require BASE_PATH . '/config/container.php';
$application = $container->get(Hyperf\Contract\ApplicationInterface::class);
$application->run();
})();

@ -0,0 +1,89 @@
{
"name": "hyperf/hyperf-skeleton",
"type": "project",
"keywords": [
"php",
"swoole",
"framework",
"hyperf",
"microservice",
"middleware"
],
"description": "A coroutine framework that focuses on hyperspeed and flexible, specifically use for build microservices and middlewares.",
"license": "Apache-2.0",
"require": {
"php": ">=7.3",
"hyperf/async-queue": "~2.2.0",
"hyperf/cache": "~2.2.0",
"hyperf/command": "~2.2.0",
"hyperf/config": "~2.2.0",
"hyperf/constants": "~2.2.0",
"hyperf/database": "~2.2.0",
"hyperf/db-connection": "~2.2.0",
"hyperf/framework": "~2.2.0",
"hyperf/guzzle": "~2.2.0",
"hyperf/http-server": "~2.2.0",
"hyperf/json-rpc": "~2.2.0",
"hyperf/logger": "~2.2.0",
"hyperf/memory": "~2.2.0",
"hyperf/model-cache": "~2.2.0",
"hyperf/process": "~2.2.0",
"hyperf/redis": "~2.2.0",
"hyperf/rpc": "~2.2.0",
"hyperf/rpc-client": "~2.2.0",
"hyperf/rpc-server": "~2.2.0",
"hyperf/validation": "^2.2",
"phpoffice/phpspreadsheet": "^1.24"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "^3.0",
"hyperf/devtool": "~2.2.0",
"hyperf/ide-helper": "~2.2.0",
"hyperf/testing": "~2.2.0",
"mockery/mockery": "^1.0",
"phpstan/phpstan": "^0.12",
"swoole/ide-helper": "^4.5"
},
"suggest": {
"ext-openssl": "Required to use HTTPS.",
"ext-json": "Required to use JSON.",
"ext-pdo": "Required to use MySQL Client.",
"ext-pdo_mysql": "Required to use MySQL Client.",
"ext-redis": "Required to use Redis Client."
},
"autoload": {
"psr-4": {
"App\\": "app/"
},
"files": [
"app/Helper/Functions.php"
]
},
"autoload-dev": {
"psr-4": {
"HyperfTest\\": "./test/"
}
},
"minimum-stability": "dev",
"prefer-stable": true,
"config": {
"optimize-autoloader": true,
"sort-packages": true
},
"extra": [],
"scripts": {
"post-root-package-install": [
"@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
],
"post-autoload-dump": [
"rm -rf runtime/container"
],
"test": "co-phpunit --prepend test/bootstrap.php -c phpunit.xml --colors=always",
"cs-fix": "php-cs-fixer fix $1",
"analyse": "phpstan analyse --memory-limit 300M -l 0 -c phpstan.neon ./app ./config",
"start": [
"Composer\\Config::disableProcessTimeout",
"php ./bin/hyperf.php start"
]
}
}

9278
composer.lock generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -0,0 +1,21 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'scan' => [
'paths' => [
BASE_PATH . '/app',
],
'ignore_annotations' => [
'mixin',
],
],
];

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
];

@ -0,0 +1,38 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'driver' => Hyperf\AsyncQueue\Driver\RedisDriver::class,
'redis' => [
'pool' => 'default',
],
'channel' => '{queue}',
'timeout' => 2,
'retry_seconds' => 5,
'handle_timeout' => 10,
'processes' => 1,
'concurrent' => [
'limit' => 10,
],
],
'sms' => [
'driver' => Hyperf\AsyncQueue\Driver\RedisDriver::class,
'channel' => '{sms.queue}',
'timeout' => 2,
'retry_seconds' => 5,
'handle_timeout' => 10,
'processes' => 1,
'concurrent' => [
'limit' => 5,
],
],
];

@ -0,0 +1,18 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'driver' => Hyperf\Cache\Driver\RedisDriver::class,
'packer' => Hyperf\Utils\Packer\PhpSerializerPacker::class,
'prefix' => 'c:',
],
];

@ -0,0 +1,12 @@
<?php
declare(strict_types=1);
return [
'lanhuo' => [
'base_url' => env('LANHUO_URL', 'https://c.lshygame.com'),
'app_id' => 'LLWF71700000001644',
'app_key' => '31h8a',
'app_secret' => '9b0c2130ea023243ff76bf7bc724cfc2',
],
];

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
];

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'driver' => env('DB_DRIVER', 'mysql'),
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', 3306),
'database' => env('DB_DATABASE', 'hyperf'),
'username' => env('DB_USERNAME', 'root'),
'password' => env('DB_PASSWORD', ''),
'charset' => env('DB_CHARSET', 'utf8mb4'),
'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'),
'prefix' => env('DB_PREFIX', ''),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float) env('DB_MAX_IDLE_TIME', 60),
],
'cache' => [
'handler' => Hyperf\ModelCache\Handler\RedisHandler::class,
'cache_key' => '{mc:%s:m:%s}:%s:%s',
'prefix' => 'default',
'ttl' => 3600 * 24,
'empty_model_ttl' => 600,
'load_script' => true,
],
'commands' => [
'gen:model' => [
'path' => 'app/Model',
'force_casts' => true,
'inheritance' => 'Model',
'uses' => '',
'table_mapping' => [],
],
],
],
];

@ -0,0 +1,14 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
\App\Contract\SmsSender::class => \App\Factory\SmsSenderFactory::class
];

@ -0,0 +1,44 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'generator' => [
'amqp' => [
'consumer' => [
'namespace' => 'App\\Amqp\\Consumer',
],
'producer' => [
'namespace' => 'App\\Amqp\\Producer',
],
],
'aspect' => [
'namespace' => 'App\\Aspect',
],
'command' => [
'namespace' => 'App\\Command',
],
'controller' => [
'namespace' => 'App\\Controller',
],
'job' => [
'namespace' => 'App\\Job',
],
'listener' => [
'namespace' => 'App\\Listener',
],
'middleware' => [
'namespace' => 'App\\Middleware',
],
'Process' => [
'namespace' => 'App\\Processes',
],
],
];

@ -0,0 +1,19 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'handler' => [
'http' => [
Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
App\Exception\Handler\AppExceptionHandler::class,
],
],
];

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
];

@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
$logPath = rtrim(env('LOG_PATH', '@runtime'), '/');
$logPath = $logPath === '@runtime' ? BASE_PATH . '/runtime/logs/' : $logPath;
$logFileName = $logPath . '/' . env('LOG_FILE_NAME', env('APP_NAME', 'hyperf') . '.log');
/* return [
'default' => [
'handler' => [
'class' => \Monolog\Handler\StreamHandler::class,
'constructor' => [
'stream' => $logFileName,
'level' => \Monolog\Logger::DEBUG,
],
],
'formatter' => [
'class' => \Monolog\Formatter\LineFormatter::class,
'constructor' => [
'format' => null,
'dateFormat' => null,
'allowInlineLineBreaks' => true,
]
],
],
]; */
return [
'default' => [
'handler' => [
'class' => Monolog\Handler\RotatingFileHandler::class,
'constructor' => [
'filename' => $logFileName,
'maxFiles' => env('LOG_MAX_FILES', 7),
'level' => Monolog\Logger::DEBUG,
],
],
'formatter' => [
'class' => Monolog\Formatter\LineFormatter::class,
'constructor' => [
'format' => null,
'dateFormat' => 'Y-m-d H:i:s',
'allowInlineLineBreaks' => true,
],
],
],
];

@ -0,0 +1,15 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'http' => [
],
];

@ -0,0 +1,13 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
];

@ -0,0 +1,27 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'default' => [
'host' => env('REDIS_HOST', 'localhost'),
'auth' => env('REDIS_AUTH', null),
'port' => (int) env('REDIS_PORT', 6379),
'db' => (int) env('REDIS_DB', 0),
'pool' => [
'min_connections' => 1,
'max_connections' => 10,
'connect_timeout' => 10.0,
'wait_timeout' => 3.0,
'heartbeat' => -1,
'max_idle_time' => (float) env('REDIS_MAX_IDLE_TIME', 60),
],
],
];

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
use Hyperf\Server\Event;
use Hyperf\Server\Server;
use Swoole\Constant;
return [
'mode' => SWOOLE_PROCESS,
'servers' => [
[
'name' => 'http',
'type' => Server::SERVER_HTTP,
'host' => '0.0.0.0',
'port' => 9501,
'sock_type' => SWOOLE_SOCK_TCP,
'callbacks' => [
Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
],
],
],
'settings' => [
Constant::OPTION_ENABLE_COROUTINE => true,
Constant::OPTION_WORKER_NUM => swoole_cpu_num(),
Constant::OPTION_PID_FILE => BASE_PATH . '/runtime/hyperf.pid',
Constant::OPTION_OPEN_TCP_NODELAY => true,
Constant::OPTION_MAX_COROUTINE => 100000,
Constant::OPTION_OPEN_HTTP2_PROTOCOL => true,
Constant::OPTION_MAX_REQUEST => 100000,
Constant::OPTION_SOCKET_BUFFER_SIZE => 2 * 1024 * 1024,
Constant::OPTION_BUFFER_OUTPUT_SIZE => 2 * 1024 * 1024,
],
'callbacks' => [
Event::ON_WORKER_START => [Hyperf\Framework\Bootstrap\WorkerStartCallback::class, 'onWorkerStart'],
Event::ON_PIPE_MESSAGE => [Hyperf\Framework\Bootstrap\PipeMessageCallback::class, 'onPipeMessage'],
Event::ON_WORKER_EXIT => [Hyperf\Framework\Bootstrap\WorkerExitCallback::class, 'onWorkerExit'],
],
];

@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
return [
'consumers' => [
[
// The service name, this name should as same as with the name of service provider.
'name' => 'YourServiceName',
// The service registry, if `nodes` is missing below, then you should provide this configs.
'registry' => [
'protocol' => 'consul',
'address' => 'Enter the address of service registry',
],
// If `registry` is missing, then you should provide the nodes configs.
'nodes' => [
// Provide the host and port of the service provider.
// ['host' => 'The host of the service provider', 'port' => 9502]
],
],
],
];

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
/**
* This file is part of Hyperf.
*
* @link https://www.hyperf.io
* @document https://hyperf.wiki
* @contact group@hyperf.io
* @license https://github.com/hyperf/hyperf/blob/master/LICENSE
*/
use Hyperf\Contract\StdoutLoggerInterface;
use Psr\Log\LogLevel;
return [
'app_name' => env('APP_NAME', 'skeleton'),
'app_env' => env('APP_ENV', 'dev'),
'scan_cacheable' => env('SCAN_CACHEABLE', false),
StdoutLoggerInterface::class => [
'log_level' => [
LogLevel::ALERT,
LogLevel::CRITICAL,
LogLevel::DEBUG,
LogLevel::EMERGENCY,
LogLevel::ERROR,
LogLevel::INFO,
LogLevel::NOTICE,
LogLevel::WARNING,
],
],
];

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save