框架代码
commit
4a1b300b23
@ -0,0 +1,19 @@
|
|||||||
|
APP_NAME=skeleton
|
||||||
|
APP_ENV=dev
|
||||||
|
|
||||||
|
DB_DRIVER=mysql
|
||||||
|
DB_HOST=localhost
|
||||||
|
DB_PORT=3306
|
||||||
|
DB_DATABASE=hyperf
|
||||||
|
DB_USERNAME=root
|
||||||
|
DB_PASSWORD=
|
||||||
|
DB_CHARSET=utf8mb4
|
||||||
|
DB_COLLATION=utf8mb4_unicode_ci
|
||||||
|
DB_PREFIX=
|
||||||
|
|
||||||
|
REDIS_HOST=localhost
|
||||||
|
REDIS_AUTH=(null)
|
||||||
|
REDIS_PORT=6379
|
||||||
|
REDIS_DB=0
|
||||||
|
|
||||||
|
CONSUL_URL=127.0.0.1:8500
|
@ -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.15-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 print "\n" | composer install -o && php bin/hyperf.php
|
||||||
|
|
||||||
|
EXPOSE 9501
|
||||||
|
|
||||||
|
ENTRYPOINT ["php", "/opt/www/bin/hyperf.php", "start"]
|
@ -0,0 +1,12 @@
|
|||||||
|
name: Build Docker
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Build
|
||||||
|
run: cp -rf .github/workflows/Dockerfile . && docker build -t hyperf .
|
@ -0,0 +1,25 @@
|
|||||||
|
on:
|
||||||
|
push:
|
||||||
|
# Sequence of patterns matched against refs/tags
|
||||||
|
tags:
|
||||||
|
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||||
|
|
||||||
|
name: Release
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
name: Release
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
- name: Create Release
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
with:
|
||||||
|
tag_name: ${{ github.ref }}
|
||||||
|
release_name: Release ${{ github.ref }}
|
||||||
|
draft: false
|
||||||
|
prerelease: false
|
@ -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.15-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,57 @@
|
|||||||
|
<?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\Controller;
|
||||||
|
|
||||||
|
use App\Exception\BusinessException;
|
||||||
|
use Hyperf\Di\Annotation\Inject;
|
||||||
|
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||||
|
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||||
|
use Hyperf\Logger\LoggerFactory;
|
||||||
|
use Psr\Container\ContainerInterface;
|
||||||
|
|
||||||
|
abstract class BaseController
|
||||||
|
{
|
||||||
|
#[Inject]
|
||||||
|
protected ContainerInterface $container;
|
||||||
|
|
||||||
|
#[Inject]
|
||||||
|
protected RequestInterface $request;
|
||||||
|
|
||||||
|
#[Inject]
|
||||||
|
protected ResponseInterface $response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var \Psr\Log\LoggerInterface
|
||||||
|
*/
|
||||||
|
protected $logger;
|
||||||
|
|
||||||
|
public function __construct(LoggerFactory $loggerFactory)
|
||||||
|
{
|
||||||
|
// 第一个参数对应日志的 name, 第二个参数对应 config/autoload/logger.php 内的 key
|
||||||
|
$this->logger = $loggerFactory->get('log');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取RPC调用返回结果
|
||||||
|
*
|
||||||
|
* @param array $result
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getServiceResult(array $result) : array
|
||||||
|
{
|
||||||
|
if ($result['code'] === 200) {
|
||||||
|
return $result['data'];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new BusinessException($result['code'], $result['msg']);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<?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\Controller;
|
||||||
|
|
||||||
|
class IndexController extends BaseController
|
||||||
|
{
|
||||||
|
public function index()
|
||||||
|
{
|
||||||
|
$user = $this->request->input('user', 'Hyperf');
|
||||||
|
$method = $this->request->getMethod();
|
||||||
|
|
||||||
|
return [
|
||||||
|
'method' => $method,
|
||||||
|
'message' => "Hello {$user}.",
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
<?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\ErrorCode;
|
||||||
|
use Hyperf\Server\Exception\ServerException;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class BusinessException extends ServerException
|
||||||
|
{
|
||||||
|
public function __construct(int $code = 0, string $message = null, Throwable $previous = null)
|
||||||
|
{
|
||||||
|
if (is_null($message)) {
|
||||||
|
$message = ErrorCode::getMessage($code);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent::__construct($message, $code, $previous);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
<?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\Handler;
|
||||||
|
|
||||||
|
use Hyperf\Contract\StdoutLoggerInterface;
|
||||||
|
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||||
|
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class AppExceptionHandler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
public function __construct(protected StdoutLoggerInterface $logger)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handle(Throwable $throwable, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->logger->error(sprintf('%s[%s] in %s', $throwable->getMessage(), $throwable->getLine(), $throwable->getFile()));
|
||||||
|
$this->logger->error($throwable->getTraceAsString());
|
||||||
|
return $response->withHeader('Server', 'Hyperf')->withStatus(500)->withBody(new SwooleStream('Internal Server Error.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isValid(Throwable $throwable): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Exception\Handler;
|
||||||
|
|
||||||
|
use App\Constants\ErrorCode;
|
||||||
|
use App\Helper\Result;
|
||||||
|
use Hyperf\Context\Context;
|
||||||
|
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||||
|
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||||
|
use Hyperf\JsonRpc\DataFormatter;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class AppRpcExceptionHandler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
public function handle(Throwable $throwable, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$message = $throwable->getMessage();
|
||||||
|
$error = explode('|', $message, 2);
|
||||||
|
$code = $error[1] ?? $throwable->getCode() ?: ErrorCode::COMMON_ERROR;
|
||||||
|
$data = Result::error($code, $error[0]);
|
||||||
|
|
||||||
|
$dataFormatter = make(DataFormatter::class);
|
||||||
|
$request = Context::get(ServerRequestInterface::class);
|
||||||
|
$id = $request->getAttribute('request_id');
|
||||||
|
$result = $dataFormatter->formatResponse([$id, $data]);
|
||||||
|
$responseStr = json_encode($result, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
return $response->withHeader('Content-Type', 'application/json')->withBody(new SwooleStream($responseStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断该异常处理器是否要对该异常进行处理
|
||||||
|
*/
|
||||||
|
public function isValid(Throwable $throwable): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Exception\Handler;
|
||||||
|
|
||||||
|
use App\Exception\BusinessException;
|
||||||
|
use App\Helper\Result;
|
||||||
|
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||||
|
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class BusinessExceptionHandler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
public function handle(Throwable $throwable, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
// 判断被捕获到的异常是希望被捕获的异常
|
||||||
|
if ($throwable instanceof BusinessException) {
|
||||||
|
// 格式化输出
|
||||||
|
$data = json_encode(Result::error($throwable->getCode(), $throwable->getMessage()), JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
// 阻止异常冒泡
|
||||||
|
$this->stopPropagation();
|
||||||
|
return $response->withHeader('Content-Type', 'application/json; charset=utf-8')->withStatus(200)->withBody(new SwooleStream($data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// 交给下一个异常处理器
|
||||||
|
return $response;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断该异常处理器是否要对该异常进行处理
|
||||||
|
*/
|
||||||
|
public function isValid(Throwable $throwable): bool
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Exception\Handler;
|
||||||
|
|
||||||
|
use App\Constants\ErrorCode;
|
||||||
|
use App\Helper\Result;
|
||||||
|
use Hyperf\Context\Context;
|
||||||
|
use Hyperf\ExceptionHandler\ExceptionHandler;
|
||||||
|
use Hyperf\Validation\ValidationException;
|
||||||
|
use Hyperf\HttpMessage\Stream\SwooleStream;
|
||||||
|
use Hyperf\JsonRpc\DataFormatter;
|
||||||
|
use Psr\Http\Message\ResponseInterface;
|
||||||
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
use Throwable;
|
||||||
|
|
||||||
|
class ValidateExceptionHandler extends ExceptionHandler
|
||||||
|
{
|
||||||
|
public function handle(Throwable $throwable, ResponseInterface $response)
|
||||||
|
{
|
||||||
|
$this->stopPropagation();
|
||||||
|
$babMessages = $throwable->validator->errors();
|
||||||
|
$message = $babMessages->first();
|
||||||
|
$error = explode('|', $message, 2);
|
||||||
|
$code = $error[1] ?? ErrorCode::COMMON_ERROR;
|
||||||
|
$data = Result::error($code, $error[0]);
|
||||||
|
|
||||||
|
$dataFormatter = make(DataFormatter::class);
|
||||||
|
$request = Context::get(ServerRequestInterface::class);
|
||||||
|
$id = $request->getAttribute('request_id');
|
||||||
|
$result = $dataFormatter->formatResponse([$id, $data]);
|
||||||
|
$responseStr = json_encode($result, JSON_UNESCAPED_UNICODE);
|
||||||
|
|
||||||
|
return $response->withHeader('Content-Type', 'application/json')->withBody(new SwooleStream($responseStr));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断该异常处理器是否要对该异常进行处理
|
||||||
|
*/
|
||||||
|
public function isValid(Throwable $throwable): bool
|
||||||
|
{
|
||||||
|
return $throwable instanceof ValidationException;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Helper;
|
||||||
|
|
||||||
|
use App\Constants\ErrorCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回处理公共类
|
||||||
|
*/
|
||||||
|
class Result
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* 返回数据格式化
|
||||||
|
*
|
||||||
|
* @param array|null $data
|
||||||
|
* @param int $code
|
||||||
|
* @param string $message
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function result(?array $data = null, int $code = 200, string $message = 'success') : array
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'code' => $code,
|
||||||
|
'data' => $data ?? [],
|
||||||
|
'msg' => $message
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 错误返回
|
||||||
|
*
|
||||||
|
* @param int $code
|
||||||
|
* @param string|null $message
|
||||||
|
* @param array|null $data
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public static function error(int $code = ErrorCode::SERVER_ERROR, ?string $message = null, ?array $data = null) : array
|
||||||
|
{
|
||||||
|
if ($message === null) {
|
||||||
|
$message = ErrorCode::getMessage($code);
|
||||||
|
}
|
||||||
|
|
||||||
|
return self::result($data, $code, $message);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,59 @@
|
|||||||
|
<?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): void
|
||||||
|
{
|
||||||
|
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,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
|
||||||
|
*/
|
||||||
|
namespace App\Model;
|
||||||
|
|
||||||
|
use Hyperf\DbConnection\Model\Model as BaseModel;
|
||||||
|
use Hyperf\ModelCache\Cacheable;
|
||||||
|
use Hyperf\ModelCache\CacheableInterface;
|
||||||
|
|
||||||
|
abstract class Model extends BaseModel implements CacheableInterface
|
||||||
|
{
|
||||||
|
use Cacheable;
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
#!/usr/bin/env php
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* 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
|
||||||
|
*/
|
||||||
|
ini_set('display_errors', 'on');
|
||||||
|
ini_set('display_startup_errors', 'on');
|
||||||
|
ini_set('memory_limit', '1G');
|
||||||
|
|
||||||
|
error_reporting(E_ALL);
|
||||||
|
|
||||||
|
! 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,88 @@
|
|||||||
|
{
|
||||||
|
"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": ">=8.0",
|
||||||
|
"hyperf/amqp": "~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/paginator": "^2.2",
|
||||||
|
"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/service-governance-consul": "~2.2.0",
|
||||||
|
"hyperf/validation": "^2.2"
|
||||||
|
},
|
||||||
|
"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": []
|
||||||
|
},
|
||||||
|
"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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,40 @@
|
|||||||
|
<?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('AMQP_HOST', 'localhost'),
|
||||||
|
'port' => (int) env('AMQP_PORT', 5672),
|
||||||
|
'user' => env('AMQP_USER', 'guest'),
|
||||||
|
'password' => env('AMQP_PASSWORD', 'guest'),
|
||||||
|
'vhost' => env('AMQP_VHOST', '/'),
|
||||||
|
'concurrent' => [
|
||||||
|
'limit' => 1,
|
||||||
|
],
|
||||||
|
'pool' => [
|
||||||
|
'connections' => 2,
|
||||||
|
],
|
||||||
|
'params' => [
|
||||||
|
'insist' => false,
|
||||||
|
'login_method' => 'AMQPLAIN',
|
||||||
|
'login_response' => null,
|
||||||
|
'locale' => 'en_US',
|
||||||
|
'connection_timeout' => 3,
|
||||||
|
'read_write_timeout' => 6,
|
||||||
|
'context' => null,
|
||||||
|
'keepalive' => true,
|
||||||
|
'heartbeat' => 3,
|
||||||
|
'channel_rpc_timeout' => 0.0,
|
||||||
|
'close_on_destruct' => false,
|
||||||
|
'max_idle_channels' => 10,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
@ -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,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,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,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,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,24 @@
|
|||||||
|
<?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' => [
|
||||||
|
App\Exception\Handler\BusinessExceptionHandler::class,
|
||||||
|
Hyperf\HttpServer\Exception\Handler\HttpExceptionHandler::class,
|
||||||
|
App\Exception\Handler\AppExceptionHandler::class,
|
||||||
|
],
|
||||||
|
'jsonrpc-http' => [
|
||||||
|
App\Exception\Handler\ValidateExceptionHandler::class,
|
||||||
|
App\Exception\Handler\AppRpcExceptionHandler::class
|
||||||
|
]
|
||||||
|
],
|
||||||
|
];
|
@ -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 [
|
||||||
|
Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class
|
||||||
|
];
|
@ -0,0 +1,30 @@
|
|||||||
|
<?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' => [
|
||||||
|
'handler' => [
|
||||||
|
'class' => Monolog\Handler\RotatingFileHandler::class,
|
||||||
|
'constructor' => [
|
||||||
|
'filename' => BASE_PATH . '/runtime/logs/hyperf.log',
|
||||||
|
'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,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
|
||||||
|
*/
|
||||||
|
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' => 9901,
|
||||||
|
'sock_type' => SWOOLE_SOCK_TCP,
|
||||||
|
'callbacks' => [
|
||||||
|
Event::ON_REQUEST => [Hyperf\HttpServer\Server::class, 'onRequest'],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'jsonrpc-http',
|
||||||
|
'type' => Server::SERVER_HTTP,
|
||||||
|
'host' => '0.0.0.0',
|
||||||
|
'port' => 9902,
|
||||||
|
'sock_type' => SWOOLE_SOCK_TCP,
|
||||||
|
'callbacks' => [
|
||||||
|
Event::ON_REQUEST => [\Hyperf\JsonRpc\HttpServer::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 [
|
||||||
|
'enable' => [
|
||||||
|
'discovery' => true,
|
||||||
|
'register' => true,
|
||||||
|
],
|
||||||
|
'consumers' => [],
|
||||||
|
'providers' => [],
|
||||||
|
'drivers' => [
|
||||||
|
'consul' => [
|
||||||
|
'uri' => env('CONSUL_URL', '127.0.0.1:8500'),
|
||||||
|
'token' => '',
|
||||||
|
'check' => [
|
||||||
|
'deregister_critical_service_after' => '90m',
|
||||||
|
'interval' => '1s',
|
||||||
|
],
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
@ -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,
|
||||||
|
],
|
||||||
|
],
|
||||||
|
];
|
@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Initialize a dependency injection container that implemented PSR-11 and return the container.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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\Di\Container;
|
||||||
|
use Hyperf\Di\Definition\DefinitionSourceFactory;
|
||||||
|
use Hyperf\Utils\ApplicationContext;
|
||||||
|
|
||||||
|
$container = new Container((new DefinitionSourceFactory(true))());
|
||||||
|
|
||||||
|
if (! $container instanceof \Psr\Container\ContainerInterface) {
|
||||||
|
throw new RuntimeException('The dependency injection container is invalid.');
|
||||||
|
}
|
||||||
|
return ApplicationContext::setContainer($container);
|
@ -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
|
||||||
|
*/
|
||||||
|
use Hyperf\HttpServer\Router\Router;
|
||||||
|
|
||||||
|
Router::addRoute(['GET', 'POST', 'HEAD'], '/', 'App\Controller\IndexController@index');
|
||||||
|
|
||||||
|
Router::get('/favicon.ico', function () {
|
||||||
|
return '';
|
||||||
|
});
|
@ -0,0 +1,30 @@
|
|||||||
|
version: '3.7'
|
||||||
|
services:
|
||||||
|
hyperf:
|
||||||
|
image: $REGISTRY_URL/$PROJECT_NAME:test
|
||||||
|
environment:
|
||||||
|
- "APP_PROJECT=hyperf"
|
||||||
|
- "APP_ENV=test"
|
||||||
|
ports:
|
||||||
|
- 9501:9501
|
||||||
|
deploy:
|
||||||
|
replicas: 1
|
||||||
|
restart_policy:
|
||||||
|
condition: on-failure
|
||||||
|
delay: 5s
|
||||||
|
max_attempts: 5
|
||||||
|
update_config:
|
||||||
|
parallelism: 2
|
||||||
|
delay: 5s
|
||||||
|
order: start-first
|
||||||
|
networks:
|
||||||
|
- hyperf_net
|
||||||
|
configs:
|
||||||
|
- source: hyperf_v1.0
|
||||||
|
target: /opt/www/.env
|
||||||
|
configs:
|
||||||
|
hyperf_v1.0:
|
||||||
|
external: true
|
||||||
|
networks:
|
||||||
|
hyperf_net:
|
||||||
|
external: true
|
@ -0,0 +1,10 @@
|
|||||||
|
# Magic behaviour with __get, __set, __call and __callStatic is not exactly static analyser-friendly :)
|
||||||
|
# Fortunately, You can ignore it by the following config.
|
||||||
|
#
|
||||||
|
# vendor/bin/phpstan analyse app --memory-limit 200M -l 0
|
||||||
|
#
|
||||||
|
parameters:
|
||||||
|
reportUnmatchedIgnoredErrors: false
|
||||||
|
ignoreErrors:
|
||||||
|
- '#Static call to instance method Hyperf\\HttpServer\\Router\\Router::[a-zA-Z0-9\\_]+\(\)#'
|
||||||
|
- '#Static call to instance method Hyperf\\DbConnection\\Db::[a-zA-Z0-9\\_]+\(\)#'
|
@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<phpunit backupGlobals="false"
|
||||||
|
backupStaticAttributes="false"
|
||||||
|
bootstrap="./test/bootstrap.php"
|
||||||
|
colors="true"
|
||||||
|
convertErrorsToExceptions="true"
|
||||||
|
convertNoticesToExceptions="true"
|
||||||
|
convertWarningsToExceptions="true"
|
||||||
|
processIsolation="false"
|
||||||
|
stopOnFailure="false">
|
||||||
|
<testsuites>
|
||||||
|
<testsuite name="Tests">
|
||||||
|
<directory suffix="Test.php">./test</directory>
|
||||||
|
</testsuite>
|
||||||
|
</testsuites>
|
||||||
|
<filter>
|
||||||
|
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||||
|
<directory suffix=".php">./app</directory>
|
||||||
|
</whitelist>
|
||||||
|
</filter>
|
||||||
|
</phpunit>
|
@ -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
|
||||||
|
*/
|
||||||
|
namespace HyperfTest\Cases;
|
||||||
|
|
||||||
|
use HyperfTest\HttpTestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* @coversNothing
|
||||||
|
*/
|
||||||
|
class ExampleTest extends HttpTestCase
|
||||||
|
{
|
||||||
|
public function testExample()
|
||||||
|
{
|
||||||
|
$this->assertTrue(true);
|
||||||
|
$this->assertTrue(is_array($this->get('/')));
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,42 @@
|
|||||||
|
<?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 HyperfTest;
|
||||||
|
|
||||||
|
use Hyperf\Testing\Client;
|
||||||
|
use PHPUnit\Framework\TestCase;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class HttpTestCase.
|
||||||
|
* @method get($uri, $data = [], $headers = [])
|
||||||
|
* @method post($uri, $data = [], $headers = [])
|
||||||
|
* @method json($uri, $data = [], $headers = [])
|
||||||
|
* @method file($uri, $data = [], $headers = [])
|
||||||
|
* @method request($method, $path, $options = [])
|
||||||
|
*/
|
||||||
|
abstract class HttpTestCase extends TestCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @var Client
|
||||||
|
*/
|
||||||
|
protected $client;
|
||||||
|
|
||||||
|
public function __construct($name = null, array $data = [], $dataName = '')
|
||||||
|
{
|
||||||
|
parent::__construct($name, $data, $dataName);
|
||||||
|
$this->client = make(Client::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __call($name, $arguments)
|
||||||
|
{
|
||||||
|
return $this->client->{$name}(...$arguments);
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
|
*/
|
||||||
|
ini_set('display_errors', 'on');
|
||||||
|
ini_set('display_startup_errors', 'on');
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
Swoole\Runtime::enableCoroutine(true);
|
||||||
|
|
||||||
|
require BASE_PATH . '/vendor/autoload.php';
|
||||||
|
|
||||||
|
Hyperf\Di\ClassLoader::init();
|
||||||
|
|
||||||
|
$container = require BASE_PATH . '/config/container.php';
|
||||||
|
|
||||||
|
$container->get(Hyperf\Contract\ApplicationInterface::class);
|
Loading…
Reference in New Issue