diff --git a/.editorconfig b/.editorconfig
index 4149af9e5..f79f8a466 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -16,6 +16,9 @@ trim_trailing_whitespace = false
[*.json]
indent_size = 2
+[*.yml]
+indent_size = 2
+
[*.html]
indent_size = 2
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 000000000..7a0f48ea6
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,75 @@
+# Add 'kind/annotation' label to any change within the 'annotation' component
+kind/annotation:
+ - src/annotation/**/*
+# add label for 'aop' component
+kind/aop:
+ - src/aop/**/*
+# add label for 'bean' component
+kind/bean:
+ - src/bean/**/*
+# add label for 'config' component
+kind/config:
+ - src/config/**/*
+# add label for 'connection-pool' component
+kind/connection-pool:
+ - src/connection-pool/**/*
+# add label for 'console' component
+kind/console:
+ - src/console/**/*
+# add label for 'db' component
+kind/db:
+ - src/db/**/*
+# add label for 'error' component
+kind/error:
+ - src/error/**/*
+# add label for 'event' component
+kind/event:
+ - src/event/**/*
+# add label for 'framework' component
+kind/framework:
+ - src/framework/**/*
+# add label for 'http-message' component
+kind/http-message:
+ - src/http-message/**/*
+# add label for 'http-server' component
+kind/http-server:
+ - src/http-server/**/*
+# add label for 'i18n' component
+kind/i18n:
+ - src/i18n/**/*
+# add label for 'log' component
+kind/log:
+ - src/log/**/*
+# add label for 'process' component
+kind/process:
+ - src/process/**/*
+# add label for 'proxy' component
+kind/proxy:
+ - src/proxy/**/*
+# add label for 'redis' component
+kind/redis:
+ - src/redis/**/*
+# add label for 'rpc-server' component
+kind/rpc-server:
+ - src/rpc-server/**/*
+ - src/rpc-client/**/*
+ - src/rpc/**/*
+# add label for 'server' component
+kind/server:
+ - src/server/**/*
+# add label for 'stdlib' component
+kind/stdlib:
+ - src/stdlib/**/*
+# add label for 'task' component
+kind/task:
+ - src/task/**/*
+# add label for 'tcp-server' component
+kind/tcp-server:
+ - src/tcp-server/**/*
+ - src/tcp/**/*
+# add label for 'validator' component
+kind/validator:
+ - src/validator/**/*
+# add label for 'websocket-server' component
+kind/websocket-server:
+ - src/websocket-server/**/*
diff --git a/.github/pr-labeler.yml b/.github/pr-labeler.yml
new file mode 100644
index 000000000..7a0f48ea6
--- /dev/null
+++ b/.github/pr-labeler.yml
@@ -0,0 +1,75 @@
+# Add 'kind/annotation' label to any change within the 'annotation' component
+kind/annotation:
+ - src/annotation/**/*
+# add label for 'aop' component
+kind/aop:
+ - src/aop/**/*
+# add label for 'bean' component
+kind/bean:
+ - src/bean/**/*
+# add label for 'config' component
+kind/config:
+ - src/config/**/*
+# add label for 'connection-pool' component
+kind/connection-pool:
+ - src/connection-pool/**/*
+# add label for 'console' component
+kind/console:
+ - src/console/**/*
+# add label for 'db' component
+kind/db:
+ - src/db/**/*
+# add label for 'error' component
+kind/error:
+ - src/error/**/*
+# add label for 'event' component
+kind/event:
+ - src/event/**/*
+# add label for 'framework' component
+kind/framework:
+ - src/framework/**/*
+# add label for 'http-message' component
+kind/http-message:
+ - src/http-message/**/*
+# add label for 'http-server' component
+kind/http-server:
+ - src/http-server/**/*
+# add label for 'i18n' component
+kind/i18n:
+ - src/i18n/**/*
+# add label for 'log' component
+kind/log:
+ - src/log/**/*
+# add label for 'process' component
+kind/process:
+ - src/process/**/*
+# add label for 'proxy' component
+kind/proxy:
+ - src/proxy/**/*
+# add label for 'redis' component
+kind/redis:
+ - src/redis/**/*
+# add label for 'rpc-server' component
+kind/rpc-server:
+ - src/rpc-server/**/*
+ - src/rpc-client/**/*
+ - src/rpc/**/*
+# add label for 'server' component
+kind/server:
+ - src/server/**/*
+# add label for 'stdlib' component
+kind/stdlib:
+ - src/stdlib/**/*
+# add label for 'task' component
+kind/task:
+ - src/task/**/*
+# add label for 'tcp-server' component
+kind/tcp-server:
+ - src/tcp-server/**/*
+ - src/tcp/**/*
+# add label for 'validator' component
+kind/validator:
+ - src/validator/**/*
+# add label for 'websocket-server' component
+kind/websocket-server:
+ - src/websocket-server/**/*
diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml
new file mode 100644
index 000000000..646e85203
--- /dev/null
+++ b/.github/workflows/label.yml
@@ -0,0 +1,32 @@
+# This workflow will triage pull requests and apply a label based on the
+# paths that are modified in the pull request.
+#
+# To use this workflow, you will need to set up a .github/labeler.yml
+# file with configuration. For more information, see:
+# https://github.com/actions/labeler/blob/master/README.md
+
+name: Pull Request Labeler
+on: [pull_request]
+
+jobs:
+ label:
+ runs-on: ubuntu-latest
+
+ steps:
+# - uses: TimonVS/pr-labeler-action@v3
+# with:
+# configuration-path: .github/pr-labeler.yml # optional, .github/pr-labeler.yml is the default value
+# env:
+# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+# - name: PR Labeler
+# uses: paulfantom/periodic-labeler@master
+# env:
+# GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+# GITHUB_REPOSITORY: ${{ github.repository }}
+# LABEL_MAPPINGS_FILE: .github/pr-labeler.yml
+
+ - uses: actions/labeler@v2
+ with:
+ repo-token: "${{ secrets.GITHUB_TOKEN }}"
+ configuration-path: ".github/pr-labeler.yml"
diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml
new file mode 100644
index 000000000..4165bf3f9
--- /dev/null
+++ b/.github/workflows/php.yml
@@ -0,0 +1,65 @@
+#
+# Github actions for swoft component tests
+# https://github.com/marketplace?type=actions
+#
+name: Unit-tests
+
+on: [push, pull_request]
+
+# usage refer https://github.com/shivammathur/setup-php
+jobs:
+ test:
+ name: Test on php ${{ matrix.php}} and ${{ matrix.os }} OS
+ runs-on: ${{ matrix.os }}
+ timeout-minutes: 20
+ env:
+ SWOFT_DEBUG: 0
+ services:
+ mysql:
+ image: mysql:5.7
+ env:
+ MYSQL_ALLOW_EMPTY_PASSWORD: false
+ MYSQL_ROOT_PASSWORD: swoft123456
+ MYSQL_DATABASE: test
+ ports:
+ - 3306
+ options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
+ redis:
+ image: redis
+ ports:
+ - 6379/tcp
+ options: --health-cmd="redis-cli ping" --health-interval=10s --health-timeout=5s --health-retries=3
+ strategy:
+ fail-fast: false # dont fast fail
+ matrix:
+ php: [7.1, 7.2, 7.3] # 7.4
+ os: [ubuntu-latest] # , macOS-latest, windows-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Setup PHP
+ timeout-minutes: 5
+ uses: shivammathur/setup-php@v1
+ with:
+ php-version: ${{ matrix.php}}
+ extensions: mbstring, dom, fileinfo, mysql, openssl, redis #optional, setup extensions
+ ini-values: post_max_size=56M, short_open_tag=On #optional, setup php.ini configuration
+ coverage: none #optional, setup coverage driver: xdebug, none
+ pecl: true
+
+ - name: Install swoole extensions
+ timeout-minutes: 5
+ run: |
+ sudo pecl install -f swoole && php -m
+ # echo 'no' | pecl install -f redis
+ # sudo pecl update-channels && pecl install -f msgpack && pecl install -f igbinary && php -m
+
+ - name: Install dependencies
+ run: composer install --no-progress --no-suggest
+
+ # Add a test script to composer.json, for instance: "test": "vendor/bin/phpunit"
+ # Docs: https://getcomposer.org/doc/articles/scripts.md
+
+ - name: Run test suite
+ run: | # && composer run test
+ pwd && ./phpunit.sh nodb
diff --git a/.travis.yml b/.travis.yml
index 5bdfc1b6a..61915f0d3 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -49,7 +49,7 @@ before_install:
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'
install:
- echo 'no' | pecl install -f redis
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/Makefile b/Makefile
index cc28bec99..bf8fab970 100644
--- a/Makefile
+++ b/Makefile
@@ -16,17 +16,31 @@ help:
update:
git checkout . && git pull
+ installcli: ## Install the swoft releasecli tool from github
+installcli:
+ cd ~
+ git clone https://github.com/swoftlabs/swoft-releasecli
+ cd swoft-releasecli; \
+ ln -s $PWD/bin/releasecli /usr/local/bin/releasecli; \
+ chmod a+x bin/releasecli
+
+ updatecli: ## Update the swoft releasecli tool from github
+updatecli:
+ cd ~/swoft-releasecli; \
+ git pull; \
+ chmod a+x bin/releasecli
+
addrmt: ## Add the remote repository address of each component to the local remote
-addrmt:
- php dtool.php git:addrmt --all
+addrmt: update
+ releasecli git:addrmt --all
fpush: ## Push all update to remote sub-repo by git push with '--force'
-fpush:
- php dtool.php git:fpush --all
+fpush: update
+ releasecli git:fpush --all
release: ## Release all sub-repo to new tag version and push to remote repo. eg: tag=v2.0.3
release:
- php dtool.php tag:release --all -y -t $(TAG)
+ releasecli tag:release --all -y -t $(TAG)
sami: ## Gen classes docs by sami.phar
classdoc:
diff --git a/README.md b/README.md
index 83bb0d73c..57df1a07e 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,9 @@
# Swoft Component
+[![Actions Status](https://github.com/swoft-cloud/swoft-component/workflows/Unit-tests/badge.svg)](https://github.com/swoft-cloud/swoft-component/actions)
+[![Build Status](https://travis-ci.org/swoft-cloud/swoft-component.svg?branch=master)](https://travis-ci.org/swoft-cloud/swoft-component)
+
+
This repository is used to manage all swoft core components.
## [中文说明](README.zh-CN.md)
@@ -20,7 +24,7 @@ Add require to `composer.json`
Install:
-```json
+```bash
composer update
```
@@ -57,6 +61,10 @@ phpdbg -dauto_globals_jit=Off -qrr /usr/local/bin/phpunit --coverage-text
phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c src/event/phpunit.xml
```
+## Releases
+
+Please see https://github.com/swoftlabs/swoft-releasecli
+
## Document
- [中文文档](https://www.swoft.org/docs)
diff --git a/README.zh-CN.md b/README.zh-CN.md
index c34d287c5..68e9c977a 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -1,12 +1,15 @@
# Swoft Component
+[![Actions Status](https://github.com/swoft-cloud/swoft-component/workflows/Unit-tests/badge.svg)](https://github.com/swoft-cloud/swoft-component/actions)
+[![Build Status](https://travis-ci.org/swoft-cloud/swoft-component.svg?branch=master)](https://travis-ci.org/swoft-cloud/swoft-component)
+
这里是swoft基础和核心组件的开发仓库,所有的核心组件都是由这里分发出去的。
## [English](README.md)
## 如何使用
-Add require to `composer.json`
+添加组件到`composer.json`
```json
"require": {
@@ -14,15 +17,15 @@ Add require to `composer.json`
}
```
-Install:
+安装:
-```json
+```bash
composer update
```
### 单元测试
-Quick run tests for component:
+快速运行测试:
```bash
// For all components
@@ -33,7 +36,7 @@ Quick run tests for component:
./phpunit.sh event
```
-Only tests an special component:
+测试指定的组件:
```bash
./phpunit.sh event
@@ -43,7 +46,7 @@ php run.php -c src/event/phpunit.xml
php run.php -c src/event/phpunit.xml --filter testAddModule
```
-Output coverage data:
+输出测试覆盖率:
```bash
// output coverage. require xdebug ext
@@ -53,6 +56,10 @@ phpdbg -dauto_globals_jit=Off -qrr /usr/local/bin/phpunit --coverage-text
phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c src/event/phpunit.xml
```
+## 版本发布
+
+需要使用工具 https://github.com/swoftlabs/swoft-releasecli
+
## 使用文档
- [中文文档](https://www.swoft.org/docs)
diff --git a/coverage.sh b/coverage.sh
index b49423133..6b5b6804e 100755
--- a/coverage.sh
+++ b/coverage.sh
@@ -44,19 +44,23 @@ echo ""
for lbName in ${components} ; do
if [[ "${lbName}" == "component" ]]; then
echo "======> Testing the【components】"
- yellow_text "> phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c phpunit.xml"
- phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c phpunit.xml
- echo $?
+ yellow_text "> phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c phpunit.xml"
+ phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c phpunit.xml
else
if [[ ! -d "src/${lbName}" ]]; then
- echo "!! Skip invalid component: ${lbName}"
+ cyan_text "!! Skip invalid component: ${lbName}"
else
echo "======> Testing the component【${lbName}】"
yellow_text "> phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c src/${lbName}/phpunit.xml"
phpdbg -dauto_globals_jit=Off -qrr run.php --coverage-text -c src/${lbName}/phpunit.xml
- echo $?
fi
fi
+
+ CODE=$?
+ # shellcheck disable=SC2181
+ if [ "$CODE" != "0" ]; then
+ exit 1
+ fi
done
cyan_text "\nTest Completed!"
diff --git a/dtool.php b/dtool.php
deleted file mode 100644
index 6ceadbe70..000000000
--- a/dtool.php
+++ /dev/null
@@ -1,35 +0,0 @@
-addByConfig($gi = new GitFindTag(), $gi->getHelpConfig());
-$cli->addByConfig($drt = new DeleteRemoteTag(), $drt->getHelpConfig());
-$cli->addByConfig($grt = new GitReleaseTag(), $grt->getHelpConfig());
-$cli->addByConfig($gar = new GitAddRemote(), $gar->getHelpConfig());
-$cli->addByConfig($gfp = new GitForcePush(), $gfp->getHelpConfig());
-$cli->addByConfig($gsp1 = new GitSubtreePush(), $gsp1->getHelpConfig());
-$cli->addByConfig($gsp2 = new GitSubtreePull(), $gsp2->getHelpConfig());
-
-$cli->addByConfig($cmd = new GenReadme(), $cmd->getHelpConfig());
-$cli->addByConfig($cmd = new GenVersion(), $cmd->getHelpConfig());
-$cli->addByConfig($cmd = new UpdateSwooleVer(), $cmd->getHelpConfig());
-
-$cli->run();
diff --git a/phpunit.sh b/phpunit.sh
index 8948a5e8d..23c0496ca 100755
--- a/phpunit.sh
+++ b/phpunit.sh
@@ -28,14 +28,14 @@ if [[ "$1" != "all" ]]; then
if [[ "$1" == "nodb" ]]; then
components=$(ls src | grep -v db | grep -v redis)
else
- components=$@
+ components=$*
fi
else
components=$(ls src/)
fi
colored_text "Will test components:"
-echo ${components}
+echo "${components}"
echo ""
# do run phpunit
@@ -43,20 +43,26 @@ echo ""
# set -ex
for lbName in ${components} ; do
if [[ "${lbName}" == "component" ]]; then
- echo "======> Testing the【component】"
- echo "> php run.php -c phpunit.xml"
+ colored_text "======> Testing the【component】"
+ yellow_text "> php run.php -c phpunit.xml"
php run.php -c phpunit.xml
- echo $?
else
if [[ ! -d "src/${lbName}" ]]; then
- echo "!! Skip invalid component: ${lbName}"
+ cyan_text "!! Skip invalid component: ${lbName}"
else
- echo "======> Testing the component【${lbName}】"
- echo "> php run.php -c src/${lbName}/phpunit.xml"
+ colored_text "======> Testing the component【${lbName}】"
+ yellow_text "> php run.php -c src/${lbName}/phpunit.xml"
php run.php -c src/${lbName}/phpunit.xml
- echo $?
fi
fi
+
+ CODE=$?
+ # shellcheck disable=SC2181
+ if [ "$CODE" != "0" ]; then
+ exit 1
+ fi
+
+ echo ""
done
-cyan_text "\nTest Completed!"
+cyan_text ":) Test Completed!"
diff --git a/phpunit.xml b/phpunit.xml
index 8d38abcd8..920915b40 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -13,12 +13,12 @@
stopOnFailure="false">
- ./test/unit
+ test/unit
- ./src/*
+ src/*
-
\ No newline at end of file
+
diff --git a/run.php b/run.php
index 55974b80f..00c64bac4 100755
--- a/run.php
+++ b/run.php
@@ -19,15 +19,9 @@
* file that was distributed with this source code.
*/
if (version_compare('7.1.0', PHP_VERSION, '>')) {
- fwrite(
- STDERR,
- sprintf(
- 'This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL .
- 'You are using PHP %s (%s).' . PHP_EOL,
- PHP_VERSION,
- PHP_BINARY
- )
- );
+ fwrite(STDERR,
+ sprintf('This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL . 'You are using PHP %s (%s).' . PHP_EOL,
+ PHP_VERSION, PHP_BINARY));
die(1);
}
@@ -37,11 +31,10 @@
// add loader file
foreach ([
- __DIR__ . '/../../autoload.php',
- __DIR__ . '/../vendor/autoload.php',
- __DIR__ . '/vendor/autoload.php'
- ] as $__loader_file
-) {
+ __DIR__ . '/../../autoload.php',
+ __DIR__ . '/../vendor/autoload.php',
+ __DIR__ . '/vendor/autoload.php'
+] as $__loader_file) {
if (file_exists($__loader_file)) {
define('PHPUNIT_COMPOSER_INSTALL', $__loader_file);
break;
@@ -49,12 +42,8 @@
}
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
- fwrite(
- STDERR,
- 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL .
- ' composer install' . PHP_EOL . PHP_EOL .
- 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL
- );
+ fwrite(STDERR,
+ 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . ' composer install' . PHP_EOL . PHP_EOL . 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL);
die(1);
}
@@ -88,7 +77,7 @@
$status = Command::main(false);
} catch (ExitException $e) {
$status = $e->getCode();
- echo 'ExitException: ' .$e->getMessage(), "\n";
+ echo 'ExitException: ' . $e->getMessage(), "\n";
}
});
diff --git a/script/Command/BaseCommand.php b/script/Command/BaseCommand.php
deleted file mode 100644
index b6ddbf931..000000000
--- a/script/Command/BaseCommand.php
+++ /dev/null
@@ -1,121 +0,0 @@
-baseDir = BASE_PATH;
- $this->libsDir = BASE_PATH . '/src/';
- }
-
- /**
- * @param App $app
- * @param string $allOpt Default is --all
- *
- * @return Generator|void
- */
- protected function findComponents(App $app, string $allOpt = 'all')
- {
- // For all components
- if ($app->getOpt($allOpt, false)) {
- $flags = GLOB_ONLYDIR | GLOB_MARK;
- $pattern = $this->libsDir . '*';
-
- yield from glob($pattern, $flags);
- return;
- }
-
- // For some components
- if (!$names = $app->getArgs()) {
- throw new InvalidArgumentException('Please input component names arguments');
- }
-
- foreach ($names as $name) {
- $dir = $this->libsDir . $name;
- if (!is_dir($dir)) {
- echo Color::render("Invalid component name: $name\n", 'error');
- continue;
- }
-
- yield $dir . '/';
- }
- }
-
- /**
- * @param string $cmd
- * @param string $workDir
- * @param bool $coRun
- *
- * @return array
- */
- public static function exec(string $cmd, string $workDir = '', bool $coRun = false): array
- {
- Color::println("> $cmd", 'yellow');
-
- if ($coRun) {
- $ret = Coroutine::exec($cmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Exec command error. Output: {$ret['output']}";
- Color::println($msg, 'error');
- }
-
- return $ret;
- }
-
- // normal run
- [$code, $output,] = Sys::run($cmd, $workDir);
- if ($code !== 0) {
- $msg = "Exec command error. Output: {$output}";
- Color::println($msg, 'error');
- }
-
- return [
- 'code' => $code,
- 'output' => $output,
- ];
- }
-
- /**
- * @param string $message
- */
- public static function gitCommit(string $message): void
- {
- $ret = self::exec(sprintf('git add . && git commit -m "%s"', $message));
- if ((int)$ret['code'] === 0) {
- echo $ret['output'] . PHP_EOL;
- }
- }
-}
diff --git a/script/Command/DeleteRemoteTag.php b/script/Command/DeleteRemoteTag.php
deleted file mode 100644
index b1ab4f133..000000000
--- a/script/Command/DeleteRemoteTag.php
+++ /dev/null
@@ -1,116 +0,0 @@
- The tag version. eg: v2.0.2
-
-Example:
- {{fullCmd}} -t v2.0.3 --all
- {{fullCmd}} -t v2.0.3 event
- {{fullCmd}} -t v2.0.3 event config
-
-STR;
-
- return [
- 'name' => 'tag:delete',
- 'desc' => 'delete git remote tag for components',
- 'usage' => 'tag:delete [options] [arguments]',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app): void
- {
- $tag = $app->getStrOpt('tag', $app->getStrOpt('t'));
- if (!$tag) {
- Color::println('Please input an exist tag for delete', 'error');
- return;
- }
-
- // operate the component project
- $first = $app->getArg(0);
- if ($first === self::MAIN) {
- $this->deleteForMainProject($tag);
- return;
- }
-
- $this->debug = $app->getBoolOpt('debug');
-
- // create runner
- $runner = Scheduler::new();
-
- foreach ($this->findComponents($app) as $dir) {
- $name = basename($dir);
- $cmd = "git push $name :refs/tags/$tag";
-
- $runner->add(function () use ($name, $cmd) {
- Color::println("====== Delete remote tag for component:【{$name}】");
- Color::println("> $cmd", 'yellow');
-
- if ($this->debug) {
- Color::println('[DEBUG] use co::sleep(1) to mock remote operation');
- Coroutine::sleep(1);
- return;
- }
-
- $ret = Coroutine::exec($cmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Delete remote tag fail of the {$name}. Output: {$ret['output']}";
- Color::println($msg, 'error');
- $this->result[$name] = 'Fail';
- return;
- }
-
- $this->result[$name] = 'OK';
- Color::println("- Complete for {$name}\n", 'cyan');
- });
- }
-
- $runner->start();
-
- Color::println("\nDelete Tag({$tag}) Complete", 'cyan');
- Show::aList($this->result);
- }
-
- private function deleteForMainProject(string $tag): void
- {
- $cmd = "git tag --delete $tag && git push origin :refs/tags/$tag";
- Color::println("> $cmd", 'yellow');
-
- $ret = Coroutine::exec($cmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Delete remote tag fail of the component. Output: {$ret['output']}";
- Color::println($msg, 'error');
- return;
- }
-
- Color::println("\nDelete Tag({$tag}) Complete", 'cyan');
- }
-}
diff --git a/script/Command/GenReadme.php b/script/Command/GenReadme.php
deleted file mode 100644
index be95341af..000000000
--- a/script/Command/GenReadme.php
+++ /dev/null
@@ -1,88 +0,0 @@
- 'gen:readme',
- 'desc' => 'generate readme file for swoft component(s)',
- 'usage' => 'gen:readme NAME(s)',
- 'help' => $help,
- ];
- }
-
- public function __construct()
- {
- parent::__construct();
-
- $this->tplFile = BASE_PATH . '/script/template/readme.tpl';
- }
-
- public function __invoke(App $app): void
- {
- $tplStr = file_get_contents($this->tplFile);
-
- foreach ($this->findComponents($app) as $dir) {
- $this->genReadmeFile($tplStr, $dir);
- }
-
- echo Color::render("Complete\n", 'cyan');
- }
-
- /**
- * @param string $str
- * @param string $dir
- */
- private function genReadmeFile(string $str, string $dir): void
- {
- $name = basename($dir);
-
- echo Color::render("Generate README.md for the component: $name\n", 'info');
-
- $data = [
- '{{component}}' => $name,
- '{{componentUpWord}}' => ucwords(str_replace('-', ' ', $name)),
- ];
-
- $str = strtr($str, $data);
-
- file_put_contents($dir . 'README.md', $str);
- }
-}
diff --git a/script/Command/GenTravisYml.php b/script/Command/GenTravisYml.php
deleted file mode 100644
index 092531c6c..000000000
--- a/script/Command/GenTravisYml.php
+++ /dev/null
@@ -1,101 +0,0 @@
-tplFile = dirname(__DIR__) . '/template/.travis.yml.tpl';
- }
-
- public function getHelpConfig(): array
- {
- $help = << 'gen:travis',
- 'desc' => 'generate an travis yml file for components',
- 'usage' => 'gen:travis NAME(s)',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app): void
- {
- $defVersion = '';
- if (defined('SWOOLE_VERSION')) {
- $defVersion = 'v' . SWOOLE_VERSION;
- }
-
- if (!$version = $app->getStrOpt('v', $defVersion)) {
- echo Color::render("Please input an version by option: -v\n", 'error');
- return;
- }
-
- $this->version = $version;
-
- $tplStr = file_get_contents($this->tplFile);
-
- foreach ($this->findComponents($app) as $dir) {
- $this->genReadmeFile($tplStr, $dir);
- }
-
- echo Color::render("Complete\n", 'cyan');
- }
-
- /**
- * @param string $str
- * @param string $dir
- */
- private function genReadmeFile(string $str, string $dir): void
- {
- $name = basename($dir);
- if (in_array($name, ['db', 'redis'], true)) {
- echo Color::render("Skip the component: $name\n", 'yellow');
- return;
- }
-
- echo Color::render("Generate .travis.yml for the component: $name\n", 'info');
-
- $data = [
- '{{SWOOLE_VERSION}}' => $this->version,
- ];
-
- file_put_contents($dir . '.travis.yml', strtr($str, $data));
- }
-}
diff --git a/script/Command/GenVersion.php b/script/Command/GenVersion.php
deleted file mode 100644
index 914af934b..000000000
--- a/script/Command/GenVersion.php
+++ /dev/null
@@ -1,117 +0,0 @@
- 'gen:version',
- 'desc' => 'generate an version info to composer.json',
- 'usage' => 'gen:version NAME(s)',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app): void
- {
- if (!$version = $app->getStrOpt('v')) {
- echo Color::render("Please input an version by option: -v\n", 'error');
- return;
- }
-
- $this->version = $version;
-
- echo Color::render("Input new version is: $version\n", 'info');
-
- foreach ($this->findComponents($app) as $dir) {
- $this->addVersionToComposer($dir . 'composer.json', basename($dir));
- }
-
- if ($this->updated > 0 && $app->getBoolOpt('c')) {
- self::gitCommit("update: add {$this->version} for all component composer.json");
- }
-
- echo Color::render("Complete\n", 'cyan');
- }
-
- /**
- * @param string $file
- * @param string $name
- */
- private function addVersionToComposer(string $file, string $name = ''): void
- {
- $text = file_get_contents($file);
- $name = $name ?: basename(dirname($file));
-
- // New version line
- $replace = sprintf('"version": "%s"', $this->version);
-
- $count = 0;
- $text = preg_replace(self::MATCH_VERSION, $replace, $text, 1, $count);
-
- // Not found, is first add.
- if (1 !== $count) {
- $replace = self::ADD_POSITION . "\n {$replace},";
- $text = str_replace(self::ADD_POSITION, $replace, $text, $count);
-
- $this->updated++;
- }
-
- if (0 === $count) {
- echo Color::render("Failed for add version for component: $name\n", 'error');
- return;
- }
-
- $this->updated += $count;
-
- echo Color::render("Append version for the component: $name\n", 'info');
-
- file_put_contents($file, $text);
- }
-}
diff --git a/script/Command/GitAddRemote.php b/script/Command/GitAddRemote.php
deleted file mode 100644
index da77c14ac..000000000
--- a/script/Command/GitAddRemote.php
+++ /dev/null
@@ -1,74 +0,0 @@
- 'git:addrmt',
- 'desc' => 'Add the remote repository address of each component',
- 'usage' => 'git:addrmt [options] [arguments]',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app)
- {
- $prefix = self::REMOTE_PREFIX;
-
- foreach ($this->findComponents($app) as $dir) {
- $name = basename($dir);
- Color::println("===== Add remote for $name");
-
- $check = "git remote -v | grep swoft-{$name}.git";
- Color::println('> ' . $check, 'yellow');
-
- [$code, , ] = Sys::run($check, $this->baseDir);
- if ($code === 0) {
- Color::println("The remote '{$name}' exist, skip add");
- continue;
- }
-
- $cmd = "git remote add $name $prefix{$name}.git";
- Color::println('> ' . $cmd, 'yellow');
-
- [$code, $ret, ] = Sys::run($cmd, $this->baseDir);
- if ($code !== 0) {
- echo "Add remote error for '{$name}'. Return: $ret\n";
- continue;
- }
-
- Color::println('> OK');
- }
-
- Color::println('Complete');
- }
-}
diff --git a/script/Command/GitFindTag.php b/script/Command/GitFindTag.php
deleted file mode 100644
index 09f0706e2..000000000
--- a/script/Command/GitFindTag.php
+++ /dev/null
@@ -1,129 +0,0 @@
- v2.0.3
- --only-tag Only output tag information
-
-Example:
- {{fullCmd}}
- {{fullCmd}} --only-tag
- {{fullCmd}} -d ../view --next-tag
- {{fullCmd}} -d ../view --next-tag --only-tag
-
-STR;
-
- return [
- 'name' => 'tag:find',
- 'desc' => 'get the latest/next tag from the project directory',
- 'usage' => 'tag:find [DIR]',
- 'help' => $help,
- ];
- }
-
- /**
- * echo $(php dtool.php git:tag --only-tag -d ../view)
- *
- * @param App $app
- */
- public function __invoke(App $app): void
- {
- $dir = $app->getOpt('dir', $app->getOpt('d'));
- $dir = $dir ?: $app->getPwd();
-
- $onlyTag = $app->getBoolOpt('only-tag');
- $nextTag = $app->getBoolOpt('next-tag');
-
- $tagName = $this->findTag($dir, !$onlyTag);
- if (!$tagName) {
- Show::error('No any tags of the project', -2);
- return;
- }
-
- $title = 'The latest tag: %s';
-
- if ($nextTag) {
- $title = "The next tag: %s (current: {$tagName})";
- $nodes = explode('.', $tagName);
-
- $lastNum = array_pop($nodes);
- $nodes[] = (int)$lastNum + 1;
- $tagName = implode('.', $nodes);
- }
-
- if ($onlyTag) {
- echo $tagName;
- return;
- }
-
- Show::writef("$title", $tagName);
- }
-
- /**
- * @param string $workDir
- * @param bool $showInfo
- *
- * @return string
- */
- public function findTag(string $workDir, bool $showInfo = false): string
- {
- if (!is_dir($workDir)) {
- return '';
- }
-
- $cmd = 'git describe --tags $(git rev-list --tags --max-count=1)';
-
- if ($showInfo) {
- $info = [
- 'command' => $cmd,
- 'workDir' => $workDir,
- ];
- Show::aList($info, 'info');
- }
-
- [$code, $tagName,] = Sys::run($cmd, $workDir);
- if ($code !== 0) {
- return '';
- }
-
- return trim($tagName);
- }
-
- /**
- * Get next tag version. eg: v2.0.3 => v2.0.4
- *
- * @param string $tagName
- *
- * @return string
- */
- public function buildNextTag(string $tagName): string
- {
- $nodes = explode('.', $tagName);
-
- $lastNum = array_pop($nodes);
- $nodes[] = (int)$lastNum + 1;
-
- return implode('.', $nodes);
- }
-}
diff --git a/script/Command/GitForcePush.php b/script/Command/GitForcePush.php
deleted file mode 100644
index b33adf53d..000000000
--- a/script/Command/GitForcePush.php
+++ /dev/null
@@ -1,79 +0,0 @@
- 'git:fpush',
- 'desc' => 'Force push all update to remote sub-repo by git push with --force',
- 'usage' => 'git:fpush [options] [arguments]',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app)
- {
- $targetBranch = 'master';
- $this->debug = $app->getBoolOpt('debug');
-
- $result = [];
- $runner = Scheduler::new();
-
- // force push:
- // git push tcp-server `git subtree split --prefix src/tcp-server master`:master --force
- foreach ($this->findComponents($app) as $dir) {
- $name = basename($dir);
- // 先分割,在强推上去
- $cmd = "git push {$name} `git subtree split --prefix src/{$name} master`:{$targetBranch} --force";
-
- $runner->add(function () use ($name, $cmd, &$result) {
- Color::println("\n====== Push the component:【{$name}】");
- Color::println("> $cmd", 'yellow');
-
- $ret = Coroutine::exec($cmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Push to remote fail of the {$name}. Output: {$ret['output']}";
- Color::println($msg, 'error');
- $result[$name] = 'Fail';
- return;
- }
-
- $result[$name] = 'OK';
- Color::println("- Complete for {$name}\n", 'cyan');
- Coroutine::sleep(1);
- });
- }
-
- $runner->start();
- Color::println("\nForce Push Complete", 'cyan');
- Show::aList($result);
- }
-}
diff --git a/script/Command/GitHubInfo.php b/script/Command/GitHubInfo.php
deleted file mode 100644
index 550be0efb..000000000
--- a/script/Command/GitHubInfo.php
+++ /dev/null
@@ -1,19 +0,0 @@
- The tag version. eg: v2.0.2
- -y, --yes No confirmation required
-
-Example:
- {{fullCmd}} -t v2.0.3 --all
- {{fullCmd}} -t v2.0.3 event
- {{fullCmd}} -t v2.0.3 event config
-
-STR;
-
- // --recopy Recopy components codes to tmp dir for operation
- return [
- 'name' => 'tag:release',
- 'desc' => 'Release all sub-repo to new tag version and push to remote repo',
- 'usage' => 'tag:release [options] [arguments]',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app)
- {
- $newTag = $app->getStrOpt('tag', $app->getStrOpt('t'));
- if (!$newTag) {
- Color::println('Please input an new tag for release. eg: v2.0.4', 'error');
- return;
- }
-
- // operate the component project
- if ($app->getArg(0) === self::MAIN) {
- self::doTagAndPush('component', $newTag, $this->baseDir);
- Color::println("\nRelease Tag({$newTag}) Complete", 'cyan');
- return;
- }
-
- $this->tmpDir = '/tmp/sub-repos';
- $this->debug = $app->getBoolOpt('debug');
- $debugText = $this->debug ? 'True' : 'False';
-
- Color::println("Will release new tag: $newTag (DEBUG: $debugText)");
-
- $yes = $app->getBoolOpt('yes', $app->getBoolOpt('y'));
- if (!$yes && Interact::unConfirm('Now, continue')) {
- Color::println('Bye Bye');
- return;
- }
-
- // $targetBranch = 'master';
- $makeTmpDir = "rm -rf {$this->tmpDir} && mkdir {$this->tmpDir}";
-
- Color::println("> $makeTmpDir", 'yellow');
- [$code, $msg,] = Sys::run($makeTmpDir);
- if ($code !== 0) {
- Color::println('[ERROR]' . $msg, 'error');
- return;
- }
-
- $finder = new GitFindTag();
- $runner = Scheduler::new();
-
- foreach ($this->findComponents($app) as $dir) {
- $this->releaseTag($runner, $finder, basename($dir), $newTag);
- }
-
- $runner->start();
- Color::println("\nRelease Tag({$newTag}) Complete", 'cyan');
- Show::aList($this->result);
- }
-
- /**
- * @param Scheduler $runner
- * @param GitFindTag $finder
- * @param string $name
- * @param string $newTag
- */
- private function releaseTag(Scheduler $runner, GitFindTag $finder, string $name, string $newTag): void
- {
- $tmpDir = $this->tmpDir;
- $repoDir = $tmpDir . '/' . $name;
-
- // - ensure no repo dir
- $rmRepoDir = "rm -rf $repoDir";
- Color::println("> $rmRepoDir", 'yellow');
-
- [$code, $msg,] = Sys::run($rmRepoDir);
- if ($code !== 0) {
- $msg = "Remove repo dir fail of the {$name}. Output: {$msg}";
- Color::println($msg, 'error');
- return;
- }
-
- // $remoteTpl = 'https://github.com/swoft-cloud/swoft-%s.git';
- $remoteTpl = 'git@github.com:swoft-cloud/swoft-%s.git';
- $remoteUrl = sprintf($remoteTpl, $name);
-
- // - clone remote repo
- $cloneCmd = "cd {$tmpDir} && git clone {$remoteUrl} $name";
- Color::println("> $cloneCmd", 'yellow');
-
- if (!$this->debug) {
- [$code, $msg,] = Sys::run($cloneCmd, $tmpDir);
-
- if ($code !== 0) {
- $msg = "Clone repo fail of the {$name}. Output: {$msg}";
- Color::println($msg, 'error');
- return;
- }
- }
-
- // - check last tag
- Color::println("------ Check last tag for thr component: $name");
-
- $lastTag = $finder->findTag($repoDir);
- if ($lastTag === $newTag) {
- Color::println("The component '{$name}' has been exists tag: {$newTag}, skip release");
- return;
- }
-
- $runner->add(function () use ($name, $newTag, $repoDir) {
- $ok = self::doTagAndPush($name, $newTag, $repoDir);
-
- // Save result status
- $this->result[$name] = $ok ? 'OK' : 'Fail';
- Color::println("- Complete for {$name}\n", 'cyan');
- });
- }
-
- /**
- * @param string $name
- * @param string $newTag
- * @param string $repoDir
- *
- * @return bool
- */
- private static function doTagAndPush(string $name, string $newTag, string $repoDir): bool
- {
- $addTagCmd = "cd {$repoDir} && git tag -a {$newTag} -m \"Release {$newTag}\"";
-
- Color::println("====== Release the component:【{$name}】");
- Color::println("> $addTagCmd", 'yellow');
-
- // - add new tag
- $ret = Coroutine::exec($addTagCmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Add tag fail of the {$name}. Output: {$ret['output']}";
- Color::println($msg, 'error');
- return false;
- }
-
- $pushTagCmd = "cd {$repoDir} && git push origin {$newTag}";
- Color::println("> $pushTagCmd", 'yellow');
-
- // - push new tag
- $ret = Coroutine::exec($pushTagCmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Push tag fail of the {$name}. Output: {$ret['output']}";
- Color::println($msg, 'error');
- return false;
- }
-
- return true;
- }
-}
diff --git a/script/Command/GitSubtreePull.php b/script/Command/GitSubtreePull.php
deleted file mode 100644
index 8bf3976a4..000000000
--- a/script/Command/GitSubtreePull.php
+++ /dev/null
@@ -1,89 +0,0 @@
- 'git:spull',
- 'desc' => 'Pull all update from remote sub-repo by git subtree pull',
- 'usage' => 'git:spull [options] [arguments]',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app)
- {
- if ($app->getCommand()) {
- Color::println('Please use git:fpush instead of the command', 'error');
- return;
- }
-
- $targetBranch = 'master';
- $this->debug = $app->getBoolOpt('debug');
-
- $result = [];
- $runner = Scheduler::new();
-
- // git subtree pull --prefix=src/annotation git@github.com:swoft-cloud/swoft-annotation.git master --squash
- // git subtree pull --prefix=src/stdlib stdlib master
- foreach ($this->findComponents($app) as $dir) {
- $name = basename($dir);
- $cmd = "git subtree pull --prefix=src/{$name} {$name} {$targetBranch} --squash";
-
- $runner->add(function () use ($name, $cmd, &$result) {
- Color::println("\n====== Pull the component:【{$name}】");
- Color::println("> $cmd", 'yellow');
-
- if ($this->debug) {
- Color::println('[DEBUG] use co::sleep(2) to mock remote operation');
- Coroutine::sleep(2);
- return;
- }
-
- $ret = Coroutine::exec($cmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Pull from remote fail of the {$name}. Output: {$ret['output']}";
- Color::println($msg, 'error');
- $result[$name] = 'Fail';
- return;
- }
-
- $result[$name] = 'OK';
- Color::println("- Complete for {$name}\n", 'cyan');
- Coroutine::sleep(1);
- });
- }
-
- $runner->start();
- Color::println("\nComplete", 'cyan');
- Show::aList($result);
- }
-}
diff --git a/script/Command/GitSubtreePush.php b/script/Command/GitSubtreePush.php
deleted file mode 100644
index 355960fc6..000000000
--- a/script/Command/GitSubtreePush.php
+++ /dev/null
@@ -1,91 +0,0 @@
- 'git:spush',
- 'desc' => 'Push all update to remote sub-repo by git subtree push',
- 'usage' => 'git:spush [options] [arguments]',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app)
- {
- if ($app->getCommand()) {
- Color::println('Please use git:fpush instead of the command', 'error');
- return;
- }
-
- $targetBranch = 'master';
- $this->debug = $app->getBoolOpt('debug');
-
- $result = [];
- $runner = Scheduler::new();
-
- // git subtree push --prefix=src/annotation git@github.com:swoft-cloud/swoft-annotation.git master --squash
- // git subtree push --prefix=src/stdlib stdlib master
- foreach ($this->findComponents($app) as $dir) {
- $name = basename($dir);
- // push 加 --squash 是没有意义的
- // link https://stackoverflow.com/questions/20102594/git-subtree-push-squash-does-not-squash
- $cmd = "git subtree push --prefix=src/{$name} {$name} $targetBranch";
-
- $runner->add(function () use ($name, $cmd, &$result) {
- Color::println("\n====== Push the component:【{$name}】");
- Color::println("> $cmd", 'yellow');
-
- if ($this->debug) {
- Color::println('[DEBUG] use co::sleep(2) to mock remote operation');
- Coroutine::sleep(2);
- return;
- }
-
- $ret = Coroutine::exec($cmd);
- if ((int)$ret['code'] !== 0) {
- $msg = "Push to remote fail of the {$name}. Output: {$ret['output']}";
- Color::println($msg, 'error');
- $result[$name] = 'Fail';
- return;
- }
-
- $result[$name] = 'OK';
- Color::println("- Complete for {$name}\n", 'cyan');
- Coroutine::sleep(1);
- });
- }
-
- $runner->start();
- Color::println("\nComplete", 'cyan');
- Show::aList($result);
- }
-}
diff --git a/script/Command/Scheduler.php b/script/Command/Scheduler.php
deleted file mode 100644
index e22ac5658..000000000
--- a/script/Command/Scheduler.php
+++ /dev/null
@@ -1,93 +0,0 @@
-handlers[] = [$callable, []];
- }
- }
- }
-
- /**
- * @param callable $callable
- * @param mixed ...$args
- */
- public function add(callable $callable, ...$args): void
- {
- $this->handlers[] = [$callable, $args];
- }
-
- /**
- * @return bool
- */
- public function start(): bool
- {
- if (!$this->handlers) {
- throw new RuntimeException('Not add any callable handler, cannot start');
- }
-
- // >= 4.4
- if ($this->isGteSwoole44()) {
- $scheduler = new CoScheduler;
-
- foreach ($this->handlers as [$callable, $args]) {
- $scheduler->add($callable, ...$args);
- }
-
- return $scheduler->start();
- }
-
- // < 4.4
- foreach ($this->handlers as [$callable, $args]) {
- Coroutine::create($callable, ...$args);
- }
-
- Event::wait();
- return true;
- }
-
- /**
- * Check swoole is >= 4.4.0
- *
- * @return bool
- */
- public function isGteSwoole44(): bool
- {
- return SWOOLE_VERSION_ID >= 40400;
- }
-}
diff --git a/script/Command/UpdateSwooleVer.php b/script/Command/UpdateSwooleVer.php
deleted file mode 100644
index 9ce75ac3b..000000000
--- a/script/Command/UpdateSwooleVer.php
+++ /dev/null
@@ -1,106 +0,0 @@
- 'up:swover',
- 'desc' => 'update the swoole version for all .travis.yml',
- 'usage' => 'up:swover -v VERSION',
- 'help' => $help,
- ];
- }
-
- public function __invoke(App $app): void
- {
- $defVersion = '';
- if (defined('SWOOLE_VERSION')) {
- $defVersion = 'v' . SWOOLE_VERSION;
- }
-
- if (!$version = $app->getStrOpt('v', $defVersion)) {
- echo Color::render("Please input an version by option: -v\n", 'error');
- return;
- }
-
- $this->version = 'v' . trim($version, 'v');
-
- echo Color::render("New swoole version is: {$this->version}\n", 'info');
-
- // for all
- $app->setOpts(array_merge($app->getOpts(), ['all' => true]));
- foreach ($this->findComponents($app) as $dir) {
- $this->updateSwooleVersion($dir . '.travis.yml', basename($dir));
- }
-
- $mainDir = $app->getPwd();
- $this->updateSwooleVersion($mainDir . '/.travis.yml', basename($mainDir));
-
- if ($this->updated > 0 && $app->getBoolOpt('c')) {
- self::gitCommit('update: update the swoole version for .travis.yml');
- }
-
- echo Color::render("Complete. Updated: {$this->updated}\n", 'cyan');
- }
-
- private function updateSwooleVersion(string $file, string $cptName): void
- {
- if (!file_exists($file)) {
- Color::println("Skip the component: $cptName", 'mga');
- return;
- }
-
- $updated = 0;
- // .../swoole-src/archive/v4.4.1.tar.gz
- $regexp = '#swoole-src/archive/(v\d.\d.\d).tar.gz#';
- $replace = "swoole-src/archive/{$this->version}.tar.gz";
- $content = file_get_contents($file);
-
- // replace
- $content = preg_replace($regexp, $replace, $content, 1, $updated);
- if ($updated) {
- $this->updated++;
- }
-
- Color::println("- Updated the component: $cptName");
-
- file_put_contents($file, $content);
- }
-}
diff --git a/script/bootstrap.php b/script/bootstrap.php
deleted file mode 100644
index 32dc873cb..000000000
--- a/script/bootstrap.php
+++ /dev/null
@@ -1,40 +0,0 @@
- $dir) {
- $loader->addPsr4($prefix, $componentDir . '/' . $dir);
- }
-} else {
- exit('Please run "composer install" to install the dependencies' . PHP_EOL);
-}
-
-$libDir = __DIR__ . '/';
-$npMap = [
- 'SwoftTool\\' => $libDir,
- // 'Inhere\\ValidateTest\\' => $libDir . '/test/',
-];
-
-spl_autoload_register(function ($class) use ($npMap) {
- foreach ($npMap as $np => $dir) {
- if (strpos($class, $np) !== 0) {
- continue;
- }
-
- $file = $dir . str_replace('\\', '/', substr($class, strlen($np))) . '.php';
-
- if (file_exists($file)) {
- include $file;
- }
- }
-});
diff --git a/script/dev-doc.md b/script/dev-doc.md
new file mode 100644
index 000000000..cb6d02677
--- /dev/null
+++ b/script/dev-doc.md
@@ -0,0 +1,25 @@
+# Develop docs
+
+## add custom components
+
+update `bin/bootstrap.php`:
+
+```php
+addPsr4("Swoft\\Cache\\", 'vendor/swoft/cache/src/');
+$loader->addPsr4("Swoft\\Swlib\\", 'vendor/swoft/swlib/src/');
+$loader->addPsr4("Swoft\\Serialize\\", 'vendor/swoft/serialize/src/');
+```
diff --git a/script/template/pull-request.tpl.md b/script/template/pull-request.tpl.md
new file mode 100644
index 000000000..4c233714b
--- /dev/null
+++ b/script/template/pull-request.tpl.md
@@ -0,0 +1,58 @@
+- 请不要提交PR到各个组件仓库,它们都是 **只读的**
+- 核心组件的 **开发仓库** 是 **[swoft/swoft-component][core]**
+- 扩展组件的 **开发仓库** 是 **[swoft/swoft-ext][ext]**
+- 请 `fork` 对应的 **开发仓库**,修改后,请把你的PR提交到对应的开发仓库
+
+> 发布版本时官方会将代码同步到各个子仓库。因此,切记不要往子仓库发PR。
+
+## 发起PR时的注意事项
+
+开发组非常欢迎各位向我们提交PR(_Pull Request_),但是为了保证代码质量和统一的风格,
+向官方的主仓库 [swoft/swoft][main] 和 **开发仓库** 贡献代码时需要注意代码和commit格式
+
+### Commit Message
+
+- commit message 只能是英文信息
+- 请尽量保证commit message是有意义的说明
+- 最好以 `add:` `update:` `fix:` 等关键字开头
+
+### 代码风格
+
+- 提交的PHP代码 **必须** 遵循 PSR-2 代码风格
+- 合理且有意义的类、方法、变量命名
+- 适当的注释,合理的使用空行保持代码的简洁,易于阅读
+- 不要包含一些无意义的信息 例如 `@author` 等(_提交者是能够从commit log里看到的_)
+
+------------------
+
+> English Version (_translate by Google_)
+
+The development team welcomes you to submit PR (_Pull Request_) to us, but to ensure code quality and uniform style,
+go to the official main repository [swoft/swoft][main] and Development repository, Note the code and commit format when contributing code
+
+## Precautions when initiating PR
+
+- Please do not submit PR to each sub-repository, they are all read-only
+- The _development repository_ for the core components is **[swoft/swoft-component][core]**
+- The _development repository_ for extension components is **[swoft/swoft-ext][ext]**
+- Please `fork` the corresponding development warehouse. After modification, please submit your PR to the corresponding development warehouse.
+
+> Officially syncs code to individual sub-warehouses when new versions are released
+
+### Commit Message
+
+- the commit message can only be in English
+- Please try to ensure that the commit message is meaningful
+- it is best to start with the keyword `add:` `update:` `fix:`
+
+### Code Style
+
+- Submitted PHP code **Must** Follow PSR-2 code style
+- Reasonable and meaningful class, method, variable naming
+- Appropriate comments, reasonable use of blank lines to keep the code simple and easy to read
+- Don't include some meaningless information such as `@author`, etc. (_author is that can be seen from the commit log_)
+
+
+[main]: https://github.com/swoft-cloud/swoft
+[core]: https://github.com/swoft-cloud/swoft-component
+[ext]: https://github.com/swoft-cloud/swoft-ext
diff --git a/src/annotation/composer.json b/src/annotation/composer.json
index 755b68c68..e8c9fba53 100644
--- a/src/annotation/composer.json
+++ b/src/annotation/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/annotation",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/annotation/src/Resource/AnnotationResource.php b/src/annotation/src/Resource/AnnotationResource.php
index 7265f6412..83769476e 100644
--- a/src/annotation/src/Resource/AnnotationResource.php
+++ b/src/annotation/src/Resource/AnnotationResource.php
@@ -16,6 +16,7 @@
use Swoft\Stdlib\Helper\ComposerHelper;
use Swoft\Stdlib\Helper\DirectoryHelper;
use Swoft\Stdlib\Helper\ObjectHelper;
+use function array_merge;
use function class_exists;
use function file_exists;
use function get_included_files;
@@ -83,7 +84,7 @@ class AnnotationResource extends AbstractResource
* @var array
* eg. ['Psr\\', 'PHPUnit\\', 'Symfony\\']
*/
- private $excludedPsr4Prefixes;
+ private $excludedPsr4Prefixes = [];
/**
* Can disable AutoLoader class before load component classes.
@@ -119,9 +120,9 @@ class AnnotationResource extends AbstractResource
*/
public function __construct(array $config = [])
{
- // Init $excludedPsr4Prefixes
+ // Init $excludedPsr4Prefixes
$this->excludedPsr4Prefixes = self::DEFAULT_EXCLUDED_PSR4_PREFIXES;
-
+
// Can set property by array
ObjectHelper::init($this, $config);
@@ -473,11 +474,11 @@ public function getExcludedPsr4Prefixes(): array
}
/**
- * @param array $excludedPsr4Prefixes
+ * @param array $psr4Prefixes
*/
- public function setExcludedPsr4Prefixes(array $excludedPsr4Prefixes): void
+ public function setExcludedPsr4Prefixes(array $psr4Prefixes): void
{
- $this->excludedPsr4Prefixes = $excludedPsr4Prefixes;
+ $this->excludedPsr4Prefixes = array_merge($this->excludedPsr4Prefixes, $psr4Prefixes);
}
/**
@@ -489,11 +490,11 @@ public function getExcludedFilenames(): array
}
/**
- * @param array $excludedFilenames
+ * @param array $filenames
*/
- public function setExcludedFilenames(array $excludedFilenames): void
+ public function setExcludedFilenames(array $filenames): void
{
- $this->excludedFilenames = $excludedFilenames;
+ $this->excludedFilenames = array_merge($this->excludedFilenames, $filenames);
}
/**
diff --git a/src/annotation/test/unit/Resource/AnnotationResourceTest.php b/src/annotation/test/unit/Resource/AnnotationResourceTest.php
new file mode 100644
index 000000000..9625c7997
--- /dev/null
+++ b/src/annotation/test/unit/Resource/AnnotationResourceTest.php
@@ -0,0 +1,54 @@
+assertFalse($ar->isInPhar());
+ $this->assertEmpty($ar->getBasePath());
+ $this->assertEmpty($ar->getOnlyNamespaces());
+ $this->assertEmpty($ar->getDisabledAutoLoaders());
+
+ $this->assertSame('AutoLoader', $ar->getLoaderClassName());
+
+ $this->assertNotEmpty($names = $ar->getExcludedFilenames());
+ $this->assertArrayHasKey('Swoft.php', $names);
+
+ $this->assertNotEmpty($prefixes = $ar->getExcludedPsr4Prefixes());
+ $this->assertArrayContainValue($prefixes, 'PHPUnit\\');
+ $this->assertArrayContainValue($prefixes, 'Monolog\\');
+ $this->assertArrayNotContainValue($prefixes, 'TestNamespace\\');
+ $this->assertTrue($ar->isExcludedPsr4Prefix('Monolog\\SomeClass'));
+
+ $ar = new AnnotationResource([
+ 'inPhar' => true,
+ 'basePath' => '/bash/path',
+ 'notifyHandler' => function () {},
+ // TODO force load framework components: bean, error, event, aop
+ 'disabledAutoLoaders' => ['Some\\TestLoader'],
+ 'excludedPsr4Prefixes' => ['TestNamespace\\'],
+ ]);
+
+ $this->assertTrue($ar->isInPhar());
+
+ $this->assertNotEmpty($loaders = $ar->getDisabledAutoLoaders());
+ $this->assertArrayContainValue($loaders, 'Some\\TestLoader');
+
+ $this->assertNotEmpty($prefixes = $ar->getExcludedPsr4Prefixes());
+ $this->assertArrayContainValue($prefixes, 'PHPUnit\\');
+ $this->assertArrayContainValue($prefixes, 'TestNamespace\\');
+ }
+}
diff --git a/src/aop/composer.json b/src/aop/composer.json
index efaa6fd42..aecdbc157 100644
--- a/src/aop/composer.json
+++ b/src/aop/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/aop",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/aop/phpunit.xml b/src/aop/phpunit.xml
index 15311104a..e491bd4a9 100644
--- a/src/aop/phpunit.xml
+++ b/src/aop/phpunit.xml
@@ -1,14 +1,14 @@
+ bootstrap="test/bootstrap.php"
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false">
./test/unit
@@ -19,4 +19,4 @@
./src/*
-
\ No newline at end of file
+
diff --git a/src/aop/src/Aop.php b/src/aop/src/Aop.php
index 0813c4820..5257122c4 100644
--- a/src/aop/src/Aop.php
+++ b/src/aop/src/Aop.php
@@ -8,7 +8,6 @@
use function count;
use function explode;
use function preg_match;
-use SwoftTest\Component\Testing\Aop\RegAop;
/**
* Class AopRegister
@@ -170,4 +169,4 @@ private static function isExecution(string $class, string $method, array $execut
return false;
}
-}
\ No newline at end of file
+}
diff --git a/src/aop/src/AspectHandler.php b/src/aop/src/AspectHandler.php
index 2907a0bbf..85a5f94dd 100644
--- a/src/aop/src/AspectHandler.php
+++ b/src/aop/src/AspectHandler.php
@@ -1,6 +1,5 @@
invokeAdvice($afThw, $this->throwable);
}
throw $this->throwable;
- } else {
- // Invoke afterReturning advice
- if (!empty($afRetn)) {
- $result = $this->invokeAdvice($afRetn, null, $result);
- }
+ }
+
+ // Invoke afterReturning advice
+ if (!empty($afRetn)) {
+ $result = $this->invokeAdvice($afRetn, null, $result);
}
return $result;
@@ -244,7 +243,7 @@ private function invokeAdvice(array $aspectAry, Throwable $catch = null, $return
continue;
}
- if ($type == Throwable::class) {
+ if ($type === Throwable::class) {
$aspectArgs[] = $catch;
}
@@ -310,7 +309,7 @@ private function getJoinPoint(Throwable $catch = null, $return = null): JoinPoin
*/
private function nextHandler(): AspectHandler
{
- $aspect = clone $this;
+ $aspect = clone $this;
// Next aspect data
$aspect->aspect = array_shift($this->aspects);
@@ -318,4 +317,4 @@ private function nextHandler(): AspectHandler
return $aspect;
}
-}
\ No newline at end of file
+}
diff --git a/src/aop/src/Ast/Visitor/ProxyVisitor.php b/src/aop/src/Ast/Visitor/ProxyVisitor.php
index 7b39275fc..6c5801b9e 100644
--- a/src/aop/src/Ast/Visitor/ProxyVisitor.php
+++ b/src/aop/src/Ast/Visitor/ProxyVisitor.php
@@ -1,18 +1,16 @@
name->toString();
- $this->proxyName = sprintf('%s%s%s', $name, self::PROXY, $this->proxyId);
+ $this->proxyName = sprintf('%s%s%s', $name, self::PROXY, $this->proxyId);
$this->originalClassName = sprintf('%s\\%s', $this->namespace, $name);
return null;
@@ -196,11 +194,7 @@ private function proxyMethod(ClassMethod $node): ClassMethod
];
// Proxy method call
- $proxyCall = new Node\Expr\MethodCall(
- new Node\Expr\Variable('this'),
- '__proxyCall',
- $newParams
- );
+ $proxyCall = new Node\Expr\MethodCall(new Node\Expr\Variable('this'), '__proxyCall', $newParams);
// New method stmts
$type = $node->returnType;
diff --git a/src/aop/src/Concern/AopTrait.php b/src/aop/src/Concern/AopTrait.php
index 28894b9af..9ea043c2e 100644
--- a/src/aop/src/Concern/AopTrait.php
+++ b/src/aop/src/Concern/AopTrait.php
@@ -1,6 +1,5 @@
assertTrue(true);
}
-}
\ No newline at end of file
+}
diff --git a/src/aop/test/unit/AopTest.php b/src/aop/test/unit/AopTest.php
index 5f49725c2..2a92ec109 100644
--- a/src/aop/test/unit/AopTest.php
+++ b/src/aop/test/unit/AopTest.php
@@ -4,16 +4,16 @@
namespace SwoftTest\Aop\Unit;
-use function class_exists;
-use const PHP_EOL;
use PHPUnit\Framework\TestCase;
-use function sprintf;
use Swoft\Aop\Ast\Visitor\ProxyVisitor;
use Swoft\Aop\Proxy;
use Swoft\Proxy\Ast\Parser;
use Swoft\Proxy\Exception\ProxyException;
use Swoft\Proxy\Proxy as BaseProxy;
use SwoftTest\Aop\Testing\AopClass;
+use function class_exists;
+use function sprintf;
+use const PHP_EOL;
/**
@@ -52,7 +52,7 @@ public function testProxyCode()
// Proxy file and proxy code
$proxyCode = sprintf('assertEquals($originalClass, $className);
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/composer.json b/src/bean/composer.json
index 212a970c9..1082d4051 100644
--- a/src/bean/composer.json
+++ b/src/bean/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/bean",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/bean/phpunit.xml b/src/bean/phpunit.xml
index 15311104a..e491bd4a9 100644
--- a/src/bean/phpunit.xml
+++ b/src/bean/phpunit.xml
@@ -1,14 +1,14 @@
+ bootstrap="test/bootstrap.php"
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false">
./test/unit
@@ -19,4 +19,4 @@
./src/*
-
\ No newline at end of file
+
diff --git a/src/bean/src/Annotation/Parser/BeanParser.php b/src/bean/src/Annotation/Parser/BeanParser.php
index 7b4b028c0..7fbd07974 100644
--- a/src/bean/src/Annotation/Parser/BeanParser.php
+++ b/src/bean/src/Annotation/Parser/BeanParser.php
@@ -30,7 +30,7 @@ class BeanParser extends Parser
public function parse(int $type, $annotationObject): array
{
// Only to parse class annotation with `@Bean`
- if ($type != self::TYPE_CLASS) {
+ if ($type !== self::TYPE_CLASS) {
return [];
}
@@ -61,4 +61,4 @@ private function registerInterface(string $beanName): void
InterfaceRegister::registerInterface($interface->getName(), $this->className, $beanName);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/src/BF.php b/src/bean/src/BF.php
index 63a835561..ff1036548 100644
--- a/src/bean/src/BF.php
+++ b/src/bean/src/BF.php
@@ -1,6 +1,5 @@
singletonPool[$id])) {
return $this->singletonPool[$id];
}
- // Prototype by clone
+ // Prototype bean by clone
if (isset($this->prototypePool[$id])) {
return clone $this->prototypePool[$id];
}
- // Alias name
+ // Has alias name
$aliasId = $this->aliases[$id] ?? '';
if ($aliasId) {
return $this->get($aliasId);
@@ -432,7 +432,7 @@ public function get($id)
/* @var ObjectDefinition $objectDefinition */
$objectDefinition = $this->objectDefinitions[$id];
- // Prototype
+ // Prototype bean
return $this->safeNewBean($objectDefinition->getName());
}
@@ -532,7 +532,7 @@ public function create(string $name, array $definition = [])
];
}
- $definitionObjParser = new DefinitionObjParser([$name=>$definition], [], [], $this->aliases);
+ $definitionObjParser = new DefinitionObjParser([$name => $definition], [], [], $this->aliases);
[, $objectDefinitions] = $definitionObjParser->parseDefinitions();
$this->objectDefinitions[$name] = $objectDefinitions[$name];
@@ -648,9 +648,8 @@ public function addParsers(array $annotationParsers): void
*/
private function parseAnnotations(): void
{
- $annotationParser = new AnnotationObjParser(
- $this->definitions, $this->objectDefinitions, $this->classNames, $this->aliases
- );
+ $annotationParser = new AnnotationObjParser($this->definitions, $this->objectDefinitions, $this->classNames,
+ $this->aliases);
$annotationData = $annotationParser->parseAnnotations($this->annotations, $this->parsers);
[$this->definitions, $this->objectDefinitions, $this->classNames, $this->aliases] = $annotationData;
@@ -661,9 +660,8 @@ private function parseAnnotations(): void
*/
private function parseDefinitions(): void
{
- $annotationParser = new DefinitionObjParser(
- $this->definitions, $this->objectDefinitions, $this->classNames, $this->aliases
- );
+ $annotationParser = new DefinitionObjParser($this->definitions, $this->objectDefinitions, $this->classNames,
+ $this->aliases);
// Collect info
$definitionData = $annotationParser->parseDefinitions();
@@ -922,8 +920,9 @@ private function newBean(string $beanName, string $id = '')
// Inject properties values
$this->newProperty($reflectObject, $reflectionClass, $propertyInjects, $id);
- // Alias
- if (!empty($alias)) {
+ // Alias name
+ // Fix: $aliasId !== $id for deny loop get
+ if ($alias && $alias !== $beanName) {
$this->aliases[$alias] = $beanName;
}
diff --git a/src/bean/src/Definition/Parser/AnnotationObjParser.php b/src/bean/src/Definition/Parser/AnnotationObjParser.php
index 882107531..99b5950b5 100644
--- a/src/bean/src/Definition/Parser/AnnotationObjParser.php
+++ b/src/bean/src/Definition/Parser/AnnotationObjParser.php
@@ -2,9 +2,6 @@
namespace Swoft\Bean\Definition\Parser;
-use function array_merge;
-use function count;
-use function get_class;
use InvalidArgumentException;
use Swoft\Annotation\Annotation\Parser\Parser;
use Swoft\Annotation\Annotation\Parser\ParserInterface;
@@ -12,6 +9,9 @@
use Swoft\Bean\Definition\MethodInjection;
use Swoft\Bean\Definition\ObjectDefinition;
use Swoft\Bean\Definition\PropertyInjection;
+use function array_merge;
+use function count;
+use function get_class;
/**
* Class AnnotationParser
@@ -108,9 +108,8 @@ private function parseOneClassAnnotations(string $className, array $classOneAnno
{
// Check class annotation tag
if (!isset($classOneAnnotations['annotation'])) {
- throw new AnnotationException(
- sprintf('Property or method(%s) with `@xxx` must be define class annotation', $className)
- );
+ throw new AnnotationException(sprintf('Property or method(%s) with `@xxx` must be define class annotation',
+ $className));
}
// Parse class annotations
diff --git a/src/bean/src/Definition/Parser/ObjectParser.php b/src/bean/src/Definition/Parser/ObjectParser.php
index 7c245b57b..fcab2a34a 100644
--- a/src/bean/src/Definition/Parser/ObjectParser.php
+++ b/src/bean/src/Definition/Parser/ObjectParser.php
@@ -2,9 +2,9 @@
namespace Swoft\Bean\Definition\Parser;
+use Swoft\Bean\Definition\ObjectDefinition;
use function is_string;
use function preg_match;
-use Swoft\Bean\Definition\ObjectDefinition;
/**
* Class ObjectParser
@@ -120,4 +120,4 @@ protected function getValueByRef($value): array
return [$value, false];
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/src/InterfaceRegister.php b/src/bean/src/InterfaceRegister.php
index 9c9f7d08f..e7484a866 100644
--- a/src/bean/src/InterfaceRegister.php
+++ b/src/bean/src/InterfaceRegister.php
@@ -1,6 +1,5 @@
[
'SwoftTest\\Bean\\Testing\\',
'Swoft\\Bean\\',
'Swoft\\Annotation\\',
],
- ]
-);
+ ]);
$definitions = require 'testing/bean.php';
$parsers = AnnotationRegister::getParsers();
@@ -50,4 +48,4 @@
BeanFactory::addDefinitions($definitions);
BeanFactory::addAnnotations($annotations);
BeanFactory::addParsers($parsers);
-BeanFactory::init();
\ No newline at end of file
+BeanFactory::init();
diff --git a/src/bean/test/testing/Contract/TestInterface.php b/src/bean/test/testing/Contract/TestInterface.php
index 8aea766eb..bc5e2b1b7 100644
--- a/src/bean/test/testing/Contract/TestInterface.php
+++ b/src/bean/test/testing/Contract/TestInterface.php
@@ -13,5 +13,5 @@ interface TestInterface
/**
* @return string
*/
- public function getName():string ;
-}
\ No newline at end of file
+ public function getName(): string;
+}
diff --git a/src/bean/test/testing/Definition/CommaNameClass.php b/src/bean/test/testing/Definition/CommaNameClass.php
index ee7a4eaf6..8e9f6bdb8 100644
--- a/src/bean/test/testing/Definition/CommaNameClass.php
+++ b/src/bean/test/testing/Definition/CommaNameClass.php
@@ -1,9 +1,7 @@
manyInstance2;
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/InterfaceBean.php b/src/bean/test/testing/Definition/InterfaceBean.php
index 50aaae2bb..c5e4ca27f 100644
--- a/src/bean/test/testing/Definition/InterfaceBean.php
+++ b/src/bean/test/testing/Definition/InterfaceBean.php
@@ -1,6 +1,5 @@
pInterfaceThree->getName();
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/InterfaceBeanDefinition.php b/src/bean/test/testing/Definition/InterfaceBeanDefinition.php
index 631531b17..f93343176 100644
--- a/src/bean/test/testing/Definition/InterfaceBeanDefinition.php
+++ b/src/bean/test/testing/Definition/InterfaceBeanDefinition.php
@@ -1,9 +1,7 @@
pinterface->getName();
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/InterfaceOne.php b/src/bean/test/testing/Definition/InterfaceOne.php
index 52a6f25ec..4c04f69c5 100644
--- a/src/bean/test/testing/Definition/InterfaceOne.php
+++ b/src/bean/test/testing/Definition/InterfaceOne.php
@@ -1,9 +1,7 @@
definitionBeanClass;
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/RequestClass.php b/src/bean/test/testing/Definition/RequestClass.php
index f4bba416b..a6829ea82 100644
--- a/src/bean/test/testing/Definition/RequestClass.php
+++ b/src/bean/test/testing/Definition/RequestClass.php
@@ -1,9 +1,7 @@
definitionBeanClass;
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/SessionClass.php b/src/bean/test/testing/Definition/SessionClass.php
index 2878e3e9f..0b7925b66 100644
--- a/src/bean/test/testing/Definition/SessionClass.php
+++ b/src/bean/test/testing/Definition/SessionClass.php
@@ -1,9 +1,7 @@
definitionBeanClass;
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/SingletonClass.php b/src/bean/test/testing/Definition/SingletonClass.php
index ecf6f9beb..da802f748 100644
--- a/src/bean/test/testing/Definition/SingletonClass.php
+++ b/src/bean/test/testing/Definition/SingletonClass.php
@@ -1,9 +1,7 @@
definitionBeanClass;
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/Definition/TypeBean.php b/src/bean/test/testing/Definition/TypeBean.php
index 940da33c7..93c83ec89 100644
--- a/src/bean/test/testing/Definition/TypeBean.php
+++ b/src/bean/test/testing/Definition/TypeBean.php
@@ -1,6 +1,5 @@
arrayVar;
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/testing/bean.php b/src/bean/test/testing/bean.php
index 9a3a02608..0a42220d7 100644
--- a/src/bean/test/testing/bean.php
+++ b/src/bean/test/testing/bean.php
@@ -11,7 +11,7 @@
use SwoftTest\Bean\Testing\InjectBean;
return [
- 'singleton' => [
+ 'singleton' => [
'class' => SingletonClass::class,
'privateProp' => 'privateProp',
'publicProp' => 12,
@@ -26,7 +26,7 @@
'alias' => 'singleton-alias'
]
],
- 'prototype' => [
+ 'prototype' => [
'class' => PrototypeClass::class,
'privateProp' => 'privateProp',
'publicProp' => 12,
@@ -40,7 +40,7 @@
'alias' => 'prototype-alias'
]
],
- 'requestClass' => [
+ 'requestClass' => [
'class' => RequestClass::class,
'privateProp' => 'privateProp',
'publicProp' => 12,
@@ -54,7 +54,7 @@
'alias' => 'request-alias'
]
],
- 'sessionClass' => [
+ 'sessionClass' => [
'class' => SessionClass::class,
'privateProp' => 'privateProp',
'publicProp' => 12,
@@ -68,19 +68,19 @@
'alias' => 'session-alias'
]
],
- 'manyOneInstance' => [
+ 'manyOneInstance' => [
'class' => ManyInstance::class,
],
- 'manyTwoInstance' => [
+ 'manyTwoInstance' => [
'class' => ManyInstance::class,
],
- 'two.many' => [
+ 'two.many' => [
'class' => ManyInstance::class,
],
- 'commaNameClass' => [
+ 'commaNameClass' => [
'manyInstance2' => \bean('two.many')
],
- 'testTypeBean' => [
+ 'testTypeBean' => [
'stringVar' => 1,
'intVar' => '1',
'integerVar' => '2',
@@ -88,7 +88,7 @@
'doubleVar' => '1.2',
],
'interfaceBeanDefinition' => [
- 'class' => InterfaceBeanDefinition::class,
+ 'class' => InterfaceBeanDefinition::class,
'pinterface' => \bean(PrimaryInterface::class)
]
-];
\ No newline at end of file
+];
diff --git a/src/bean/test/unit/DefinitionTest.php b/src/bean/test/unit/DefinitionTest.php
index 08691a89c..3c89e2c2e 100644
--- a/src/bean/test/unit/DefinitionTest.php
+++ b/src/bean/test/unit/DefinitionTest.php
@@ -1,12 +1,11 @@
assertTrue($singletoClass instanceof SingletonClass);
+ /* @var SingletonClass $singletonClass */
+ $singletonClass = BeanFactory::getBean('singleton');
+ $this->assertInstanceOf(SingletonClass::class, $singletonClass);
- $this->beanCase($singletoClass);
+ $this->beanCase($singletonClass);
- /* @var SingletonClass $singletoClass */
- $singletoClass = BeanFactory::getSingleton('singleton');
- $this->assertTrue($singletoClass instanceof SingletonClass);
+ /* @var SingletonClass $singletonClass */
+ $singletonClass = BeanFactory::getSingleton('singleton');
+ $this->assertInstanceOf(SingletonClass::class, $singletonClass);
- $this->beanCase($singletoClass);
+ $this->beanCase($singletonClass);
$this->assertTrue(BeanFactory::hasBean('singleton'));
- /* @var SingletonClass $singletoClass */
- $singletoClass = BeanFactory::getBean('singleton-alias');
- $this->assertTrue($singletoClass instanceof SingletonClass);
+ /* @var SingletonClass $singletonClass */
+ $singletonClass = BeanFactory::getBean('singleton-alias');
+ $this->assertInstanceOf(SingletonClass::class, $singletonClass);
- $this->beanCase($singletoClass);
+ $this->beanCase($singletonClass);
- /* @var SingletonClass $singletoClass */
- $singletoClass = BeanFactory::getSingleton('singleton-alias');
- $this->assertTrue($singletoClass instanceof SingletonClass);
+ /* @var SingletonClass $singletonClass */
+ $singletonClass = BeanFactory::getSingleton('singleton-alias');
+ $this->assertInstanceOf(SingletonClass::class, $singletonClass);
- $this->beanCase($singletoClass);
+ $this->beanCase($singletonClass);
$this->assertTrue(BeanFactory::hasBean('singleton-alias'));
- /* @var SingletonClass $singletoClass */
- $singletoClass = BeanFactory::getBean(SingletonClass::class);
- $this->assertTrue($singletoClass instanceof SingletonClass);
+ /* @var SingletonClass $singletonClass */
+ $singletonClass = BeanFactory::getBean(SingletonClass::class);
+ $this->assertInstanceOf(SingletonClass::class, $singletonClass);
- $this->beanCase($singletoClass);
+ $this->beanCase($singletonClass);
- /* @var SingletonClass $singletoClass */
- $singletoClass = BeanFactory::getSingleton(SingletonClass::class);
- $this->assertTrue($singletoClass instanceof SingletonClass);
+ /* @var SingletonClass $singletonClass */
+ $singletonClass = BeanFactory::getSingleton(SingletonClass::class);
+ $this->assertInstanceOf(SingletonClass::class, $singletonClass);
$this->assertTrue(BeanFactory::hasBean(SingletonClass::class));
-
- $this->beanCase($singletoClass);
+ $this->beanCase($singletonClass);
}
- /**
- * @throws \ReflectionException
- * @throws \Swoft\Bean\Exception\ContainerException
- */
- public function testPrototype()
+ public function testPrototype(): void
{
/* @var SingletonClass $prototypeClass */
$prototypeClass = BeanFactory::getBean('prototype');
- $this->assertTrue($prototypeClass instanceof PrototypeClass);
+ $this->assertInstanceOf(PrototypeClass::class, $prototypeClass);
$this->beanCase($prototypeClass);
- /* @var SingletonClass $singletoClass */
+ /* @var SingletonClass $singletonClass */
$prototypeClass = BeanFactory::getBean('prototype-alias');
- $this->assertTrue($prototypeClass instanceof PrototypeClass);
+ $this->assertInstanceOf(PrototypeClass::class, $prototypeClass);
$this->beanCase($prototypeClass);
- /* @var SingletonClass $singletoClass */
+ /* @var SingletonClass $singletonClass */
$prototypeClass = BeanFactory::getBean(PrototypeClass::class);
- $this->assertTrue($prototypeClass instanceof PrototypeClass);
+ $this->assertInstanceOf(PrototypeClass::class, $prototypeClass);
$this->beanCase($prototypeClass);
}
- /**
- * @throws \ReflectionException
- * @throws \Swoft\Bean\Exception\ContainerException
- */
- public function testRequest()
+ public function testRequest(): void
{
- $id = uniqid();
+ $id = Str::uniqID();
/* @var RequestClass $requestClass */
$requestClass = BeanFactory::getRequestBean('requestClass', $id);
@@ -112,16 +98,12 @@ public function testRequest()
BeanFactory::destroyRequest($id);
- $this->assertTrue(empty(Container::getInstance()->getRequestPool()));
+ $this->assertEmpty(Container::getInstance()->getRequestPool());
}
- /**
- * @throws \ReflectionException
- * @throws \Swoft\Bean\Exception\ContainerException
- */
- public function testSession()
+ public function testSession(): void
{
- $id = uniqid();
+ $id = Str::uniqID();
/* @var SessionClass $sessionClass */
$sessionClass = BeanFactory::getSessionBean('sessionClass', $id);
@@ -137,46 +119,46 @@ public function testSession()
BeanFactory::destroySession($id);
- $this->assertTrue(empty(Container::getInstance()->getSessionPool()));
+ $this->assertEmpty(Container::getInstance()->getSessionPool());
}
/**
- * @param SingletonClass|PrototypeClass|RequestClass|SessionClass $singletoClass
+ * @param SingletonClass|PrototypeClass|RequestClass|SessionClass $singletonClass
*/
- private function beanCase($singletoClass)
+ private function beanCase($singletonClass): void
{
- $this->assertEquals($singletoClass->getClassPrivate(), 'classPrivate');
- $this->assertEquals($singletoClass->getClassPublic(), 12);
- $this->assertEquals($singletoClass->getPrivateProp(), 'privateProp');
- $this->assertEquals($singletoClass->getPublicProp(), 12);
- $this->assertEquals($singletoClass->getSetProp(), 'setProp-setter');
-
- $injectBean = $singletoClass->getInjectBean();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $this->assertEquals($singletonClass->getClassPrivate(), 'classPrivate');
+ $this->assertEquals($singletonClass->getClassPublic(), 12);
+ $this->assertEquals($singletonClass->getPrivateProp(), 'privateProp');
+ $this->assertEquals($singletonClass->getPublicProp(), 12);
+ $this->assertEquals($singletonClass->getSetProp(), 'setProp-setter');
+
+ $injectBean = $singletonClass->getInjectBean();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
- $injectBean = $singletoClass->getInjectBeanAlias();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $injectBean = $singletonClass->getInjectBeanAlias();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
- $injectBean = $singletoClass->getInjectBeanName();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $injectBean = $singletonClass->getInjectBeanName();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
- $injectBean = $singletoClass->getInjectBeanClass();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $injectBean = $singletonClass->getInjectBeanClass();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
- $injectBean = $singletoClass->getDefinitionBean();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $injectBean = $singletonClass->getDefinitionBean();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
- $injectBean = $singletoClass->getDefinitionBeanAlias();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $injectBean = $singletonClass->getDefinitionBeanAlias();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
- $injectBean = $singletoClass->getDefinitionBeanClass();
- $this->assertTrue($injectBean instanceof InjectBean);
+ $injectBean = $singletonClass->getDefinitionBeanClass();
+ $this->assertInstanceOf(InjectBean::class, $injectBean);
$this->assertEquals($injectBean->getData(), 'InjectBeanData-InjectChildBeanData');
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/unit/InterfaceTest.php b/src/bean/test/unit/InterfaceTest.php
index adbe5692b..cf8f9b5fd 100644
--- a/src/bean/test/unit/InterfaceTest.php
+++ b/src/bean/test/unit/InterfaceTest.php
@@ -1,20 +1,17 @@
getName3();
$this->assertEquals('InterfaceOne', $name3);
- $obj = BF::getBean(TestInterface::class);
- $this->assertInstanceOf(InterfaceOne::class, $obj);
+ $faceClass = TestInterface::class;
+
+ $beanName = InterfaceRegister::getInterfaceInjectBean($faceClass);
+ if ($beanName === 'interfaceOne') {
+ $wantClass = InterfaceOne::class;
+ $this->assertEquals($beanName, 'interfaceOne');
+ } else {
+ $wantClass = InterfaceTwo::class;
+ $this->assertEquals($beanName, 'interfaceTwo');
+ }
- $beanName = InterfaceRegister::getInterfaceInjectBean(TestInterface::class);
- $this->assertEquals($beanName, 'interfaceOne');
+ $obj = BF::getBean($faceClass);
+ $this->assertInstanceOf($wantClass, $obj);
- $obj = BF::getSingleton(TestInterface::class);
- $this->assertInstanceOf(InterfaceOne::class, $obj);
+ $obj = BF::getSingleton($faceClass);
+ $this->assertInstanceOf($wantClass, $obj);
}
- /**
- * @throws ReflectionException
- * @throws ContainerException
- */
public function testGetPname(): void
{
/* @var InterfaceBean $testInterface */
@@ -77,10 +74,6 @@ public function testGetPname(): void
$this->assertInstanceOf(PrimaryInterfaceTwo::class, $obj);
}
- /**
- * @throws ReflectionException
- * @throws ContainerException
- */
public function testGetPnameDefinition(): void
{
/* @var InterfaceBeanDefinition $testInterface */
@@ -98,4 +91,4 @@ public function testGetPnameDefinition(): void
$obj = BF::getSingleton(PrimaryInterfaceTwo::class);
$this->assertInstanceOf(PrimaryInterfaceTwo::class, $obj);
}
-}
\ No newline at end of file
+}
diff --git a/src/bean/test/unit/ManyBeanTest.php b/src/bean/test/unit/ManyBeanTest.php
index 637fecd30..c27f64001 100644
--- a/src/bean/test/unit/ManyBeanTest.php
+++ b/src/bean/test/unit/ManyBeanTest.php
@@ -1,9 +1,7 @@
gets(ManyInstance::class);
- $this->assertEquals(3, count($beans));
+ $this->assertCount(3, $beans);
foreach ($beans as $bean) {
- $this->assertTrue($bean instanceof ManyInstance);
+ $this->assertInstanceOf(ManyInstance::class, $bean);
}
$beans = BeanFactory::getBeans(ManyInstance::class);
- $this->assertEquals(3, count($beans));
+ $this->assertCount(3, $beans);
foreach ($beans as $bean) {
- $this->assertTrue($bean instanceof ManyInstance);
+ $this->assertInstanceOf(ManyInstance::class, $bean);
}
- /* @var CommaNameClass $comma*/
+ /* @var CommaNameClass $comma */
$comma = BeanFactory::getBean(CommaNameClass::class);
$two = $comma->getManyInstance2();
- $this->assertTrue($two instanceof ManyInstance);
+ $this->assertInstanceOf(ManyInstance::class, $two);
}
-}
\ No newline at end of file
+}
diff --git a/src/config/composer.json b/src/config/composer.json
index 52231e1c7..67049deb1 100644
--- a/src/config/composer.json
+++ b/src/config/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/config",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/connection-pool/composer.json b/src/connection-pool/composer.json
index 2d8439155..09a6ef2b1 100644
--- a/src/connection-pool/composer.json
+++ b/src/connection-pool/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/connection-pool",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/connection-pool/src/AbstractPool.php b/src/connection-pool/src/AbstractPool.php
index adf894e3e..91d55a0f6 100644
--- a/src/connection-pool/src/AbstractPool.php
+++ b/src/connection-pool/src/AbstractPool.php
@@ -274,6 +274,10 @@ private function popByChannel(): ?ConnectionInterface
// Out of `maxIdleTime`
if ($time - $lastTime > $this->maxIdleTime) {
+
+ // Fix expired connection not released
+ $connection->close();
+
$this->count--;
continue;
}
@@ -289,7 +293,7 @@ private function popByChannel(): ?ConnectionInterface
*
* @param ConnectionInterface $connection
*/
- private function releaseToChannel(ConnectionInterface $connection)
+ private function releaseToChannel(ConnectionInterface $connection): void
{
$stats = $this->channel->stats();
if ($stats['queue_num'] < $this->maxActive) {
diff --git a/src/console/composer.json b/src/console/composer.json
index 2471c7380..4cb40067c 100644
--- a/src/console/composer.json
+++ b/src/console/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/console",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/console/src/Advanced/Formatter/Padding.php b/src/console/src/Advanced/Formatter/Padding.php
index 6bf38d01b..c0a940881 100644
--- a/src/console/src/Advanced/Formatter/Padding.php
+++ b/src/console/src/Advanced/Formatter/Padding.php
@@ -5,15 +5,14 @@
use Swoft\Console\Advanced\MessageFormatter;
use Swoft\Console\Console;
use Swoft\Stdlib\Helper\Arr;
+use Swoft\Stdlib\Helper\Str;
use Toolkit\Cli\ColorTag;
use function array_merge;
-use function str_pad;
use function trim;
use function ucfirst;
/**
* Class Padding
- * @package Swoft\Console\Advanced\Formatter
*/
class Padding extends MessageFormatter
{
@@ -49,7 +48,7 @@ public static function show(array $data, string $title = '', array $opts = []):
foreach ($data as $label => $value) {
$value = ColorTag::wrap((string)$value, $opts['valueStyle']);
- $string .= $opts['indent'] . str_pad($label, $paddingLen, $opts['char']) . " $value\n";
+ $string .= $opts['indent'] . Str::pad($label, $paddingLen, $opts['char']) . " $value\n";
}
Console::write(trim($string));
diff --git a/src/console/src/Advanced/Formatter/Panel.php b/src/console/src/Advanced/Formatter/Panel.php
index 52f59cb80..9f34645fd 100644
--- a/src/console/src/Advanced/Formatter/Panel.php
+++ b/src/console/src/Advanced/Formatter/Panel.php
@@ -5,6 +5,7 @@
use Swoft\Console\Advanced\MessageFormatter;
use Swoft\Console\Console;
use Swoft\Console\Helper\FormatUtil;
+use Swoft\Stdlib\Helper\Str;
use Swoft\Stdlib\StrBuffer;
use function array_filter;
use function array_merge;
@@ -12,9 +13,7 @@
use function is_array;
use function is_bool;
use function is_numeric;
-use function mb_strlen;
use function rtrim;
-use function str_pad;
use function strip_tags;
use function trim;
use function ucwords;
@@ -111,7 +110,7 @@ public static function show($data, string $title = 'Information Panel', array $o
foreach ($data as $label => $value) {
// label exists
if (!is_numeric($label)) {
- $width = mb_strlen($label, 'UTF-8');
+ $width = Str::len($label, 'UTF-8');
// save max value
$labelMaxWidth = $width > $labelMaxWidth ? $width : $labelMaxWidth;
}
@@ -141,7 +140,7 @@ public static function show($data, string $title = 'Information Panel', array $o
// get value width
/** @var string $value */
$value = trim($value);
- $width = mb_strlen(strip_tags($value), 'UTF-8'); // must clear style tag
+ $width = Str::len(strip_tags($value), 'UTF-8'); // must clear style tag
$valueMaxWidth = $width > $valueMaxWidth ? $width : $valueMaxWidth;
$panelData[$label] = $value;
@@ -159,16 +158,16 @@ public static function show($data, string $title = 'Information Panel', array $o
if ($title) {
$title = ucwords($title);
$titleStyle = $opts['titleStyle'] ?: 'bold';
- $titleLength = mb_strlen($title, 'UTF-8');
+ $titleLength = Str::len($title, 'UTF-8');
$panelWidth = $panelWidth > $titleLength ? $panelWidth : $titleLength;
$lenValue = (int)(ceil($panelWidth / 2) - ceil($titleLength / 2));
- $indentSpace = str_pad(' ', $lenValue + 2 * 2, ' ');
+ $indentSpace = Str::pad(' ', $lenValue + 2 * 2, ' ');
Console::write("$leftIndent{$indentSpace}<{$titleStyle}>{$title}{$titleStyle}>");
}
// output panel top border
if ($borderChar) {
- $border = str_pad($borderChar, $panelWidth + (3 * 4), $borderChar);
+ $border = Str::pad($borderChar, $panelWidth + (3 * 4), $borderChar);
Console::write($leftIndent . $border);
}
@@ -211,7 +210,7 @@ public function format(): string
foreach ($data as $label => $value) {
// label exists
if (!is_numeric($label)) {
- $width = mb_strlen($label, 'UTF-8');
+ $width = Str::len($label, 'UTF-8');
$labelMaxWidth = $width > $labelMaxWidth ? $width : $labelMaxWidth;
}
@@ -240,7 +239,7 @@ public function format(): string
// get value width
/** @var string $value */
$value = trim($value);
- $width = mb_strlen(strip_tags($value), 'UTF-8'); // must clear style tag
+ $width = Str::len(strip_tags($value), 'UTF-8'); // must clear style tag
$valueMaxWidth = $width > $valueMaxWidth ? $width : $valueMaxWidth;
$panelData[$label] = $value;
@@ -251,15 +250,15 @@ public function format(): string
// output title
if ($title) {
$title = ucwords($title);
- $titleLength = mb_strlen($title, 'UTF-8');
+ $titleLength = Str::len($title, 'UTF-8');
$panelWidth = $panelWidth > $titleLength ? $panelWidth : $titleLength;
- $indentSpace = str_pad(' ', ceil($panelWidth / 2) - ceil($titleLength / 2) + 2 * 2, ' ');
+ $indentSpace = Str::pad(' ', ceil($panelWidth / 2) - ceil($titleLength / 2) + 2 * 2, ' ');
$buffer->write(" {$indentSpace}{$title}\n");
}
// output panel top border
if ($topBorder = $this->titleBorder) {
- $border = str_pad($topBorder, $panelWidth + (3 * 3), $topBorder);
+ $border = Str::pad($topBorder, $panelWidth + (3 * 3), $topBorder);
$buffer->write(' ' . $border . PHP_EOL);
}
@@ -276,7 +275,7 @@ public function format(): string
// output panel bottom border
if ($footBorder = $this->footerBorder) {
- $border = str_pad($footBorder, $panelWidth + (3 * 3), $footBorder);
+ $border = Str::pad($footBorder, $panelWidth + (3 * 3), $footBorder);
$buffer->write(' ' . $border . PHP_EOL);
}
diff --git a/src/console/src/Advanced/Formatter/Section.php b/src/console/src/Advanced/Formatter/Section.php
index ef9e8998b..2577befef 100644
--- a/src/console/src/Advanced/Formatter/Section.php
+++ b/src/console/src/Advanced/Formatter/Section.php
@@ -10,7 +10,6 @@
use function ceil;
use function implode;
use function is_array;
-use function str_pad;
use function trim;
use function ucwords;
use const PHP_EOL;
@@ -51,9 +50,9 @@ public static function show(string $title, $body, array $opts = []): void
if ($tLength >= $width) {
$titleIndent = Str::pad(self::CHAR_SPACE, $indent, self::CHAR_SPACE);
} elseif ($opts['titlePos'] === self::POS_RIGHT) {
- $titleIndent = str_pad(self::CHAR_SPACE, ceil($width - $tLength) + $indent, self::CHAR_SPACE);
+ $titleIndent = Str::pad(self::CHAR_SPACE, ceil($width - $tLength) + $indent, self::CHAR_SPACE);
} elseif ($opts['titlePos'] === self::POS_MIDDLE) {
- $titleIndent = str_pad(self::CHAR_SPACE, ceil(($width - $tLength) / 2) + $indent, self::CHAR_SPACE);
+ $titleIndent = Str::pad(self::CHAR_SPACE, ceil(($width - $tLength) / 2) + $indent, self::CHAR_SPACE);
} else {
$titleIndent = Str::pad(self::CHAR_SPACE, $indent, self::CHAR_SPACE);
}
@@ -66,7 +65,7 @@ public static function show(string $title, $body, array $opts = []): void
$showBBorder = (bool)$opts['bottomBorder'];
if ($showTBorder || $showBBorder) {
- $border = str_pad($char, $width, $char);
+ $border = Str::pad($char, $width, $char);
if ($showTBorder) {
$topBorder = "{$indentStr}$border\n";
diff --git a/src/console/src/Advanced/Formatter/Table.php b/src/console/src/Advanced/Formatter/Table.php
index bb969430b..b2b0524b9 100644
--- a/src/console/src/Advanced/Formatter/Table.php
+++ b/src/console/src/Advanced/Formatter/Table.php
@@ -4,6 +4,7 @@
use Swoft\Console\Advanced\MessageFormatter;
use Swoft\Console\Helper\Show;
+use Swoft\Stdlib\Helper\Str;
use Swoft\Stdlib\StrBuffer;
use Toolkit\Cli\ColorTag;
use function array_keys;
@@ -12,8 +13,6 @@
use function ceil;
use function count;
use function is_string;
-use function mb_strlen;
-use function str_pad;
use function ucwords;
/**
@@ -123,7 +122,7 @@ public static function show(array $data, string $title = 'Data Table', array $op
$hasHead = true;
}
- $info['columnMaxWidth'][$index] = mb_strlen((string)$name, 'UTF-8');
+ $info['columnMaxWidth'][$index] = Str::len($name, 'UTF-8');
}
}
@@ -132,14 +131,14 @@ public static function show(array $data, string $title = 'Data Table', array $op
foreach ((array)$row as $value) {
// collection column max width
if (isset($info['columnMaxWidth'][$colIndex])) {
- $colWidth = mb_strlen((string)$value, 'UTF-8');
+ $colWidth = Str::len($value, 'UTF-8');
// If current column width gt old column width. override old width.
if ($colWidth > $info['columnMaxWidth'][$colIndex]) {
$info['columnMaxWidth'][$colIndex] = $colWidth;
}
} else {
- $info['columnMaxWidth'][$colIndex] = mb_strlen((string)$value, 'UTF-8');
+ $info['columnMaxWidth'][$colIndex] = Str::len((string)$value, 'UTF-8');
}
$colIndex++;
@@ -155,13 +154,13 @@ public static function show(array $data, string $title = 'Data Table', array $op
if ($title) {
$tStyle = $opts['titleStyle'] ?: 'bold';
$title = ucwords(trim($title));
- $titleLength = mb_strlen($title, 'UTF-8');
+ $titleLength = Str::len($title, 'UTF-8');
$padLength = ceil($tableWidth / 2) - ceil($titleLength / 2) + ($columnCount * 2);
- $indentSpace = str_pad(' ', (int)$padLength, ' ');
+ $indentSpace = Str::pad(' ', (int)$padLength, ' ');
$buf->write(" {$indentSpace}<$tStyle>{$title}$tStyle>\n");
}
- $border = $leftIndent . str_pad($rowBorderChar, $tableWidth + ($columnCount * 3) + 2, $rowBorderChar);
+ $border = $leftIndent . Str::pad($rowBorderChar, $tableWidth + ($columnCount * 3) + 2, $rowBorderChar);
// output table top border
if ($showBorder) {
@@ -177,7 +176,7 @@ public static function show(array $data, string $title = 'Data Table', array $op
foreach ($head as $index => $name) {
$colMaxWidth = $info['columnMaxWidth'][$index];
// format
- $name = str_pad($name, $colMaxWidth, ' ');
+ $name = Str::pad($name, $colMaxWidth, ' ');
$name = ColorTag::wrap($name, $opts['headStyle']);
$headStr .= " {$name} {$colBorderChar}";
}
@@ -186,9 +185,9 @@ public static function show(array $data, string $title = 'Data Table', array $op
// head border: split head and body
if ($headBorderChar = $opts['headBorderChar']) {
- $headBorder = $leftIndent . str_pad($headBorderChar, $tableWidth + ($columnCount * 3) + 2,
- $headBorderChar);
- $buf->write($headBorder . "\n");
+ $headPadLen = $tableWidth + ($columnCount * 3) + 2;
+ $headBorder = Str::pad($headBorderChar, $headPadLen, $headBorderChar);
+ $buf->write($leftIndent . $headBorder . "\n");
}
}
@@ -202,7 +201,7 @@ public static function show(array $data, string $title = 'Data Table', array $op
foreach ((array)$row as $value) {
$colMaxWidth = $info['columnMaxWidth'][$colIndex];
// format
- $value = str_pad((string)$value, $colMaxWidth, ' ');
+ $value = Str::pad((string)$value, $colMaxWidth, ' ');
$value = ColorTag::wrap($value, $opts['bodyStyle']);
$rowStr .= " {$value} {$colBorderChar}";
$colIndex++;
diff --git a/src/console/src/Advanced/Formatter/Title.php b/src/console/src/Advanced/Formatter/Title.php
index e44fdcb71..f9ea7084a 100644
--- a/src/console/src/Advanced/Formatter/Title.php
+++ b/src/console/src/Advanced/Formatter/Title.php
@@ -8,11 +8,9 @@
use Swoft\Stdlib\Helper\Sys;
use function array_merge;
use function ceil;
-use function str_pad;
/**
* Class Title
- * @package Swoft\Console\Advanced\Formatter
*/
class Title extends MessageFormatter
{
@@ -60,7 +58,7 @@ public static function show(string $title, array $opts = []): void
}
$titleLine = "$titleIndent$title\n";
- $borderLine = $bdIndent . str_pad($char, $width, $char);
+ $borderLine = $bdIndent . Str::pad($char, $width, $char);
Console::write($titleLine . $borderLine);
}
diff --git a/src/console/src/Advanced/Formatter/Tree.php b/src/console/src/Advanced/Formatter/Tree.php
index e18f02e9e..6fedea502 100644
--- a/src/console/src/Advanced/Formatter/Tree.php
+++ b/src/console/src/Advanced/Formatter/Tree.php
@@ -5,11 +5,11 @@
use Swoft\Console\Advanced\MessageFormatter;
use Swoft\Console\Console;
use Swoft\Console\Helper\FormatUtil;
+use Swoft\Stdlib\Helper\Str;
use Toolkit\Cli\Cli;
use function array_merge;
use function is_array;
use function is_scalar;
-use function str_pad;
/**
* Class Tree
@@ -53,7 +53,7 @@ public static function show(array $data, array $opts = []): void
foreach ($data as $key => $value) {
if (is_scalar($value)) {
$counter++;
- $leftString = $opts['leftPadding'] . str_pad($opts['prefix'], $opts['_level'] + 1, $opts['char']);
+ $leftString = $opts['leftPadding'] . Str::pad($opts['prefix'], $opts['_level'] + 1, $opts['char']);
Console::write($leftString . ' ' . FormatUtil::typeToString($value));
} elseif (is_array($value)) {
diff --git a/src/console/src/Advanced/PharCompiler.php b/src/console/src/Advanced/PharCompiler.php
index 863d424f7..b502a44c3 100644
--- a/src/console/src/Advanced/PharCompiler.php
+++ b/src/console/src/Advanced/PharCompiler.php
@@ -14,6 +14,7 @@
use RuntimeException;
use Seld\PharUtils\Timestamps;
use SplFileInfo;
+use SplQueue;
use Swoft\Stdlib\Helper\Dir;
use Swoft\Stdlib\Helper\FSHelper;
use Swoft\Stdlib\Helper\Sys;
@@ -33,8 +34,6 @@
use function is_file;
use function is_string;
use function ltrim;
-use function openssl_pkey_export;
-use function openssl_pkey_get_details;
use function preg_replace;
use function realpath;
use function str_replace;
@@ -62,6 +61,9 @@ class PharCompiler
public const ON_SKIP = 'skip';
public const ON_ERROR = 'error';
+ public const ON_MESSAGE = 'message';
+ public const ON_COLLECTED = 'collected';
+
/** @var array */
private static $supportedSignatureTypes = [
Phar::SHA512 => 1,
@@ -172,6 +174,8 @@ class PharCompiler
*/
private $versionFile = '';
+ private $versionFileContent = '';
+
// -------------------- internal properties --------------------
/** @var int */
@@ -197,6 +201,11 @@ class PharCompiler
*/
private $modifies;
+ /**
+ * @var SplQueue
+ */
+ private $fileQueue;
+
/**
* @param string $pharFile
* @param string $extractTo
@@ -240,7 +249,8 @@ public function __construct(string $basePath)
{
self::checkEnv();
- $this->basePath = realpath($basePath);
+ $this->basePath = realpath($basePath);
+ $this->fileQueue = new SplQueue();
if (!is_dir($this->basePath)) {
throw new RuntimeException("The inputted path is not exists. PATH: {$this->basePath}");
@@ -399,7 +409,7 @@ public function setModifies($modifies): self
* @throws InvalidArgumentException
* @throws Exception
*/
- public function pack(string $pharFile, $refresh = true): string
+ public function pack(string $pharFile, bool $refresh = true): string
{
if (!$this->directories) {
throw new RuntimeException("Please setting the 'directories' want building directories by 'in()'");
@@ -430,36 +440,25 @@ public function pack(string $pharFile, $refresh = true): string
$phar->setSignatureAlgorithm($this->selectSignatureType());
}
- $basePath = $this->basePath;
- $phar->startBuffering();
+ // Collect files
+ $this->collectFiles($exists, $refresh);
- // Only build modifies
- if (!$refresh && $exists && $this->modifies) {
- foreach ($this->modifies as $file) {
- if ('/' === $file[0] || is_file($file = $basePath . '/' . $file)) {
- $this->packFile($phar, new SplFileInfo($file));
- }
- }
- } else {
- // Collect files in there are dirs.
- foreach ($this->directories as $directory) {
- foreach ($this->findFiles($directory) as $file) {
- $this->packFile($phar, $file);
- }
- }
- }
+ // Begin packing
+ $this->fire(self::ON_COLLECTED, $this->counter);
+ $phar->startBuffering();
- // Add special files
- foreach ($this->files as $filename) {
- if ('/' === $filename[0] || is_file($filename = $basePath . '/' . $filename)) {
- $this->packFile($phar, new SplFileInfo($filename));
- }
- }
+ $this->fire(self::ON_MESSAGE, 'Files collect complete, begin add file to Phar');
+ $phar->buildFromIterator($this->fileQueue, $this->basePath);
// Add index files
$this->packIndexFile($phar);
- // Stubs
+ // Add version file
+ if ($content = $this->versionFileContent) {
+ $phar->addFromString($this->versionFile, $content);
+ }
+
+ // Add Stubs
// $phar->setDefaultStub($this->cliIndex, $this->webIndex));
$phar->setStub($this->createStub());
@@ -477,6 +476,7 @@ public function pack(string $pharFile, $refresh = true): string
// 'Date' => date('Y-m-d')
// );
// $phar->setMetadata($metaData);
+ $this->fire(self::ON_MESSAGE, 'Write requests to the Phar archive, save changes to disk');
$phar->stopBuffering();
unset($phar);
@@ -490,6 +490,68 @@ public function pack(string $pharFile, $refresh = true): string
return $pharFile;
}
+ /**
+ * @param bool $exists
+ * @param bool $refresh
+ */
+ protected function collectFiles(bool $exists, bool $refresh): void
+ {
+ $basePath = $this->basePath;
+
+ // Only build modifies
+ if (!$refresh && $exists && $this->modifies) {
+ foreach ($this->modifies as $file) {
+ if ('/' === $file[0] || is_file($file = $basePath . '/' . $file)) {
+ $this->collectFileInfo(new SplFileInfo($file));
+ }
+ }
+ } else {
+ // Collect files in there are dirs.
+ foreach ($this->directories as $directory) {
+ foreach ($this->findFiles($directory) as $fileInfo) {
+ $this->collectFileInfo($fileInfo);
+ }
+ }
+ }
+
+ // Add special files
+ foreach ($this->files as $filename) {
+ if ('/' === $filename[0] || is_file($filename = $basePath . '/' . $filename)) {
+ // $this->packFile($phar, new SplFileInfo($filename));
+ $this->collectFileInfo(new SplFileInfo($filename));
+ }
+ }
+ }
+
+ /**
+ * @param SplFileInfo $file
+ */
+ protected function collectFileInfo(SplFileInfo $file): void
+ {
+ $filePath = $file->getPathname();
+
+ // Skip not exist file
+ if (!file_exists($filePath)) {
+ $this->fire(self::ON_ERROR, "File $filePath is not exists!");
+ return;
+ }
+
+ $this->counter++;
+ $relativePath = $this->getRelativeFilePath($file);
+
+ $this->fire(self::ON_ADD, $relativePath, $this->counter);
+
+ // have version file
+ if ($relativePath === $this->versionFile) {
+ $content = file_get_contents($filePath);
+ // save content
+ $this->versionFileContent = $this->addVersionInfo($content);
+ return;
+ }
+
+ $this->fileQueue->push($file);
+ }
+
/**
* find changed or new created files by git status.
* @throws RuntimeException
@@ -537,56 +599,16 @@ protected function findFiles(string $directory)
}
/**
- * Add a file to the Phar.
- * @param Phar $phar
- * @param SplFileInfo $file
+ * @param string $content
+ *
+ * @return string
*/
- private function packFile(Phar $phar, SplFileInfo $file): void
+ private function addVersionInfo(string $content): string
{
- $filePath = $file->getPathname();
-
- // skip error
- if (!file_exists($filePath)) {
- $this->fire(self::ON_ERROR, "File $filePath is not exists!");
- return;
- }
-
- $strip = $this->stripComments;
- $path = $this->getRelativeFilePath($file);
-
- $this->counter++;
- $this->fire(self::ON_ADD, $path, $this->counter);
-
- // clear php file comments
- if ($strip && strpos($path, '.php')) {
- $filter = $this->stripFilter;
-
- if (!$filter || $filter($file)) {
- $content = $this->stripWhitespace(file_get_contents($filePath));
-
- // add content to phar
- $phar->addFromString(
- $path,
- $this->addVersionInfo($content) . "\n// added by phar pack"
- );
- return;
- }
- }
-
- // have versionFile
- if ($path === $this->versionFile) {
- $content = file_get_contents($filePath);
-
- $phar->addFromString($path, $this->addVersionInfo($content));
- return;
+ if (!$this->collectVersionInfo) {
+ return $content;
}
- // add file to phar
- $phar->addFile($filePath, $path);
- }
-
- private function addVersionInfo(string $content): string
- {
return str_replace([
'{@package_last_commit}',
'{@package_last_version}',
@@ -1008,4 +1030,12 @@ public function getPharFile(): string
{
return $this->pharFile;
}
+
+ /**
+ * @return int
+ */
+ public function getFileCount(): int
+ {
+ return $this->fileQueue->count();
+ }
}
diff --git a/src/console/src/Advanced/Progress/SimpleBar.php b/src/console/src/Advanced/Progress/SimpleBar.php
index bb0b57573..37074c879 100644
--- a/src/console/src/Advanced/Progress/SimpleBar.php
+++ b/src/console/src/Advanced/Progress/SimpleBar.php
@@ -11,7 +11,6 @@
/**
* Class SimpleBar
- * @package Swoft\Console\Advanced\Progress
*/
class SimpleBar extends NotifyMessage
{
@@ -51,8 +50,8 @@ public static function gen(int $total, array $opts = []): Generator
'msg' => '',
'doneMsg' => '',
], $opts);
- $msg = Console::style()->render($opts['msg']);
+ $waitMsg = Console::style()->render($opts['msg']);
$doneMsg = Console::style()->render($opts['doneMsg']);
$waitChar = $opts['waitChar'];
@@ -68,10 +67,10 @@ public static function gen(int $total, array $opts = []): Generator
}
$current += $step;
- $percent = ceil(($current / $total) * 100);
+ $percent = (int)ceil(($current / $total) * 100);
if ($percent >= 100) {
- $msg = $doneMsg ?: $msg;
+ $waitMsg = $doneMsg ?: $waitMsg;
$percent = 100;
$finished = true;
}
@@ -86,7 +85,7 @@ public static function gen(int $total, array $opts = []): Generator
printf("{$tplPrefix}[%'{$waitChar}-100s] %' 3d%% %s",
str_repeat($opts['doneChar'], $percent) . ($finished ? '' : $opts['signChar']),
$percent,
- $msg
+ $waitMsg
);// ♥ ■ ☺ ☻ = #
if ($finished) {
diff --git a/src/console/src/Advanced/Progress/SimpleTextBar.php b/src/console/src/Advanced/Progress/SimpleTextBar.php
index 36b775f08..9dfeee79c 100644
--- a/src/console/src/Advanced/Progress/SimpleTextBar.php
+++ b/src/console/src/Advanced/Progress/SimpleTextBar.php
@@ -9,23 +9,24 @@
/**
* Class SimpleTextBar
- * @package Swoft\Console\Advanced\Progress
*/
class SimpleTextBar extends NotifyMessage
{
/**
* Render a simple text progress bar by 'yield'
+ *
* @param int $total
- * @param string $msg
+ * @param string $waitMsg
* @param string $doneMsg
+ *
* @return Generator
*/
- public static function gen(int $total, string $msg, string $doneMsg = ''): Generator
+ public static function gen(int $total, string $waitMsg, string $doneMsg = ''): Generator
{
$current = 0;
$finished = false;
$tpl = (Cli::isSupportColor() ? "\x0D\x1B[2K" : "\x0D\r") . "%' 3d%% %s";
- $msg = Console::style()->render($msg);
+ $waitMsg = Console::style()->render($waitMsg);
$doneMsg = $doneMsg ? Console::style()->render($doneMsg) : '';
while (true) {
@@ -45,13 +46,13 @@ public static function gen(int $total, string $msg, string $doneMsg = ''): Gener
if ($percent >= 100) {
$percent = 100;
$finished = true;
- $msg = $doneMsg ?: $msg;
+ $waitMsg = $doneMsg ?: $waitMsg;
}
// printf("\r%d%% %s", $percent, $msg);
// printf("\x0D\x2K %d%% %s", $percent, $msg);
// printf("\x0D\r%'2d%% %s", $percent, $msg);
- printf($tpl, $percent, $msg);
+ printf($tpl, $percent, $waitMsg);
if ($finished) {
echo "\n";
diff --git a/src/console/src/Annotation/Parser/CommandArgumentParser.php b/src/console/src/Annotation/Parser/CommandArgumentParser.php
index 17661fc4a..f98518c26 100644
--- a/src/console/src/Annotation/Parser/CommandArgumentParser.php
+++ b/src/console/src/Annotation/Parser/CommandArgumentParser.php
@@ -7,6 +7,7 @@
use Swoft\Annotation\Exception\AnnotationException;
use Swoft\Console\Annotation\Mapping\CommandArgument;
use Swoft\Console\CommandRegister;
+use Swoft\Console\FlagType;
use Toolkit\Cli\Flags;
/**
@@ -44,8 +45,8 @@ public function parse(int $type, $annotation): array
'name' => $annotation->getName(),
'desc' => $annotation->getDesc(),
'mode' => $annotation->getMode(),
- 'type' => $annotation->getType(),
- 'default' => $valType === 'BOOL' ? Flags::filterBool($defVal) : $defVal,
+ 'type' => $valType,
+ 'default' => $valType === FlagType::BOOL ? Flags::filterBool($defVal) : $defVal,
]);
return [];
diff --git a/src/console/src/Annotation/Parser/CommandOptionParser.php b/src/console/src/Annotation/Parser/CommandOptionParser.php
index e6c081901..2ed3cdcb0 100644
--- a/src/console/src/Annotation/Parser/CommandOptionParser.php
+++ b/src/console/src/Annotation/Parser/CommandOptionParser.php
@@ -7,6 +7,7 @@
use Swoft\Annotation\Exception\AnnotationException;
use Swoft\Console\Annotation\Mapping\CommandOption;
use Swoft\Console\CommandRegister;
+use Swoft\Console\FlagType;
use Toolkit\Cli\Flags;
/**
@@ -20,8 +21,8 @@ class CommandOptionParser extends Parser
/**
* Parse object
*
- * @param int $type Class or Method or Property
- * @param CommandOption $annotation Annotation object
+ * @param int $type Class or Method or Property
+ * @param CommandOption $option Annotation object
*
* @return array
* Return empty array is nothing to do!
@@ -29,25 +30,29 @@ class CommandOptionParser extends Parser
* When property type return [$propertyValue, $isRef] is to reference value
* @throws AnnotationException
*/
- public function parse(int $type, $annotation): array
+ public function parse(int $type, $option): array
{
if ($type === self::TYPE_PROPERTY) {
throw new AnnotationException('`@CommandOption` must be defined on class or method!');
}
$method = $this->methodName;
- $valType = $annotation->getType();
- $defVal = $annotation->getDefault();
+ $defVal = $option->getDefault();
+ $valType = $option->getType();
+
+ // if ($valType === 'BOOL') {
+ // $defVal = Flags::filterBool($defVal);
+ // }
// Add route info for group command action
- CommandRegister::bindOption($this->className, $method, $annotation->getName(), [
+ CommandRegister::bindOption($this->className, $method, $option->getName(), [
'method' => $method,
- 'name' => $annotation->getName(),
- 'short' => $annotation->getShort(),
- 'desc' => $annotation->getDesc(),
- 'mode' => $annotation->getMode(),
- 'type' => $annotation->getType(),
- 'default' => $valType === 'BOOL' ? Flags::filterBool($defVal) : $defVal,
+ 'name' => $option->getName(),
+ 'short' => $option->getShort(),
+ 'desc' => $option->getDesc(),
+ 'mode' => $option->getMode(),
+ 'type' => $valType,
+ 'default' => $valType === FlagType::BOOL ? Flags::filterBool($defVal) : $defVal,
]);
return [];
diff --git a/src/console/src/Application.php b/src/console/src/Application.php
index 4f6d47668..bd9421512 100644
--- a/src/console/src/Application.php
+++ b/src/console/src/Application.php
@@ -5,10 +5,8 @@
use Swoft;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\BeanFactory;
-use Swoft\Console\Annotation\Mapping\Command;
use Swoft\Console\Concern\RenderHelpInfoTrait;
use Swoft\Console\Contract\ConsoleInterface;
-use Swoft\Console\Exception\CommandFlagException;
use Swoft\Console\Input\Input;
use Swoft\Console\Output\Output;
use Swoft\Console\Router\Router;
@@ -18,8 +16,6 @@
use Throwable;
use function array_merge;
use function implode;
-use function input;
-use function output;
use function strpos;
use function strtr;
use function trim;
@@ -44,8 +40,8 @@ class Application implements ConsoleInterface
'--debug' => 'Setting the application runtime debug level(0 - 4)',
// '--profile' => 'Display timing and memory usage information',
'--no-color' => 'Disable color/ANSI for message output',
- '-h, --help' => 'Display this help message',
- '-V, --version' => 'Show application version information',
+ '-h, --help' => 'Display help message for application or command',
+ '-V, --version' => 'Display application version information',
];
/**
@@ -113,6 +109,7 @@ public function commentsVars(): array
'workDir' => $this->input->getPwd(),
'script' => $script, // bin/app
'binFile' => $script,
+ 'binName' => $this->input->getScriptName(),
'command' => $this->input->getCommand(), // demo OR home:test
'fullCmd' => $fullCmd,
'fullCommand' => $fullCmd,
@@ -121,8 +118,8 @@ public function commentsVars(): array
protected function prepare(): void
{
- $this->input = input();
- $this->output = output();
+ $this->input = Swoft::getBean('input');
+ $this->output = Swoft::getBean('output');
// load builtin comments vars
$this->setCommentsVars($this->commentsVars());
@@ -183,11 +180,18 @@ protected function doRun(string $inputCmd): void
return;
}
- $info = $result[1];
+ $info = $result[1];
+ $group = $info['group'];
+ $this->addCommentsVar('groupName', $group);
// Only input a group name, display help for the group
if ($result[0] === Router::ONLY_GROUP) {
- $this->showGroupHelp($info['group']);
+ // Has error command
+ if ($cmd = $info['cmd']) {
+ $output->error("Command '{$cmd}' is not exist in group: {$group}");
+ }
+
+ $this->showGroupHelp($group);
return;
}
@@ -198,7 +202,7 @@ protected function doRun(string $inputCmd): void
}
// Parse default options and arguments
- $this->bindCommandFlags($info);
+ $this->input->parseFlags($info, true);
$this->input->setCommandId($info['cmdId']);
Swoft::triggerByArray(ConsoleEvent::DISPATCH_BEFORE, $this, $info);
@@ -228,75 +232,6 @@ private function filterSpecialOption(): void
$this->showApplicationHelp(false);
}
- /**
- * Bind option and argument values by route info
- *
- * @param array $info
- *
- * @throws CommandFlagException
- */
- protected function bindCommandFlags(array $info): void
- {
- // Bind options
- if ($opts = $info['options']) {
- $sOpts = $this->input->getSOpts();
- $lOpts = $this->input->getLOpts();
-
- foreach ($opts as $name => $opt) {
- $inputVal = $this->input->getLongOpt($name);
-
- // Exist short
- if (null === $inputVal && $opt['short']) {
- $inputVal = $this->input->getShortOpt($opt['short']);
- }
-
- // Exist default value
- if (null === $inputVal && isset($opt['default'])) {
- $inputVal = $opt['default'];
- }
-
- if (null !== $inputVal) {
- $sOpts[$name] = $lOpts[$name] = $inputVal;
-
- // Required check
- } elseif ($opt['mode'] === Command::OPT_REQUIRED) {
- $short = $opt['short'] ? "(short: {$opt['short']})" : '';
- throw new CommandFlagException("The option '{$name}'{$short} is required");
- }
- }
-
- // Save to input
- $this->input->setLOpts($lOpts, true);
- $this->input->setSOpts($sOpts, true);
- }
-
- // Bind named argument by index
- if ($args = $info['arguments']) {
- $index = 0;
- $values = $this->input->getArgs();
-
- foreach ($args as $name => $arg) {
- // Bind value to name
- if (isset($values[$index])) {
- $values[$name] = $values[$index];
- // Bind default value
- } elseif (isset($arg['default'])) {
- $values[$name] = $arg['default'];
- $values[$index] = $arg['default'];
- }
-
- // Check arg is required
- if ($arg['mode'] === Command::ARG_REQUIRED && empty($values[$name])) {
- throw new CommandFlagException("The argument '{$name}'(position: {$index}) is required");
- }
-
- $index++;
- }
-
- $this->input->setArgs($values, true);
- }
- }
-
/**
* Replace the variable in the comment with the corresponding value
*
@@ -340,6 +275,15 @@ public function setCommentsVars(array $vars): void
}
}
+ /**
+ * @param string $name
+ * @param string $value
+ */
+ public function addCommentsVar(string $name, string $value): void
+ {
+ $this->commentsVars[$name] = $value;
+ }
+
/**
* @return string
*/
diff --git a/src/console/src/CommandRegister.php b/src/console/src/CommandRegister.php
index b48f47080..4143495a3 100644
--- a/src/console/src/CommandRegister.php
+++ b/src/console/src/CommandRegister.php
@@ -90,19 +90,19 @@ public static function bindArgument(string $class, string $method, string $argNa
* @param string $class
* @param string $method
* @param string $optName
- * @param array $info
+ * @param array $optInfo
*/
- public static function bindOption(string $class, string $method, string $optName, array $info): void
+ public static function bindOption(string $class, string $method, string $optName, array $optInfo): void
{
// if not 'commands', is bind group options.
if (!isset(self::$commands[$class]['commands'])) {
- self::$commands[$class]['options'][$optName] = $info;
+ self::$commands[$class]['options'][$optName] = $optInfo;
return;
}
$cmdInfo = self::$commands[$class]['commands'][$method];
// add option info
- $cmdInfo['options'][$optName] = $info;
+ $cmdInfo['options'][$optName] = $optInfo;
// re-setting
self::$commands[$class]['commands'][$method] = $cmdInfo;
}
diff --git a/src/console/src/Concern/RenderHelpInfoTrait.php b/src/console/src/Concern/RenderHelpInfoTrait.php
index 948c8d86e..bbe7a5330 100644
--- a/src/console/src/Concern/RenderHelpInfoTrait.php
+++ b/src/console/src/Concern/RenderHelpInfoTrait.php
@@ -5,15 +5,16 @@
use Swoft;
use Swoft\Console\Console;
use Swoft\Console\ConsoleEvent;
+use Swoft\Console\FlagType;
use Swoft\Console\Helper\FormatUtil;
use Swoft\Console\Helper\Show;
use Swoft\Console\Output\Output;
use Swoft\Console\Router\Router;
use Swoft\Stdlib\Helper\Arr;
+use Swoft\Stdlib\Helper\JsonHelper;
use Swoft\Stdlib\Helper\Str;
use function array_shift;
use function explode;
-use function implode;
use function is_array;
use function is_bool;
use function is_scalar;
@@ -23,6 +24,7 @@
use function sprintf;
use function strlen;
use function strpos;
+use function strtoupper;
use function trim;
use const PHP_EOL;
use const PHP_VERSION;
@@ -30,6 +32,7 @@
/**
* Trait RenderHelpInfoTrait
+ *
* @package Swoft\Console\Concern
*/
trait RenderHelpInfoTrait
@@ -56,10 +59,8 @@ protected function showVersionInfo(): void
$this->renderBannerLogo();
// Display some information
- $output->writef(
- 'PHP: %s, Swoft: %s, Swoole: %s',
- $phpVersion, $swoftVersion, $swooleVersion
- );
+ $output->writef('PHP: %s, Swoft: %s, Swoole: %s', $phpVersion,
+ $swoftVersion, $swooleVersion);
}
protected function renderBannerLogo(): void
@@ -84,7 +85,7 @@ protected function showApplicationHelp(bool $showLogo = true): void
/** @var Swoft\Console\Input\Input $input */
$input = $this->input;
- $script = $input->getScriptFile();
+ $script = $input->getScriptName();
// Global options
$globalOptions = self::$globalOptions;
// Append expand option
@@ -111,21 +112,15 @@ protected function showApplicationHelp(bool $showLogo = true): void
Console::writeln('Available Commands:');
$grpHandler = function (string $group, array $info) use ($keyWidth) {
- Console::writef(
- ' %s%s%s',
- Str::padRight($group, $keyWidth),
+ Console::writef(' %s%s%s', Str::padRight($group, $keyWidth),
$info['desc'] ?: 'No description message',
- $info['alias'] ? "(alias: {$info['alias']})" : ''
- );
+ $info['alias'] ? "(alias: {$info['alias']})" : '');
};
$cmdHandler = function (string $cmdId, array $info) use ($keyWidth) {
- Console::writef(
- ' %s %s%s',
- Str::padRight($cmdId, $keyWidth),
+ Console::writef(' %s %s%s', Str::padRight($cmdId, $keyWidth),
$info['desc'] ?: 'No description message',
- $info['alias'] ? "(alias: {$info['alias']})" : ''
- );
+ $info['alias'] ? "(alias: {$info['alias']})" : '');
};
$router->sortedEach($grpHandler, $expand ? $cmdHandler : null);
@@ -138,7 +133,7 @@ protected function showApplicationHelp(bool $showLogo = true): void
* Display help, command list of the group
*
* @param string $group Group name
- * @param array $info Some base info of the group
+ * @param array $info Some base info of the group
*/
protected function showGroupHelp(string $group, array $info = []): void
{
@@ -156,7 +151,7 @@ protected function showGroupHelp(string $group, array $info = []): void
/** @var Swoft\Console\Input\Input $input */
$input = $this->input;
- $script = $input->getScriptFile();
+ $script = $input->getScriptName();
Console::startBuffer();
Console::writeln($info['desc'] . PHP_EOL);
@@ -174,12 +169,9 @@ protected function showGroupHelp(string $group, array $info = []): void
foreach ($names as $name) {
$cmdId = $router->buildCommandID($group, $name);
$cInfo = $router->getRouteByID($cmdId);
- Console::writef(
- ' %s %s%s',
- Str::padRight($name, $keyWidth),
+ Console::writef(' %s %s%s', Str::padRight($name, $keyWidth),
$cInfo['desc'] ?: 'No description message',
- $cInfo['alias'] ? "(alias: {$cInfo['alias']})" : ''
- );
+ $cInfo['alias'] ? "(alias: {$cInfo['alias']})" : '');
}
if ($info['example']) {
@@ -202,7 +194,7 @@ protected function showCommandHelp(array $info): void
/** @var Swoft\Console\Input\Input $input */
$input = $this->input;
- $script = $input->getScriptFile();
+ $script = $input->getScriptName();
$usage = sprintf('%s %s [arg ...] [--opt ...]', $script, $info['cmdId']);
// If has been custom usage.
@@ -229,7 +221,7 @@ protected function showCommandHelp(array $info): void
foreach ($arguments as $name => $meta) {
Console::writef(
' %s %s %s%s',
- Str::padRight($name, $keyWidth), $meta['type'],
+ Str::padRight($name, $keyWidth), strtoupper($meta['type']),
$meta['desc'],
$this->renderDefaultValue($meta['default'])
);
@@ -268,7 +260,11 @@ protected function renderCommandOptions(array $options): void
continue;
}
- $typeName = $meta['type'] === 'BOOL' ? '' : $meta['type'];
+ $typeName = $meta['type'] === FlagType::BOOL ? '' : $meta['type'];
+ if ($typeName) {
+ $typeName = strtoupper($typeName);
+ }
+
if ($len === 1) {
$key = sprintf('-%s %s', $name, $typeName);
} else {
@@ -281,9 +277,9 @@ protected function renderCommandOptions(array $options): void
$key = sprintf('%s--%s %s', $shortMark, $name, $typeName);
}
- $kenLen = strlen($key);
- if ($kenLen > $maxLen) {
- $maxLen = $kenLen;
+ $keyLen = strlen($key);
+ if ($keyLen > $maxLen) {
+ $maxLen = $keyLen;
}
$newOpts[$key] = $meta;
@@ -323,6 +319,7 @@ protected function renderCommandOptions(array $options): void
/**
* @param mixed $defVal
+ *
* @return string
*/
private function renderDefaultValue($defVal): string
@@ -336,9 +333,9 @@ private function renderDefaultValue($defVal): string
if (is_bool($defVal)) {
$text .= $defVal ? 'True' : 'False';
} elseif (is_scalar($defVal)) {
- $text .= $defVal;
+ $text .= $defVal;
} elseif (is_array($defVal)) {
- $text .= implode(', ', $defVal);
+ $text .= JsonHelper::encode($defVal);
} else {
$text .= $defVal;
}
diff --git a/src/console/src/Contract/RouterInterface.php b/src/console/src/Contract/RouterInterface.php
index 20fdad8f8..dbdfeb1c8 100644
--- a/src/console/src/Contract/RouterInterface.php
+++ b/src/console/src/Contract/RouterInterface.php
@@ -9,5 +9,4 @@
interface RouterInterface extends \Swoft\Contract\RouterInterface
{
public const ONLY_GROUP = 3;
-
}
diff --git a/src/console/src/FlagType.php b/src/console/src/FlagType.php
new file mode 100644
index 000000000..fbcfb82ad
--- /dev/null
+++ b/src/console/src/FlagType.php
@@ -0,0 +1,14 @@
+type) {
- return $upper ? strtoupper($this->type) : $this->type;
+ return $lower ? strtolower($this->type) : $this->type;
}
return '';
@@ -165,4 +173,12 @@ public function isRequired(): bool
{
return $this->required;
}
+
+ /**
+ * @return mixed
+ */
+ public function getValue()
+ {
+ return $this->_value;
+ }
}
diff --git a/src/console/src/Input/AbstractInput.php b/src/console/src/Input/AbstractInput.php
index c248c7522..5bbc4da19 100644
--- a/src/console/src/Input/AbstractInput.php
+++ b/src/console/src/Input/AbstractInput.php
@@ -12,8 +12,6 @@
/**
* Class AbstractInput
- *
- * @package Swoft\Console\Input
*/
abstract class AbstractInput implements InputInterface
{
@@ -52,6 +50,13 @@ abstract class AbstractInput implements InputInterface
*/
protected $tokens;
+ /**
+ * Input flags data
+ *
+ * @var array
+ */
+ protected $flags = [];
+
/**
* Input args data
*
@@ -314,7 +319,7 @@ public function clearArgs(): void
public function getOpt(string $name, $default = null)
{
// is long-opt
- if (isset($name{1})) {
+ if (isset($name[1])) {
return $this->lOpt($name, $default);
}
@@ -751,4 +756,20 @@ public function setTokens(array $tokens): void
{
$this->tokens = $tokens;
}
+
+ /**
+ * @return array
+ */
+ public function getFlags(): array
+ {
+ return $this->flags;
+ }
+
+ /**
+ * @param array $flags
+ */
+ public function setFlags(array $flags): void
+ {
+ $this->flags = $flags;
+ }
}
diff --git a/src/console/src/Input/Input.php b/src/console/src/Input/Input.php
index dc9db9158..5a61c982f 100644
--- a/src/console/src/Input/Input.php
+++ b/src/console/src/Input/Input.php
@@ -3,6 +3,9 @@
namespace Swoft\Console\Input;
use Swoft\Bean\Annotation\Mapping\Bean;
+use Swoft\Console\Annotation\Mapping\Command;
+use Swoft\Console\Exception\CommandFlagException;
+use Swoft\Console\FlagType;
use Toolkit\Cli\Flags;
use function array_map;
use function array_shift;
@@ -49,11 +52,14 @@ public function __construct(array $args = null, bool $parsing = true)
$args = (array)$_SERVER['argv'];
}
- $this->pwd = $this->getPwd();
- $this->tokens = $args;
+ $this->tokens = $args;
+
$this->scriptFile = array_shift($args);
$this->fullScript = implode(' ', $args);
+ $this->flags = $args;
+ $this->pwd = $this->getPwd();
+
if ($parsing) {
// list($this->args, $this->sOpts, $this->lOpts) = InputParser::fromArgv($args);
[$this->args, $this->sOpts, $this->lOpts] = Flags::parseArgv($args);
@@ -86,8 +92,8 @@ public function toString(): string
/**
* Read input information
*
- * @param string $question 若不为空,则先输出文本消息
- * @param bool $nl true 会添加换行符 false 原样输出,不添加换行符
+ * @param string $question The message before read input
+ * @param bool $nl Add new line. True: will add new line. False: direct output.
*
* @return string
*/
@@ -101,7 +107,134 @@ public function read(string $question = '', bool $nl = false): string
}
/***********************************************************************************
- * getter/setter
+ * Binding options and arguments
+ ***********************************************************************************/
+
+ /**
+ * Re-parse flags by command info
+ *
+ * @param array $info
+ * @param bool $binding
+ *
+ * @throws CommandFlagException
+ */
+ public function parseFlags(array $info, bool $binding = false): void
+ {
+ $config = [];
+
+ // Parse options(find bool and array options)
+ if ($cmdOpts = $info['options']) {
+ foreach ($cmdOpts as $name => $opt) {
+ if ($opt['type'] === FlagType::BOOL) {
+ $config['boolOpts'][] = $name;
+ } elseif ($opt['type'] === FlagType::ARRAY) {
+ $config['arrayOpts'][] = $name;
+ }
+ }
+ }
+
+ if ($this->flags) {
+ [$this->args, $this->sOpts, $this->lOpts] = Flags::parseArgv($this->flags, $config);
+
+ // Binding
+ if ($binding) {
+ $this->bindingFlags($info);
+ }
+ }
+ }
+
+ /**
+ * Binding options and arguments by give config
+ *
+ * @param array $info
+ *
+ * @throws CommandFlagException
+ */
+ public function bindingFlags(array $info): void
+ {
+ // Bind options
+ if ($opts = $info['options']) {
+ $this->bindingOptions($opts);
+ }
+
+ // Bind named argument by index
+ if ($args = $info['arguments']) {
+ $this->bindingArguments($args);
+ }
+ }
+
+ /**
+ * @param array $cmdOpts The command options definition
+ *
+ * @throws CommandFlagException
+ */
+ protected function bindingOptions(array $cmdOpts): void
+ {
+ foreach ($cmdOpts as $name => $opt) {
+ $shortName = $opt['short'];
+ $inputVal = $this->getLongOpt($name);
+
+ // Exist short name
+ if (null === $inputVal && $shortName) {
+ $inputVal = $this->getShortOpt($shortName);
+ }
+
+ // Exist default value
+ if (null === $inputVal && isset($opt['default'])) {
+ $inputVal = $opt['default'];
+ }
+
+ // Has option value
+ if (null !== $inputVal) {
+ $typedValue = FlagType::convertType($opt['type'], $inputVal);
+
+ $this->lOpts[$name] = $typedValue;
+ if ($shortName) {
+ $this->sOpts[$shortName] = $typedValue;
+ }
+
+ // Value is required
+ } elseif ($opt['mode'] === Command::OPT_REQUIRED) {
+ $short = $shortName ? "(short: {$shortName})" : '';
+ throw new CommandFlagException("The option '{$name}'{$short} is required");
+ }
+ }
+ }
+
+ /**
+ * @param array $cmdArgs The command options definition
+ *
+ * @throws CommandFlagException
+ */
+ protected function bindingArguments(array $cmdArgs): void
+ {
+ $index = 0;
+ $values = $this->getArgs();
+
+ foreach ($cmdArgs as $name => $arg) {
+ // Bind value to name
+ if (isset($values[$index])) {
+ $typeValue = FlagType::convertType($arg['type'], $values[$index]);
+ // Re-set strict type value
+ $this->args[$name] = $this->args[$index] = $typeValue;
+ // Bind default value
+ } elseif (isset($arg['default'])) {
+ $typeValue = FlagType::convertType($arg['type'], $arg['default']);
+ // Re-set strict type value
+ $this->args[$name] = $this->args[$index] = $typeValue;
+ }
+
+ // Check arg is required
+ if ($arg['mode'] === Command::ARG_REQUIRED && empty($values[$index])) {
+ throw new CommandFlagException("The argument '{$name}'(position: {$index}) is required");
+ }
+
+ $index++;
+ }
+ }
+
+ /***********************************************************************************
+ * Getter/setter methods
***********************************************************************************/
/**
diff --git a/src/console/src/Input/InputDefinition.php b/src/console/src/Input/InputDefinition.php
index 3bf00f82a..2f2423000 100644
--- a/src/console/src/Input/InputDefinition.php
+++ b/src/console/src/Input/InputDefinition.php
@@ -4,6 +4,7 @@
/**
* Class InputDefinition
+ *
* @since 2.0 refer inhere/console and symfony/console
*/
class InputDefinition
diff --git a/src/console/src/Listener/AppInitCompleteListener.php b/src/console/src/Listener/AppInitCompleteListener.php
deleted file mode 100644
index ccd0f5f10..000000000
--- a/src/console/src/Listener/AppInitCompleteListener.php
+++ /dev/null
@@ -1,27 +0,0 @@
- route info.
* 'group:cmd' => [
* 'handler' => [group class, command method],
- * 'metadata' => [
- * 'aliases' => [],
- * 'options' => [],
- * 'arguments' => [],
- * ],
+ * 'aliases' => [],
+ * 'options' => [],
+ * 'arguments' => [],
* ]
* ]
*/
@@ -148,7 +146,7 @@ public function map(string $group, string $command, $handler, array $config = []
/**
* Match route by input command
*
- * @param array $params [$route]
+ * @param string $inputCmd
*
* @return array
*
@@ -156,10 +154,10 @@ public function map(string $group, string $command, $handler, array $config = []
* status, info(array)
* ]
*/
- public function match(...$params): array
+ public function match(string $inputCmd): array
{
$delimiter = $this->delimiter;
- $inputCmd = trim($params[0], "$delimiter ");
+ $inputCmd = trim($inputCmd, "$delimiter ");
$noSepChar = strpos($inputCmd, $delimiter) === false;
// If is full command ID
@@ -181,12 +179,11 @@ public function match(...$params): array
$group = $this->defaultGroup;
$command = $this->resolveCommandAlias($inputCmd);
- // Only a group name
+ // Only an group name
} elseif ($noSepChar) {
$group = $this->resolveGroupAlias($inputCmd);
-
if (isset($this->groups[$group])) {
- return [self::ONLY_GROUP, ['group' => $group]];
+ return [self::ONLY_GROUP, ['group' => $group, 'cmd' => '']];
}
return [self::NOT_FOUND];
@@ -216,8 +213,12 @@ public function match(...$params): array
return [self::FOUND, $info];
}
+ // Group is valid, but command is error
if ($group && isset($this->groups[$group])) {
- return [self::ONLY_GROUP, ['group' => $group]];
+ return [self::ONLY_GROUP, [
+ 'group' => $group,
+ 'cmd' => $command
+ ]];
}
return [self::NOT_FOUND];
diff --git a/src/console/test/testing/Listener/AppInitCompleteListener.php b/src/console/test/testing/Listener/AppInitCompleteListener.php
deleted file mode 100644
index a09c9f410..000000000
--- a/src/console/test/testing/Listener/AppInitCompleteListener.php
+++ /dev/null
@@ -1,35 +0,0 @@
-setLOpts([
- 'comm1' => 'v1',
- 'comm2' => 'v2',
+ $input->setFlags([
+ '--comm1', 'v1',
+ '--comm2', 'v2',
+ 'a1'
]);
- $input->setArgs(['a1']);
$input->setCommand('demo:sub');
$app->run();
diff --git a/src/console/test/unit/Input/InputTest.php b/src/console/test/unit/Input/InputTest.php
new file mode 100644
index 000000000..9dec7ba04
--- /dev/null
+++ b/src/console/test/unit/Input/InputTest.php
@@ -0,0 +1,49 @@
+assertSame('input:test', $in->getCommand());
+ }
+
+ /**
+ * @throws CommandFlagException
+ */
+ public function testBindingFlags(): void
+ {
+ $args = ['bin/swoft', '-d', '12'];
+ // value sync binding
+ $info = [
+ 'options' => [
+ 'day' => [
+ 'short' => 'd',
+ 'type' => 'int',
+ ],
+ ],
+ 'arguments' => [],
+ ];
+
+ $in = new Input($args);
+ $in->bindingFlags($info);
+
+ $this->assertSame(12, $in->getOpt('day'));
+ $this->assertSame(12, $in->getOpt('d'));
+
+ $args = ['bin/swoft', '--day', '12'];
+ $in = new Input($args);
+ $in->bindingFlags($info);
+
+ $this->assertSame(12, $in->getOpt('day'));
+ $this->assertSame(12, $in->getOpt('d'));
+ }
+}
diff --git a/src/db/.travis.yml b/src/db/.travis.yml
index 5f461825d..5bf0c641b 100644
--- a/src/db/.travis.yml
+++ b/src/db/.travis.yml
@@ -50,7 +50,7 @@ before_install:
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=34 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;'
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/db/composer.json b/src/db/composer.json
index d43c50fc5..8fe3f9a64 100644
--- a/src/db/composer.json
+++ b/src/db/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/db",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/db/src/Concern/BuildsQueries.php b/src/db/src/Concern/BuildsQueries.php
index c26a36d2e..bdc50646d 100644
--- a/src/db/src/Concern/BuildsQueries.php
+++ b/src/db/src/Concern/BuildsQueries.php
@@ -8,6 +8,7 @@
use Swoft\Db\Exception\DbException;
use Swoft\Db\Query\Builder;
use Swoft\Db\Eloquent\Builder as EloquentBuilder;
+use Swoft\Stdlib\Contract\Arrayable;
/**
* Class BuildsQueries
@@ -96,6 +97,31 @@ public function first(array $columns = ['*'])
return $builder->get($columns)->first();
}
+ /**
+ * Execute the query and get the first array result.
+ *
+ * @param array $columns
+ *
+ * @return array
+ * @throws DbException
+ */
+ public function firstArray(array $columns = ['*']): array
+ {
+ /* @var \Swoft\Db\Eloquent\Builder $builder */
+ $builder = $this->take(1);
+ $result = $builder->get($columns)->first();
+
+ if (!$result) {
+ return [];
+ }
+
+ if (is_object($result) && $result instanceof Arrayable) {
+ return $result->toArray();
+ }
+
+ return (array)$result;
+ }
+
/**
* Apply the callback's query changes if the given "value" is true.
*
diff --git a/src/db/src/Concern/HasAttributes.php b/src/db/src/Concern/HasAttributes.php
index 8eaf2c2c7..3c652fa18 100644
--- a/src/db/src/Concern/HasAttributes.php
+++ b/src/db/src/Concern/HasAttributes.php
@@ -524,7 +524,7 @@ public function syncOriginal(): self
/**
* Sync a single original attribute with its current value.
*
- * @param string $attribute
+ * @param string|array $attribute
*
* @return $this
*/
diff --git a/src/db/src/Connection/Connection.php b/src/db/src/Connection/Connection.php
index f266f5465..a93b85084 100644
--- a/src/db/src/Connection/Connection.php
+++ b/src/db/src/Connection/Connection.php
@@ -109,6 +109,13 @@ class Connection extends AbstractConnection implements ConnectionInterface
*/
protected $selectDb = '';
+ /**
+ * @link https://php.net/manual/en/pdo.constants.php#pdo.constants.fetch-obj
+ *
+ * @var int
+ */
+ protected $fetchMode = 0;
+
/**
* Replace constructor
*
@@ -237,6 +244,9 @@ public function release(bool $force = false): void
// Reset select db name
$this->resetDb();
+ // Reset fetch mode
+ $this->resetFetchMode();
+
// Release connection
parent::release($force);
}
@@ -646,19 +656,30 @@ public function prepareBindings(array $bindings): array
protected function run(string $query, array $bindings, Closure $callback)
{
$this->reconnectIfMissingConnection();
-
+ $start = microtime(true);
// Here we will run this query. If an exception occurs we'll determine if it was
// caused by a connection that has been lost. If that is the cause, we'll try
$result = $this->runQueryCallback($query, $bindings, $callback);
-
- $this->fireEvent(DbEvent::SQL_RAN, $query, $bindings);
+ $time = $this->getElapsedTime($start);
+ $this->fireEvent(DbEvent::SQL_RAN, $query, $bindings, $time);
// Once we have run the query we will calculate the time that it took to run and
// then log the query, bindings, and execution time so we will report them on
// the event that the developer needs them. We'll log time in milliseconds.
return $result;
}
-
+
+ /**
+ * Get the elapsed time since a given starting point.
+ *
+ * @param int $start
+ * @return float
+ */
+ protected function getElapsedTime($start)
+ {
+ return round((microtime(true) - $start) * 1000, 2);
+ }
+
/**
* Run a SQL statement.
*
@@ -784,10 +805,12 @@ protected function reconnectIfMissingConnection()
*/
protected function prepared(PDOStatement $statement): PDOStatement
{
- $config = $this->database->getConfig();
- $fetchMode = $config['fetchMode'] ?? self::DEFAULT_FETCH_MODE;
+ if (!$this->fetchMode) {
+ $config = $this->database->getConfig();
+ $this->fetchMode = $config['fetchMode'] ?? self::DEFAULT_FETCH_MODE;
+ }
- $statement->setFetchMode($fetchMode);
+ $statement->setFetchMode($this->fetchMode);
return $statement;
}
@@ -1178,4 +1201,21 @@ private function releaseOrRemove(): void
$this->release();
}
}
+
+ /**
+ * @param int $fetchMode
+ */
+ public function setFetchMode(int $fetchMode): void
+ {
+ $this->fetchMode = $fetchMode;
+ }
+
+ /**
+ * Reset fetch mode
+ *
+ */
+ private function resetFetchMode(): void
+ {
+ $this->fetchMode = 0;
+ }
}
diff --git a/src/db/src/Eloquent/Builder.php b/src/db/src/Eloquent/Builder.php
index 834d16b70..99d3cf1d2 100644
--- a/src/db/src/Eloquent/Builder.php
+++ b/src/db/src/Eloquent/Builder.php
@@ -117,7 +117,7 @@
* @method Connection getConnection()
* @method string implode(string $column, string $glue = '')
* @method Builder useWritePdo()
- *
+ * @method Builder setFetchMode(int $mode)
*/
class Builder
{
diff --git a/src/db/src/Eloquent/Model.php b/src/db/src/Eloquent/Model.php
index 8335b3f91..279fdb36d 100644
--- a/src/db/src/Eloquent/Model.php
+++ b/src/db/src/Eloquent/Model.php
@@ -169,6 +169,9 @@
* @method static float|int average(string $column)
* @method static void truncate()
* @method static Builder useWritePdo()
+ * @method static Builder setFetchMode(int $mode)
+ * @method static static|null first()
+ * @method static array firstArray()
*/
abstract class Model implements ArrayAccess, Arrayable, Jsonable, JsonSerializable
{
@@ -459,7 +462,7 @@ public function syncCounter(array $counters, array $extra = []): self
if ($extra) {
// Sync extra
- $this->fill($extra);
+ $this->setRawAttributes($extra, true);
}
return $this;
@@ -604,8 +607,7 @@ protected function setKeysForSaveQuery(Builder $query)
*/
protected function getKeyForSaveQuery()
{
- return $this->modelOriginal[$this->getKeyName()]
- ?? $this->getKey();
+ return $this->modelOriginal[$this->getKeyName()] ?? $this->getKey();
}
/**
diff --git a/src/db/src/Query/Builder.php b/src/db/src/Query/Builder.php
index 8dd780b01..2c343e0bb 100644
--- a/src/db/src/Query/Builder.php
+++ b/src/db/src/Query/Builder.php
@@ -241,6 +241,13 @@ class Builder implements PrototypeInterface
*/
public $db = '';
+ /**
+ * @link https://php.net/manual/en/pdo.constants.php#pdo.constants.fetch-obj
+ *
+ * @var int
+ */
+ protected $fetchMode = 0;
+
/**
* @var array
*/
@@ -2748,6 +2755,11 @@ public function aggregate(string $function, array $columns = ['*'])
->get($columns);
if (!$results->isEmpty()) {
+ // Compatible group aggregate
+ if (isset($this->groups)) {
+ return $results->pluck('aggregate')->$function();
+ }
+
return array_change_key_case((array)$results[0])['aggregate'];
}
@@ -3073,6 +3085,11 @@ public function warpCounters(array $counters): array
{
// Convert counters to expression
foreach ($counters as $column => $value) {
+ if (empty($value)) {
+ unset($counters[$column]);
+ continue;
+ }
+
if (!$value instanceof Expression) {
$wrapped = $this->grammar->wrap($column);
@@ -3307,12 +3324,26 @@ public function mergeBindings(Builder $query)
*
* @return $this
*/
- public function db(string $dbname)
+ public function db(string $dbname): self
{
$this->db = $dbname;
return $this;
}
+ /**
+ * Set fetch mode
+ *
+ * @param int $mode
+ *
+ * @return $this
+ */
+ public function setFetchMode(int $mode): self
+ {
+ $this->fetchMode = $mode;
+
+ return $this;
+ }
+
/**
* Get the database connection instance.
*
@@ -3328,6 +3359,11 @@ public function getConnection()
$connection->db($this->db);
}
+ // Choose this select fetch mode
+ if (!empty($this->fetchMode)) {
+ $connection->setFetchMode($this->fetchMode);
+ }
+
return $connection;
}
diff --git a/src/db/test/unit/Eloquent/ModelTest.php b/src/db/test/unit/Eloquent/ModelTest.php
index 811b119c5..8b8249d95 100644
--- a/src/db/test/unit/Eloquent/ModelTest.php
+++ b/src/db/test/unit/Eloquent/ModelTest.php
@@ -709,8 +709,9 @@ public function testUpdateAllCounters()
$this->assertEquals($user->getAge() - 1, User::find($id)->getAge());
$user = User::find($id);
- $user->updateCounters(['age' => -1]);
+ $user->updateCounters(['age' => -1], ['udesc' => 'swoft']);
+ $this->assertEquals([], $user->getDirty());
$this->assertEquals($user->getAge(), User::find($id)->getAge());
}
@@ -877,4 +878,110 @@ public function testFindOrFail()
$this->expectException(DbException::class);
$user->update(['age' => 2]);
}
+
+ public function testDirty(): void
+ {
+ $origin = ['age' => 1, 'name' => 'swoft'];
+ User::updateOrCreate(['id' => 1], $origin);
+
+ $user = User::find(1);
+
+ $dirty = $user->getDirty();
+ // No changes
+ $this->assertEquals([], $dirty);
+
+
+ $user->setAge(2);
+ $dirty = $user->getDirty();
+ // Change age to 2
+ $this->assertEquals(['age' => 2], $dirty);
+
+
+ $user->setName('swoft2');
+ $dirty = $user->getDirty();
+ // Change name to swoft2
+ $this->assertEquals(['age' => 2, 'name' => 'swoft2'], $dirty);
+
+
+ // recovery changes
+ $fillOrigin = $user->fill($origin)->getDirty();
+ $this->assertEquals([], $fillOrigin);
+
+ // setter
+ $user->setModelAttribute('name', 'on');
+ $dirty = $user->getDirty();
+ $this->assertEquals(['name' => 'on'], $dirty);
+ }
+
+ public function testGroupAggregate(): void
+ {
+ User::truncate();
+
+ $origin = ['age' => 1, 'user_desc' => 'swoft'];
+ $origin2 = ['age' => 2, 'user_desc' => 'swoft2'];
+
+ User::updateOrCreate(['id' => 1], $origin);
+ User::updateOrCreate(['id' => 2], $origin2);
+ User::updateOrCreate(['id' => 3], $origin2);
+
+ $count = User::groupBy('user_desc')->count();
+
+ $this->assertEquals(2, $count);
+
+ $originCount = User::count();
+ $this->assertEquals(3, $originCount);
+
+ $minAge = User::groupBy('age')->min('age');
+ $this->assertEquals(1, $minAge);
+ $this->assertEquals(1, User::min('age'));
+
+ $maxAge = User::groupBy('age')->max('age');
+ $this->assertEquals(2, $maxAge);
+ $this->assertEquals(2, User::max('age'));
+
+ $this->assertEquals(1.6667, User::avg('age'));
+ $this->assertEquals(1.5, User::groupBy('age')->avg('age'));
+ }
+
+ public function testFillSave(): void
+ {
+ $id = 1;
+ $origin = ['age' => 1, 'user_desc' => 'swoft'];
+
+ User::updateOrCreate(['id' => $id], $origin);
+
+ $newUser = User::find($id);
+
+ $newUser->fill([
+ 'age' => 2,
+ 'udesc' => 'changed user_desc'
+ ]);
+
+ $newUser->save();
+
+ $this->assertEquals(2, $newUser->getAge());
+ $this->assertEquals('changed user_desc', $newUser->getUserDesc());
+
+ $findUser = User::find($id);
+ $this->assertEquals(2, $findUser->getAge());
+ $this->assertEquals('changed user_desc', $findUser->getUserDesc());
+ }
+
+ public function testModelFirstArray(): void
+ {
+ $id = 1;
+ $origin = ['age' => 1, 'user_desc' => 'swoft'];
+
+ User::updateOrCreate(['id' => $id], $origin);
+
+ $user1 = User::first();
+ $this->assertInstanceOf(User::class, $user1);
+
+ $user1 = User::where('id', $id)->first();
+ $this->assertInstanceOf(User::class, $user1);
+
+ $user1 = User::where('id', $id)->firstArray();
+ $this->assertIsArray($user1);
+ $this->assertArrayHasKey('testJson', $user1);
+ }
}
diff --git a/src/db/test/unit/Query/BuilderTest.php b/src/db/test/unit/Query/BuilderTest.php
index bb80fa15b..efa8d0c6b 100644
--- a/src/db/test/unit/Query/BuilderTest.php
+++ b/src/db/test/unit/Query/BuilderTest.php
@@ -778,4 +778,52 @@ public function testWhereArray()
$this->assertEquals($expectSql, $res);
}
+
+ public function testAndOr(): void
+ {
+ $where = [
+ 'name' => 'swoft',
+ ];
+ $orWhere = [
+ 'status' => 1,
+ ['age', '>', 0, 'or'],
+ ];
+
+ $sql = DB::table('user')->where($where)->where($orWhere)->toSql();
+
+ $expectSql = 'select * from `user` where (`name` = ?) and (`status` = ? or `age` > ?)';
+
+ $this->assertEquals($expectSql, $sql);
+ }
+
+ public function testFetchMode(): void
+ {
+ $mode = \PDO::FETCH_OBJ;
+
+ $user = DB::table('user')->setFetchMode($mode)->first();
+
+ $this->assertInstanceOf(\stdClass::class, $user);
+ }
+
+ public function testFirstArray(): void
+ {
+ $id = 1;
+ $origin = ['age' => 1, 'user_desc' => 'swoft'];
+
+ User::updateOrCreate(['id' => $id], $origin);
+
+ $mode = \PDO::FETCH_OBJ;
+
+ $user2 = DB::table('user')->setFetchMode($mode)->first();
+ $this->assertInstanceOf(\stdClass::class, $user2);
+
+ $user = DB::table('user')->setFetchMode($mode)->firstArray();
+ $this->assertIsArray($user);
+
+ $user1 = DB::table('user')->firstArray();
+ $this->assertIsArray($user1);
+
+ $user1 = DB::table('user')->first();
+ $this->assertIsArray($user1);
+ }
}
diff --git a/src/error/.travis.yml b/src/error/.travis.yml
index ddbf706dd..f2cf7b46b 100644
--- a/src/error/.travis.yml
+++ b/src/error/.travis.yml
@@ -5,7 +5,7 @@ php:
- 7.2
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
- composer config -g process-timeout 9000 && composer update
diff --git a/src/error/composer.json b/src/error/composer.json
index 9447e15dd..0449a924f 100644
--- a/src/error/composer.json
+++ b/src/error/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/error",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/event/.github/PULL_REQUEST_TEMPLATE.md b/src/event/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..8b742aa30
--- /dev/null
+++ b/src/event/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,60 @@
+# PR
+
+- 请不要提交PR到各个组件仓库,它们都是 **只读的**
+- 核心组件的 **开发仓库** 是 **[swoft/swoft-component][core]**
+- 扩展组件的 **开发仓库** 是 **[swoft/swoft-ext][ext]**
+- 请 `fork` 对应的 **开发仓库**,修改后,请把你的PR提交到对应的开发仓库
+
+> 发布版本时官方会将代码同步到各个子仓库。因此,切记不要往子仓库发PR。
+
+## 发起PR时的注意事项
+
+开发组非常欢迎各位向我们提交PR(_Pull Request_),但是为了保证代码质量和统一的风格,
+向官方的主仓库 [swoft/swoft][main] 和 **开发仓库** 贡献代码时需要注意代码和commit格式
+
+### Commit Message
+
+- commit message 只能是英文信息
+- 请尽量保证commit message是有意义的说明
+- 最好以 `add:` `update:` `fix:` 等关键字开头
+
+### 代码风格
+
+- 提交的PHP代码 **必须** 遵循 PSR-2 代码风格
+- 合理且有意义的类、方法、变量命名
+- 适当的注释,合理的使用空行保持代码的简洁,易于阅读
+- 不要包含一些无意义的信息 例如 `@author` 等(_提交者是能够从commit log里看到的_)
+
+------------------
+
+> English Version (_translate by Google_)
+
+The development team welcomes you to submit PR (_Pull Request_) to us, but to ensure code quality and uniform style,
+go to the official main repository [swoft/swoft][main] and Development repository, Note the code and commit format when contributing code
+
+## Precautions when initiating PR
+
+- Please do not submit PR to each sub-repository, they are all read-only
+- The _development repository_ for the core components is **[swoft/swoft-component][core]**
+- The _development repository_ for extension components is **[swoft/swoft-ext][ext]**
+- Please `fork` the corresponding development warehouse. After modification, please submit your PR to the corresponding development warehouse.
+
+> Officially syncs code to individual sub-warehouses when new versions are released
+
+### Commit Message
+
+- the commit message can only be in English
+- Please try to ensure that the commit message is meaningful
+- it is best to start with the keyword `add:` `update:` `fix:`
+
+### Code Style
+
+- Submitted PHP code **Must** Follow PSR-2 code style
+- Reasonable and meaningful class, method, variable naming
+- Appropriate comments, reasonable use of blank lines to keep the code simple and easy to read
+- Don't include some meaningless information such as `@author`, etc. (_author is that can be seen from the commit log_)
+
+
+[main]: https://github.com/swoft-cloud/swoft
+[core]: https://github.com/swoft-cloud/swoft-component
+[ext]: https://github.com/swoft-cloud/swoft-ext
diff --git a/src/event/README.md b/src/event/README.md
index d714f57f7..a0026eff4 100644
--- a/src/event/README.md
+++ b/src/event/README.md
@@ -7,6 +7,10 @@
Swoft Event Component
+## [中文说明](README.zh-CN.md)
+
+中文说明请查看 [README.zh-CN.md](README.zh-CN.md)
+
## Install
- composer command
diff --git a/src/event/README.zh-CN.md b/src/event/README.zh-CN.md
new file mode 100644
index 000000000..6a9511d47
--- /dev/null
+++ b/src/event/README.zh-CN.md
@@ -0,0 +1,34 @@
+# Swoft Event
+
+[![Latest Stable Version](http://img.shields.io/packagist/v/swoft/event.svg)](https://packagist.org/packages/swoft/event)
+[![Php Version](https://img.shields.io/badge/php-%3E=7.1-brightgreen.svg?maxAge=2592000)](https://secure.php.net/)
+[![Swoft Doc](https://img.shields.io/badge/docs-passing-green.svg?maxAge=2592000)](https://www.swoft.org/docs)
+[![Swoft License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/swoft-cloud/swoft/blob/master/LICENSE)
+
+Swoft Event Component
+
+## [ENGLISH](README.md)
+
+English readme please sess [README.md](README.md)
+
+## Install
+
+- composer command
+
+```bash
+composer require swoft/event
+```
+
+## Resources
+
+* [Documentation](https://swoft.org/docs)
+* [Contributing](https://github.com/swoft-cloud/swoft/blob/master/CONTRIBUTING.md)
+* [Report Issues][issues] and [Send Pull Requests][pulls] in the [Main Swoft Repository][repository]
+
+[pulls]: https://github.com/swoft-cloud/swoft-component/pulls
+[repository]: https://github.com/swoft-cloud/swoft
+[issues]: https://github.com/swoft-cloud/swoft/issues
+
+## LICENSE
+
+The Component is open-sourced software licensed under the [Apache license](LICENSE).
diff --git a/src/event/composer.json b/src/event/composer.json
index 31e40cad7..051c3eaa5 100644
--- a/src/event/composer.json
+++ b/src/event/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/event",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/event/test/unit/EventManagerTest.php b/src/event/test/unit/EventManagerTest.php
index a72fa3d8e..3c3c216b7 100644
--- a/src/event/test/unit/EventManagerTest.php
+++ b/src/event/test/unit/EventManagerTest.php
@@ -34,7 +34,6 @@ public function testAttach(): void
$l1 = new TestHandler();
$em->attach('test', $l1);
$em->attach('test', function () {
- //
});
$this->assertTrue($em->hasListener($l1));
@@ -45,6 +44,15 @@ public function testAttach(): void
$em->detach('test', $l1);
$this->assertCount(1, $em->getEventListeners('test'));
+
+ $buffer = '';
+ $em->attach('test1', function () use (&$buffer) {
+ $buffer = 'data';
+ });
+
+ $this->assertSame('', $buffer);
+ $em->trigger('test1');
+ $this->assertSame('data', $buffer);
}
public function testPriority(): void
@@ -98,9 +106,7 @@ public function testSubscriber(): void
$evt = $em->trigger(TestSubscriber::EVENT_ONE);
$this->assertArrayHasKey('msg', $evt->getParams());
- $this->assertSame(
- 'handle the event: test.event1 position: TestSubscriber.handleEvent1()',
- $evt->getParam('msg')
- );
+ $this->assertSame('handle the event: test.event1 position: TestSubscriber.handleEvent1()',
+ $evt->getParam('msg'));
}
}
diff --git a/src/framework/.phpstorm.meta.php b/src/framework/.phpstorm.meta.php
index 9f90525a2..0948e0535 100644
--- a/src/framework/.phpstorm.meta.php
+++ b/src/framework/.phpstorm.meta.php
@@ -8,23 +8,10 @@
// override(\bean(0), map([]));
- registerArgumentsSet('websocketOpcodes',
- \WEBSOCKET_OPCODE_TEXT,
- \WEBSOCKET_OPCODE_BINARY,
- \WEBSOCKET_OPCODE_CLOSE,
- \WEBSOCKET_OPCODE_PING,
- \WEBSOCKET_OPCODE_PONG
- );
+ registerArgumentsSet('websocketOpcodes', \WEBSOCKET_OPCODE_TEXT, \WEBSOCKET_OPCODE_BINARY, \WEBSOCKET_OPCODE_CLOSE,
+ \WEBSOCKET_OPCODE_PING, \WEBSOCKET_OPCODE_PONG);
// Code hint for:
- expectedArguments(
- \Swoft\WebSocket\Server\WebSocketServer::push(),
- 2,
- argumentsSet('websocketOpcodes')
- );
- expectedArguments(
- \Swoft\WebSocket\Server\WebSocketServer::sendTo(),
- 3,
- argumentsSet('websocketOpcodes')
- );
+ expectedArguments(\Swoft\WebSocket\Server\WebSocketServer::push(), 2, argumentsSet('websocketOpcodes'));
+ expectedArguments(\Swoft\WebSocket\Server\WebSocketServer::sendTo(), 3, argumentsSet('websocketOpcodes'));
}
diff --git a/src/framework/.travis.yml b/src/framework/.travis.yml
index 26ca156c0..14356fffc 100644
--- a/src/framework/.travis.yml
+++ b/src/framework/.travis.yml
@@ -6,7 +6,7 @@ php:
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/framework/composer.json b/src/framework/composer.json
index 9e0ab0f0b..2aff2b437 100644
--- a/src/framework/composer.json
+++ b/src/framework/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/framework",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/framework/phpunit.xml b/src/framework/phpunit.xml
index 15311104a..e491bd4a9 100644
--- a/src/framework/phpunit.xml
+++ b/src/framework/phpunit.xml
@@ -1,14 +1,14 @@
+ bootstrap="test/bootstrap.php"
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false">
./test/unit
@@ -19,4 +19,4 @@
./src/*
-
\ No newline at end of file
+
diff --git a/src/framework/run.php b/src/framework/run.php
index 535811f1a..c56feecb0 100644
--- a/src/framework/run.php
+++ b/src/framework/run.php
@@ -1,7 +1,6 @@
')) {
- fwrite(
- STDERR,
- sprintf(
- 'This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL .
- 'You are using PHP %s (%s).' . PHP_EOL,
- PHP_VERSION,
- PHP_BINARY
- )
- );
+ fwrite(STDERR,
+ sprintf('This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL . 'You are using PHP %s (%s).' . PHP_EOL,
+ PHP_VERSION, PHP_BINARY));
die(1);
}
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
foreach ([
- __DIR__ . '/../../autoload.php',
- __DIR__ . '/../vendor/autoload.php',
- __DIR__ . '/vendor/autoload.php'
- ] as $file
-) {
+ __DIR__ . '/../../autoload.php',
+ __DIR__ . '/../vendor/autoload.php',
+ __DIR__ . '/vendor/autoload.php'
+] as $file) {
if (file_exists($file)) {
define('PHPUNIT_COMPOSER_INSTALL', $file);
break;
@@ -44,12 +36,8 @@
}
unset($file);
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
- fwrite(
- STDERR,
- 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL .
- ' composer install' . PHP_EOL . PHP_EOL .
- 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL
- );
+ fwrite(STDERR,
+ 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . ' composer install' . PHP_EOL . PHP_EOL . 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL);
die(1);
} else {
if (array_reverse(explode('/', __DIR__))[0] ?? '' === 'tests') {
@@ -73,7 +61,7 @@
require PHPUNIT_COMPOSER_INSTALL;
$status = 0;
-srun(function (){
+srun(function () {
// Status
global $status;
diff --git a/src/framework/src/BeanHandler.php b/src/framework/src/BeanHandler.php
index 61e4b2b6f..c4473a8d2 100644
--- a/src/framework/src/BeanHandler.php
+++ b/src/framework/src/BeanHandler.php
@@ -2,10 +2,6 @@
namespace Swoft;
-use function array_shift;
-use function explode;
-use function get_class;
-use function implode;
use ReflectionClass;
use ReflectionException;
use Swoft;
@@ -14,6 +10,10 @@
use Swoft\Bean\Definition\ObjectDefinition;
use Swoft\Bean\Handler;
use Swoft\Proxy\Exception\ProxyException;
+use function array_shift;
+use function explode;
+use function get_class;
+use function implode;
/**
* Class BeanHandler
@@ -30,37 +30,37 @@ class BeanHandler extends Handler
* @param ObjectDefinition $objDfn
* @param array $annotation
*
+ * @throws ReflectionException
* @example
- * [
- * 'annotation' => [
- * new ClassAnnotation(),
- * new ClassAnnotation(),
- * new ClassAnnotation(),
- * ]
- * 'reflection' => new ReflectionClass(),
- * 'properties' => [
- * 'propertyName' => [
- * 'annotation' => [
+ * [
+ * 'annotation' => [
+ * new ClassAnnotation(),
+ * new ClassAnnotation(),
+ * new ClassAnnotation(),
+ * ]
+ * 'reflection' => new ReflectionClass(),
+ * 'properties' => [
+ * 'propertyName' => [
+ * 'annotation' => [
* new PropertyAnnotation(),
* new PropertyAnnotation(),
* new PropertyAnnotation(),
- * ]
- * 'reflection' => new ReflectionProperty(),
- * ]
- * ],
- * 'methods' => [
- * 'methodName' => [
- * 'annotation' => [
+ * ]
+ * 'reflection' => new ReflectionProperty(),
+ * ]
+ * ],
+ * 'methods' => [
+ * 'methodName' => [
+ * 'annotation' => [
* new MethodAnnotation(),
* new MethodAnnotation(),
* new MethodAnnotation(),
- * ]
- * 'reflection' => new ReflectionFunctionAbstract(),
- * ]
- * ],
- * ]
+ * ]
+ * 'reflection' => new ReflectionFunctionAbstract(),
+ * ]
+ * ],
+ * ]
*
- * @throws ReflectionException
*/
public function beforeInit(string $beanName, string $className, ObjectDefinition $objDfn, array $annotation): void
{
diff --git a/src/framework/src/Co.php b/src/framework/src/Co.php
index a78873399..e994182eb 100644
--- a/src/framework/src/Co.php
+++ b/src/framework/src/Co.php
@@ -5,7 +5,6 @@
use RuntimeException;
use Swoft;
use Swoft\Context\Context;
-use Swoft\Exception\SwoftException;
use Swoft\Log\Debug;
use Swoft\Log\Error;
use Swoft\Log\Helper\CLog;
@@ -117,13 +116,8 @@ public static function create(callable $callable, bool $wait = true): int
PhpHelper::call($callable);
} catch (Throwable $e) {
- Error::log(
- "Coroutine internal error: %s\nAt File %s line %d\nTrace:\n%s",
- $e->getMessage(),
- $e->getFile(),
- $e->getLine(),
- $e->getTraceAsString()
- );
+ Error::log("Coroutine internal error: %s\nAt File %s line %d\nTrace:\n%s", $e->getMessage(),
+ $e->getFile(), $e->getLine(), $e->getTraceAsString());
// Trigger co error event
Swoft::trigger(SwoftEvent::COROUTINE_EXCEPTION, $e);
@@ -149,13 +143,12 @@ public static function create(callable $callable, bool $wait = true): int
* @param int $flags
*
* @return int
- * @throws SwoftException
*/
public static function writeFile(string $filename, string $data, int $flags = FILE_USE_INCLUDE_PATH): int
{
$result = Coroutine::writeFile($filename, $data, $flags);
if ($result === false) {
- throw new SwoftException(sprintf('Write(%s) file error!', $filename));
+ throw new RuntimeException(sprintf('Write(%s) file error!', $filename));
}
return $result;
@@ -167,7 +160,6 @@ public static function writeFile(string $filename, string $data, int $flags = FI
* @param string $filename
*
* @return string
- * @throws RuntimeException
*/
public static function readFile(string $filename): string
{
@@ -287,7 +279,6 @@ public static function list(): Coroutine\Iterator
* @param int $limit
*
* @return array
- * @throws SwoftException
*/
public static function getBackTrace(
int $cid = 0,
@@ -296,7 +287,7 @@ public static function getBackTrace(
): array {
$result = Coroutine::getBackTrace($cid, $options, $limit);
if ($result === false) {
- throw new SwoftException('cid is not exist!');
+ throw new RuntimeException('cid is not exist!');
}
return $result;
@@ -323,13 +314,13 @@ public static function resume(int $cid): void
* @param int $length
*
* @return string
- * @throws SwoftException
+ * @throws RuntimeException
*/
public static function fread($handle, int $length = 0): string
{
$result = Coroutine::fread($handle, $length);
if ($result === false) {
- throw new SwoftException('Fread file error!');
+ throw new RuntimeException('Fread file error!');
}
return $result;
@@ -339,13 +330,13 @@ public static function fread($handle, int $length = 0): string
* @param resource $handle
*
* @return string
- * @throws SwoftException
+ * @throws RuntimeException
*/
public static function fgets($handle): string
{
$result = Coroutine::fgets($handle);
if ($result === false) {
- throw new SwoftException('Fgets file error!');
+ throw new RuntimeException('Fgets file error!');
}
return $result;
@@ -357,13 +348,13 @@ public static function fgets($handle): string
* @param int $length
*
* @return int
- * @throws SwoftException
+ * @throws RuntimeException
*/
public static function fwrite($handle, string $data, int $length = 0): int
{
$result = Coroutine::fwrite($handle, $data, $length);
if ($result === false) {
- throw new SwoftException('Fwrite file error! data=' . $data);
+ throw new RuntimeException('Fwrite file error! data=' . $data);
}
return $result;
@@ -383,13 +374,12 @@ public static function sleep(float $seconds): void
* @param int $family
*
* @return string
- * @throws SwoftException
*/
public static function getHostByName(string $domain, float $timeout, int $family = 2): string
{
$result = Coroutine::gethostbyname($domain, $family, $timeout);
if ($result === false) {
- throw new SwoftException('GetHostByName error! domain=' . $domain);
+ throw new RuntimeException('GetHostByName error! domain=' . $domain);
}
return $result;
@@ -403,7 +393,6 @@ public static function getHostByName(string $domain, float $timeout, int $family
* @param string|null $service
*
* @return array
- * @throws SwoftException
*/
public static function getAddrInfo(
string $domain,
@@ -414,7 +403,7 @@ public static function getAddrInfo(
): array {
$result = Coroutine::getaddrinfo($domain, $family, $socktype, $protocol, $service);
if ($result === false) {
- throw new SwoftException('GetAddrInfo error! domain=' . $domain);
+ throw new RuntimeException('GetAddrInfo error! domain=' . $domain);
}
return $result;
@@ -424,13 +413,13 @@ public static function getAddrInfo(
* @param string $cmd
*
* @return array
- * @throws SwoftException
+ * @throws RuntimeException
*/
public static function exec(string $cmd): array
{
$result = Coroutine::exec($cmd);
if ($result === false) {
- throw new SwoftException('Exec error! command=' . $cmd);
+ throw new RuntimeException('Exec error! command=' . $cmd);
}
return $result;
@@ -440,13 +429,13 @@ public static function exec(string $cmd): array
* @param string $path
*
* @return array
- * @throws SwoftException
+ * @throws RuntimeException
*/
public static function statVfs(string $path): array
{
$result = Coroutine::statvfs($path);
if ($result === false) {
- throw new SwoftException('StatVfs error! path=' . $path);
+ throw new RuntimeException('StatVfs error! path=' . $path);
}
return $result;
diff --git a/src/framework/src/Concern/AbstractDispatcher.php b/src/framework/src/Concern/AbstractDispatcher.php
index 87cb2e844..78ffcf68c 100644
--- a/src/framework/src/Concern/AbstractDispatcher.php
+++ b/src/framework/src/Concern/AbstractDispatcher.php
@@ -7,6 +7,7 @@
/**
* Class AbstractDispatcher
+ *
* @since 2.0
*/
abstract class AbstractDispatcher implements DispatcherInterface
@@ -57,8 +58,7 @@ public function init(): void
*/
public function requestMiddleware(): array
{
- return $this->middlewares ?
- array_merge($this->preMiddlewares, $this->middlewares, $this->afterMiddlewares) :
+ return $this->middlewares ? array_merge($this->preMiddlewares, $this->middlewares, $this->afterMiddlewares) :
array_merge($this->preMiddlewares, $this->afterMiddlewares);
}
diff --git a/src/framework/src/Concern/AbstractMiddlewareChain.php b/src/framework/src/Concern/AbstractMiddlewareChain.php
index 3002eaacf..6c8cb2aa7 100644
--- a/src/framework/src/Concern/AbstractMiddlewareChain.php
+++ b/src/framework/src/Concern/AbstractMiddlewareChain.php
@@ -40,7 +40,7 @@ public function use(...$middles): void
* Add middleware
* This method prepends new middleware to the application middleware stack.
*
- * @param array ...$middles Any callable that accepts two arguments:
+ * @param array ...$middles Any callable that accepts two arguments:
* 1. A Request object
* 2. A Handler object
*
diff --git a/src/framework/src/Concern/AbstractSessionManager.php b/src/framework/src/Concern/AbstractSessionManager.php
new file mode 100644
index 000000000..a999f43d3
--- /dev/null
+++ b/src/framework/src/Concern/AbstractSessionManager.php
@@ -0,0 +1,182 @@
+storage property is not empty.
+ if (!$this->storage) {
+ $this->storage = new ArrayStorage();
+ }
+ }
+
+ /**
+ * @param string $sessionId
+ *
+ * @return string eg: "wsMyHost:23"
+ */
+ public function genKey(string $sessionId): string
+ {
+ $hostname = gethostname();
+
+ return $this->prefix . $hostname . ':' . $sessionId;
+ }
+
+ /**
+ * @param string $sessionId
+ *
+ * @return bool
+ */
+ public function has(string $sessionId): bool
+ {
+ if (Session::has($sessionId)) {
+ return true;
+ }
+
+ $sessKey = $this->genKey($sessionId);
+
+ return $this->storage->exists($sessKey);
+ }
+
+ /**
+ * @param string $sessionId The session Id. eg: swoole.fd, http session id
+ * @param SessionInterface $session
+ *
+ * @return bool
+ */
+ public function set(string $sessionId, SessionInterface $session): bool
+ {
+ // Cache to Session::class
+ Session::set($sessionId, $session);
+
+ $sessKey = $this->genKey($sessionId);
+
+ return $this->storage->write($sessKey, $session->toString());
+ }
+
+ /**
+ * @param string $sessionId The session Id. eg: swoole.fd, http session id
+ *
+ * @return SessionInterface|null
+ */
+ public function get(string $sessionId): ?SessionInterface
+ {
+ // Read from caches
+ if ($sess = Session::get($sessionId)) {
+ return $sess;
+ }
+
+ // Read from storage
+ $sessionKey = $this->genKey($sessionId);
+ $sessionData = $this->storage->read($sessionKey);
+
+ if ($sessionData) {
+ $sess = $this->restoreSession($sessionData);
+
+ // Cache to memory
+ Session::set($sessionId, $sess);
+ return $sess;
+ }
+
+ return null;
+ }
+
+ /**
+ * @param string $sessionData
+ *
+ * @return SessionInterface
+ */
+ abstract protected function restoreSession(string $sessionData): SessionInterface;
+
+ /**
+ * @return SessionInterface
+ */
+ public function current(): SessionInterface
+ {
+ $sessionId = Session::getBoundedSid();
+
+ return $this->mustGet($sessionId);
+ }
+
+ /**
+ * @param string $sessionId
+ *
+ * @return SessionInterface
+ */
+ public function mustGet(string $sessionId): SessionInterface
+ {
+ if ($session = $this->get($sessionId)) {
+ return $session;
+ }
+
+ // throw new UnexpectedValueException('The session is not exists! sessionId is ' . $sessionId);
+ throw new SessionException('session information has been lost of the SID: ' . $sessionId);
+ }
+
+ /**
+ * @param string $sessionId
+ *
+ * @return bool
+ */
+ public function destroy(string $sessionId): bool
+ {
+ Session::destroy($sessionId);
+
+ $sessKey = $this->genKey($sessionId);
+
+ return $this->storage->destroy($sessKey);
+ }
+
+ /**
+ * @return bool
+ */
+ public function clear(): bool
+ {
+ return $this->storage->clear();
+ }
+
+ /**
+ * @return SessionStorageInterface
+ */
+ public function getStorage(): SessionStorageInterface
+ {
+ return $this->storage;
+ }
+
+ /**
+ * @param SessionStorageInterface $storage
+ */
+ public function setStorage(SessionStorageInterface $storage): void
+ {
+ $this->storage = $storage;
+ }
+}
diff --git a/src/framework/src/Concern/DataPropertyTrait.php b/src/framework/src/Concern/DataPropertyTrait.php
index 2e5e96d30..d7e514c2f 100644
--- a/src/framework/src/Concern/DataPropertyTrait.php
+++ b/src/framework/src/Concern/DataPropertyTrait.php
@@ -7,7 +7,7 @@
/**
* Trait DataPropertyTrait
*
- * @since 2.0
+ * @since 2.0
* @deprecated please use Swoft\Stdlib\Concern\DataPropertyTrait instead.
*/
trait DataPropertyTrait
diff --git a/src/framework/src/Concern/PathAliasTrait.php b/src/framework/src/Concern/PathAliasTrait.php
index bd99b1d13..bd11d7784 100644
--- a/src/framework/src/Concern/PathAliasTrait.php
+++ b/src/framework/src/Concern/PathAliasTrait.php
@@ -14,7 +14,7 @@
trait PathAliasTrait
{
/**
- * Aliases
+ * Path aliases
*
* @var array
*/
@@ -39,7 +39,6 @@ public static function setAliases(array $aliases): void
* @param string $path
*
* @return void
- * @throws InvalidArgumentException
*/
public static function setAlias(string $alias, string $path = ''): void
{
@@ -82,7 +81,6 @@ public static function setAlias(string $alias, string $path = ''): void
* @param string $alias
*
* @return string
- * @throws InvalidArgumentException
*/
public static function getAlias(string $alias): string
{
@@ -97,7 +95,7 @@ public static function getAlias(string $alias): string
[$root] = explode('/', $alias, 2);
if (!isset(self::$aliases[$root])) {
- throw new InvalidArgumentException('The set root alias does not exist,alias=' . $root);
+ throw new InvalidArgumentException('The alias does not exist,alias=' . $root);
}
$rootPath = self::$aliases[$root];
diff --git a/src/framework/src/Concern/SwoftTrait.php b/src/framework/src/Concern/SwoftTrait.php
index 25906e82b..8add7b7ba 100644
--- a/src/framework/src/Concern/SwoftTrait.php
+++ b/src/framework/src/Concern/SwoftTrait.php
@@ -4,6 +4,7 @@
/**
* Trait SwoftTrait
+ *
* @since 2.0
*/
trait SwoftTrait
diff --git a/src/framework/src/Context/AbstractContext.php b/src/framework/src/Context/AbstractContext.php
index c616140f5..1d136007a 100644
--- a/src/framework/src/Context/AbstractContext.php
+++ b/src/framework/src/Context/AbstractContext.php
@@ -2,8 +2,8 @@
namespace Swoft\Context;
-use Swoft\Stdlib\Concern\DataPropertyTrait;
use Swoft\Contract\ContextInterface;
+use Swoft\Stdlib\Concern\DataPropertyTrait;
/**
* Class AbstractContext
diff --git a/src/framework/src/Contract/ContextInterface.php b/src/framework/src/Contract/ContextInterface.php
index b68ce8341..64e1b63f1 100644
--- a/src/framework/src/Contract/ContextInterface.php
+++ b/src/framework/src/Contract/ContextInterface.php
@@ -33,16 +33,20 @@ public function get(string $key, $default = null);
*
* @param string $key
* @param mixed $value
+ *
+ * @return bool
*/
- public function set(string $key, $value): void;
+ public function set(string $key, $value): bool;
/**
* Set multi value to context
*
* @param array $map
* [key => value]
+ *
+ * @return bool
*/
- public function setMulti(array $map): void;
+ public function setMulti(array $map): bool;
/**
* Unset key
diff --git a/src/framework/src/Contract/RouterInterface.php b/src/framework/src/Contract/RouterInterface.php
index b86d22f33..c4a148ef8 100644
--- a/src/framework/src/Contract/RouterInterface.php
+++ b/src/framework/src/Contract/RouterInterface.php
@@ -4,6 +4,7 @@
/**
* Interface RouterInterface - base interface for service router
+ *
* @since 2.0
*/
interface RouterInterface
@@ -11,7 +12,7 @@ interface RouterInterface
/**
* Found route
*/
- public const FOUND = 1;
+ public const FOUND = 1;
/**
* Not found
diff --git a/src/framework/src/Contract/SessionInterface.php b/src/framework/src/Contract/SessionInterface.php
index 79b55ebf8..fcc79f65b 100644
--- a/src/framework/src/Contract/SessionInterface.php
+++ b/src/framework/src/Contract/SessionInterface.php
@@ -12,6 +12,13 @@
*/
interface SessionInterface extends Arrayable, JsonSerializable
{
+ /**
+ * @param array $metadata
+ *
+ * @return static
+ */
+ public static function newFromArray(array $metadata): self;
+
/**
* Check if an item exists in an array using "dot" notation.
*
@@ -36,16 +43,20 @@ public function get(string $key, $default = null);
*
* @param string $key
* @param mixed $value
+ *
+ * @return bool
*/
- public function set(string $key, $value): void;
+ public function set(string $key, $value): bool;
/**
* Set multi value to context
*
* @param array $map
* [key => value]
+ *
+ * @return bool
*/
- public function setMulti(array $map): void;
+ public function setMulti(array $map): bool;
/**
* Clear resource
diff --git a/src/framework/src/Contract/SessionStorageInterface.php b/src/framework/src/Contract/SessionStorageInterface.php
new file mode 100644
index 000000000..d00a14be8
--- /dev/null
+++ b/src/framework/src/Contract/SessionStorageInterface.php
@@ -0,0 +1,64 @@
+validate($data, $validatorName, $fields, $userValidators);
+ return $validator->validate($data, $validatorName, $fields, $userValidators, $unfields);
}
}
diff --git a/src/framework/src/Listener/AfterTimerAfterListener.php b/src/framework/src/Listener/AfterTimerAfterListener.php
index f5e33f1be..7e092824b 100644
--- a/src/framework/src/Listener/AfterTimerAfterListener.php
+++ b/src/framework/src/Listener/AfterTimerAfterListener.php
@@ -3,10 +3,10 @@
namespace Swoft\Listener;
use Swoft;
+use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\SwoftEvent;
-use Swoft\Event\Annotation\Mapping\Listener;
/**
* Class AfterTimerAfterListener
diff --git a/src/framework/src/Listener/AfterTimerTickListener.php b/src/framework/src/Listener/AfterTimerTickListener.php
index fc7a37e01..a9ee742e2 100644
--- a/src/framework/src/Listener/AfterTimerTickListener.php
+++ b/src/framework/src/Listener/AfterTimerTickListener.php
@@ -3,10 +3,10 @@
namespace Swoft\Listener;
use Swoft;
+use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\SwoftEvent;
-use Swoft\Event\Annotation\Mapping\Listener;
/**
* Class AfterTimerTickListener
diff --git a/src/framework/src/Listener/ManagerStartListener.php b/src/framework/src/Listener/ManagerStartListener.php
index cceca6ff5..fc310a6ee 100644
--- a/src/framework/src/Listener/ManagerStartListener.php
+++ b/src/framework/src/Listener/ManagerStartListener.php
@@ -25,10 +25,7 @@ public function handle(EventInterface $event): void
{
$server = $event->coServer;
- Console::writef(
- 'Server start success (Master PID: %d, Manager PID: %d)',
- $server->master_pid,
- $server->manager_pid
- );
+ Console::writef('Server start success (Master PID: %d, Manager PID: %d)',
+ $server->master_pid, $server->manager_pid);
}
}
diff --git a/src/framework/src/Listener/MasterStartListener.php b/src/framework/src/Listener/MasterStartListener.php
index f5ee06593..78d03d28e 100644
--- a/src/framework/src/Listener/MasterStartListener.php
+++ b/src/framework/src/Listener/MasterStartListener.php
@@ -7,9 +7,9 @@
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
use Swoft\Server\Event\ServerStartEvent;
+use Swoft\Server\SwooleEvent;
use Swoft\Stdlib\Helper\Sys;
use Swoole\Process;
-use Swoft\Server\SwooleEvent;
/**
* Class MasterStartListener
diff --git a/src/framework/src/Listener/SessionCompleteListener.php b/src/framework/src/Listener/SessionCompleteListener.php
index c8054c361..4ea14deeb 100644
--- a/src/framework/src/Listener/SessionCompleteListener.php
+++ b/src/framework/src/Listener/SessionCompleteListener.php
@@ -10,6 +10,7 @@
/**
* Class SessionCompleteListener
+ *
* @Listener(SwoftEvent::SESSION_COMPLETE)
*/
class SessionCompleteListener implements EventHandlerInterface
diff --git a/src/framework/src/Processor/AnnotationProcessor.php b/src/framework/src/Processor/AnnotationProcessor.php
index 6afb3c02a..32938ca76 100644
--- a/src/framework/src/Processor/AnnotationProcessor.php
+++ b/src/framework/src/Processor/AnnotationProcessor.php
@@ -9,6 +9,7 @@
/**
* Annotation processor
+ *
* @since 2.0
*/
class AnnotationProcessor extends Processor
@@ -35,17 +36,13 @@ public function handle(): bool
'notifyHandler' => [$this, 'notifyHandle'],
// TODO force load framework components: bean, error, event, aop
'disabledAutoLoaders' => $app->getDisabledAutoLoaders(),
- 'disabledPsr4Prefixes' => $app->getDisabledPsr4Prefixes(),
+ 'excludedPsr4Prefixes' => $app->getDisabledPsr4Prefixes(),
]);
$stats = AnnotationRegister::getClassStats();
- CLog::info(
- 'Annotations is scanned(autoloader %d, annotation %d, parser %d)',
- $stats['autoloader'],
- $stats['annotation'],
- $stats['parser']
- );
+ CLog::info('Annotations is scanned(autoloader %d, annotation %d, parser %d)', $stats['autoloader'],
+ $stats['annotation'], $stats['parser']);
return $this->application->afterAnnotation();
}
@@ -53,6 +50,7 @@ public function handle(): bool
/**
* @param string $type
* @param string $target
+ *
* @see \Swoft\Annotation\Resource\AnnotationResource::load()
*/
public function notifyHandle(string $type, $target): void
diff --git a/src/framework/src/Processor/ApplicationProcessor.php b/src/framework/src/Processor/ApplicationProcessor.php
index e62fcf0bf..d8f68fd63 100644
--- a/src/framework/src/Processor/ApplicationProcessor.php
+++ b/src/framework/src/Processor/ApplicationProcessor.php
@@ -7,6 +7,7 @@
/**
* Application processor
+ *
* @since 2.0
*/
class ApplicationProcessor extends Processor
@@ -41,6 +42,7 @@ public function handle(): bool
* Add first processor
*
* @param Processor[] $processor
+ *
* @return bool
*/
public function addFirstProcessor(Processor ...$processor): bool
diff --git a/src/framework/src/Processor/ConsoleProcessor.php b/src/framework/src/Processor/ConsoleProcessor.php
index 044803101..87bbde2ef 100644
--- a/src/framework/src/Processor/ConsoleProcessor.php
+++ b/src/framework/src/Processor/ConsoleProcessor.php
@@ -10,6 +10,7 @@
/**
* Console processor
+ *
* @since 2.0
*/
class ConsoleProcessor extends Processor
@@ -32,11 +33,7 @@ public function handle(): bool
// Register console routes
CommandRegister::register($router);
- CLog::info(
- 'Console command route registered (group %d, command %d)',
- $router->groupCount(),
- $router->count()
- );
+ CLog::info('Console command route registered (group %d, command %d)', $router->groupCount(), $router->count());
// Run console application
bean('cliApp')->run();
diff --git a/src/framework/src/Processor/EnvProcessor.php b/src/framework/src/Processor/EnvProcessor.php
index 435d5eba5..288820be9 100644
--- a/src/framework/src/Processor/EnvProcessor.php
+++ b/src/framework/src/Processor/EnvProcessor.php
@@ -2,16 +2,18 @@
namespace Swoft\Processor;
+use Dotenv\Dotenv;
use Dotenv\Environment\Adapter\EnvConstAdapter;
use Dotenv\Environment\Adapter\PutenvAdapter;
use Dotenv\Environment\Adapter\ServerConstAdapter;
use Dotenv\Environment\DotenvFactory;
-use Dotenv\Dotenv;
+use Swoft;
use Swoft\Log\Helper\CLog;
-use function alias;
+use Swoft\Stdlib\Helper\Str;
use function basename;
use function dirname;
use function file_exists;
+use const IN_PHAR;
/**
* Env processor
@@ -32,23 +34,29 @@ public function handle(): bool
return false;
}
- $envFile = alias($this->application->getEnvFile());
- $path = dirname($envFile);
- $name = basename($envFile);
+ $envFile = Swoft::getAlias($this->application->getEnvFile());
+
+ // Fix: In phar package, remove phar:// prefix
+ if (IN_PHAR) {
+ $envFile = Str::rmPharPrefix($envFile);
+ }
if (!file_exists($envFile)) {
CLog::warning('Env file(%s) is not exist! skip load it', $envFile);
- return true;
+ return $this->application->afterEnv();
}
- // Load env
+ // Load env info
$factory = new DotenvFactory([
new EnvConstAdapter,
new PutenvAdapter,
new ServerConstAdapter
]);
- Dotenv::create($path, $name, $factory)->load();
+ $path = dirname($envFile);
+ $name = basename($envFile);
+
+ Dotenv::create($path, $name, $factory)->overload();
CLog::info('Env file(%s) is loaded', $envFile);
return $this->application->afterEnv();
diff --git a/src/framework/src/Processor/EventProcessor.php b/src/framework/src/Processor/EventProcessor.php
index d07c4e3ca..4b0d44c00 100644
--- a/src/framework/src/Processor/EventProcessor.php
+++ b/src/framework/src/Processor/EventProcessor.php
@@ -11,12 +11,14 @@
/**
* Event processor
+ *
* @since 2.0
*/
class EventProcessor extends Processor
{
/**
* Handle event register
+ *
* @return bool
*/
public function handle(): bool
diff --git a/src/framework/src/Processor/Processor.php b/src/framework/src/Processor/Processor.php
index 79d763235..3fa3ba761 100644
--- a/src/framework/src/Processor/Processor.php
+++ b/src/framework/src/Processor/Processor.php
@@ -7,6 +7,7 @@
/**
* Abstract processor
+ *
* @since 2.0
*/
abstract class Processor implements ProcessorInterface
diff --git a/src/framework/src/Processor/ProcessorInterface.php b/src/framework/src/Processor/ProcessorInterface.php
index 476f769a5..a2f848d27 100644
--- a/src/framework/src/Processor/ProcessorInterface.php
+++ b/src/framework/src/Processor/ProcessorInterface.php
@@ -4,6 +4,7 @@
/**
* Processor interface
+ *
* @since 2.0
*/
interface ProcessorInterface
diff --git a/src/framework/src/Session/ArrayStorage.php b/src/framework/src/Session/ArrayStorage.php
new file mode 100644
index 000000000..d400fe92d
--- /dev/null
+++ b/src/framework/src/Session/ArrayStorage.php
@@ -0,0 +1,99 @@
+ session data, ...]
+ *
+ * @var array
+ */
+ private $map = [];
+
+ /**
+ * Read session data
+ *
+ * @param string $sessionId The session id to read data for.
+ *
+ * @return string
+ * Returns an encoded string of the read data.
+ * If nothing was read, it must return an empty string.
+ * Note this value is returned internally to PHP for processing.
+ */
+ public function read(string $sessionId): string
+ {
+ return $this->map[$sessionId] ?? '';
+ }
+
+ /**
+ * Write session data
+ *
+ * @param string $sessionId The session id.
+ * @param string $sessionData The encoded session data. This data is a serialized
+ * string and passing it as this parameter.
+ * Please note sessions use an alternative serialization method.
+ *
+ * @return bool
+ * The return value (usually TRUE on success, FALSE on failure).
+ * Note this value is returned internally to PHP for processing.
+ */
+ public function write(string $sessionId, string $sessionData): bool
+ {
+ $this->map[$sessionId] = $sessionData;
+
+ return true;
+ }
+
+ /**
+ * Destroy a session
+ *
+ * @param string $sessionId The session ID being destroyed.
+ *
+ * @return bool
+ * The return value (usually TRUE on success, FALSE on failure).
+ * Note this value is returned internally to PHP for processing.
+ */
+ public function destroy(string $sessionId): bool
+ {
+ if (isset($this->map[$sessionId])) {
+ unset($this->map[$sessionId]);
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Whether the session exists
+ *
+ * @param string $sessionId
+ *
+ * @return bool
+ */
+ public function exists(string $sessionId): bool
+ {
+ return isset($this->map[$sessionId]);
+ }
+
+ /**
+ * Clear all session
+ *
+ * @return bool
+ */
+ public function clear(): bool
+ {
+ $this->map = [];
+ return true;
+ }
+}
diff --git a/src/framework/src/Session/Session.php b/src/framework/src/Session/Session.php
index 351ae22fa..4984ac3a5 100644
--- a/src/framework/src/Session/Session.php
+++ b/src/framework/src/Session/Session.php
@@ -22,7 +22,9 @@ class Session
private static $idMap = [];
/**
- * Session connection list
+ * Activity ws/tcp session connection list.
+ *
+ * NOTICE: storage data will lost of on worker reload.
*
* @var SessionInterface[]
*
@@ -101,6 +103,7 @@ public static function has(string $sid): bool
* Get session by FD
*
* @param string $sid If not specified, return the current corresponding session
+ *
* @return SessionInterface|Connection
*/
public static function get(string $sid = ''): ?SessionInterface
@@ -129,6 +132,7 @@ public static function current(): SessionInterface
* Get connection by FD. if not found will throw exception.
*
* @param string $sid
+ *
* @return SessionInterface|Connection
*/
public static function mustGet(string $sid = ''): SessionInterface
diff --git a/src/framework/src/Session/SwooleStorage.php b/src/framework/src/Session/SwooleStorage.php
new file mode 100644
index 000000000..8509310fa
--- /dev/null
+++ b/src/framework/src/Session/SwooleStorage.php
@@ -0,0 +1,179 @@
+create();
+ }
+
+ /**
+ * destroy swoole table on exist
+ */
+ public function __destruct()
+ {
+ $this->db->destroy();
+ }
+
+ /**
+ * create table
+ */
+ public function create(): void
+ {
+ $this->db = new Table($this->tableSize);
+
+ // add columns
+ $this->db->column(self::KEY_FIELD, Table::TYPE_STRING, 48);
+ $this->db->column(self::VAL_FIELD, Table::TYPE_STRING, $this->valueSize);
+
+ // Create it
+ $this->db->create();
+ }
+
+ /**
+ * Read session data
+ *
+ * @param string $storageKey The session id to read data for.
+ *
+ * @return string
+ * Returns an encoded string of the read data.
+ * If nothing was read, it must return an empty string.
+ * Note this value is returned internally to PHP for processing.
+ */
+ public function read(string $storageKey): string
+ {
+ if ($data = $this->db->get($storageKey, self::VAL_FIELD)) {
+ return $data;
+ }
+
+ return '';
+ }
+
+ /**
+ * Write session data
+ *
+ * @param string $storageKey The session id.
+ * @param string $sessionData The encoded session data. This data is a serialized
+ * string and passing it as this parameter.
+ *
+ * @return bool
+ * The return value (usually TRUE on success, FALSE on failure).
+ * Note this value is returned internally to PHP for processing.
+ */
+ public function write(string $storageKey, string $sessionData): bool
+ {
+ return $this->db->set($storageKey, [
+ self::KEY_FIELD => $storageKey,
+ self::VAL_FIELD => $sessionData,
+ ]);
+ }
+
+ /**
+ * Destroy a session
+ *
+ * @param string $storageKey The session ID being destroyed.
+ *
+ * @return bool
+ * The return value (usually TRUE on success, FALSE on failure).
+ * Note this value is returned internally to PHP for processing.
+ */
+ public function destroy(string $storageKey): bool
+ {
+ return $this->db->del($storageKey);
+ }
+
+ /**
+ * Whether the session exists
+ *
+ * @param string $storageKey
+ *
+ * @return bool
+ */
+ public function exists(string $storageKey): bool
+ {
+ return $this->db->exist($storageKey);
+ }
+
+ /**
+ * clear table data
+ */
+ public function clear(): bool
+ {
+ foreach ($this->db as $row) {
+ $this->db->del($row[self::KEY_FIELD]);
+ }
+
+ return true;
+ }
+
+ /**
+ * @return Table
+ */
+ public function getDb(): Table
+ {
+ return $this->db;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTableSize(): int
+ {
+ return $this->tableSize;
+ }
+
+ /**
+ * @param int $tableSize
+ */
+ public function setTableSize(int $tableSize): void
+ {
+ $this->tableSize = $tableSize;
+ }
+
+ /**
+ * @return int
+ */
+ public function getValueSize(): int
+ {
+ return $this->valueSize;
+ }
+
+ /**
+ * @param int $valueSize
+ */
+ public function setValueSize(int $valueSize): void
+ {
+ $this->valueSize = $valueSize;
+ }
+}
diff --git a/src/framework/src/Swoft.php b/src/framework/src/Swoft.php
index 0aa68f9dc..f250c53a0 100644
--- a/src/framework/src/Swoft.php
+++ b/src/framework/src/Swoft.php
@@ -120,11 +120,11 @@ public static function getBean(string $name)
}
/**
- * @see Container::getSingleton()
- *
* @param string $name
*
* @return mixed
+ * @see Container::getSingleton()
+ *
*/
public static function getSingleton(string $name)
{
diff --git a/src/framework/src/SwoftApplication.php b/src/framework/src/SwoftApplication.php
index 3417a0719..3a0f4c3b2 100644
--- a/src/framework/src/SwoftApplication.php
+++ b/src/framework/src/SwoftApplication.php
@@ -8,6 +8,7 @@
use Swoft\Contract\ApplicationInterface;
use Swoft\Contract\SwoftInterface;
use Swoft\Helper\SwoftHelper;
+use Swoft\Log\Helper\CLog;
use Swoft\Processor\AnnotationProcessor;
use Swoft\Processor\ApplicationProcessor;
use Swoft\Processor\BeanProcessor;
@@ -21,12 +22,12 @@
use Swoft\Stdlib\Helper\FSHelper;
use Swoft\Stdlib\Helper\ObjectHelper;
use Swoft\Stdlib\Helper\Str;
-use Swoft\Log\Helper\CLog;
use Throwable;
use function define;
use function defined;
use function dirname;
use function get_class;
+use function sprintf;
use const IN_PHAR;
/**
@@ -125,6 +126,7 @@ class SwoftApplication implements SwoftInterface, ApplicationInterface
/**
* Get the application version
+ *
* @return string
*/
public static function getVersion(): string
@@ -220,7 +222,7 @@ public function run(): void
$this->processor->handle();
} catch (Throwable $e) {
- CLog::error('%s(code:%d) %s', get_class($e), $e->getCode(), $e->getMessage());
+ Console::colored(sprintf('%s(code:%d) %s', get_class($e), $e->getCode(), $e->getMessage()), 'red');
Console::colored('Code Trace:', 'comment');
echo $e->getTraceAsString(), "\n";
}
@@ -228,6 +230,7 @@ public function run(): void
/**
* @noinspection PhpDocSignatureInspection
+ *
* @param string[] ...$classes
*/
public function disableAutoLoader(string ...$classes)
@@ -239,6 +242,7 @@ public function disableAutoLoader(string ...$classes)
/**
* @noinspection PhpDocSignatureInspection
+ *
* @param string ...$classes
*/
public function disableProcessor(string ...$classes)
diff --git a/src/framework/src/SwoftComponent.php b/src/framework/src/SwoftComponent.php
index 2cf2a6843..e3200f545 100644
--- a/src/framework/src/SwoftComponent.php
+++ b/src/framework/src/SwoftComponent.php
@@ -32,6 +32,7 @@ abstract class SwoftComponent implements ComponentInterface
* 'description' => 'description for the component',
* 'homepage' => 'https://github.com/inhere/some-component',
* ]
+ *
* @var array
*/
private $metadata;
diff --git a/src/framework/src/SwoftEvent.php b/src/framework/src/SwoftEvent.php
index 493411db6..85fbe0052 100644
--- a/src/framework/src/SwoftEvent.php
+++ b/src/framework/src/SwoftEvent.php
@@ -4,6 +4,7 @@
/**
* Class SwoftEvent
+ *
* @since 2.0
*/
final class SwoftEvent
diff --git a/src/framework/src/Timer.php b/src/framework/src/Timer.php
index 64740e102..e139c4c4a 100644
--- a/src/framework/src/Timer.php
+++ b/src/framework/src/Timer.php
@@ -17,9 +17,9 @@
class Timer
{
/**
- * @param int $msec
+ * @param int $msec
* @param array|callable $callback
- * @param array ...$params
+ * @param array ...$params
*
* @return int
*/
@@ -47,9 +47,9 @@ public static function tick(int $msec, $callback, ...$params): int
}
/**
- * @param int $msec
+ * @param int $msec
* @param array|callable $callback
- * @param array ...$params
+ * @param array ...$params
*
* @return int
*/
@@ -125,7 +125,7 @@ public static function stats(): array
*/
private static function getLogItems(): array
{
- $data = [];
+ $data = [];
$items = Log::getLogger()->getItems();
foreach ($items as $item) {
diff --git a/src/framework/test/testing/Concern/CommonTestAssertTrait.php b/src/framework/test/testing/Concern/CommonTestAssertTrait.php
index 3194453d1..151c42630 100644
--- a/src/framework/test/testing/Concern/CommonTestAssertTrait.php
+++ b/src/framework/test/testing/Concern/CommonTestAssertTrait.php
@@ -2,7 +2,9 @@
namespace SwoftTest\Testing\Concern;
+use Closure;
use PHPUnit\Framework\Assert;
+use Throwable;
use function in_array;
use function strpos;
@@ -21,7 +23,7 @@ public function assertContainString(string $haystack, string $needle): void
{
$exist = strpos($haystack, $needle) !== false;
- Assert::assertTrue($exist);
+ Assert::assertTrue($exist, "Failed asserting that \"$haystack\" contains \"$needle\"");
}
/**
@@ -45,4 +47,78 @@ public function assertArrayNotContainValue(array $haystack, $needle): void
Assert::assertFalse($exist);
}
+
+ /**
+ * Usage:
+ *
+ * $this->assetException(function() use($object) {
+ * $object->someMethod();
+ * }, XXException::class);
+ *
+ * @param Closure $closure
+ * @param string $wantErrClass
+ * @param string $wantErrMsg
+ * @param int $wantErrCode
+ */
+ public function assetException(
+ Closure $closure,
+ string $wantErrClass,
+ string $wantErrMsg = '',
+ int $wantErrCode = 0
+ ): void {
+ $e = null;
+ try {
+ $closure();
+ } catch (Throwable $e) {
+ }
+
+ Assert::assertNotNull($e);
+
+ if ($wantErrClass) {
+ /** @var Throwable $e */
+ Assert::assertSame($wantErrClass, get_class($e));
+ }
+
+ if ($wantErrMsg) {
+ Assert::assertSame($wantErrMsg, $e->getMessage());
+ }
+
+ if ($wantErrCode) {
+ Assert::assertSame($wantErrCode, $e->getCode());
+ }
+ }
+
+ /**
+ * @param Closure $closure
+ * @param string $wantErrMsg
+ */
+ public function assetExceptionWithMessage(Closure $closure, string $wantErrMsg): void
+ {
+ $this->assetException($closure, '', $wantErrMsg);
+ }
+
+ /**
+ * @param Closure $closure
+ * @param int $wantCode
+ */
+ public function assetExceptionWithCode(Closure $closure, int $wantCode): void
+ {
+ $this->assetException($closure, '', '', $wantCode);
+ }
+
+ /**
+ * @param Closure $closure
+ * @param string $needle
+ */
+ public function assetExceptionContainMessage(Closure $closure, string $needle): void
+ {
+ $e = null;
+ try {
+ $closure();
+ } catch (Throwable $e) {
+ }
+
+ Assert::assertNotNull($e);
+ $this->assertContainString($e->getMessage(), $needle);
+ }
}
diff --git a/src/framework/test/testing/ConsoleProcessor.php b/src/framework/test/testing/ConsoleProcessor.php
new file mode 100644
index 000000000..8a589d2d0
--- /dev/null
+++ b/src/framework/test/testing/ConsoleProcessor.php
@@ -0,0 +1,45 @@
+application->beforeConsole()) {
+ return false;
+ }
+
+ /** @var Router $router */
+ $router = bean('cliRouter');
+
+ // Register console routes
+ CommandRegister::register($router);
+
+ CLog::info('Console command route registered (group %d, command %d)', $router->groupCount(), $router->count());
+
+ // Run console application
+ // Dont run on unit tests
+ // bean('cliApp')->run();
+
+ return $this->application->afterConsole();
+ }
+}
diff --git a/src/tcp-server/test/testing/TempArray.php b/src/framework/test/testing/TempArray.php
similarity index 79%
rename from src/tcp-server/test/testing/TempArray.php
rename to src/framework/test/testing/TempArray.php
index c07dac799..1ccd1a040 100644
--- a/src/tcp-server/test/testing/TempArray.php
+++ b/src/framework/test/testing/TempArray.php
@@ -1,6 +1,6 @@
assertEquals($this->create, $current);
}
- /**
- * @throws SwoftException
- */
public function testFile(): void
{
$data = 'datas1tring';
@@ -71,16 +67,13 @@ public function testFile(): void
Co::exec('rm -rf ' . $fileName);
}
- /**
- * @throws SwoftException
- */
public function testGetHostByName(): void
{
- $ip = '39.106.56.0';
- $result = Co::getHostByName('www.swoft.org', 2);
+ $ip = '193.187.118.225';
+ $result = Co::getHostByName('www.swoft.io', 2);
$this->assertEquals($result, $ip);
- $result = Co::getAddrInfo('www.swoft.org');
+ $result = Co::getAddrInfo('www.swoft.io');
$this->assertEquals($result, [$ip]);
}
}
diff --git a/src/framework/test/unit/Helper/FunctionsTest.php b/src/framework/test/unit/Helper/FunctionsTest.php
new file mode 100644
index 000000000..500a0391f
--- /dev/null
+++ b/src/framework/test/unit/Helper/FunctionsTest.php
@@ -0,0 +1,72 @@
+assertSame('/php/home', env('TEST_PHP_HOME'));
+ $this->assertNotEmpty(env());
+
+ $tests = [
+ // bool: true
+ 'on' => true,
+ 'yes' => true,
+ 'true' => true,
+ '(true)' => true,
+ // bool: false
+ 'off' => false,
+ 'no' => false,
+ 'false' => false,
+ '(false)' => false,
+ // null
+ 'null' => null,
+ '(null)' => null,
+ ];
+ foreach ($tests as $val => $want) {
+ putenv('TEST_PHP_HOME=' . $val);
+ $this->assertSame($want, env('TEST_PHP_HOME'));
+ }
+
+ // unset var
+ putenv('TEST_PHP_HOME');
+ $this->assertNull(env('TEST_PHP_HOME'));
+ $this->assertSame('def', env('TEST_PHP_HOME', 'def'));
+ }
+
+ public function testAlias(): void
+ {
+ $this->assertSame('', alias(''));
+ $this->assertSame('invalid', alias('invalid'));
+
+ $this->assetExceptionWithMessage(function () {
+ alias('@notExist');
+ }, 'The alias does not exist,alias=@notExist');
+
+ $this->assetExceptionContainMessage(function () {
+ alias('@notExist');
+ }, 'alias=@notExist');
+
+ Swoft::setAlias('testAlias', 'alias/value');
+ $this->assertSame('testAlias', alias('testAlias'));
+ $this->assertSame('alias/value', alias('@testAlias'));
+
+ // remove
+ Swoft::setAlias('@testAlias');
+ $this->assetExceptionWithMessage(function () {
+ alias('@testAlias');
+ }, 'The alias does not exist,alias=@testAlias');
+ }
+}
diff --git a/src/framework/test/unit/TimerTest.php b/src/framework/test/unit/TimerTest.php
index 11c03ec5f..46173d028 100644
--- a/src/framework/test/unit/TimerTest.php
+++ b/src/framework/test/unit/TimerTest.php
@@ -5,8 +5,6 @@
use PHPUnit\Framework\TestCase;
-use ReflectionException;
-use Swoft\Bean\Exception\ContainerException;
use Swoft\Co;
use Swoft\Context\Context;
use Swoft\Exception\SwoftException;
diff --git a/src/http-message/composer.json b/src/http-message/composer.json
index 1d1564905..240f13ede 100644
--- a/src/http-message/composer.json
+++ b/src/http-message/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/http-message",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/http-message/src/Concern/MessageTrait.php b/src/http-message/src/Concern/MessageTrait.php
index b7ad61129..66b403fd9 100644
--- a/src/http-message/src/Concern/MessageTrait.php
+++ b/src/http-message/src/Concern/MessageTrait.php
@@ -389,7 +389,7 @@ protected function setHeaders(array $headers): self
protected function initializeHeaders(array $headers): void
{
foreach ($headers as $name => $value) {
- $name = strtolower($name);
+ $name = strtolower((string)$name);
$this->headers[$name] = [$value];
$this->headerNames[$name] = $name;
diff --git a/src/http-server/.github/PULL_REQUEST_TEMPLATE.md b/src/http-server/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..8b742aa30
--- /dev/null
+++ b/src/http-server/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,60 @@
+# PR
+
+- 请不要提交PR到各个组件仓库,它们都是 **只读的**
+- 核心组件的 **开发仓库** 是 **[swoft/swoft-component][core]**
+- 扩展组件的 **开发仓库** 是 **[swoft/swoft-ext][ext]**
+- 请 `fork` 对应的 **开发仓库**,修改后,请把你的PR提交到对应的开发仓库
+
+> 发布版本时官方会将代码同步到各个子仓库。因此,切记不要往子仓库发PR。
+
+## 发起PR时的注意事项
+
+开发组非常欢迎各位向我们提交PR(_Pull Request_),但是为了保证代码质量和统一的风格,
+向官方的主仓库 [swoft/swoft][main] 和 **开发仓库** 贡献代码时需要注意代码和commit格式
+
+### Commit Message
+
+- commit message 只能是英文信息
+- 请尽量保证commit message是有意义的说明
+- 最好以 `add:` `update:` `fix:` 等关键字开头
+
+### 代码风格
+
+- 提交的PHP代码 **必须** 遵循 PSR-2 代码风格
+- 合理且有意义的类、方法、变量命名
+- 适当的注释,合理的使用空行保持代码的简洁,易于阅读
+- 不要包含一些无意义的信息 例如 `@author` 等(_提交者是能够从commit log里看到的_)
+
+------------------
+
+> English Version (_translate by Google_)
+
+The development team welcomes you to submit PR (_Pull Request_) to us, but to ensure code quality and uniform style,
+go to the official main repository [swoft/swoft][main] and Development repository, Note the code and commit format when contributing code
+
+## Precautions when initiating PR
+
+- Please do not submit PR to each sub-repository, they are all read-only
+- The _development repository_ for the core components is **[swoft/swoft-component][core]**
+- The _development repository_ for extension components is **[swoft/swoft-ext][ext]**
+- Please `fork` the corresponding development warehouse. After modification, please submit your PR to the corresponding development warehouse.
+
+> Officially syncs code to individual sub-warehouses when new versions are released
+
+### Commit Message
+
+- the commit message can only be in English
+- Please try to ensure that the commit message is meaningful
+- it is best to start with the keyword `add:` `update:` `fix:`
+
+### Code Style
+
+- Submitted PHP code **Must** Follow PSR-2 code style
+- Reasonable and meaningful class, method, variable naming
+- Appropriate comments, reasonable use of blank lines to keep the code simple and easy to read
+- Don't include some meaningless information such as `@author`, etc. (_author is that can be seen from the commit log_)
+
+
+[main]: https://github.com/swoft-cloud/swoft
+[core]: https://github.com/swoft-cloud/swoft-component
+[ext]: https://github.com/swoft-cloud/swoft-ext
diff --git a/src/http-server/.travis.yml b/src/http-server/.travis.yml
index 35eb61e41..4afb5e7e7 100644
--- a/src/http-server/.travis.yml
+++ b/src/http-server/.travis.yml
@@ -6,7 +6,7 @@ php:
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/http-server/README.md b/src/http-server/README.md
index daca24000..e41152e19 100644
--- a/src/http-server/README.md
+++ b/src/http-server/README.md
@@ -7,6 +7,10 @@
Swoft Http Server Component
+## [中文说明](README.zh-CN.md)
+
+中文说明请查看 [README.zh-CN.md](README.zh-CN.md)
+
## Install
- composer command
diff --git a/src/http-server/README.zh-CN.md b/src/http-server/README.zh-CN.md
new file mode 100644
index 000000000..b699a1b74
--- /dev/null
+++ b/src/http-server/README.zh-CN.md
@@ -0,0 +1,34 @@
+# Swoft Http Server
+
+[![Latest Stable Version](http://img.shields.io/packagist/v/swoft/http-server.svg)](https://packagist.org/packages/swoft/http-server)
+[![Php Version](https://img.shields.io/badge/php-%3E=7.1-brightgreen.svg?maxAge=2592000)](https://secure.php.net/)
+[![Swoft Doc](https://img.shields.io/badge/docs-passing-green.svg?maxAge=2592000)](https://www.swoft.org/docs)
+[![Swoft License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/swoft-cloud/swoft/blob/master/LICENSE)
+
+Swoft Http Server Component
+
+## [ENGLISH](README.md)
+
+English readme please sess [README.md](README.md)
+
+## Install
+
+- composer command
+
+```bash
+composer require swoft/http-server
+```
+
+## Resources
+
+* [Documentation](https://swoft.org/docs)
+* [Contributing](https://github.com/swoft-cloud/swoft/blob/master/CONTRIBUTING.md)
+* [Report Issues][issues] and [Send Pull Requests][pulls] in the [Main Swoft Repository][repository]
+
+[pulls]: https://github.com/swoft-cloud/swoft-component/pulls
+[repository]: https://github.com/swoft-cloud/swoft
+[issues]: https://github.com/swoft-cloud/swoft/issues
+
+## LICENSE
+
+The Component is open-sourced software licensed under the [Apache license](LICENSE).
diff --git a/src/http-server/composer.json b/src/http-server/composer.json
index a09749284..51ebbd98e 100644
--- a/src/http-server/composer.json
+++ b/src/http-server/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/http-server",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/http-server/src/Command/HttpServerCommand.php b/src/http-server/src/Command/HttpServerCommand.php
index 3954d31c1..1d515dfc1 100644
--- a/src/http-server/src/Command/HttpServerCommand.php
+++ b/src/http-server/src/Command/HttpServerCommand.php
@@ -20,8 +20,8 @@
*
* @Command("http", alias="httpsrv", coroutine=false)
* @example
- * {fullCmd}:start Start the http server
- * {fullCmd}:stop Stop the http server
+ * {groupName}:start Start the http server
+ * {groupName}:stop Stop the http server
*/
class HttpServerCommand extends BaseServerCommand
{
diff --git a/src/http-server/src/Exception/MethodNotAllowedException.php b/src/http-server/src/Exception/MethodNotAllowedException.php
index 84c268b33..e70f14e80 100644
--- a/src/http-server/src/Exception/MethodNotAllowedException.php
+++ b/src/http-server/src/Exception/MethodNotAllowedException.php
@@ -3,6 +3,8 @@
namespace Swoft\Http\Server\Exception;
+use Throwable;
+
/**
* Class MethodNotAllowedException
*
@@ -10,5 +12,15 @@
*/
class MethodNotAllowedException extends HttpServerException
{
-
+ /**
+ * Class constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param Throwable|null $previous
+ */
+ public function __construct($message = '', $code = 405, Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
}
diff --git a/src/http-server/src/Exception/NotFoundRouteException.php b/src/http-server/src/Exception/NotFoundRouteException.php
index 776329592..0573433d0 100644
--- a/src/http-server/src/Exception/NotFoundRouteException.php
+++ b/src/http-server/src/Exception/NotFoundRouteException.php
@@ -3,6 +3,8 @@
namespace Swoft\Http\Server\Exception;
+use Throwable;
+
/**
* Class NotFoundRouteException
*
@@ -10,5 +12,15 @@
*/
class NotFoundRouteException extends HttpServerException
{
-
+ /**
+ * Class constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param Throwable|null $previous
+ */
+ public function __construct($message = '', $code = 404, Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
}
diff --git a/src/http-server/src/HttpDispatcher.php b/src/http-server/src/HttpDispatcher.php
index cae844281..edee580fe 100644
--- a/src/http-server/src/HttpDispatcher.php
+++ b/src/http-server/src/HttpDispatcher.php
@@ -146,7 +146,6 @@ private function afterRequest(Response $response): void
* @param Request $request
*
* @return Request
- * @throws SwoftException
*/
private function matchRouter(Request $request): Request
{
diff --git a/src/http-server/src/Middleware/MiddlewareRegister.php b/src/http-server/src/Middleware/MiddlewareRegister.php
index 8f4adda77..20b870b6c 100644
--- a/src/http-server/src/Middleware/MiddlewareRegister.php
+++ b/src/http-server/src/Middleware/MiddlewareRegister.php
@@ -103,7 +103,7 @@ public static function register(): void
$methodMiddlewares = $middlewares['methods'] ?? [];
foreach ($methodMiddlewares as $methodName => $oneMethodMiddlewares) {
- if (!empty($oneMethodMiddlewares) || !empty($oneMethodMiddlewares)) {
+ if (!empty($oneMethodMiddlewares)) {
$allMiddlewares = array_merge($controllerMiddlewares, $oneMethodMiddlewares);
self::$handlerMiddlewares[$className][$methodName] = array_unique($allMiddlewares);
@@ -128,4 +128,4 @@ public static function getMiddlewares(string $className, string $methodName): ar
$middlewares = self::$middlewares[$className]['controller'] ?? [];
return $middlewares;
}
-}
\ No newline at end of file
+}
diff --git a/src/http-server/src/Router/RouteRegister.php b/src/http-server/src/Router/RouteRegister.php
index 7feaa3f67..47a85d217 100644
--- a/src/http-server/src/Router/RouteRegister.php
+++ b/src/http-server/src/Router/RouteRegister.php
@@ -77,7 +77,7 @@ public static function registerRoutes(Router $router): void
$path = $routePath[0] === '/' ? $routePath : $prefix . '/' . $routePath;
$handler = $class . '@' . $route['action'];
- $router->map($route['method'], $path, $handler, $route['params']);
+ $router->map($route['method'], $path, $handler, $route['params'], ['name' => $route['name']]);
}
}
}
diff --git a/src/i18n/.travis.yml b/src/i18n/.travis.yml
index e605c2b1b..198d4bc4b 100644
--- a/src/i18n/.travis.yml
+++ b/src/i18n/.travis.yml
@@ -5,7 +5,7 @@ php:
- 7.2
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
- composer config -g process-timeout 9000 && composer update
diff --git a/src/i18n/composer.json b/src/i18n/composer.json
index 87e48615c..b50a8254c 100644
--- a/src/i18n/composer.json
+++ b/src/i18n/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/i18n",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/log/composer.json b/src/log/composer.json
index 151e1a604..43f566e33 100644
--- a/src/log/composer.json
+++ b/src/log/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/log",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/log/src/Handler/CFileHandler.php b/src/log/src/Handler/CFileHandler.php
index f1dc651bd..b939509f9 100644
--- a/src/log/src/Handler/CFileHandler.php
+++ b/src/log/src/Handler/CFileHandler.php
@@ -3,45 +3,72 @@
namespace Swoft\Log\Handler;
-
-use Monolog\Formatter\FormatterInterface;
-use Monolog\Handler\AbstractProcessingHandler;
+use InvalidArgumentException;
+use Swoft\Bean\BeanFactory;
+use Swoft\Log\Helper\Log;
+use Swoft\Log\Logger;
/**
* Class CFileHandler
*
* @since 2.0
*/
-class CFileHandler extends AbstractProcessingHandler
+class CFileHandler extends FileHandler
{
/**
- * Write log levels
+ * booting console log
*
- * @var string
+ * @var array
*/
- protected $levels = '';
+ private $bootingRecords = [];
/**
- * Write log file
+ * Write console log to file
*
- * @var string
- */
- protected $logFile = '';
-
- /**
* @param array $record
*/
protected function write(array $record): void
{
-// var_dump($record);
- }
+ if (empty($this->logFile)) {
+ return;
+ }
- /**
- * @param FormatterInterface $formatter
- */
- public function setFormatter(FormatterInterface $formatter): void
- {
- $this->formatter = $formatter;
+ // Not boot bean
+ if (false === BeanFactory::hasBean('logger')) {
+ $this->bootingRecords[] = $record;
+ return;
+ }
+
+ $records = [$record];
+
+ // Not init
+ if ($this->logFile[0] === '@') {
+ $this->init();
+
+ $this->bootingRecords[] = $record;
+
+ $records = $this->bootingRecords;
+
+ unset($this->bootingRecords);
+ }
+
+ if (Log::getLogger()->isJson()) {
+ $records = array_map([$this, 'formatJson'], $records);
+ } else {
+ $records = array_column($records, 'formatted');
+ }
+ $messageText = implode("\n", $records) . "\n";
+
+ $logFile = $this->formatFile($this->logFile);
+
+ // Not all console log in coroutine
+ $res = file_put_contents($logFile, $messageText, FILE_APPEND);
+
+ if ($res === false) {
+ throw new InvalidArgumentException(
+ sprintf('Unable to append to log file: %s', $logFile)
+ );
+ }
}
/**
@@ -49,6 +76,9 @@ public function setFormatter(FormatterInterface $formatter): void
*/
public function setLevels(string $levels): void
{
+ $levelNames = explode(',', $levels);
+ $this->levelValues = Logger::getLevelByNames($levelNames);
+
$this->levels = $levels;
}
@@ -59,4 +89,4 @@ public function setLogFile(string $logFile): void
{
$this->logFile = $logFile;
}
-}
\ No newline at end of file
+}
diff --git a/src/log/src/Handler/FileHandler.php b/src/log/src/Handler/FileHandler.php
index 43de452c7..93583eaf3 100644
--- a/src/log/src/Handler/FileHandler.php
+++ b/src/log/src/Handler/FileHandler.php
@@ -99,7 +99,6 @@ protected function write(array $records): void
} else {
$records = array_column($records, 'formatted');
}
-
$messageText = implode("\n", $records) . "\n";
if (Co::id() <= 0) {
@@ -107,7 +106,8 @@ protected function write(array $records): void
}
$logFile = $this->formatFile($this->logFile);
- $res = Co::writeFile($logFile, $messageText, FILE_APPEND);
+ $res = Co::writeFile($logFile, $messageText, FILE_APPEND);
+
if ($res === false) {
throw new InvalidArgumentException(
sprintf('Unable to append to log file: %s', $logFile)
@@ -219,4 +219,4 @@ public function formatFile(string $logFile): string
return $formatFile;
}
-}
\ No newline at end of file
+}
diff --git a/src/log/src/Helper/CLog.php b/src/log/src/Helper/CLog.php
index b4d330e94..40fcf424c 100644
--- a/src/log/src/Helper/CLog.php
+++ b/src/log/src/Helper/CLog.php
@@ -4,10 +4,10 @@
namespace Swoft\Log\Helper;
use Monolog\Formatter\LineFormatter;
-use function sprintf;
use Swoft\Log\CLogger;
use Swoft\Log\Handler\CEchoHandler;
use Swoft\Log\Handler\CFileHandler;
+use function sprintf;
/**
* Class CLog
diff --git a/src/log/src/Logger.php b/src/log/src/Logger.php
index 4905453fa..bd367f10f 100644
--- a/src/log/src/Logger.php
+++ b/src/log/src/Logger.php
@@ -435,15 +435,17 @@ public function flushLog(): void
return;
}
+ $messages = $this->messages;
+
+ // Clear message
+ $this->messages = [];
+
reset($this->handlers);
while ($handler = current($this->handlers)) {
- $handler->handleBatch($this->messages);
+ $handler->handleBatch($messages);
next($this->handlers);
}
-
- // Clear message
- $this->messages = [];
}
/**
diff --git a/src/process/composer.json b/src/process/composer.json
index f3cfcf2c6..2fcf734d5 100644
--- a/src/process/composer.json
+++ b/src/process/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/process",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/process/phpunit.xml b/src/process/phpunit.xml
index 15311104a..e491bd4a9 100644
--- a/src/process/phpunit.xml
+++ b/src/process/phpunit.xml
@@ -1,14 +1,14 @@
+ bootstrap="test/bootstrap.php"
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false">
./test/unit
@@ -19,4 +19,4 @@
./src/*
-
\ No newline at end of file
+
diff --git a/src/process/src/Listener/AddProcessListener.php b/src/process/src/Listener/AddProcessListener.php
index d4c4d3736..13246af10 100644
--- a/src/process/src/Listener/AddProcessListener.php
+++ b/src/process/src/Listener/AddProcessListener.php
@@ -65,8 +65,8 @@ private function addProcess(Server $server): void
$pipeType = $userProcess->getPipeType();
$coroutine = $userProcess->isCoroutine();
- $function = function (SwooleProcess $process) use ($callback, $server, $name) {
- $process = Process::new($process);
+ $function = function (SwooleProcess $swProcess) use ($callback, $server, $name) {
+ $process = Process::new($swProcess);
// Before
Swoft::trigger(ProcessEvent::BEFORE_USER_PROCESS, null, $server, $process, $name);
@@ -85,4 +85,4 @@ private function addProcess(Server $server): void
$server->getSwooleServer()->addProcess($process);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/process/src/Listener/AfterProcessListener.php b/src/process/src/Listener/AfterProcessListener.php
index 046f6a760..a2dc789b1 100644
--- a/src/process/src/Listener/AfterProcessListener.php
+++ b/src/process/src/Listener/AfterProcessListener.php
@@ -3,24 +3,23 @@
namespace Swoft\Process\Listener;
use Swoft;
+use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
-use Swoft\SwoftEvent;
-use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Process\ProcessEvent;
+use Swoft\SwoftEvent;
/**
* Class AfterProcessListener
*
* @since 2.0
*
- * @Listener(event=ProcessEvent::AFTER_PROCESS)
+ * @Listener(event=ProcessEvent::AFTER_PROCESS_START)
*/
class AfterProcessListener implements EventHandlerInterface
{
/**
* @param EventInterface $event
- *
*/
public function handle(EventInterface $event): void
{
diff --git a/src/process/src/Listener/BeforeProcessListener.php b/src/process/src/Listener/BeforeProcessListener.php
index 94f5805f4..3f234573a 100644
--- a/src/process/src/Listener/BeforeProcessListener.php
+++ b/src/process/src/Listener/BeforeProcessListener.php
@@ -17,7 +17,7 @@
*
* @since 2.0
*
- * @Listener(event=ProcessEvent::BEFORE_PROCESS)
+ * @Listener(event=ProcessEvent::BEFORE_PROCESS_START)
*/
class BeforeProcessListener implements EventHandlerInterface
{
diff --git a/src/process/src/Process.php b/src/process/src/Process.php
index 205d129aa..05fdf0705 100644
--- a/src/process/src/Process.php
+++ b/src/process/src/Process.php
@@ -7,6 +7,8 @@
use Swoft\Process\Exception\ProcessException;
use Swoole\Coroutine\Socket;
use Swoole\Process as SwooleProcess;
+use function swoole_errno;
+use function swoole_strerror;
/**
* Class Process
@@ -307,6 +309,6 @@ public static function setAffinity(array $cpuSet): bool
private function getError(): string
{
$errno = swoole_errno();
- return (string)swoole_strerror($errno);
+ return swoole_strerror($errno);
}
}
diff --git a/src/process/src/ProcessDispatcher.php b/src/process/src/ProcessDispatcher.php
index 230aea80b..3ac223a07 100644
--- a/src/process/src/ProcessDispatcher.php
+++ b/src/process/src/ProcessDispatcher.php
@@ -3,10 +3,8 @@
namespace Swoft\Process;
-use ReflectionException;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\BeanFactory;
-use Swoft\Bean\Exception\ContainerException;
use Swoft\Log\Error;
use Swoft\Process\Contract\ProcessInterface;
use Swoft\Process\Exception\ProcessException;
@@ -41,9 +39,8 @@ public function dispatcher(Pool $pool, int $workerId): void
$process = $this->getProcess($workerId);
PhpHelper::call([$process, self::METHOD], $pool, $workerId);
} catch (Throwable $e) {
- Error::log(
- sprintf('Run process for process pool fail(%s %s %d)!', $e->getMessage(), $e->getFile(), $e->getLine())
- );
+ Error::log(sprintf('Run process for process pool fail(%s %s %d)!', $e->getMessage(), $e->getFile(),
+ $e->getLine()));
}
}
diff --git a/src/process/src/ProcessEvent.php b/src/process/src/ProcessEvent.php
index 8e3f07a66..d176c2237 100644
--- a/src/process/src/ProcessEvent.php
+++ b/src/process/src/ProcessEvent.php
@@ -23,10 +23,12 @@ class ProcessEvent
/**
* Before process
*/
- public const BEFORE_PROCESS = 'swoft.process.before';
+ public const BEFORE_PROCESS_START = 'swoft.process.start.before';
+ public const AFTER_PROCESS_START = 'swoft.process.start.after';
/**
* After process
*/
- public const AFTER_PROCESS = 'swoft.process.after';
+ public const BEFORE_PROCESS_STOP = 'swoft.process.stop.before';
+ public const AFTER_PROCESS_STOP = 'swoft.process.stop.after';
}
diff --git a/src/process/src/ProcessPool.php b/src/process/src/ProcessPool.php
index f30fd121f..d01caf904 100644
--- a/src/process/src/ProcessPool.php
+++ b/src/process/src/ProcessPool.php
@@ -159,6 +159,7 @@ public function stop(): bool
/**
* Quick restart
+ *
* @throws SwoftException
*/
public function restart(): void
diff --git a/src/process/src/Swoole/WorkerStartListener.php b/src/process/src/Swoole/WorkerStartListener.php
index 7df367d68..8608e67a9 100644
--- a/src/process/src/Swoole/WorkerStartListener.php
+++ b/src/process/src/Swoole/WorkerStartListener.php
@@ -4,16 +4,14 @@
namespace Swoft\Process\Swoole;
-use ReflectionException;
use Swoft;
use Swoft\Bean\Annotation\Mapping\Bean;
-use Swoft\Bean\Exception\ContainerException;
+use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Process\Contract\WorkerStartInterface;
use Swoft\Process\ProcessDispatcher;
use Swoft\Process\ProcessEvent;
use Swoft\Process\ProcessPool;
use Swoole\Process\Pool;
-use Swoft\Bean\Annotation\Mapping\Inject;
/**
@@ -43,12 +41,12 @@ public function onWorkerStart(Pool $pool, int $workerId): void
ProcessPool::$processPool->initProcessPool($pool);
// Before
- Swoft::trigger(ProcessEvent::BEFORE_PROCESS, $this, $pool, $workerId);
+ Swoft::trigger(ProcessEvent::BEFORE_PROCESS_START, $this, $pool, $workerId);
// Dispatcher
$this->processDispatcher->dispatcher($pool, $workerId);
// After
- Swoft::trigger(ProcessEvent::BEFORE_PROCESS, $this, $pool, $workerId);
+ Swoft::trigger(ProcessEvent::AFTER_PROCESS_START, $this, $pool, $workerId);
}
}
diff --git a/src/process/src/Swoole/WorkerStopListener.php b/src/process/src/Swoole/WorkerStopListener.php
index 8300263fd..3cef6645e 100644
--- a/src/process/src/Swoole/WorkerStopListener.php
+++ b/src/process/src/Swoole/WorkerStopListener.php
@@ -1,11 +1,11 @@
coroutine;
}
-}
\ No newline at end of file
+}
diff --git a/src/process/test/bootstrap.php b/src/process/test/bootstrap.php
index 75378126e..a3b73f86d 100644
--- a/src/process/test/bootstrap.php
+++ b/src/process/test/bootstrap.php
@@ -1,4 +1,5 @@
$dir) {
$loader->addPsr4($prefix, $componentDir . '/' . $dir);
}
@@ -25,7 +26,7 @@
$loader = require dirname(__DIR__, 5) . '/autoload.php';
// need load testing psr4 config map
- $composerData = json_decode(file_get_contents($componentJson), true);
+ $composerData = json_decode(file_get_contents($componentJson), true);
foreach ($composerData['autoload-dev']['psr-4'] as $prefix => $dir) {
$loader->addPsr4($prefix, $componentDir . '/' . $dir);
@@ -35,7 +36,7 @@
}
$application = new TestApplication([
- 'basePath' => __DIR__
+ 'basePath' => __DIR__
]);
$application->setBeanFile(__DIR__ . '/testing/bean.php');
$application->run();
diff --git a/src/process/test/testing/bean.php b/src/process/test/testing/bean.php
index b62512838..0b67a5fe4 100644
--- a/src/process/test/testing/bean.php
+++ b/src/process/test/testing/bean.php
@@ -1,4 +1,3 @@
> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/redis/composer.json b/src/redis/composer.json
index 3d53d8d58..69f327000 100644
--- a/src/redis/composer.json
+++ b/src/redis/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/redis",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/redis/src/Connection/Connection.php b/src/redis/src/Connection/Connection.php
index bb2c2f825..c7a2efca4 100644
--- a/src/redis/src/Connection/Connection.php
+++ b/src/redis/src/Connection/Connection.php
@@ -27,6 +27,7 @@
*
* @since 2.0
* @method int append(string $key, string $value)
+ * @method int bitCount(string $key, int $start, int $end)
* @method array blPop(array $keys, int $timeout)
* @method array brPop(array $keys, int $timeout)
* @method string brpoplpush(string $srcKey, string $dstKey, int $timeout)
@@ -150,6 +151,7 @@ abstract class Connection extends AbstractConnection implements ConnectionInterf
*/
protected $supportedMethods = [
'append',
+ 'bitcount',
'blpop',
'brpop',
'brpoplpush',
@@ -464,11 +466,14 @@ public function release(bool $force = false): void
public function hMGet(string $key, array $keys): array
{
$values = $this->command('hMGet', [$key, $keys]);
+ if ($values === false) {
+ $values = [];
+ }
$result = [];
- foreach ($values as $key => $value) {
+ foreach ($values as $subKey => $value) {
if ($value !== false) {
- $result[$key] = $value;
+ $result[$subKey] = $value;
}
}
@@ -525,23 +530,20 @@ public function get(string $key)
}
/**
- * @param string $key
- * @param mixed $value
- * @param int|null $timeout
+ * @param string $key
+ * @param mixed $value
+ * @param int|array|null $timeout
*
* @return bool
* @throws ContainerException
* @throws RedisException
* @throws ReflectionException
*/
- public function set(string $key, $value, int $timeout = null): bool
+ public function set(string $key, $value, $timeout = null): bool
{
- $result = $this->command('set', [$key, $value, $timeout]);
-
- return $result;
+ return $this->command('set', [$key, $value, $timeout]);
}
-
/**
* @param array $keys
*
@@ -579,7 +581,7 @@ public function mget(array $keys): array
public function mset(array $keyValues, int $ttl = 0): bool
{
$result = $this->command('mset', [$keyValues]);
- if ($ttl == 0) {
+ if ($ttl === 0) {
return $result;
}
@@ -669,7 +671,7 @@ private function getCountingKey(string $name): string
*/
private function multi(int $mode, callable $callback, bool $reconnect = false): array
{
- $name = ($mode == Redis::PIPELINE) ? 'pipeline' : 'transaction';
+ $name = ($mode === Redis::PIPELINE) ? 'pipeline' : 'transaction';
$proKey = sprintf('redis.%s', $name);
try {
Log::profileStart($proKey);
diff --git a/src/redis/src/Connector/PhpRedisConnector.php b/src/redis/src/Connector/PhpRedisConnector.php
index 048bb2796..9bcd424c1 100644
--- a/src/redis/src/Connector/PhpRedisConnector.php
+++ b/src/redis/src/Connector/PhpRedisConnector.php
@@ -83,7 +83,7 @@ public function connectToCluster(array $config, array $option): RedisCluster
$parameters = array_values($parameters);
if (version_compare(phpversion('redis'), '4.3.0', '>=')) {
- $parameters[] = $option['auth'] ?? '';
+ $parameters[] = $auth;
}
$redisCluster = new RedisCluster(...$parameters);
diff --git a/src/redis/src/Contract/ConnectionInterface.php b/src/redis/src/Contract/ConnectionInterface.php
index 84d869bc5..f337fdc6d 100644
--- a/src/redis/src/Contract/ConnectionInterface.php
+++ b/src/redis/src/Contract/ConnectionInterface.php
@@ -59,13 +59,13 @@ public function mset(array $keyValues, int $ttl = 0): bool;
public function get(string $key);
/**
- * @param string $key
- * @param mixed $value
- * @param int|null $timeout
+ * @param string $key
+ * @param mixed $value
+ * @param int|array|null $timeout
*
* @return bool
*/
- public function set(string $key, $value, int $timeout = null): bool;
+ public function set(string $key, $value, $timeout = null): bool;
/**
* Execute commands in a pipeline.
@@ -84,4 +84,4 @@ public function pipeline(callable $callback): array;
* @return array
*/
public function transaction(callable $callback): array;
-}
\ No newline at end of file
+}
diff --git a/src/redis/src/Pool.php b/src/redis/src/Pool.php
index 3f197b353..8b775e462 100644
--- a/src/redis/src/Pool.php
+++ b/src/redis/src/Pool.php
@@ -3,9 +3,7 @@
namespace Swoft\Redis;
-use ReflectionException;
use Swoft\Bean\BeanFactory;
-use Swoft\Bean\Exception\ContainerException;
use Swoft\Connection\Pool\AbstractPool;
use Swoft\Connection\Pool\Contract\ConnectionInterface;
use Swoft\Redis\Connection\Connection;
@@ -31,7 +29,7 @@
* @method float geoDist(string $key, string $member1, string $member2, string $unit = 'm')
* @method array geohash(string $key, string ...$members)
* @method array geopos(string $key, string ...$members)
- * @method mixed|bool get(string $key)
+ * @method mixed|false get(string $key)
* @method int getBit(string $key, int $offset)
* @method int getOption(string $name)
* @method string getRange(string $key, int $start, int $end)
@@ -85,8 +83,8 @@
* @method int sUnionStore(string $dstKey, string $key1, string $key2, string $keyN = null)
* @method array|bool scan(int &$iterator, string $pattern = null, int $count = 0)
* @method mixed script(string|array $nodeParams, string $command, string $script)
- * @method bool set(string $key, $value, int $timeout = null)
- * @method int setBit(string $key, int $offset, int $value)
+ * @method bool set(string $key, $value, $timeout = null)
+ * @method int setBit(string $key, int $offset, bool $value)
* @method string setRange(string $key, int $offset, $value)
* @method int setex(string $key, int $ttl, $value)
* @method bool setnx(string $key, $value)
@@ -131,7 +129,7 @@
* @method int zUnionStore(string $Output, array $ZSetKeys, array $Weights = null, string $aggregateFunction = 'SUM')
* @method array hMGet(string $key, array $keys)
* @method bool hMSet(string $key, array $keyValues)
- * @method int zAdd(string $key, array $scoreValues)
+ * @method int zAdd(string $key, array $scoreValues)
* @method array mget(array $keys)
* @method bool mset(array $keyValues, int $ttl = 0)
* @method array pipeline(callable $callback)
@@ -147,7 +145,7 @@ class Pool extends AbstractPool
/**
* Default pool
*/
- const DEFAULT_POOL = 'redis.pool';
+ public const DEFAULT_POOL = 'redis.pool';
/**
* @var RedisDb
diff --git a/src/redis/src/Redis.php b/src/redis/src/Redis.php
index 1f1775c23..a745b60f0 100644
--- a/src/redis/src/Redis.php
+++ b/src/redis/src/Redis.php
@@ -15,6 +15,7 @@
* @since 2.0
*
* @method static int append(string $key, string $value)
+ * @method int bitCount(string $key, int $start, int $end)
* @method static array blPop(array $keys, int $timeout)
* @method static array brPop(array $keys, int $timeout)
* @method static string brpoplpush(string $srcKey, string $dstKey, int $timeout)
@@ -81,8 +82,8 @@
* @method static int sUnionStore(string $dstKey, string $key1, string $key2, string $keyN = null)
* @method static array|bool scan(int &$iterator, string $pattern = null, int $count = 0)
* @method static mixed script(string|array $nodeParams, string $command, string $script)
- * @method static bool set(string $key, $value, int $timeout = null)
- * @method static int setBit(string $key, int $offset, int $value)
+ * @method static bool set(string $key, $value, $timeout = null)
+ * @method static int setBit(string $key, int $offset, bool $value)
* @method static string setRange(string $key, int $offset, $value)
* @method static int setex(string $key, int $ttl, $value)
* @method static bool setnx(string $key, $value)
diff --git a/src/redis/test/unit/Command/StringTest.php b/src/redis/test/unit/Command/StringTest.php
index f6a016c93..e740a2860 100644
--- a/src/redis/test/unit/Command/StringTest.php
+++ b/src/redis/test/unit/Command/StringTest.php
@@ -57,8 +57,8 @@ public function testInc()
{
$key = \uniqid();
- $redis = Redis::connection('redis.inc.pool');
-
+ $redis = Redis::connection('redis.inc.pool');
+
$this->assertEquals(1, $redis->incrBy($key, 1));
$redis->set($key, 2);
$redis->incr($key);
@@ -92,4 +92,10 @@ public function testMsetAndMget()
$this->assertEquals(count($values), 2);
$this->assertEquals($values, $keys);
}
+
+ public function testBit()
+ {
+ Redis::setBit('user:sign' . date('ymd'), 16, false);
+ $this->assertTrue(true);
+ }
}
diff --git a/src/rpc-client/.travis.yml b/src/rpc-client/.travis.yml
index 58fb5c81f..d837f4f4f 100644
--- a/src/rpc-client/.travis.yml
+++ b/src/rpc-client/.travis.yml
@@ -5,7 +5,7 @@ php:
- 7.2
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/rpc-client/composer.json b/src/rpc-client/composer.json
index f08f75c36..fc2e5dfaf 100644
--- a/src/rpc-client/composer.json
+++ b/src/rpc-client/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/rpc-client",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/rpc-server/.github/PULL_REQUEST_TEMPLATE.md b/src/rpc-server/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..8b742aa30
--- /dev/null
+++ b/src/rpc-server/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,60 @@
+# PR
+
+- 请不要提交PR到各个组件仓库,它们都是 **只读的**
+- 核心组件的 **开发仓库** 是 **[swoft/swoft-component][core]**
+- 扩展组件的 **开发仓库** 是 **[swoft/swoft-ext][ext]**
+- 请 `fork` 对应的 **开发仓库**,修改后,请把你的PR提交到对应的开发仓库
+
+> 发布版本时官方会将代码同步到各个子仓库。因此,切记不要往子仓库发PR。
+
+## 发起PR时的注意事项
+
+开发组非常欢迎各位向我们提交PR(_Pull Request_),但是为了保证代码质量和统一的风格,
+向官方的主仓库 [swoft/swoft][main] 和 **开发仓库** 贡献代码时需要注意代码和commit格式
+
+### Commit Message
+
+- commit message 只能是英文信息
+- 请尽量保证commit message是有意义的说明
+- 最好以 `add:` `update:` `fix:` 等关键字开头
+
+### 代码风格
+
+- 提交的PHP代码 **必须** 遵循 PSR-2 代码风格
+- 合理且有意义的类、方法、变量命名
+- 适当的注释,合理的使用空行保持代码的简洁,易于阅读
+- 不要包含一些无意义的信息 例如 `@author` 等(_提交者是能够从commit log里看到的_)
+
+------------------
+
+> English Version (_translate by Google_)
+
+The development team welcomes you to submit PR (_Pull Request_) to us, but to ensure code quality and uniform style,
+go to the official main repository [swoft/swoft][main] and Development repository, Note the code and commit format when contributing code
+
+## Precautions when initiating PR
+
+- Please do not submit PR to each sub-repository, they are all read-only
+- The _development repository_ for the core components is **[swoft/swoft-component][core]**
+- The _development repository_ for extension components is **[swoft/swoft-ext][ext]**
+- Please `fork` the corresponding development warehouse. After modification, please submit your PR to the corresponding development warehouse.
+
+> Officially syncs code to individual sub-warehouses when new versions are released
+
+### Commit Message
+
+- the commit message can only be in English
+- Please try to ensure that the commit message is meaningful
+- it is best to start with the keyword `add:` `update:` `fix:`
+
+### Code Style
+
+- Submitted PHP code **Must** Follow PSR-2 code style
+- Reasonable and meaningful class, method, variable naming
+- Appropriate comments, reasonable use of blank lines to keep the code simple and easy to read
+- Don't include some meaningless information such as `@author`, etc. (_author is that can be seen from the commit log_)
+
+
+[main]: https://github.com/swoft-cloud/swoft
+[core]: https://github.com/swoft-cloud/swoft-component
+[ext]: https://github.com/swoft-cloud/swoft-ext
diff --git a/src/rpc-server/.travis.yml b/src/rpc-server/.travis.yml
index 58fb5c81f..fb54190b5 100644
--- a/src/rpc-server/.travis.yml
+++ b/src/rpc-server/.travis.yml
@@ -1,11 +1,11 @@
language: php
-
php:
- 7.1
- 7.2
- 7.3
+
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/rpc-server/README.md b/src/rpc-server/README.md
index a142bdacc..0dc0f6255 100644
--- a/src/rpc-server/README.md
+++ b/src/rpc-server/README.md
@@ -7,6 +7,10 @@
Swoft Rpc Server Component
+## [中文说明](README.zh-CN.md)
+
+中文说明请查看 [README.zh-CN.md](README.zh-CN.md)
+
## Install
- composer command
diff --git a/src/rpc-server/README.zh-CN.md b/src/rpc-server/README.zh-CN.md
new file mode 100644
index 000000000..09a96f184
--- /dev/null
+++ b/src/rpc-server/README.zh-CN.md
@@ -0,0 +1,34 @@
+# Swoft Rpc Server
+
+[![Latest Stable Version](http://img.shields.io/packagist/v/swoft/rpc-server.svg)](https://packagist.org/packages/swoft/rpc-server)
+[![Php Version](https://img.shields.io/badge/php-%3E=7.1-brightgreen.svg?maxAge=2592000)](https://secure.php.net/)
+[![Swoft Doc](https://img.shields.io/badge/docs-passing-green.svg?maxAge=2592000)](https://www.swoft.org/docs)
+[![Swoft License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/swoft-cloud/swoft/blob/master/LICENSE)
+
+Swoft Rpc Server Component
+
+## [ENGLISH](README.md)
+
+English readme please sess [README.md](README.md)
+
+## Install
+
+- composer command
+
+```bash
+composer require swoft/rpc-server
+```
+
+## Resources
+
+* [Documentation](https://swoft.org/docs)
+* [Contributing](https://github.com/swoft-cloud/swoft/blob/master/CONTRIBUTING.md)
+* [Report Issues][issues] and [Send Pull Requests][pulls] in the [Main Swoft Repository][repository]
+
+[pulls]: https://github.com/swoft-cloud/swoft-component/pulls
+[repository]: https://github.com/swoft-cloud/swoft
+[issues]: https://github.com/swoft-cloud/swoft/issues
+
+## LICENSE
+
+The Component is open-sourced software licensed under the [Apache license](LICENSE).
diff --git a/src/rpc-server/composer.json b/src/rpc-server/composer.json
index 7a9362967..eee10a09d 100644
--- a/src/rpc-server/composer.json
+++ b/src/rpc-server/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/rpc-server",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/rpc-server/src/Command/ServiceServerCommand.php b/src/rpc-server/src/Command/ServiceServerCommand.php
index 723246030..c73ce7df8 100644
--- a/src/rpc-server/src/Command/ServiceServerCommand.php
+++ b/src/rpc-server/src/Command/ServiceServerCommand.php
@@ -21,8 +21,8 @@
* @Command("rpc", coroutine=false, desc="Provide some commands to manage swoft RPC server")
*
* @example
- * {fullCmd}:start Start the rpc server
- * {fullCmd}:stop Stop the rpc server
+ * {groupName}:start Start the rpc server
+ * {groupName}:stop Stop the rpc server
*/
class ServiceServerCommand extends BaseServerCommand
{
diff --git a/src/rpc/composer.json b/src/rpc/composer.json
index fcd8d2261..6a92e59e9 100644
--- a/src/rpc/composer.json
+++ b/src/rpc/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/rpc",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/server/composer.json b/src/server/composer.json
index 1caa9192a..76ead6a0f 100644
--- a/src/server/composer.json
+++ b/src/server/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/server",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/server/src/Server.php b/src/server/src/Server.php
index a856eddf9..900eab217 100644
--- a/src/server/src/Server.php
+++ b/src/server/src/Server.php
@@ -830,8 +830,6 @@ public function startWithDaemonize(): void
/**
* Quick restart
- *
- * @throws Swoft\Exception\SwoftException
*/
public function restart(): void
{
@@ -906,7 +904,7 @@ public function shutdown(): void
*
* @return bool
*/
- public function stopWorker(int $workerId = -1, bool $waitEvent = false): bool
+ public function stopWorker(int $workerId, bool $waitEvent = false): bool
{
if ($workerId > -1 && $this->swooleServer) {
return $this->swooleServer->stop($workerId, $waitEvent);
@@ -956,8 +954,9 @@ public function log(string $msg, array $data = [], string $type = 'info'): void
$tid = Co::tid();
$cid = Co::id();
$wid = $this->getPid('workerId');
+ $pid = $this->getPid('workerPid');
- Console::log("[WorkerId:$wid, TID:$tid, CID:$cid] " . $msg, $data, $type);
+ Console::log("[WID:$wid, PID:$pid, TID:$tid, CID:$cid] " . $msg, $data, $type);
}
}
diff --git a/src/stdlib/composer.json b/src/stdlib/composer.json
index cdd2ca244..a1aa5ed8c 100644
--- a/src/stdlib/composer.json
+++ b/src/stdlib/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/stdlib",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/stdlib/src/Concern/DataPropertyTrait.php b/src/stdlib/src/Concern/DataPropertyTrait.php
index 612af42b1..f835cf7fb 100644
--- a/src/stdlib/src/Concern/DataPropertyTrait.php
+++ b/src/stdlib/src/Concern/DataPropertyTrait.php
@@ -23,10 +23,13 @@ trait DataPropertyTrait
*
* @param string $key
* @param mixed $value
+ *
+ * @return bool
*/
- public function set(string $key, $value): void
+ public function set(string $key, $value): bool
{
$this->data[$key] = $value;
+ return true;
}
/**
@@ -69,10 +72,13 @@ public function has(string $key): bool
*
* @param array $map
* [key => value]
+ *
+ * @return bool
*/
- public function setMulti(array $map): void
+ public function setMulti(array $map): bool
{
$this->data = array_merge($this->data, $map);
+ return true;
}
/**
diff --git a/src/stdlib/src/Concern/RandomStringTrait.php b/src/stdlib/src/Concern/RandomStringTrait.php
index 6ff6a0ace..42f59e304 100644
--- a/src/stdlib/src/Concern/RandomStringTrait.php
+++ b/src/stdlib/src/Concern/RandomStringTrait.php
@@ -5,9 +5,12 @@
use Exception;
use RuntimeException;
use Swoft\Stdlib\Helper\EnvHelper;
+use function base_convert;
use function bin2hex;
use function ceil;
+use function microtime;
use function random_bytes;
+use function random_int;
use function substr;
/**
@@ -68,7 +71,7 @@ public static function getUniqid(string $prefix = '', bool $moreEntropy = false)
public static function uniqIdReal(int $length = 13): string
{
// uniqid gives 13 chars, but you could adjust it to your needs.
- $bytes = random_bytes(ceil($length / 2));
+ $bytes = random_bytes((int)ceil($length / 2));
return (string)substr(bin2hex($bytes), 0, $length);
}
@@ -242,4 +245,18 @@ public static function quickRandom(int $length = 16): string
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}
+
+ /**
+ * @param int $randMin
+ * @param int $randMax
+ *
+ * @return string
+ * @throws Exception
+ */
+ public static function timeUniId(int $randMin = 100, int $randMax = 999): string
+ {
+ $mt = str_replace('.', '', microtime(true));
+
+ return base_convert($mt . random_int($randMin, $randMax), 10, 16);
+ }
}
diff --git a/src/stdlib/src/Helper/Functions.php b/src/stdlib/src/Helper/Functions.php
index 7ee507278..9942f0931 100644
--- a/src/stdlib/src/Helper/Functions.php
+++ b/src/stdlib/src/Helper/Functions.php
@@ -61,7 +61,7 @@ function printr(...$vars)
$pos = $trace[1]['class'] ?? $trace[0]['file'];
if ($pos) {
- echo "CALL ON $pos($line):\n";
+ echo "PRINT ON $pos($line):\n";
}
foreach ($vars as $var) {
@@ -86,7 +86,7 @@ function vdump(...$vars)
$pos = $trace[1]['class'] ?? $trace[0]['file'];
if ($pos) {
- echo "CALL ON $pos($line):\n";
+ echo "PRINT ON $pos($line):\n";
}
ob_start();
diff --git a/src/stdlib/src/Helper/StringHelper.php b/src/stdlib/src/Helper/StringHelper.php
index 8540bbbd3..f22ca757b 100644
--- a/src/stdlib/src/Helper/StringHelper.php
+++ b/src/stdlib/src/Helper/StringHelper.php
@@ -12,6 +12,7 @@
use function preg_match;
use function preg_replace;
use function str_pad;
+use function str_repeat;
use function str_replace;
use function strlen;
use function strpos;
@@ -221,43 +222,83 @@ public static function is(string $pattern, string $value): bool
/**
* Return the length of the given string.
*
- * @param string $value
+ * @param string|int $value
+ * @param string $encode
*
* @return int
*/
- public static function length($value): int
+ public static function length($value, string $encode = 'utf-8'): int
{
- return mb_strlen($value);
+ return mb_strlen((string)$value, $encode);
}
- public static function len(string $value): int
+ /**
+ * Return the length of the given string.
+ *
+ * @param string|int $value
+ * @param string|null $encode
+ *
+ * @return int
+ */
+ public static function len($value, string $encode = 'utf-8'): int
{
- return mb_strlen($value);
+ return mb_strlen((string)$value, $encode);
}
/**
- * @param string $string
- * @param int $padLen
+ * @param string|int $string
+ * @param int|float $padLen
* @param string $padStr
* @param int $padType
*
* @return string
*/
- public static function pad(string $string, int $padLen, string $padStr = ' ', int $padType = STR_PAD_RIGHT): string
+ public static function pad($string, $padLen, string $padStr = ' ', int $padType = STR_PAD_RIGHT): string
{
- return $padLen > 0 ? str_pad($string, $padLen, $padStr, $padType) : $string;
+ $string = (string)$string;
+
+ return $padLen > 0 ? str_pad($string, (int)$padLen, $padStr, $padType) : $string;
}
- public static function padLeft(string $string, int $padLen, string $padStr = ' '): string
+ /**
+ * @param string|int $string
+ * @param int $padLen
+ * @param string $padStr
+ *
+ * @return string
+ */
+ public static function padLeft($string, int $padLen, string $padStr = ' '): string
{
+ $string = (string)$string;
+
return $padLen > 0 ? str_pad($string, $padLen, $padStr, STR_PAD_LEFT) : $string;
}
- public static function padRight(string $string, int $padLen, string $padStr = ' '): string
+ /**
+ * @param string|int $string
+ * @param int $padLen
+ * @param string $padStr
+ *
+ * @return string
+ */
+ public static function padRight($string, int $padLen, string $padStr = ' '): string
{
+ $string = (string)$string;
+
return $padLen > 0 ? str_pad($string, $padLen, $padStr) : $string;
}
+ /**
+ * @param string|int $string
+ * @param int $length
+ *
+ * @return string
+ */
+ public static function repeat($string, $length): string
+ {
+ return str_repeat((string)$string, (int)$length);
+ }
+
/**
* Limit the number of characters in a string.
*
diff --git a/src/stdlib/src/PhpType.php b/src/stdlib/src/PhpType.php
index daf9de286..8931f0a85 100644
--- a/src/stdlib/src/PhpType.php
+++ b/src/stdlib/src/PhpType.php
@@ -4,10 +4,12 @@
/**
* Class PhpType
+ *
+ * @since 2.0.1
*/
-final class PhpType
+abstract class PhpType
{
- // basic type
+ // Basic data type
public const INT = 'int';
public const BOOL = 'bool';
public const BOOLEAN = 'boolean';
@@ -15,7 +17,36 @@ final class PhpType
public const FLOAT = 'float';
public const STRING = 'string';
- // complex type
+ // Complex data type
public const ARRAY = 'array';
public const OBJECT = 'object';
+
+ /**
+ * @param string $type
+ * @param mixed $value
+ *
+ * @return mixed
+ */
+ public static function convertType(string $type, $value)
+ {
+ switch ($type) {
+ case self::BOOL:
+ case self::BOOLEAN:
+ $value = (bool)$value;
+ break;
+ case self::INT:
+ case self::INTEGER:
+ $value = (int)$value;
+ break;
+ case self::FLOAT:
+ $value = (float)$value;
+ break;
+ case self::STRING:
+ $value = (string)$value;
+ break;
+
+ }
+
+ return $value;
+ }
}
diff --git a/src/stdlib/test/unit/Helper/StringHelperTest.php b/src/stdlib/test/unit/Helper/StringHelperTest.php
index 268825cfb..8f064b9ee 100644
--- a/src/stdlib/test/unit/Helper/StringHelperTest.php
+++ b/src/stdlib/test/unit/Helper/StringHelperTest.php
@@ -2,8 +2,10 @@
namespace SwoftTest\Stdlib\Unit\Helper;
+use Exception;
use PHPUnit\Framework\TestCase;
use Swoft\Stdlib\Helper\Str;
+use const STR_PAD_LEFT;
/**
* Class StringHelperTest
@@ -44,11 +46,25 @@ public function testRmPharPrefix(): void
$this->assertSame('/vendor/composer/.env', $path);
}
+ /**
+ * @throws Exception
+ */
public function testGetUnique(): void
{
$uniqueId = Str::getUniqid();
$this->assertNotEmpty($uniqueId);
$this->assertIsString($uniqueId);
+
+ $uniqueId = Str::uniqIdReal();
+ $this->assertNotEmpty($uniqueId);
+ }
+
+ public function testPad(): void
+ {
+ $this->assertSame('ABC ', Str::pad('ABC', 6));
+ $this->assertSame(' ABC', Str::pad('ABC', 6, ' ', STR_PAD_LEFT));
+
+ $this->assertSame('123 ', Str::pad(123, 6));
}
}
diff --git a/src/task/.travis.yml b/src/task/.travis.yml
index 58fb5c81f..d837f4f4f 100644
--- a/src/task/.travis.yml
+++ b/src/task/.travis.yml
@@ -5,7 +5,7 @@ php:
- 7.2
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/task/composer.json b/src/task/composer.json
index 72a2da0a9..89e025d63 100644
--- a/src/task/composer.json
+++ b/src/task/composer.json
@@ -1,36 +1,36 @@
{
- "name": "swoft/task",
- "type": "library",
- "version": "v2.0.7",
- "keywords": [
- "php",
- "swoole",
- "swoft",
- "task",
- "routine"
- ],
- "description": "swoft task component",
- "license": "Apache-2.0",
- "require": {
- "swoft/framework": "~2.0.0"
+ "name": "swoft/task",
+ "type": "library",
+ "version": "v2.0.8",
+ "keywords": [
+ "php",
+ "swoole",
+ "swoft",
+ "task",
+ "routine"
+ ],
+ "description": "swoft task component",
+ "license": "Apache-2.0",
+ "require": {
+ "swoft/framework": "~2.0.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Swoft\\Task\\": "src/"
},
- "autoload": {
- "psr-4": {
- "Swoft\\Task\\": "src/"
- },
- "files": [
- ]
- },
- "autoload-dev": {
- "psr-4": {
- "SwoftTest\\Task\\Testing\\": "test/testing",
- "SwoftTest\\Task\\Unit\\": "test/unit"
- }
- },
- "require-dev": {
- "phpunit/phpunit": "^7.5"
- },
- "scripts": {
- "test": "php run.php -c phpunit.xml"
+ "files": [
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "SwoftTest\\Task\\Testing\\": "test/testing",
+ "SwoftTest\\Task\\Unit\\": "test/unit"
}
+ },
+ "require-dev": {
+ "phpunit/phpunit": "^7.5"
+ },
+ "scripts": {
+ "test": "php run.php -c phpunit.xml"
+ }
}
diff --git a/src/task/phpunit.xml b/src/task/phpunit.xml
index 15311104a..e491bd4a9 100644
--- a/src/task/phpunit.xml
+++ b/src/task/phpunit.xml
@@ -1,14 +1,14 @@
+ bootstrap="test/bootstrap.php"
+ backupGlobals="false"
+ backupStaticAttributes="false"
+ colors="true"
+ convertErrorsToExceptions="true"
+ convertNoticesToExceptions="true"
+ convertWarningsToExceptions="true"
+ processIsolation="false"
+ stopOnFailure="false">
./test/unit
@@ -19,4 +19,4 @@
./src/*
-
\ No newline at end of file
+
diff --git a/src/task/run.php b/src/task/run.php
index 38fb45fb9..650facf87 100644
--- a/src/task/run.php
+++ b/src/task/run.php
@@ -15,26 +15,19 @@
* file that was distributed with this source code.
*/
if (version_compare('7.1.0', PHP_VERSION, '>')) {
- fwrite(
- STDERR,
- sprintf(
- 'This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL .
- 'You are using PHP %s (%s).' . PHP_EOL,
- PHP_VERSION,
- PHP_BINARY
- )
- );
+ fwrite(STDERR,
+ sprintf('This version of PHPUnit is supported on PHP 7.1 and PHP 7.2.' . PHP_EOL . 'You are using PHP %s (%s).' . PHP_EOL,
+ PHP_VERSION, PHP_BINARY));
die(1);
}
if (!ini_get('date.timezone')) {
ini_set('date.timezone', 'UTC');
}
foreach ([
- __DIR__ . '/../../autoload.php',
- __DIR__ . '/../vendor/autoload.php',
- __DIR__ . '/vendor/autoload.php'
- ] as $file
-) {
+ __DIR__ . '/../../autoload.php',
+ __DIR__ . '/../vendor/autoload.php',
+ __DIR__ . '/vendor/autoload.php'
+] as $file) {
if (file_exists($file)) {
define('PHPUNIT_COMPOSER_INSTALL', $file);
break;
@@ -42,12 +35,8 @@
}
unset($file);
if (!defined('PHPUNIT_COMPOSER_INSTALL')) {
- fwrite(
- STDERR,
- 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL .
- ' composer install' . PHP_EOL . PHP_EOL .
- 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL
- );
+ fwrite(STDERR,
+ 'You need to set up the project dependencies using Composer:' . PHP_EOL . PHP_EOL . ' composer install' . PHP_EOL . PHP_EOL . 'You can learn all about Composer on https://getcomposer.org/.' . PHP_EOL);
die(1);
} else {
if (array_reverse(explode('/', __DIR__))[0] ?? '' === 'tests') {
diff --git a/src/task/src/FinishContext.php b/src/task/src/FinishContext.php
index acea30155..11419fb40 100644
--- a/src/task/src/FinishContext.php
+++ b/src/task/src/FinishContext.php
@@ -56,7 +56,7 @@ public static function new(Server $server, int $taskId, string $data): self
$instance->server = $server;
$instance->taskData = $data;
$instance->taskId = $taskId;
- $instance->taskUniqid = Task::getUniqid($taskId);
+ $instance->taskUniqid = Task::getUniqId($taskId);
return $instance;
}
@@ -92,4 +92,4 @@ public function getTaskUniqid(): string
{
return $this->taskUniqid;
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/Listener/BeforeTaskListener.php b/src/task/src/Listener/BeforeTaskListener.php
index 490764a82..910875c2d 100644
--- a/src/task/src/Listener/BeforeTaskListener.php
+++ b/src/task/src/Listener/BeforeTaskListener.php
@@ -1,9 +1,7 @@
getParams();
+
$context = TaskContext::new($request, $response);
if (Log::getLogger()->isEnable()) {
@@ -46,6 +45,7 @@ public function handle(EventInterface $event): void
];
$context->setMulti($data);
}
+
Context::set($context);
}
}
diff --git a/src/task/src/Packet.php b/src/task/src/Packet.php
index d561d751f..be8b93d10 100644
--- a/src/task/src/Packet.php
+++ b/src/task/src/Packet.php
@@ -52,21 +52,17 @@ public static function unpack(string $string): array
$ext = $data['ext'] ?? [];
if (empty($name) || empty($method) || empty($type)) {
- throw new TaskException(
- sprintf('Name or method(name=%s method=%s) can not be empty!', $name, $method)
- );
+ throw new TaskException(sprintf('Name or method(name=%s method=%s) can not be empty!', $name, $method));
}
if (!is_array($params)) {
- throw new TaskException(
- sprintf('Params(%s) is not formated!', JsonHelper::encode($params, JSON_UNESCAPED_UNICODE))
- );
+ throw new TaskException(sprintf('Params(%s) is not formated!',
+ JsonHelper::encode($params, JSON_UNESCAPED_UNICODE)));
}
if (!is_array($ext)) {
- throw new TaskException(
- sprintf('Ext(%s) is not formated!', JsonHelper::encode($ext, JSON_UNESCAPED_UNICODE))
- );
+ throw new TaskException(sprintf('Ext(%s) is not formated!',
+ JsonHelper::encode($ext, JSON_UNESCAPED_UNICODE)));
}
return [$type, $name, $method, $params, $ext];
@@ -112,4 +108,4 @@ public static function unpackResponse(string $string): array
return [null, $errorCode, $errorMessage];
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/Request.php b/src/task/src/Request.php
index 0b1ccc1f9..acb9f78a5 100644
--- a/src/task/src/Request.php
+++ b/src/task/src/Request.php
@@ -94,7 +94,7 @@ public static function new(Server $server = null, SwooleTask $task = null): self
$instance->srcWorkerId = $task->worker_id;
$instance->data = $task->data;
$instance->task = $task;
- $instance->taskUniqid = Task::getUniqid($task->id);
+ $instance->taskUniqid = Task::getUniqId($task->id);
[
$instance->type,
@@ -210,4 +210,4 @@ public function clear(): void
$this->ext = [];
$this->data = [];
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/Router/RouteRegister.php b/src/task/src/Router/RouteRegister.php
index dbd96fb1f..7ffdc370a 100644
--- a/src/task/src/Router/RouteRegister.php
+++ b/src/task/src/Router/RouteRegister.php
@@ -62,7 +62,7 @@ public static function registerRoutes(Router $router): void
}
$name = $task['name'] ?: $className;
-
+
foreach ($mapping as $methodName => $map) {
$mappingName = $map['name'] ?? '';
if (empty($mappingName)) {
diff --git a/src/task/src/Swoole/SyncTaskListener.php b/src/task/src/Swoole/SyncTaskListener.php
index 47dc094de..6f5a8f426 100644
--- a/src/task/src/Swoole/SyncTaskListener.php
+++ b/src/task/src/Swoole/SyncTaskListener.php
@@ -1,9 +1,7 @@
dispatcher->dispatch($type, $name, $method, $params, $ext);
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/Swoole/TaskListener.php b/src/task/src/Swoole/TaskListener.php
index af00c8f2c..5469ed3d5 100644
--- a/src/task/src/Swoole/TaskListener.php
+++ b/src/task/src/Swoole/TaskListener.php
@@ -1,9 +1,7 @@
dispatch($request, $response);
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/SyncTaskDispatcher.php b/src/task/src/SyncTaskDispatcher.php
index 560f3c4ed..e0e44a2e1 100644
--- a/src/task/src/SyncTaskDispatcher.php
+++ b/src/task/src/SyncTaskDispatcher.php
@@ -1,6 +1,5 @@
task($data, $dstWorkerId, $fallback);
if ($result === false) {
- throw new TaskException(
- sprintf('Task error name=%d method=%d', $name, $method)
- );
+ throw new TaskException(sprintf('Task error name=%d method=%d', $name, $method));
}
- return self::getUniqid($result);
+ return self::getUniqId($result);
}
/**
@@ -119,16 +117,12 @@ public static function cos(array $tasks, float $timeout = 3, array $ext = []): a
foreach ($taskResults as $key => $taskResult) {
if ($taskResult == false) {
[$name, $method] = $tasks[$key];
- throw new TaskException(
- sprintf('Task co error(name=%s method=%s)', $name, $method)
- );
+ throw new TaskException(sprintf('Task co error(name=%s method=%s)', $name, $method));
}
[$result, $errorCode, $errorMessage] = Packet::unpackResponse($taskResult);
if ($errorCode !== null) {
- throw new TaskException(
- sprintf('%s(code=%d)', $errorMessage, $errorCode)
- );
+ throw new TaskException(sprintf('%s(code=%d)', $errorMessage, $errorCode));
}
$resultData[] = $result;
}
@@ -143,14 +137,13 @@ public static function cos(array $tasks, float $timeout = 3, array $ext = []): a
*
* @return string
*/
- public static function getUniqid(int $taskId): string
+ public static function getUniqId(int $taskId): string
{
$server = Server::getServer();
- if (empty($server)) {
- return sprintf('unit-%d', $taskId);
+ if ($server === null) {
+ return sprintf('unit%d', $taskId);
}
- $serverUniqid = Server::getServer()->getUniqid();
- return sprintf('%s-%d', $serverUniqid, $taskId);
+ return sprintf('%s%d', $server->getUniqid(), $taskId);
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/TaskContext.php b/src/task/src/TaskContext.php
index 0677093c4..10714db96 100644
--- a/src/task/src/TaskContext.php
+++ b/src/task/src/TaskContext.php
@@ -1,9 +1,7 @@
request = $request;
- $intance->repsonse = $response;
+ $instance->request = $request;
+ $instance->response = $response;
- $intance->setMulti($request->getExt());
- return $intance;
+ $instance->setMulti($request->getExt());
+ return $instance;
}
/**
@@ -57,9 +55,25 @@ public function getRequest(): Request
/**
* @return Response
*/
- public function getRepsonse(): Response
+ public function getResponse(): Response
+ {
+ return $this->response;
+ }
+
+ /**
+ * @return int
+ */
+ public function getTaskId(): int
+ {
+ return $this->request->getTaskId();
+ }
+
+ /**
+ * @return string
+ */
+ public function getTaskUniqId(): string
{
- return $this->repsonse;
+ return $this->request->getTaskUniqid();
}
/**
@@ -68,6 +82,6 @@ public function getRepsonse(): Response
public function clear(): void
{
$this->request = null;
- $this->repsonse = null;
+ $this->response = null;
}
-}
\ No newline at end of file
+}
diff --git a/src/task/src/TaskDispatcher.php b/src/task/src/TaskDispatcher.php
index 1c8198341..f62baef7e 100644
--- a/src/task/src/TaskDispatcher.php
+++ b/src/task/src/TaskDispatcher.php
@@ -1,12 +1,11 @@
handle($request);
$response->setResult($result);
} catch (Throwable $e) {
+ CLog::error('task exec error: %s', $e->getMessage());
$response->setErrorCode($e->getCode());
$response->setErrorMessage($e->getMessage());
}
@@ -59,20 +58,16 @@ private function handle(Request $request)
$match = $router->match($name, $method);
[$status, $handler] = $match;
- if ($status != Router::FOUND || empty($handler)) {
- throw new TaskException(
- sprintf('Task(name=%s method=%s) is not exist!', $name, $method)
- );
+ if ($status !== Router::FOUND || empty($handler)) {
+ throw new TaskException(sprintf('Task(name=%s method=%s) is not exist!', $name, $method));
}
[$className, $methodName] = $handler;
$object = BeanFactory::getBean($className);
if (!method_exists($object, $methodName)) {
- throw new TaskException(
- sprintf('Task(name=%s method=%s) method is not exist!', $name, $method)
- );
+ throw new TaskException(sprintf('Task(name=%s method=%s) method is not exist!', $name, $method));
}
- return PhpHelper::call([$object, $methodName], ... $params);
+ return PhpHelper::call([$object, $methodName], ...$params);
}
-}
\ No newline at end of file
+}
diff --git a/src/task/test/testing/MockResponse.php b/src/task/test/testing/MockResponse.php
index 607dad093..bccc849a7 100644
--- a/src/task/test/testing/MockResponse.php
+++ b/src/task/test/testing/MockResponse.php
@@ -28,9 +28,7 @@ public function getResult()
[$result, $errorCode, $errorMessage] = Packet::unpackResponse($result);
if ($errorCode !== null) {
- throw new TaskException(
- sprintf('%s(code=%d)', $errorMessage, $errorCode)
- );
+ throw new TaskException(sprintf('%s(code=%d)', $errorMessage, $errorCode));
}
return $result;
@@ -40,4 +38,4 @@ public function send(): void
{
}
-}
\ No newline at end of file
+}
diff --git a/src/task/test/testing/MockTaskServer.php b/src/task/test/testing/MockTaskServer.php
index 3c265e345..cb1fefc77 100644
--- a/src/task/test/testing/MockTaskServer.php
+++ b/src/task/test/testing/MockTaskServer.php
@@ -48,9 +48,7 @@ public function co(string $name, string $method, array $params = [], array $ext
$taskResult = $response->getResponseData();
[$result, $errorCode, $errorMessage] = Packet::unpackResponse($taskResult);
if ($errorCode !== null) {
- throw new TaskException(
- sprintf('%s(code=%d)', $errorMessage, $errorCode)
- );
+ throw new TaskException(sprintf('%s(code=%d)', $errorMessage, $errorCode));
}
return $result;
@@ -94,4 +92,4 @@ private function task(Request $request, Response $response)
$dispatcher = BeanFactory::getBean('taskDispatcher');
$dispatcher->dispatch($request, $response);
}
-}
\ No newline at end of file
+}
diff --git a/src/task/test/unit/TaskTest.php b/src/task/test/unit/TaskTest.php
index b82bf1a88..9e26b75d4 100644
--- a/src/task/test/unit/TaskTest.php
+++ b/src/task/test/unit/TaskTest.php
@@ -1,6 +1,5 @@
mockTaskServer->co('demoTestTask', 'method', []);
}
@@ -25,7 +24,7 @@ public function testCo()
/**
* @throws TaskException
*/
- public function testCo2()
+ public function testCo2(): void
{
$data = [
'name',
@@ -38,7 +37,7 @@ public function testCo2()
/**
* @throws TaskException
*/
- public function testCo3()
+ public function testCo3(): void
{
$data = [
'name',
@@ -63,26 +62,26 @@ public function testCo3()
* @throws TaskException
* @expectedException \Swoft\Task\Exception\TaskException
*/
- public function testCo6()
+ public function testCo6(): void
{
$this->mockTaskServer->co('demoTestTask', 'method3', ['name', 18306]);
}
/**
*/
- public function testAsync()
+ public function testAsync(): void
{
-// $id = $this->mockTaskServer->async('demoTestTask', 'method2', ['name', 18306]);
-// $this->assertGreaterThan(0, $id);
+ // $id = $this->mockTaskServer->async('demoTestTask', 'method2', ['name', 18306]);
+ // $this->assertGreaterThan(0, $id);
}
/**
* @throws TaskException
*/
- public function testContext()
+ public function testContext(): void
{
$data = [
- 'unit-1',
+ 'unit1',
1,
'co',
'demoTestTask',
@@ -100,7 +99,7 @@ public function testContext()
/**
* @throws TaskException
*/
- public function testNotMapping()
+ public function testNotMapping(): void
{
$result = $this->mockTaskServer->co('demoTestTask', 'notMapping', []);
$this->assertEquals($result, ['notMapping']);
@@ -109,7 +108,7 @@ public function testNotMapping()
/**
* @throws TaskException
*/
- public function testBooReturn()
+ public function testBooReturn(): void
{
$result = $this->mockTaskServer->co('demoTestTask', 'booReturn', []);
$this->assertTrue($result);
@@ -127,9 +126,9 @@ public function testNullReturn()
/**
* @throws TaskException
*/
- public function testVoidReturn()
+ public function testVoidReturn(): void
{
$result = $this->mockTaskServer->co('demoTestTask', 'voidReturn2', []);
$this->assertNull($result);
}
-}
\ No newline at end of file
+}
diff --git a/src/tcp-server/.github/PULL_REQUEST_TEMPLATE.md b/src/tcp-server/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..8b742aa30
--- /dev/null
+++ b/src/tcp-server/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,60 @@
+# PR
+
+- 请不要提交PR到各个组件仓库,它们都是 **只读的**
+- 核心组件的 **开发仓库** 是 **[swoft/swoft-component][core]**
+- 扩展组件的 **开发仓库** 是 **[swoft/swoft-ext][ext]**
+- 请 `fork` 对应的 **开发仓库**,修改后,请把你的PR提交到对应的开发仓库
+
+> 发布版本时官方会将代码同步到各个子仓库。因此,切记不要往子仓库发PR。
+
+## 发起PR时的注意事项
+
+开发组非常欢迎各位向我们提交PR(_Pull Request_),但是为了保证代码质量和统一的风格,
+向官方的主仓库 [swoft/swoft][main] 和 **开发仓库** 贡献代码时需要注意代码和commit格式
+
+### Commit Message
+
+- commit message 只能是英文信息
+- 请尽量保证commit message是有意义的说明
+- 最好以 `add:` `update:` `fix:` 等关键字开头
+
+### 代码风格
+
+- 提交的PHP代码 **必须** 遵循 PSR-2 代码风格
+- 合理且有意义的类、方法、变量命名
+- 适当的注释,合理的使用空行保持代码的简洁,易于阅读
+- 不要包含一些无意义的信息 例如 `@author` 等(_提交者是能够从commit log里看到的_)
+
+------------------
+
+> English Version (_translate by Google_)
+
+The development team welcomes you to submit PR (_Pull Request_) to us, but to ensure code quality and uniform style,
+go to the official main repository [swoft/swoft][main] and Development repository, Note the code and commit format when contributing code
+
+## Precautions when initiating PR
+
+- Please do not submit PR to each sub-repository, they are all read-only
+- The _development repository_ for the core components is **[swoft/swoft-component][core]**
+- The _development repository_ for extension components is **[swoft/swoft-ext][ext]**
+- Please `fork` the corresponding development warehouse. After modification, please submit your PR to the corresponding development warehouse.
+
+> Officially syncs code to individual sub-warehouses when new versions are released
+
+### Commit Message
+
+- the commit message can only be in English
+- Please try to ensure that the commit message is meaningful
+- it is best to start with the keyword `add:` `update:` `fix:`
+
+### Code Style
+
+- Submitted PHP code **Must** Follow PSR-2 code style
+- Reasonable and meaningful class, method, variable naming
+- Appropriate comments, reasonable use of blank lines to keep the code simple and easy to read
+- Don't include some meaningless information such as `@author`, etc. (_author is that can be seen from the commit log_)
+
+
+[main]: https://github.com/swoft-cloud/swoft
+[core]: https://github.com/swoft-cloud/swoft-component
+[ext]: https://github.com/swoft-cloud/swoft-ext
diff --git a/src/tcp-server/README.md b/src/tcp-server/README.md
index 727a60540..26fe19a96 100644
--- a/src/tcp-server/README.md
+++ b/src/tcp-server/README.md
@@ -7,6 +7,10 @@
Swoft Tcp Server Component
+## [中文说明](README.zh-CN.md)
+
+中文说明请查看 [README.zh-CN.md](README.zh-CN.md)
+
## Install
- composer command
diff --git a/src/tcp-server/README.zh-CN.md b/src/tcp-server/README.zh-CN.md
new file mode 100644
index 000000000..38d38dc9b
--- /dev/null
+++ b/src/tcp-server/README.zh-CN.md
@@ -0,0 +1,34 @@
+# Swoft Tcp Server
+
+[![Latest Stable Version](http://img.shields.io/packagist/v/swoft/tcp-server.svg)](https://packagist.org/packages/swoft/tcp-server)
+[![Php Version](https://img.shields.io/badge/php-%3E=7.1-brightgreen.svg?maxAge=2592000)](https://secure.php.net/)
+[![Swoft Doc](https://img.shields.io/badge/docs-passing-green.svg?maxAge=2592000)](https://www.swoft.org/docs)
+[![Swoft License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/swoft-cloud/swoft/blob/master/LICENSE)
+
+Swoft Tcp Server Component
+
+## [ENGLISH](README.md)
+
+English readme please sess [README.md](README.md)
+
+## Install
+
+- composer command
+
+```bash
+composer require swoft/tcp-server
+```
+
+## Resources
+
+* [Documentation](https://swoft.org/docs)
+* [Contributing](https://github.com/swoft-cloud/swoft/blob/master/CONTRIBUTING.md)
+* [Report Issues][issues] and [Send Pull Requests][pulls] in the [Main Swoft Repository][repository]
+
+[pulls]: https://github.com/swoft-cloud/swoft-component/pulls
+[repository]: https://github.com/swoft-cloud/swoft
+[issues]: https://github.com/swoft-cloud/swoft/issues
+
+## LICENSE
+
+The Component is open-sourced software licensed under the [Apache license](LICENSE).
diff --git a/src/tcp-server/composer.json b/src/tcp-server/composer.json
index 387abd135..aab03fdf5 100644
--- a/src/tcp-server/composer.json
+++ b/src/tcp-server/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/tcp-server",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/tcp-server/src/AutoLoader.php b/src/tcp-server/src/AutoLoader.php
index d5beb2410..a95ad214d 100644
--- a/src/tcp-server/src/AutoLoader.php
+++ b/src/tcp-server/src/AutoLoader.php
@@ -50,7 +50,7 @@ public function getPrefixDirs(): array
public function beans(): array
{
return [
- 'tcpServer' => [
+ TcpServerBean::SERVER => [
'port' => 18309,
'on' => [
SwooleEvent::CONNECT => bean(ConnectListener::class),
@@ -60,9 +60,12 @@ public function beans(): array
// SwooleEvent::PIPE_MESSAGE => bean(PipeMessageListener::class),
]
],
- 'tcpServerProtocol' => [
+ TcpServerBean::PROTOCOL => [
'class' => Protocol::class,
],
+ TcpServerBean::MANAGER => [
+ 'prefix' => 'tcp',
+ ]
];
}
}
diff --git a/src/tcp-server/src/Command/TcpServerCommand.php b/src/tcp-server/src/Command/TcpServerCommand.php
index f99879bad..ff187ef38 100644
--- a/src/tcp-server/src/Command/TcpServerCommand.php
+++ b/src/tcp-server/src/Command/TcpServerCommand.php
@@ -8,6 +8,7 @@
use Swoft\Server\Command\BaseServerCommand;
use Swoft\Server\Exception\ServerException;
use Swoft\Tcp\Server\TcpServer;
+use Swoft\Tcp\Server\TcpServerBean;
use Throwable;
use function bean;
use function input;
@@ -107,7 +108,7 @@ private function createServer(): TcpServer
$command = $this->getFullCommand();
/* @var TcpServer $server */
- $server = bean('tcpServer');
+ $server = bean(TcpServerBean::SERVER);
$server->setScriptFile($script);
$server->setFullCommand($command);
diff --git a/src/tcp-server/src/Connection.php b/src/tcp-server/src/Connection.php
index 961f01252..c4ee1c184 100644
--- a/src/tcp-server/src/Connection.php
+++ b/src/tcp-server/src/Connection.php
@@ -2,6 +2,7 @@
namespace Swoft\Tcp\Server;
+use Swoft;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Contract\SessionInterface;
use Swoft\Stdlib\Concern\DataPropertyTrait;
@@ -13,7 +14,7 @@
* Class Connection
*
* @since 2.0.3
- * @Bean(scope=Bean::PROTOTYPE)
+ * @Bean(name=TcpServerBean::CONNECTION, scope=Bean::PROTOTYPE)
*/
class Connection implements SessionInterface
{
@@ -24,7 +25,23 @@ class Connection implements SessionInterface
/**
* @var int
*/
- private $fd = 0;
+ private $fd = -1;
+
+ /**
+ * @return ConnectionManager
+ */
+ public static function manager(): ConnectionManager
+ {
+ return Swoft::getBean(TcpServerBean::MANAGER);
+ }
+
+ /**
+ * @return static
+ */
+ public static function current(): self
+ {
+ return Swoft::getBean(TcpServerBean::MANAGER)->current();
+ }
/**
* @param int $fd
@@ -35,7 +52,7 @@ class Connection implements SessionInterface
public static function new(int $fd, array $clientInfo): self
{
/** @var self $conn */
- $conn = bean(self::class);
+ $conn = Swoft::getBean(TcpServerBean::CONNECTION);
// Initial properties
$conn->fd = $fd;
@@ -48,17 +65,17 @@ public static function new(int $fd, array $clientInfo): self
/**
* Create an connection from metadata array
*
- * @param array $metadata
+ * @param array $data
*
* @return Connection
*/
- public static function newFromArray(array $metadata): self
+ public static function newFromArray(array $data): SessionInterface
{
/** @var self $conn */
$conn = bean(self::class);
- $conn->fd = $metadata['fd'];
- $conn->set(self::METADATA_KEY, $metadata);
+ $conn->fd = (int)$data['fd'];
+ $conn->set(self::METADATA_KEY, $data);
return $conn;
}
@@ -115,7 +132,7 @@ public function getMetaValue(string $key)
*/
public function clear(): void
{
- $this->fd = 0;
+ $this->fd = -1;
$this->data = [];
}
diff --git a/src/tcp-server/src/ConnectionManager.php b/src/tcp-server/src/ConnectionManager.php
new file mode 100644
index 000000000..6d0afffd8
--- /dev/null
+++ b/src/tcp-server/src/ConnectionManager.php
@@ -0,0 +1,30 @@
+fd = -1;
+
$this->request = null;
$this->response = null;
}
@@ -81,6 +83,8 @@ public function getRequest(): Request
*/
public function setRequest(Request $request): void
{
+ $this->fd = $request->getFd();
+
$this->request = $request;
}
diff --git a/src/tcp-server/src/Exception/CommandNotFoundException.php b/src/tcp-server/src/Exception/CommandNotFoundException.php
index bc6d01ada..268c211c8 100644
--- a/src/tcp-server/src/Exception/CommandNotFoundException.php
+++ b/src/tcp-server/src/Exception/CommandNotFoundException.php
@@ -2,10 +2,22 @@
namespace Swoft\Tcp\Server\Exception;
+use Throwable;
+
/**
* Class CommandNotFoundException
*/
class CommandNotFoundException extends TcpServerException
{
-
+ /**
+ * Class constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param Throwable|null $previous
+ */
+ public function __construct($message = '', $code = 404, Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
}
diff --git a/src/tcp-server/src/Listener/BeforeSettingListener.php b/src/tcp-server/src/Listener/BeforeSettingListener.php
index fb8f19765..8dd49b0cb 100644
--- a/src/tcp-server/src/Listener/BeforeSettingListener.php
+++ b/src/tcp-server/src/Listener/BeforeSettingListener.php
@@ -9,6 +9,7 @@
use Swoft\Server\ServerEvent;
use Swoft\Tcp\Protocol;
use Swoft\Tcp\Server\TcpServer;
+use Swoft\Tcp\Server\TcpServerBean;
use function bean;
/**
@@ -30,7 +31,7 @@ public function handle(EventInterface $event): void
CLog::debug('sync tcp protocol setting from bean(tcpServerProtocol)');
/** @var Protocol $proto */
- $proto = bean('tcpServerProtocol');
+ $proto = bean(TcpServerBean::PROTOCOL);
$server->setSetting($proto->getConfig());
}
}
diff --git a/src/tcp-server/src/Request.php b/src/tcp-server/src/Request.php
index b9964dd77..01edcb4b7 100644
--- a/src/tcp-server/src/Request.php
+++ b/src/tcp-server/src/Request.php
@@ -11,8 +11,8 @@
/**
* Class Request
*
- * @since 2.0
- * @Bean(name="tcpRequest", scope=Bean::PROTOTYPE)
+ * @since 2.0.4
+ * @Bean(name=TcpServerBean::REQUEST, scope=Bean::PROTOTYPE)
*/
class Request implements RequestInterface
{
@@ -68,7 +68,7 @@ class Request implements RequestInterface
public static function new(int $fd, string $data, int $reactorId): self
{
/** @var self $self */
- $self = Swoft::getBean('tcpRequest');
+ $self = Swoft::getBean(TcpServerBean::REQUEST);
// Set properties
$self->fd = $fd;
diff --git a/src/tcp-server/src/Response.php b/src/tcp-server/src/Response.php
index 81b12f02b..3af0ae764 100644
--- a/src/tcp-server/src/Response.php
+++ b/src/tcp-server/src/Response.php
@@ -4,7 +4,6 @@
use Swoft;
use Swoft\Bean\Annotation\Mapping\Bean;
-use Swoft\Log\Helper\CLog;
use Swoft\Tcp\Protocol;
use Swoft\Tcp\Response as TcpResponse;
use Swoft\Tcp\Server\Contract\ResponseInterface;
@@ -14,8 +13,8 @@
/**
* Class Response
*
- * @since 2.0
- * @Bean(name="tcpResponse", scope=Bean::PROTOTYPE)
+ * @since 2.0.4
+ * @Bean(name=TcpServerBean::RESPONSE, scope=Bean::PROTOTYPE)
*/
class Response extends TcpResponse implements ResponseInterface
{
@@ -48,7 +47,7 @@ class Response extends TcpResponse implements ResponseInterface
public static function new(int $fd = -1): TcpResponse
{
/** @var self $self */
- $self = Swoft::getBean('tcpResponse');
+ $self = Swoft::getBean(TcpServerBean::RESPONSE);
// Set properties
$self->fd = $fd;
@@ -76,12 +75,12 @@ public function send(Server $server = null): int
// Content is empty, skip send
if ($this->isEmpty()) {
- CLog::warning('cannot send empty content to tcp client');
- return 0;
+ // CLog::warning('cannot send empty content to tcp client');
+ return -1;
}
/** @var Protocol $protocol */
- $protocol = Swoft::getBean('tcpServerProtocol');
+ $protocol = Swoft::getBean(TcpServerBean::PROTOCOL);
$content = $protocol->packResponse($this);
$server = $server ?: Swoft::server()->getSwooleServer();
@@ -90,12 +89,23 @@ public function send(Server $server = null): int
Swoft::trigger(TcpServerEvent::CONTENT_SEND, $server, $content, $this);
// Do send content
+ $this->doSend($server, $content);
+
+ return 1;
+ }
+
+ /**
+ * @param Server $server
+ * @param string $content
+ *
+ * @throws TcpResponseException
+ */
+ protected function doSend(Server $server, string $content): void
+ {
if ($server->send($this->fd, $content) === false) {
$code = $server->getLastError();
throw new TcpResponseException("Error on send data to client #{$this->fd}", $code);
}
-
- return 1;
}
/**
diff --git a/src/tcp-server/src/Router/Router.php b/src/tcp-server/src/Router/Router.php
index 19163d362..70619dbbc 100644
--- a/src/tcp-server/src/Router/Router.php
+++ b/src/tcp-server/src/Router/Router.php
@@ -5,13 +5,14 @@
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Contract\RouterInterface;
use Swoft\Tcp\Server\Exception\TcpServerRouteException;
+use Swoft\Tcp\Server\TcpServerBean;
use function count;
use function trim;
/**
* Class Router
*
- * @Bean("tcpRouter")
+ * @Bean(TcpServerBean::ROUTER)
*/
class Router implements RouterInterface
{
diff --git a/src/tcp-server/src/Swoole/CloseListener.php b/src/tcp-server/src/Swoole/CloseListener.php
index 8b35691c3..d6c0d3d61 100644
--- a/src/tcp-server/src/Swoole/CloseListener.php
+++ b/src/tcp-server/src/Swoole/CloseListener.php
@@ -13,6 +13,7 @@
use Swoft\Tcp\Server\Connection;
use Swoft\Tcp\Server\Context\TcpCloseContext;
use Swoft\Tcp\Server\TcpErrorDispatcher;
+use Swoft\Tcp\Server\TcpServerBean;
use Swoft\Tcp\Server\TcpServerEvent;
use Swoole\Server;
use Throwable;
@@ -20,7 +21,7 @@
/**
* Class CloseListener
*
- * @since 2.0
+ * @since 2.0.4
* @Bean()
*/
class CloseListener implements CloseInterface
@@ -41,6 +42,9 @@ public function onClose(Server $server, int $fd, int $reactorId): void
// Bind cid => sid(fd)
Session::bindCo($sid);
+ /** @var Swoft\Tcp\Server\ConnectionManager $manager */
+ $manager = Swoft::getBean(TcpServerBean::MANAGER);
+
try {
// Trigger event
Swoft::trigger(TcpServerEvent::CLOSE, $fd, $server, $reactorId);
@@ -55,7 +59,8 @@ public function onClose(Server $server, int $fd, int $reactorId): void
server()->log("Close: conn#{$fd} has been closed. server conn count $total", [], 'debug');
/** @var Connection $conn */
- $conn = Session::mustGet();
+ // $conn = Session::mustGet();
+ $conn = $manager->current();
if (!$meta = $conn->getMetadata()) {
server()->log("Close: conn#{$fd} connection meta info has been lost");
return;
@@ -79,6 +84,7 @@ public function onClose(Server $server, int $fd, int $reactorId): void
// Remove connection
Swoft::trigger(SwoftEvent::SESSION_COMPLETE, $sid);
+ $manager->destroy($sid);
// Unbind cid => sid(fd)
Session::unbindCo();
diff --git a/src/tcp-server/src/Swoole/ConnectListener.php b/src/tcp-server/src/Swoole/ConnectListener.php
index 0f84c37fb..c553e9f38 100644
--- a/src/tcp-server/src/Swoole/ConnectListener.php
+++ b/src/tcp-server/src/Swoole/ConnectListener.php
@@ -12,6 +12,7 @@
use Swoft\Tcp\Server\Context\TcpConnectContext;
use Swoft\Tcp\Server\TcpDispatcher;
use Swoft\Tcp\Server\TcpErrorDispatcher;
+use Swoft\Tcp\Server\TcpServerBean;
use Swoft\Tcp\Server\TcpServerEvent;
use Swoole\Server;
use Throwable;
@@ -37,17 +38,16 @@ public function onConnect(Server $server, int $fd, int $reactorId): void
$ctx = TcpConnectContext::new($fd, $reactorId);
$conn = Connection::new($fd, (array)$server->getClientInfo($fd));
- // Bind session connection and bind cid => sid(fd)
- Session::set($sid, $conn);
+ // Storage session connection and bind cid => sid(fd)
+ // old: Session::set($sid, $conn);
+ $manager = Swoft::getBean(TcpServerBean::MANAGER);
+ $manager->set($sid, $conn);
// Storage context
Context::set($ctx);
try {
// Trigger connect event
Swoft::trigger(TcpServerEvent::CONNECT, $fd, $server, $reactorId);
-
- /** @var TcpDispatcher $dispatcher */
- // $dispatcher = Swoft::getSingleton('tcpDispatcher');
} catch (Throwable $e) {
Swoft::trigger(TcpServerEvent::CONNECT_ERROR, $e, $fd);
@@ -56,6 +56,9 @@ public function onConnect(Server $server, int $fd, int $reactorId): void
// Handle connect error
$errDispatcher->connectError($e, $fd);
+
+ // Should clear session data on handshake fail
+ $manager->destroy($sid);
} finally {
// Trigger defer event
Swoft::trigger(SwoftEvent::COROUTINE_DEFER);
diff --git a/src/tcp-server/src/Swoole/PipeMessageListener.php b/src/tcp-server/src/Swoole/PipeMessageListener.php
deleted file mode 100644
index a4bf59404..000000000
--- a/src/tcp-server/src/Swoole/PipeMessageListener.php
+++ /dev/null
@@ -1,71 +0,0 @@
-log("PipeMessage: received pipe-message fromWID=$srcWorkerId data=", $data);
-
- // Ensure is tcp notify message
- if (!isset($data['from']) || $data['from'] !== 'tcpServer') {
- return;
- }
-
- // Handle
- if (isset($data['event'])) {
- $event = (string)$data['event'];
-
- /** @see CloseListener::onClose() */
- if ($event === 'onClose') {
- $this->handleOnClose($data, $srcWorkerId);
- }
- }
- }
-
- /**
- * @param array $data
- * @param int $srcWID
- */
- protected function handleOnClose(array $data, int $srcWID): void
- {
- $sid = $data['sid'];
-
- if (Session::has($sid)) {
- server()->log("PipeMessage: destroy tcp connection for fd=$sid fromWID=$srcWID");
- Session::destroy($sid);
- }
- }
-}
diff --git a/src/tcp-server/src/Swoole/ReceiveListener.php b/src/tcp-server/src/Swoole/ReceiveListener.php
index 3cc870ed4..e1221a380 100644
--- a/src/tcp-server/src/Swoole/ReceiveListener.php
+++ b/src/tcp-server/src/Swoole/ReceiveListener.php
@@ -14,6 +14,7 @@
use Swoft\Tcp\Server\Response;
use Swoft\Tcp\Server\TcpDispatcher;
use Swoft\Tcp\Server\TcpErrorDispatcher;
+use Swoft\Tcp\Server\TcpServerBean;
use Swoft\Tcp\Server\TcpServerEvent;
use Swoole\Server;
use Throwable;
@@ -21,7 +22,7 @@
/**
* Class ReceiveListener
*
- * @since 2.0
+ * @since 2.0.4
* @Bean()
*/
class ReceiveListener implements ReceiveInterface
@@ -54,7 +55,7 @@ public function onReceive(Server $server, int $fd, int $reactorId, string $data)
Swoft::trigger(TcpServerEvent::RECEIVE_BEFORE, $fd, $server, $reactorId);
/** @var TcpDispatcher $dispatcher */
- $dispatcher = Swoft::getSingleton('tcpDispatcher');
+ $dispatcher = Swoft::getSingleton(TcpServerBean::DISPATCHER);
// Dispatching. allow user disable dispatch.
if ($dispatcher->isEnable()) {
diff --git a/src/tcp-server/src/TcpDispatcher.php b/src/tcp-server/src/TcpDispatcher.php
index edc26f173..499e232ef 100644
--- a/src/tcp-server/src/TcpDispatcher.php
+++ b/src/tcp-server/src/TcpDispatcher.php
@@ -83,7 +83,7 @@ class TcpDispatcher implements MiddlewareInterface
public function dispatch(Request $request, Response $response): ResponseInterface
{
/** @var Protocol $protocol */
- $protocol = Swoft::getBean('tcpServerProtocol');
+ $protocol = Swoft::getBean(TcpServerBean::PROTOCOL);
CLog::info('Tcp protocol data packer is %s', $protocol->getPackerClass());
try {
@@ -95,7 +95,7 @@ public function dispatch(Request $request, Response $response): ResponseInterfac
}
/** @var Router $router */
- $router = Swoft::getSingleton('tcpRouter');
+ $router = Swoft::getSingleton(TcpServerBean::ROUTER);
$command = $package->getCmd() ?: $router->getDefaultCommand();
// Match command
@@ -144,7 +144,6 @@ public function dispatch(Request $request, Response $response): ResponseInterfac
* @return ResponseInterface|Response
* @throws CommandNotFoundException
* @throws ReflectionException
- * @throws Swoft\Exception\SwoftException
*/
public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
@@ -262,10 +261,15 @@ public function getMiddlewares(): array
/**
* @param string $middleware
+ * @param string $name
*/
- public function addMiddleware(string $middleware): void
+ public function addMiddleware(string $middleware, string $name = ''): void
{
- $this->middlewares[] = $middleware;
+ if ($name) {
+ $this->middlewares[$name] = $middleware;
+ } else {
+ $this->middlewares[] = $middleware;
+ }
}
/**
diff --git a/src/tcp-server/src/TcpErrorDispatcher.php b/src/tcp-server/src/TcpErrorDispatcher.php
index 1dd043f1f..e4a4748b3 100644
--- a/src/tcp-server/src/TcpErrorDispatcher.php
+++ b/src/tcp-server/src/TcpErrorDispatcher.php
@@ -86,8 +86,9 @@ public function closeError(Throwable $e, int $fd): void
*/
private function defaultHandle(string $typeName, Throwable $e): void
{
- Log::error($e->getMessage());
- CLog::error("Tcp %s Error(no handler, %s): %s\nAt File %s line %d\nTrace:\n%s", $typeName, get_class($e),
- $e->getMessage(), $e->getFile(), $e->getLine(), $e->getTraceAsString());
+ Log::error($msg = $e->getMessage());
+
+ $logFormat = "Tcp %s Error(no handler, %s): %s\nAt File %s line %d\nTrace:\n%s";
+ CLog::error($logFormat, $typeName, get_class($e), $msg, $e->getFile(), $e->getLine(), $e->getTraceAsString());
}
}
diff --git a/src/tcp-server/src/TcpServerBean.php b/src/tcp-server/src/TcpServerBean.php
new file mode 100644
index 000000000..c181a322a
--- /dev/null
+++ b/src/tcp-server/src/TcpServerBean.php
@@ -0,0 +1,27 @@
+exec($php, [ $dir . '/test/bin/swoft', 'ws:start');
+ $proc->exec($php, ['test/bin/swoft', $type . ':start']);
+ });
+ $pid = $proc->start();
+ echo "Swoft test server started, PID $pid\n";
+
+ // wait server starting...
+ sleep(2);
+ echo file_get_contents('http://127.0.0.1:28308/hi');
+}
+
$application = new TestApplication([
'basePath' => __DIR__
]);
$application->setBeanFile(__DIR__ . '/testing/bean.php');
$application->run();
+
+if (isset($pid) && $pid > 0) {
+ echo "Stop server on tests end. PID $pid";
+ $ok = Process::kill($pid, 15);
+ echo $ok ? " OK\n" : " FAIL\n";
+}
diff --git a/src/tcp-server/test/testing/AutoLoader.php b/src/tcp-server/test/testing/AutoLoader.php
index 47212f202..b0744ccd8 100644
--- a/src/tcp-server/test/testing/AutoLoader.php
+++ b/src/tcp-server/test/testing/AutoLoader.php
@@ -3,6 +3,7 @@
namespace SwoftTest\Tcp\Server\Testing;
use Swoft\SwoftComponent;
+use Swoft\Tcp\Server\TcpServerBean;
/**
* Class AutoLoader
@@ -29,7 +30,7 @@ public function getPrefixDirs(): array
public function metadata(): array
{
return [
- 'tcpServer' => [
+ TcpServerBean::SERVER => [
'debug' => 0,
'setting' => [
'log_file' => '',
diff --git a/src/tcp-server/test/testing/Controller/TcpTestController.php b/src/tcp-server/test/testing/Controller/TcpTestController.php
index 01ff801a5..31d4a878b 100644
--- a/src/tcp-server/test/testing/Controller/TcpTestController.php
+++ b/src/tcp-server/test/testing/Controller/TcpTestController.php
@@ -4,8 +4,10 @@
use Swoft\Tcp\Server\Annotation\Mapping\TcpController;
use Swoft\Tcp\Server\Annotation\Mapping\TcpMapping;
+use Swoft\Tcp\Server\Response;
use SwoftTest\Tcp\Server\Testing\Middleware\User1Middleware;
use SwoftTest\Tcp\Server\Testing\Middleware\User2Middleware;
+use SwoftTest\Testing\TempArray;
/**
* Class TcpTestController
@@ -16,17 +18,21 @@ class TcpTestController
{
/**
* @TcpMapping()
+ * @param Response $response
*/
- public function index(): void
+ public function index(Response $response): void
{
-
+ TempArray::set(__METHOD__, 'hello');
+ $response->setContent($response->getContent() . '[INDEX]');
}
/**
* @TcpMapping(middlewares={User2Middleware::class})
+ * @param Response $response
*/
- public function test(): void
+ public function test(Response $response): void
{
-
+ TempArray::set(__METHOD__, 'hello');
+ $response->setContent($response->getContent() . '[TEST]');
}
}
diff --git a/src/tcp-server/test/testing/Listener/TcpEventSubscriber.php b/src/tcp-server/test/testing/Listener/TcpEventSubscriber.php
new file mode 100644
index 000000000..5e522997f
--- /dev/null
+++ b/src/tcp-server/test/testing/Listener/TcpEventSubscriber.php
@@ -0,0 +1,37 @@
+ 'handler method'
+ * 'event name' => ['handler method', priority]
+ * ]
+ */
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ TcpServerEvent::RECEIVE_BEFORE => 'handle',
+ ];
+ }
+
+ public function handle(Event $event): void
+ {
+ TempArray::set($event->getName(), __METHOD__);
+ }
+}
diff --git a/src/tcp-server/test/testing/Middleware/CoreMiddleware.php b/src/tcp-server/test/testing/Middleware/CoreMiddleware.php
index 26266533a..16b7b7b38 100644
--- a/src/tcp-server/test/testing/Middleware/CoreMiddleware.php
+++ b/src/tcp-server/test/testing/Middleware/CoreMiddleware.php
@@ -25,7 +25,7 @@ class CoreMiddleware implements MiddlewareInterface
public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$resp = Response::new(100);
- $resp->setData('[CORE]');
+ $resp->setContent('[CORE]');
return $resp;
}
diff --git a/src/tcp-server/test/testing/Middleware/Global1Middleware.php b/src/tcp-server/test/testing/Middleware/Global1Middleware.php
new file mode 100644
index 000000000..52e863171
--- /dev/null
+++ b/src/tcp-server/test/testing/Middleware/Global1Middleware.php
@@ -0,0 +1,35 @@
+global ';
+
+ $resp = $handler->handle($request);
+ $old = $resp->getContent();
+
+ $resp->setContent($start . $old . ' global>');
+
+ return $resp;
+ }
+}
diff --git a/src/tcp-server/test/testing/Middleware/User1Middleware.php b/src/tcp-server/test/testing/Middleware/User1Middleware.php
index e65dc09e7..35c8ee8ad 100644
--- a/src/tcp-server/test/testing/Middleware/User1Middleware.php
+++ b/src/tcp-server/test/testing/Middleware/User1Middleware.php
@@ -24,9 +24,11 @@ class User1Middleware implements MiddlewareInterface
public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$start = '>user1 ';
- $resp = $handler->handle($request);
- $resp->setData($start . $resp->getData() . ' user1>');
+ $resp = $handler->handle($request);
+ $old = $resp->getContent();
+
+ $resp->setContent($start . $old . ' user1>');
return $resp;
}
diff --git a/src/tcp-server/test/testing/Middleware/User2Middleware.php b/src/tcp-server/test/testing/Middleware/User2Middleware.php
index 26f1b12c1..6e687b233 100644
--- a/src/tcp-server/test/testing/Middleware/User2Middleware.php
+++ b/src/tcp-server/test/testing/Middleware/User2Middleware.php
@@ -24,9 +24,11 @@ class User2Middleware implements MiddlewareInterface
public function process(RequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$start = '>user2 ';
- $resp = $handler->handle($request);
- $resp->setData($start . $resp->getData() . ' user2>');
+ $resp = $handler->handle($request);
+ $old = $resp->getContent();
+
+ $resp->setContent($start . $old . ' user2>');
return $resp;
}
diff --git a/src/tcp-server/test/testing/MockTcpResponse.php b/src/tcp-server/test/testing/MockTcpResponse.php
index 7cc87da98..c029bdc4f 100644
--- a/src/tcp-server/test/testing/MockTcpResponse.php
+++ b/src/tcp-server/test/testing/MockTcpResponse.php
@@ -4,6 +4,7 @@
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Tcp\Server\Response;
+use Swoole\Server;
/**
* Class MockTcpResponse
@@ -12,5 +13,13 @@
*/
class MockTcpResponse extends Response
{
+ /**
+ * @var string
+ */
+ public $responseBody = '';
+ protected function doSend(Server $server, string $content): void
+ {
+ $this->responseBody = $content;
+ }
}
diff --git a/src/tcp-server/test/testing/MockTcpServer.php b/src/tcp-server/test/testing/MockTcpServer.php
index 66a4c646d..ad7d28347 100644
--- a/src/tcp-server/test/testing/MockTcpServer.php
+++ b/src/tcp-server/test/testing/MockTcpServer.php
@@ -30,6 +30,8 @@ class MockTcpServer
private $tcpServer;
/**
+ * TODO ...
+ *
* @var Server
*/
private $swServer;
diff --git a/src/tcp-server/test/testing/bean.php b/src/tcp-server/test/testing/bean.php
index fc289baee..1954f6edd 100644
--- a/src/tcp-server/test/testing/bean.php
+++ b/src/tcp-server/test/testing/bean.php
@@ -1,7 +1,19 @@
[
+ 'config' => [
'path' => dirname(__DIR__) . '/config',
],
+ /** @see \Swoft\Tcp\Server\TcpDispatcher */
+ 'tcpDispatcher' => [
+ 'middlewares' => [
+ 'global1test' => \SwoftTest\Tcp\Server\Testing\Middleware\Global1Middleware::class
+ ]
+ ],
+ /** @see \Swoft\Tcp\Protocol */
+ 'tcpServerProtocol' => [
+ // 'type' => \Swoft\Tcp\Packer\JsonPacker::TYPE,
+ 'type' => \Swoft\Tcp\Packer\SimpleTokenPacker::TYPE,
+ // 'openLengthCheck' => true,
+ ],
];
diff --git a/src/tcp-server/test/unit/ConnectionTest.php b/src/tcp-server/test/unit/ConnectionTest.php
index 857ff2893..8716184a4 100644
--- a/src/tcp-server/test/unit/ConnectionTest.php
+++ b/src/tcp-server/test/unit/ConnectionTest.php
@@ -39,6 +39,5 @@ public function testConnection(): void
$this->assertNotEmpty($conn->getData());
$conn->clear();
$this->assertEmpty($conn->getData());
-
}
}
diff --git a/src/tcp-server/test/unit/Context/TcpCloseContextTest.php b/src/tcp-server/test/unit/Context/TcpCloseContextTest.php
new file mode 100644
index 000000000..e99b470e2
--- /dev/null
+++ b/src/tcp-server/test/unit/Context/TcpCloseContextTest.php
@@ -0,0 +1,17 @@
+assertSame(2, $ctx->getFd());
+ $this->assertSame(3, $ctx->getReactorId());
+ }
+}
diff --git a/src/tcp-server/test/unit/Context/TcpConnectContextTest.php b/src/tcp-server/test/unit/Context/TcpConnectContextTest.php
new file mode 100644
index 000000000..9dcaccf20
--- /dev/null
+++ b/src/tcp-server/test/unit/Context/TcpConnectContextTest.php
@@ -0,0 +1,18 @@
+assertSame(2, $ctx->getFd());
+ $this->assertSame(3, $ctx->getReactorId());
+ }
+}
diff --git a/src/tcp-server/test/unit/Context/TcpReceiveContextTest.php b/src/tcp-server/test/unit/Context/TcpReceiveContextTest.php
new file mode 100644
index 000000000..73215cf71
--- /dev/null
+++ b/src/tcp-server/test/unit/Context/TcpReceiveContextTest.php
@@ -0,0 +1,45 @@
+setFd(2);
+ $res->setContent('CONTENT');
+
+ $ctx = TcpReceiveContext::new(2, $req, $res);
+
+ $this->assertSame(2, $ctx->getFd());
+ $this->assertSame(3, $ctx->getRequest()->getReactorId());
+ $this->assertSame('data', $ctx->getRequest()->getRawData());
+
+ $this->assertSame(2, $ctx->getResponse()->getFd());
+ $this->assertSame('CONTENT', $ctx->getResponse()->getContent());
+
+ $ctx->clear();
+ $this->assertSame(-1, $ctx->getFd());
+
+ $ctx = new TcpReceiveContext();
+ $this->assertSame(-1, $ctx->getFd());
+
+ $ctx->setRequest($req);
+ $this->assertSame(2, $ctx->getFd());
+ $this->assertSame(3, $ctx->getRequest()->getReactorId());
+
+ $ctx->setResponse($res);
+ $this->assertSame(2, $ctx->getResponse()->getFd());
+ $this->assertSame('CONTENT', $ctx->getResponse()->getContent());
+ }
+}
diff --git a/src/tcp-server/test/unit/RequestHandlerTest.php b/src/tcp-server/test/unit/RequestHandlerTest.php
index e65032b86..3d569a844 100644
--- a/src/tcp-server/test/unit/RequestHandlerTest.php
+++ b/src/tcp-server/test/unit/RequestHandlerTest.php
@@ -4,8 +4,8 @@
use PHPUnit\Framework\TestCase;
use Swoft\Tcp\Server\Exception\TcpMiddlewareException;
-use Swoft\Tcp\Server\RequestHandler;
use Swoft\Tcp\Server\Request;
+use Swoft\Tcp\Server\RequestHandler;
use SwoftTest\Tcp\Server\Testing\Middleware\CoreMiddleware;
use SwoftTest\Tcp\Server\Testing\Middleware\User1Middleware;
use SwoftTest\Tcp\Server\Testing\Middleware\User2Middleware;
@@ -30,6 +30,6 @@ public function testRun(): void
$resp = $mc->run($req);
// $this->assertSame(100, $resp->getSender());
- $this->assertSame('>user1 >user2 [CORE] user2> user1>', $resp->getData());
+ $this->assertSame('>user1 >user2 [CORE] user2> user1>', $resp->getContent());
}
}
diff --git a/src/tcp-server/test/unit/RequestTest.php b/src/tcp-server/test/unit/RequestTest.php
index 0fdaf43ef..06c46fe5e 100644
--- a/src/tcp-server/test/unit/RequestTest.php
+++ b/src/tcp-server/test/unit/RequestTest.php
@@ -3,6 +3,7 @@
namespace SwoftTest\Tcp\Server\Unit;
use PHPUnit\Framework\TestCase;
+use Swoft\Tcp\Package;
use Swoft\Tcp\Server\Request;
/**
@@ -17,5 +18,10 @@ public function testBasic(): void
$this->assertSame(1, $r->getFd());
$this->assertSame(2, $r->getReactorId());
$this->assertSame('data', $r->getRawData());
+
+ $pkg = Package::new('tcp.cmd', 'data', []);
+ $r->setPackage($pkg);
+
+ $this->assertSame('tcp.cmd', $r->getPackage()->getCmd());
}
}
diff --git a/src/tcp-server/test/unit/ResponseTest.php b/src/tcp-server/test/unit/ResponseTest.php
index b8c361b60..6d4af70cc 100644
--- a/src/tcp-server/test/unit/ResponseTest.php
+++ b/src/tcp-server/test/unit/ResponseTest.php
@@ -4,6 +4,7 @@
use PHPUnit\Framework\TestCase;
use Swoft\Tcp\Server\Response;
+use SwoftTest\Tcp\Server\Testing\MockTcpResponse;
/**
* Class ResponseTest
@@ -15,6 +16,8 @@ public function testBasic(): void
$w = Response::new(22);
$this->assertFalse($w->isSent());
+ $this->assertFalse($w->isFail());
+ $this->assertTrue($w->isOK());
$this->assertSame(22, $w->getFd());
$this->assertSame(22, $w->getReqFd());
@@ -26,9 +29,29 @@ public function testBasic(): void
$this->assertTrue($w->isEmpty());
$w->setContent('hi');
+ $this->assertSame('hi', $w->getContent());
$this->assertFalse($w->isEmpty());
+
$w->setCode(23);
$w->setContent('');
+ $this->assertFalse($w->isOK());
+ $this->assertSame(23, $w->getCode());
$this->assertFalse($w->isEmpty());
+
+ $this->assertSame('OK', $w->getMsg());
+ $w->setMsg('Fail');
+ $this->assertSame('Fail', $w->getMsg());
+
+ $this->assertNotEmpty($arr = $w->toArray());
+ $this->assertSame(23, $arr['code']);
+ $this->assertSame('Fail', $arr['msg']);
+
+ $this->assertSame('{"code":23,"msg":"Fail","data":null,"ext":[]}', (string)$w);
}
+
+ // public function testSend(): void
+ // {
+ // $w = new MockTcpResponse();
+ // $w->send();
+ // }
}
diff --git a/src/tcp-server/test/unit/Router/RouterTest.php b/src/tcp-server/test/unit/Router/RouterTest.php
index ab0ef431c..df31d0491 100644
--- a/src/tcp-server/test/unit/Router/RouterTest.php
+++ b/src/tcp-server/test/unit/Router/RouterTest.php
@@ -5,6 +5,7 @@
use PHPUnit\Framework\TestCase;
use Swoft\Tcp\Server\Exception\TcpServerRouteException;
use Swoft\Tcp\Server\Router\Router;
+use Swoft\Tcp\Server\TcpServerBean;
use SwoftTest\Tcp\Server\Testing\Middleware\User1Middleware;
use SwoftTest\Tcp\Server\Testing\Middleware\User2Middleware;
use Throwable;
@@ -74,7 +75,7 @@ public function testAddError(): void
public function testMiddlewares(): void
{
/** @var Router $router */
- $router = bean('tcpRouter');
+ $router = bean(TcpServerBean::ROUTER);
$this->assertNotEmpty($ms = $router->getMiddlewares());
$this->assertArrayHasKey('tcpTest.test', $ms);
diff --git a/src/tcp-server/test/unit/TcpDispatcherTest.php b/src/tcp-server/test/unit/TcpDispatcherTest.php
index cf7152ea0..693aab51d 100644
--- a/src/tcp-server/test/unit/TcpDispatcherTest.php
+++ b/src/tcp-server/test/unit/TcpDispatcherTest.php
@@ -2,12 +2,14 @@
namespace SwoftTest\Tcp\Server\Unit;
-use ReflectionException;
use Swoft\Tcp\Server\Exception\CommandNotFoundException;
-use Swoft\Tcp\Server\Exception\TcpMiddlewareException;
-use Swoft\Tcp\Server\Exception\TcpUnpackingException;
use Swoft\Tcp\Server\Request;
+use Swoft\Tcp\Server\TcpDispatcher;
+use Swoft\Tcp\Server\TcpServerBean;
+use SwoftTest\Tcp\Server\Testing\Controller\TcpTestController;
+use SwoftTest\Tcp\Server\Testing\Middleware\Global1Middleware;
use SwoftTest\Tcp\Server\Testing\MockTcpResponse;
+use SwoftTest\Testing\TempArray;
use Throwable;
use function bean;
use function get_class;
@@ -17,15 +19,82 @@
*/
class TcpDispatcherTest extends TcpServerTestCase
{
- /**
- * @throws ReflectionException
- * @throws CommandNotFoundException
- * @throws TcpMiddlewareException
- * @throws TcpUnpackingException
- */
+ public function testSetting(): void
+ {
+ $td = new TcpDispatcher();
+ $this->assertTrue($td->isEnable());
+ $this->assertTrue($td->isPreCheckRoute());
+
+ $td->setEnable(false);
+ $this->assertFalse($td->isEnable());
+
+ $td->setPreCheckRoute(false);
+ $this->assertFalse($td->isPreCheckRoute());
+ }
+
public function testDispatch(): void
{
- $td = bean('tcpDispatcher');
+ $td = bean(TcpServerBean::DISPATCHER);
+ $this->assertTrue($td->isEnable());
+
+ TempArray::reset();
+
+ // token-text proto:
+ // COMMAND BODY
+ $ctx = $this->newTcpReceiveContext($fd = 1, 'tcpTest.index BODY');
+ $res = $td->dispatch($ctx->getRequest(), $ctx->getResponse());
+
+ $content = $res->getContent();
+ $this->assertStringContainsString('>global', $content);
+ $this->assertStringContainsString('>user1', $content);
+ $this->assertStringContainsString('[INDEX]', $content);
+ $this->assertStringContainsString('user1>', $content);
+ $this->assertStringContainsString('global>', $content);
+
+ // reset temp data
+ $ret = TempArray::reset();
+ $this->assertNotEmpty($ret);
+
+ $key = TcpTestController::class . '::index';
+ $this->assertArrayHasKey($key, $ret);
+ $this->assertSame('hello', $ret[$key]);
+ }
+
+ public function testMiddlewares(): void
+ {
+ $td = bean(TcpServerBean::DISPATCHER);
+
+ $oldMds = $td->getMiddlewares();
+ $this->assertNotEmpty($oldMds);
+ $this->assertArrayHasKey('global1test', $oldMds);
+ $this->assertArrayNotHasKey('global1test1', $oldMds);
+
+ $td->addMiddleware(Global1Middleware::class, 'global1test1');
+ $td->addMiddlewares(['global1test2' => Global1Middleware::class]);
+ $allMds = $td->getMiddlewares();
+ $this->assertArrayHasKey('global1test', $allMds);
+ $this->assertArrayHasKey('global1test1', $allMds);
+ $this->assertArrayHasKey('global1test2', $allMds);
+
+ // reset
+ $td->setMiddlewares($oldMds);
+
+ // pre and after
+ $td = new TcpDispatcher();
+ $this->assertEmpty($td->getPreMiddlewares());
+ $td->setPreMiddlewares(['global1test1' => Global1Middleware::class]);
+ $this->assertNotEmpty($preMds = $td->getPreMiddlewares());
+ $this->assertArrayHasKey('global1test1', $preMds);
+
+ $this->assertEmpty($td->getAfterMiddlewares());
+ $td->setAfterMiddlewares(['global1test2' => Global1Middleware::class]);
+ $this->assertNotEmpty($aftMds = $td->getAfterMiddlewares());
+ $this->assertArrayHasKey('global1test2', $aftMds);
+ }
+
+ public function testCommandNotFound(): void
+ {
+ $td = bean(TcpServerBean::DISPATCHER);
try {
$req = Request::new(1, 'not-exist', 2);
diff --git a/src/tcp-server/test/unit/TcpServerTestCase.php b/src/tcp-server/test/unit/TcpServerTestCase.php
index 40553f24e..a29a9f6c6 100644
--- a/src/tcp-server/test/unit/TcpServerTestCase.php
+++ b/src/tcp-server/test/unit/TcpServerTestCase.php
@@ -3,6 +3,12 @@
namespace SwoftTest\Tcp\Server\Unit;
use PHPUnit\Framework\TestCase;
+use Swoft\Context\Context;
+use Swoft\Session\Session;
+use Swoft\Tcp\Server\Context\TcpReceiveContext;
+use Swoft\Tcp\Server\Request;
+use Swoft\Tcp\Server\Swoole\ReceiveListener;
+use SwoftTest\Tcp\Server\Testing\MockTcpResponse;
use SwoftTest\Tcp\Server\Testing\MockTcpServer;
use Swoole\Server;
@@ -24,10 +30,53 @@ public function setUp(): void
$this->tcpServer = new MockTcpServer();
$this->tcpServer->start();
+
+ // new Server('localhost', 13222);
+
+ // set server
+ // MockTcpServer::setServer($this->wsServer);
}
+ /**
+ * TODO ...
+ *
+ * @return Server
+ */
public function swServer(): Server
{
return $this->tcpServer->getSwooleServer();
}
+
+ /**
+ * @param int $fd
+ * @param string $data
+ * @param int $rid
+ *
+ * @return TcpReceiveContext
+ * @see ReceiveListener::onReceive()
+ */
+ public function newTcpReceiveContext(int $fd, string $data, int $rid = 2): TcpReceiveContext
+ {
+ $sid = (string)$fd;
+ $req = Request::new($fd, $data, $rid);
+ $res = new MockTcpResponse();
+
+ $ctx = TcpReceiveContext::new($fd, $req, $res);
+
+ // Storage context
+ Context::set($ctx);
+ // Bind cid => sid(fd)
+ Session::bindCo($sid);
+
+ return $ctx;
+ }
+
+ /**
+ * @see ReceiveListener::onReceive()
+ */
+ public function delTcpReceiveContext(): void
+ {
+ // Unbind cid => sid(fd)
+ Session::unbindCo();
+ }
}
diff --git a/src/tcp/composer.json b/src/tcp/composer.json
index 5a57c8469..0042cc2a7 100644
--- a/src/tcp/composer.json
+++ b/src/tcp/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/tcp",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/validator/.travis.yml b/src/validator/.travis.yml
index 58fb5c81f..d837f4f4f 100644
--- a/src/validator/.travis.yml
+++ b/src/validator/.travis.yml
@@ -5,7 +5,7 @@ php:
- 7.2
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/validator/composer.json b/src/validator/composer.json
index ce8bb8647..110348189 100644
--- a/src/validator/composer.json
+++ b/src/validator/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/validator",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/validator/src/Rule/IsArrayRule.php b/src/validator/src/Rule/IsArrayRule.php
index 8fcba55c1..db6da5ec0 100644
--- a/src/validator/src/Rule/IsArrayRule.php
+++ b/src/validator/src/Rule/IsArrayRule.php
@@ -48,7 +48,7 @@ public function validate(array $data, string $propertyName, $item, $default = nu
return $data;
}
- $message = (empty($message)) ? sprintf('%s must bool!', $propertyName) : $message;
+ $message = (empty($message)) ? sprintf('%s must array!', $propertyName) : $message;
throw new ValidatorException($message);
}
}
diff --git a/src/validator/test/unit/ValidatorRuleTest.php b/src/validator/test/unit/ValidatorRuleTest.php
index 45662490a..48ff82f62 100644
--- a/src/validator/test/unit/ValidatorRuleTest.php
+++ b/src/validator/test/unit/ValidatorRuleTest.php
@@ -33,7 +33,7 @@ public function testAfterDateSuccess()
}
/**
- * @expectedException Swoft\Validator\Exception\ValidatorException
+ * @expectedException \Swoft\Validator\Exception\ValidatorException
* @expectedExceptionMessage alpha message
*
* @throws ValidatorException
diff --git a/src/websocket-server/.github/PULL_REQUEST_TEMPLATE.md b/src/websocket-server/.github/PULL_REQUEST_TEMPLATE.md
new file mode 100644
index 000000000..8b742aa30
--- /dev/null
+++ b/src/websocket-server/.github/PULL_REQUEST_TEMPLATE.md
@@ -0,0 +1,60 @@
+# PR
+
+- 请不要提交PR到各个组件仓库,它们都是 **只读的**
+- 核心组件的 **开发仓库** 是 **[swoft/swoft-component][core]**
+- 扩展组件的 **开发仓库** 是 **[swoft/swoft-ext][ext]**
+- 请 `fork` 对应的 **开发仓库**,修改后,请把你的PR提交到对应的开发仓库
+
+> 发布版本时官方会将代码同步到各个子仓库。因此,切记不要往子仓库发PR。
+
+## 发起PR时的注意事项
+
+开发组非常欢迎各位向我们提交PR(_Pull Request_),但是为了保证代码质量和统一的风格,
+向官方的主仓库 [swoft/swoft][main] 和 **开发仓库** 贡献代码时需要注意代码和commit格式
+
+### Commit Message
+
+- commit message 只能是英文信息
+- 请尽量保证commit message是有意义的说明
+- 最好以 `add:` `update:` `fix:` 等关键字开头
+
+### 代码风格
+
+- 提交的PHP代码 **必须** 遵循 PSR-2 代码风格
+- 合理且有意义的类、方法、变量命名
+- 适当的注释,合理的使用空行保持代码的简洁,易于阅读
+- 不要包含一些无意义的信息 例如 `@author` 等(_提交者是能够从commit log里看到的_)
+
+------------------
+
+> English Version (_translate by Google_)
+
+The development team welcomes you to submit PR (_Pull Request_) to us, but to ensure code quality and uniform style,
+go to the official main repository [swoft/swoft][main] and Development repository, Note the code and commit format when contributing code
+
+## Precautions when initiating PR
+
+- Please do not submit PR to each sub-repository, they are all read-only
+- The _development repository_ for the core components is **[swoft/swoft-component][core]**
+- The _development repository_ for extension components is **[swoft/swoft-ext][ext]**
+- Please `fork` the corresponding development warehouse. After modification, please submit your PR to the corresponding development warehouse.
+
+> Officially syncs code to individual sub-warehouses when new versions are released
+
+### Commit Message
+
+- the commit message can only be in English
+- Please try to ensure that the commit message is meaningful
+- it is best to start with the keyword `add:` `update:` `fix:`
+
+### Code Style
+
+- Submitted PHP code **Must** Follow PSR-2 code style
+- Reasonable and meaningful class, method, variable naming
+- Appropriate comments, reasonable use of blank lines to keep the code simple and easy to read
+- Don't include some meaningless information such as `@author`, etc. (_author is that can be seen from the commit log_)
+
+
+[main]: https://github.com/swoft-cloud/swoft
+[core]: https://github.com/swoft-cloud/swoft-component
+[ext]: https://github.com/swoft-cloud/swoft-ext
diff --git a/src/websocket-server/.travis.yml b/src/websocket-server/.travis.yml
index 58fb5c81f..d837f4f4f 100644
--- a/src/websocket-server/.travis.yml
+++ b/src/websocket-server/.travis.yml
@@ -5,7 +5,7 @@ php:
- 7.2
- 7.3
install:
- - wget https://github.com/swoole/swoole-src/archive/v4.4.6.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
+ - wget https://github.com/swoole/swoole-src/archive/v4.4.14.tar.gz -O swoole.tar.gz && mkdir -p swoole && tar -xf swoole.tar.gz -C swoole --strip-components=1 && rm swoole.tar.gz && cd swoole && phpize && ./configure && make -j$(nproc) && make install && cd -
- echo "extension = swoole.so" >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
before_script:
diff --git a/src/websocket-server/README.md b/src/websocket-server/README.md
index f567c602d..c5d7d6490 100644
--- a/src/websocket-server/README.md
+++ b/src/websocket-server/README.md
@@ -7,6 +7,10 @@
Swoft Websocket Server Component
+## [中文说明](README.zh-CN.md)
+
+中文说明请查看 [README.zh-CN.md](README.zh-CN.md)
+
## Install
- composer command
diff --git a/src/websocket-server/README.zh-CN.md b/src/websocket-server/README.zh-CN.md
new file mode 100644
index 000000000..cfbc38f6c
--- /dev/null
+++ b/src/websocket-server/README.zh-CN.md
@@ -0,0 +1,34 @@
+# Swoft Websocket Server
+
+[![Latest Stable Version](http://img.shields.io/packagist/v/swoft/websocket-server.svg)](https://packagist.org/packages/swoft/websocket-server)
+[![Php Version](https://img.shields.io/badge/php-%3E=7.1-brightgreen.svg?maxAge=2592000)](https://secure.php.net/)
+[![Swoft Doc](https://img.shields.io/badge/docs-passing-green.svg?maxAge=2592000)](https://www.swoft.org/docs)
+[![Swoft License](https://img.shields.io/hexpm/l/plug.svg?maxAge=2592000)](https://github.com/swoft-cloud/swoft/blob/master/LICENSE)
+
+Swoft Websocket Server Component
+
+## [ENGLISH](README.md)
+
+English readme please sess [README.md](README.md)
+
+## Install
+
+- composer command
+
+```bash
+composer require swoft/websocket-server
+```
+
+## Resources
+
+* [Documentation](https://swoft.org/docs)
+* [Contributing](https://github.com/swoft-cloud/swoft/blob/master/CONTRIBUTING.md)
+* [Report Issues][issues] and [Send Pull Requests][pulls] in the [Main Swoft Repository][repository]
+
+[pulls]: https://github.com/swoft-cloud/swoft-component/pulls
+[repository]: https://github.com/swoft-cloud/swoft
+[issues]: https://github.com/swoft-cloud/swoft/issues
+
+## LICENSE
+
+The Component is open-sourced software licensed under the [Apache license](LICENSE).
diff --git a/src/websocket-server/composer.json b/src/websocket-server/composer.json
index 8b6f9378a..f0333a38c 100644
--- a/src/websocket-server/composer.json
+++ b/src/websocket-server/composer.json
@@ -1,7 +1,7 @@
{
"name": "swoft/websocket-server",
"type": "library",
- "version": "v2.0.7",
+ "version": "v2.0.8",
"keywords": [
"php",
"swoole",
diff --git a/src/websocket-server/src/AutoLoader.php b/src/websocket-server/src/AutoLoader.php
index 173745b24..a2b7e6e18 100644
--- a/src/websocket-server/src/AutoLoader.php
+++ b/src/websocket-server/src/AutoLoader.php
@@ -3,7 +3,6 @@
namespace Swoft\WebSocket\Server;
use Swoft\Helper\ComposerJSON;
-use Swoft\Server\Swoole\PipeMessageListener;
use Swoft\Server\SwooleEvent;
use Swoft\SwoftComponent;
use Swoft\WebSocket\Server\Router\Router;
@@ -61,26 +60,29 @@ public function metadata(): array
public function beans(): array
{
return [
- 'wsServer' => [
+ WsServerBean::SERVER => [
// 'class' => WebSocketServer::class,
'port' => 18308,
'on' => [
// Enable http handle
// SwooleEvent::REQUEST => \bean(RequestListener::class),
- // WebSocket
- SwooleEvent::HANDSHAKE => bean(HandshakeListener::class),
- SwooleEvent::MESSAGE => bean(MessageListener::class),
- SwooleEvent::CLOSE => bean(CloseListener::class),
+ // For WebSocket
+ SwooleEvent::HANDSHAKE => bean(HandshakeListener::class),
+ SwooleEvent::MESSAGE => bean(MessageListener::class),
+ SwooleEvent::CLOSE => bean(CloseListener::class),
// For handle clone connection on exist multi worker
- SwooleEvent::PIPE_MESSAGE => bean(PipeMessageListener::class),
+ // SwooleEvent::PIPE_MESSAGE => bean(PipeMessageListener::class),
]
],
- 'wsRouter' => [
+ WsServerBean::ROUTER => [
'class' => Router::class,
],
- 'wsDispatcher' => [
+ WsServerBean::DISPATCHER => [
'class' => WsDispatcher::class,
],
+ WsServerBean::MANAGER => [
+ 'prefix' => 'ws'
+ ],
];
}
}
diff --git a/src/websocket-server/src/Command/WsServerCommand.php b/src/websocket-server/src/Command/WsServerCommand.php
index 415adc2a2..fd031d5ab 100644
--- a/src/websocket-server/src/Command/WsServerCommand.php
+++ b/src/websocket-server/src/Command/WsServerCommand.php
@@ -10,6 +10,7 @@
use Swoft\Server\Server;
use Swoft\Server\SwooleEvent;
use Swoft\WebSocket\Server\WebSocketServer;
+use Swoft\WebSocket\Server\WsServerBean;
use Throwable;
use function bean;
use function input;
@@ -125,7 +126,7 @@ private function createServer(): WebSocketServer
$command = $this->getFullCommand();
/* @var WebSocketServer $server */
- $server = bean('wsServer');
+ $server = bean(WsServerBean::SERVER);
$server->setScriptFile($script);
$server->setFullCommand($command);
diff --git a/src/websocket-server/src/Connection.php b/src/websocket-server/src/Connection.php
index 4e5b62174..2f4cc1cda 100644
--- a/src/websocket-server/src/Connection.php
+++ b/src/websocket-server/src/Connection.php
@@ -24,7 +24,7 @@
* Class Connection
*
* @since 2.0
- * @Bean(scope=Bean::PROTOTYPE)
+ * @Bean(name=WsServerBean::CONNECTION, scope=Bean::PROTOTYPE)
*/
class Connection implements SessionInterface
{
@@ -37,6 +37,11 @@ class Connection implements SessionInterface
*/
private $fd = 0;
+ /**
+ * @var string
+ */
+ // private $sessionId = '';
+
/**
* Save handshake success module instance
*
@@ -70,6 +75,22 @@ class Connection implements SessionInterface
*/
private $moduleInfo = [];
+ /**
+ * @return ConnectionManager
+ */
+ public static function manager(): ConnectionManager
+ {
+ return Swoft::getBean(WsServerBean::MANAGER);
+ }
+
+ /**
+ * @return static
+ */
+ public static function current(): self
+ {
+ return Swoft::getBean(WsServerBean::MANAGER)->current();
+ }
+
/**
* @param WebSocketServer $server
* @param Request $request
@@ -80,9 +101,10 @@ class Connection implements SessionInterface
public static function new(WebSocketServer $server, Request $request, Response $response): self
{
/** @var self $sess */
- $sess = Swoft::getBean(self::class);
+ $sess = Swoft::getBean(WsServerBean::CONNECTION);
+
+ $sess->fd = $fd = $request->getFd();
- $sess->fd = $fd = $request->getFd();
$sess->server = $server;
// Init meta info
@@ -96,34 +118,36 @@ public static function new(WebSocketServer $server, Request $request, Response $
}
/**
+ * Restore connection object
+ *
* @param array $data
*
* @return static
*/
- public static function newFromArray(array $data): self
+ public static function newFromArray(array $data): SessionInterface
{
// New request and response
$req = new \Swoole\Http\Request();
$res = new \Swoole\Http\Response();
- // Init swoole request
- $req->fd = $data['fd'];
+ // Initialize swoole request
+ $req->fd = (int)$data['fd'];
$req->get = $data['get'];
$req->post = $data['post'];
$req->cookie = $data['cookie'];
$req->header = $data['header'];
$req->server = $data['server'];
- // Init swoole response
+ // Initialize swoole response
$res->cookie = $data['resCookie'];
$res->header = $data['resHeader'];
// Initialize psr7 Request and Response
$psr7Req = Psr7Request::new($req);
$psr7Res = Psr7Response::new($res);
- $wsServer = Swoft::getBean('wsServer');
+ $wsServer = Swoft::getBean(WsServerBean::SERVER);
- // Restore connection object
+ // Initialize connection
$conn = self::new($wsServer, $psr7Req, $psr7Res);
// Session data
$conn->data = $data['sessionData'];
@@ -141,7 +165,7 @@ private function buildMetadata(int $fd, string $path): void
{
$info = $this->server->getClientInfo($fd);
- server()->log("Handshake: conn#{$fd} send handshake request to {$path}, client info: ", $info, 'debug');
+ server()->log("Handshake: conn#{$fd} session data created. path: {$path}, client info: ", $info, 'debug');
$this->set(self::METADATA_KEY, [
'fd' => $fd,
diff --git a/src/websocket-server/src/ConnectionManager.php b/src/websocket-server/src/ConnectionManager.php
new file mode 100644
index 000000000..9858d76ae
--- /dev/null
+++ b/src/websocket-server/src/ConnectionManager.php
@@ -0,0 +1,30 @@
+enable) {
- return;
- }
-
- $key = self::genKey($fd = $request->fd);
- $conn = Session::mustGet($fd);
-
- $this->storage->set($key, $conn->toString());
- }
-
- /**
- * Restore connection on worker reload
- *
- * @param int $fd
- *
- * @return bool
- * @see MessageListener::onMessage()
- *
- * You should call the method on event: {@see WsServerEvent::MESSAGE_RECEIVE}
- *
- */
- public function restore(int $fd): bool
- {
- if (!$this->enable) {
- return false;
- }
-
- $key = self::genKey($fd);
-
- // If not exist
- if (!$json = $this->storage->get($key)) {
- return false;
- }
-
- // Restore connection object
- $data = JsonHelper::decode($json);
- $conn = Connection::newFromArray($data);
-
- // Bind connection and bind cid => sid(fd)
- Session::set((string)$fd, $conn);
-
- return true;
- }
-
- /**
- * Remove storage connection data on close connection
- *
- * @param int $fd
- *
- * @return bool
- * @see CloseListener::onClose()
- *
- * You should call the method on event: {@see WsServerEvent::CLOSE_BEFORE}
- *
- */
- public function remove(int $fd): bool
- {
- if (!$this->enable) {
- return false;
- }
-
- $key = self::genKey($fd);
-
- return $this->storage->del($key);
- }
-
- /**
- * @return StorageInterface
- */
- public function getStorage(): StorageInterface
- {
- return $this->storage;
- }
-
- /**
- * @param StorageInterface $storage
- */
- public function setStorage(StorageInterface $storage): void
- {
- $this->storage = $storage;
- }
-
- /**
- * @param int $fd
- *
- * @return string
- */
- public static function genKey(int $fd): string
- {
- $hostname = gethostname();
- $workerId = server()->getSwooleServer()->worker_id;
-
- return sprintf('ws%s:%d:%d', $hostname, $workerId, $fd);
- }
-
- /**
- * @return bool
- */
- public function isEnable(): bool
- {
- return $this->enable;
- }
-
- /**
- * @param bool $enable
- */
- public function setEnable(bool $enable): void
- {
- $this->enable = $enable;
- }
-}
diff --git a/src/websocket-server/src/Exception/WsModuleRouteException.php b/src/websocket-server/src/Exception/WsModuleRouteException.php
index 357b7caf0..06addaf69 100644
--- a/src/websocket-server/src/Exception/WsModuleRouteException.php
+++ b/src/websocket-server/src/Exception/WsModuleRouteException.php
@@ -2,6 +2,8 @@
namespace Swoft\WebSocket\Server\Exception;
+use Throwable;
+
/**
* Class WsModuleRouteException
*
@@ -9,5 +11,15 @@
*/
class WsModuleRouteException extends WsServerException
{
-
+ /**
+ * Class constructor.
+ *
+ * @param string $message
+ * @param int $code
+ * @param Throwable|null $previous
+ */
+ public function __construct($message = '', $code = 404, Throwable $previous = null)
+ {
+ parent::__construct($message, $code, $previous);
+ }
}
diff --git a/src/websocket-server/src/Listener/AppInitCompleteListener.php b/src/websocket-server/src/Listener/AppInitCompleteListener.php
index 3f98b0c15..59e752221 100644
--- a/src/websocket-server/src/Listener/AppInitCompleteListener.php
+++ b/src/websocket-server/src/Listener/AppInitCompleteListener.php
@@ -2,6 +2,7 @@
namespace Swoft\WebSocket\Server\Listener;
+use Swoft;
use Swoft\Event\Annotation\Mapping\Listener;
use Swoft\Event\EventHandlerInterface;
use Swoft\Event\EventInterface;
@@ -9,7 +10,7 @@
use Swoft\SwoftEvent;
use Swoft\WebSocket\Server\Router\Router;
use Swoft\WebSocket\Server\Router\RouteRegister;
-use function bean;
+use Swoft\WebSocket\Server\WsServerBean;
/**
* Class AppInitCompleteListener
@@ -25,10 +26,10 @@ class AppInitCompleteListener implements EventHandlerInterface
*/
public function handle(EventInterface $event): void
{
- // Register WebSocket routes
+ // Register webSocket routes
/** @var Router $router */
- $router = bean('wsRouter');
+ $router = Swoft::getSingleton(WsServerBean::ROUTER);
RouteRegister::registerTo($router);
diff --git a/src/websocket-server/src/Listener/ConnStorageSubscriber.php b/src/websocket-server/src/Listener/ConnStorageSubscriber.php
deleted file mode 100644
index f1c866475..000000000
--- a/src/websocket-server/src/Listener/ConnStorageSubscriber.php
+++ /dev/null
@@ -1,97 +0,0 @@
- 'handler method'
- * 'event name' => ['handler method', priority]
- * ]
- */
- public static function getSubscribedEvents(): array
- {
- return [
- WsServerEvent::HANDSHAKE_SUCCESS => 'handshakeOk',
- WsServerEvent::MESSAGE_RECEIVE => 'messageReceive',
- WsServerEvent::CLOSE_BEFORE => 'connClose',
- ];
- }
-
- /**
- * @return ConnectionStorage
- */
- protected function getStorage(): ConnectionStorage
- {
- return Swoft::getBean('wsConnStorage');
- }
-
- /**
- * @param EventInterface $event
- */
- public function handshakeOk(EventInterface $event): void
- {
- if (!$this->autoRestoreConn) {
- return;
- }
-
- $request = $event->getParam(0);
-
- $this->getStorage()->storage($request);
- }
-
- /**
- * @param EventInterface $event
- */
- public function messageReceive(EventInterface $event): void
- {
- if (!$this->autoRestoreConn) {
- return;
- }
-
- $fd = (int)$event->getTarget();
-
- if (!Session::has((string)$fd)) {
- $this->getStorage()->restore($fd);
- }
- }
-
- /**
- * @param EventInterface $event
- */
- public function connClose(EventInterface $event): void
- {
- if (!$this->autoRestoreConn) {
- return;
- }
-
- $fd = (int)$event->getTarget();
-
- $this->getStorage()->remove($fd);
- }
-}
diff --git a/src/websocket-server/src/Message/Request.php b/src/websocket-server/src/Message/Request.php
index 7e1eeef5b..266cb9c5c 100644
--- a/src/websocket-server/src/Message/Request.php
+++ b/src/websocket-server/src/Message/Request.php
@@ -7,12 +7,13 @@
use Swoft\Stdlib\Concern\DataPropertyTrait;
use Swoft\WebSocket\Server\Contract\RequestInterface;
use Swoole\WebSocket\Frame;
+use Swoft\WebSocket\Server\WsServerBean;
/**
* Class Request
*
* @since 2.0
- * @Bean(scope=Bean::PROTOTYPE)
+ * @Bean(name=WsServerBean::REQUEST, scope=Bean::PROTOTYPE)
*/
class Request implements RequestInterface
{
@@ -40,7 +41,7 @@ class Request implements RequestInterface
*/
public static function new(Frame $frame): self
{
- $self = Swoft::getBean(self::class);
+ $self = Swoft::getBean(WsServerBean::REQUEST);
// Init properties
$self->frame = $frame;
diff --git a/src/websocket-server/src/Message/Response.php b/src/websocket-server/src/Message/Response.php
index 5fb2f277e..5851ab242 100644
--- a/src/websocket-server/src/Message/Response.php
+++ b/src/websocket-server/src/Message/Response.php
@@ -5,13 +5,13 @@
use Swoft;
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Context\Context;
-use Swoft\Exception\SwoftException;
use Swoft\Log\Helper\CLog;
use Swoft\Server\Concern\CommonProtocolDataTrait;
-use Swoft\Session\Session;
use Swoft\WebSocket\Server\Connection;
use Swoft\WebSocket\Server\Context\WsMessageContext;
use Swoft\WebSocket\Server\Contract\ResponseInterface;
+use Swoft\WebSocket\Server\WebSocketServer;
+use Swoft\WebSocket\Server\WsServerBean;
use Swoft\WebSocket\Server\WsServerEvent;
use Swoole\WebSocket\Frame;
use function is_object;
@@ -21,7 +21,7 @@
* Class Response
*
* @since 2.0.1
- * @Bean(scope=Bean::PROTOTYPE)
+ * @Bean(name=WsServerBean::RESPONSE, scope=Bean::PROTOTYPE)
*/
class Response implements ResponseInterface
{
@@ -71,9 +71,9 @@ class Response implements ResponseInterface
private $sendToAll = false;
/**
- * @var bool
+ * @var int
*/
- private $finish = true;
+ private $finish = 1;
/**
* @var int WebSocket opcode value
@@ -97,7 +97,7 @@ class Response implements ResponseInterface
*/
public static function new(int $fd = 0): self
{
- $self = Swoft::getBean(self::class);
+ $self = Swoft::getBean(WsServerBean::RESPONSE);
// Use sender as default receiver
$self->fd = $fd;
@@ -169,11 +169,20 @@ public function toAll(bool $yes = true): self
return $this;
}
+ /**
+ * @return Response
+ */
+ public function broadcast(): self
+ {
+ // Exclude self
+ $this->noFds[] = $this->sender;
+ return $this;
+ }
+
/**
* @param Connection $conn
*
* @return int
- * @throws SwoftException
*/
public function send(Connection $conn = null): int
{
@@ -188,12 +197,11 @@ public function send(Connection $conn = null): int
// Fix: empty response data
if ($this->isEmpty()) {
- CLog::warning('cannot send empty response to websocket client');
- return 0;
+ // CLog::warning('cannot send empty response to websocket client');
+ return -1;
}
- /** @noinspection CallableParameterUseCaseInTypeContextInspection */
- $conn = $conn ?: Session::current();
+ $conn = $conn ?: Connection::current();
// Build response content
$content = $this->formatContent($conn);
@@ -203,30 +211,45 @@ public function send(Connection $conn = null): int
// Trigger event before push message content to client
Swoft::trigger(WsServerEvent::MESSAGE_PUSH, $server, $content, $this);
- // To all users
+ // Do sending
+ return $this->doSend($server, $content, $sender);
+ }
+
+ /**
+ * @param WebSocketServer $server
+ * @param string $content
+ * @param int $sender
+ *
+ * @return int
+ */
+ protected function doSend(WebSocketServer $server, string $content, int $sender): int
+ {
+ $opcode = $this->opcode;
$pageSize = $this->pageSize;
+
+ // To all users
if ($this->sendToAll) {
- return $server->sendToAll($content, $sender, $pageSize, $this->opcode);
+ return $server->sendToAll($content, $sender, $pageSize, $opcode);
}
// To special users
if ($this->fds) {
- return $server->sendToSome($content, $this->fds, $this->noFds, $sender, $pageSize, $this->opcode);
+ return $server->sendToSome($content, $this->fds, $this->noFds, $sender, $pageSize, $opcode);
}
// Except some users
if ($this->noFds) {
- return $server->sendToSome($content, [], $this->noFds, $sender, $pageSize, $this->opcode);
+ return $server->sendToSome($content, [], $this->noFds, $sender, $pageSize, $opcode);
}
// No receiver
if ($this->fd < 1) {
CLog::warning('no receiver for the response message');
- return 0;
+ return -2;
}
// To one user
- $ok = $server->sendTo($this->fd, $content, $sender, $this->opcode, $this->finish);
+ $ok = $server->sendTo($this->fd, $content, $sender, $opcode, $this->finish);
return $ok ? 1 : 0;
}
@@ -235,7 +258,6 @@ public function send(Connection $conn = null): int
* @param Connection|null $conn
*
* @return string
- * @throws SwoftException
*/
protected function formatContent(Connection $conn): string
{
@@ -357,18 +379,26 @@ public function setOpcode(int $opcode): self
* @return bool
*/
public function isFinish(): bool
+ {
+ return $this->finish === 1;
+ }
+
+ /**
+ * @return int
+ */
+ public function getFinish(): int
{
return $this->finish;
}
/**
- * @param bool $finish
+ * @param bool|int $finish
*
* @return self
*/
- public function setFinish(bool $finish): self
+ public function setFinish($finish): self
{
- $this->finish = $finish;
+ $this->finish = (int)$finish;
return $this;
}
diff --git a/src/websocket-server/src/Storage/RedisStorage.php b/src/websocket-server/src/Storage/RedisStorage.php
deleted file mode 100644
index 8d7455259..000000000
--- a/src/websocket-server/src/Storage/RedisStorage.php
+++ /dev/null
@@ -1,12 +0,0 @@
-db = new Table($this->size);
- $this->db->column('key', Table::TYPE_STRING, 72);
- $this->db->column('data', Table::TYPE_STRING, 3072);
- $this->db->create();
- }
-
- /**
- * @return Table
- */
- public function getDb(): Table
- {
- return $this->db;
- }
-
- /**
- * @param Table $db
- */
- public function setDb(Table $db): void
- {
- $this->db = $db;
- }
-
- /**
- * @return int
- */
- public function getSize(): int
- {
- return $this->size;
- }
-
- /**
- * @param int $size
- */
- public function setSize(int $size): void
- {
- $this->size = $size;
- }
-
- /**
- * @param string $key
- * @param mixed $value
- */
- public function set(string $key, $value): void
- {
- $this->db->set($key, [
- 'key' => $key,
- 'data' => $value,
- ]);
- }
-
- /**
- * @param string $key
- *
- * @return mixed
- */
- public function get(string $key)
- {
- return $this->db->get($key);
- }
-
- /**
- * @param string $key
- *
- * @return bool
- */
- public function del(string $key): bool
- {
- return $this->db->del($key);
- }
-
- /**
- * clear table data
- */
- public function clear(): void
- {
- foreach ($this->db as $row) {
- $this->db->del($row['key']);
- }
- }
-}
diff --git a/src/websocket-server/src/Swoole/CloseListener.php b/src/websocket-server/src/Swoole/CloseListener.php
index 6c75cac2e..48ddd7529 100644
--- a/src/websocket-server/src/Swoole/CloseListener.php
+++ b/src/websocket-server/src/Swoole/CloseListener.php
@@ -14,6 +14,7 @@
use Swoft\WebSocket\Server\Context\WsCloseContext;
use Swoft\WebSocket\Server\WsDispatcher;
use Swoft\WebSocket\Server\WsErrorDispatcher;
+use Swoft\WebSocket\Server\WsServerBean;
use Swoft\WebSocket\Server\WsServerEvent;
use Swoole\Server;
use Throwable;
@@ -57,6 +58,9 @@ public function onClose(Server $server, int $fd, int $reactorId): void
// Unbind cid => sid(fd)
Session::bindCo($sid);
+ /** @var Swoft\WebSocket\Server\ConnectionManager $manager */
+ $manager = Swoft::getBean(WsServerBean::MANAGER);
+
try {
// Call on close callback
Swoft::trigger(WsServerEvent::CLOSE_BEFORE, $fd, $server);
@@ -67,7 +71,8 @@ public function onClose(Server $server, int $fd, int $reactorId): void
$this->notifyOtherWorkersClose($fd, $sid, $server->worker_id);
} else {
/** @var Connection $conn */
- $conn = Session::mustGet();
+ // $conn = Session::mustGet();
+ $conn = $manager->current();
$total = server()->count() - 1;
server()->log("Close: conn#{$fd} has been closed. connection count $total", [], 'debug');
@@ -102,6 +107,7 @@ public function onClose(Server $server, int $fd, int $reactorId): void
// Remove connection
Swoft::trigger(SwoftEvent::SESSION_COMPLETE, $sid);
+ $manager->destroy($sid);
// Unbind cid => sid(fd)
Session::unbindCo();
diff --git a/src/websocket-server/src/Swoole/HandshakeListener.php b/src/websocket-server/src/Swoole/HandshakeListener.php
index e3d7516f1..e1e22494b 100644
--- a/src/websocket-server/src/Swoole/HandshakeListener.php
+++ b/src/websocket-server/src/Swoole/HandshakeListener.php
@@ -19,6 +19,7 @@
use Swoft\WebSocket\Server\Helper\WsHelper;
use Swoft\WebSocket\Server\WsDispatcher;
use Swoft\WebSocket\Server\WsErrorDispatcher;
+use Swoft\WebSocket\Server\WsServerBean;
use Swoft\WebSocket\Server\WsServerEvent;
use Swoole\Coroutine;
use Swoole\Http\Request;
@@ -68,14 +69,16 @@ public function onHandshake(Request $request, Response $response): bool
// Initialize psr7 Request and Response
$psr7Req = Psr7Request::new($request);
$psr7Res = Psr7Response::new($response);
- $wsServer = Swoft::getBean('wsServer');
+ $wsServer = Swoft::getBean(WsServerBean::SERVER);
+ $manager = Swoft::getBean(WsServerBean::MANAGER);
// Initialize connection session and context
$ctx = WsHandshakeContext::new($psr7Req, $psr7Res);
$conn = Connection::new($wsServer, $psr7Req, $psr7Res);
- // Bind connection and bind cid => sid(fd)
- Session::set($sid, $conn);
+ // Storage connection and bind cid => sid(fd)
+ // old: Session::set($sid, $conn);
+ $manager->set($sid, $conn);
// Storage context
Context::set($ctx);
@@ -101,6 +104,8 @@ public function onHandshake(Request $request, Response $response): bool
// Response handshake successfully
$meta = $conn->getMetadata();
$conn->setHandshake(true);
+ // NOTICE: must sync connection data to storage
+ $manager->set($sid, $conn);
$psr7Res->quickSend();
$wsServer->log("Handshake: conn#{$fd} handshake successful! meta:", $meta, 'debug');
@@ -121,6 +126,9 @@ public function onHandshake(Request $request, Response $response): bool
$psr7Res = $errDispatcher->handshakeError($e, $psr7Res);
$psr7Res->quickSend();
+
+ // Should clear session data on handshake fail
+ $manager->destroy($sid);
} finally {
// Defer
Swoft::trigger(SwoftEvent::COROUTINE_DEFER);
diff --git a/src/websocket-server/src/Swoole/MessageListener.php b/src/websocket-server/src/Swoole/MessageListener.php
index c434583cc..8ee507e48 100644
--- a/src/websocket-server/src/Swoole/MessageListener.php
+++ b/src/websocket-server/src/Swoole/MessageListener.php
@@ -67,7 +67,8 @@ public function onMessage(Server $server, Frame $frame): void
Swoft::trigger(WsServerEvent::MESSAGE_RECEIVE, $fd, $server, $frame);
/** @var Connection $conn */
- $conn = Session::current();
+ // $conn = Session::current();
+ $conn = Connection::current();
$info = $conn->getModuleInfo();
// Want custom message handle, will don't trigger message parse and dispatch.
@@ -86,7 +87,9 @@ public function onMessage(Server $server, Frame $frame): void
Swoft::trigger(WsServerEvent::MESSAGE_RESPONSE, $response);
// Do send response
- $response->send();
+ if(!$response->isEmpty()){
+ $response->send();
+ }
}
// Trigger message after event
@@ -100,8 +103,11 @@ public function onMessage(Server $server, Frame $frame): void
// Do error dispatching
$response = $errDispatcher->messageError($e, $frame, $response);
+
// Do send response
- $response->send();
+ if(!$response->isEmpty()){
+ $response->send();
+ }
} finally {
// Defer event
Swoft::trigger(SwoftEvent::COROUTINE_DEFER);
diff --git a/src/websocket-server/src/Swoole/PipeMessageListener.php b/src/websocket-server/src/Swoole/PipeMessageListener.php
deleted file mode 100644
index fdcc8e63b..000000000
--- a/src/websocket-server/src/Swoole/PipeMessageListener.php
+++ /dev/null
@@ -1,71 +0,0 @@
-log("PipeMessage: received pipe-message fromWID=$srcWorkerId data=", $data);
-
- // Ensure is websocket notify message
- if (!isset($data['from']) || $data['from'] !== 'wsServer') {
- return;
- }
-
- // Handle
- if (isset($data['event'])) {
- $event = (string)$data['event'];
-
- /** @see CloseListener::onClose() */
- if ($event === 'onClose') {
- $this->handleClose($data, $srcWorkerId);
- }
- }
- }
-
- /**
- * @param array $data
- * @param int $srcWID
- */
- protected function handleClose(array $data, int $srcWID): void
- {
- $sid = $data['sid'];
-
- if (Session::has($sid)) {
- server()->log("PipeMessage: destroy ws connection for fd=$sid fromWID=$srcWID");
- Session::destroy($sid);
- }
- }
-}
diff --git a/src/websocket-server/src/WebSocketServer.php b/src/websocket-server/src/WebSocketServer.php
index 594a19f2b..b5e9a39f8 100644
--- a/src/websocket-server/src/WebSocketServer.php
+++ b/src/websocket-server/src/WebSocketServer.php
@@ -18,7 +18,7 @@
/**
* Class WebSocketServer
*
- * @Bean("wsServer")
+ * @Bean(WsServerBean::SERVER)
*
* @since 2.0
*/
diff --git a/src/websocket-server/src/WsDispatcher.php b/src/websocket-server/src/WsDispatcher.php
index ac649e56f..44938585a 100644
--- a/src/websocket-server/src/WsDispatcher.php
+++ b/src/websocket-server/src/WsDispatcher.php
@@ -19,7 +19,7 @@
* Class WsDispatcher
*
* @since 1.0
- * @Bean("wsDispatcher")
+ * @Bean(WsServerBean::DISPATCHER)
*/
class WsDispatcher
{
@@ -36,13 +36,14 @@ class WsDispatcher
public function handshake(Request $request, Response $response): array
{
/** @var Router $router */
- $router = Swoft::getSingleton('wsRouter');
+ $router = Swoft::getSingleton(WsServerBean::ROUTER);
/** @var Connection $conn */
$conn = Session::mustGet();
$path = $request->getUriPath();
if (!$info = $router->match($path)) {
+ server()->log("Requested websocket route path '{$path}' is not exist, rejected", [], 'debug');
throw new WsModuleRouteException(sprintf('The requested websocket route path "%s" is not exist!', $path));
}
diff --git a/src/websocket-server/src/WsMessageDispatcher.php b/src/websocket-server/src/WsMessageDispatcher.php
index 582b30d83..f555bab9f 100644
--- a/src/websocket-server/src/WsMessageDispatcher.php
+++ b/src/websocket-server/src/WsMessageDispatcher.php
@@ -8,7 +8,6 @@
use Swoft\Bean\Annotation\Mapping\Bean;
use Swoft\Bean\Annotation\Mapping\Inject;
use Swoft\Log\Helper\CLog;
-use Swoft\Session\Session;
use Swoft\WebSocket\Server\Contract\MessageHandlerInterface;
use Swoft\WebSocket\Server\Contract\MiddlewareInterface;
use Swoft\WebSocket\Server\Contract\RequestInterface;
@@ -29,7 +28,7 @@
*
* @since 2.0
*
- * @Bean("wsMsgDispatcher")
+ * @Bean(WsServerBean::MSG_DISPATCHER)
*/
class WsMessageDispatcher implements MiddlewareInterface
{
@@ -85,7 +84,7 @@ class WsMessageDispatcher implements MiddlewareInterface
public function dispatch(array $module, Request $request, Response $response): ResponseInterface
{
/** @var Connection $conn */
- $conn = Session::current();
+ $conn = Connection::current();
$frame = $request->getFrame();
CLog::info('Message: message data parser is %s', $conn->getParserClass());
@@ -142,7 +141,6 @@ public function dispatch(array $module, Request $request, Response $response): R
*
* @return ResponseInterface
* @throws ReflectionException
- * @throws Swoft\Exception\SwoftException
* @throws WsMessageRouteException
* @internal for middleware dispatching
*/
diff --git a/src/websocket-server/src/WsServerBean.php b/src/websocket-server/src/WsServerBean.php
new file mode 100644
index 000000000..dc059e568
--- /dev/null
+++ b/src/websocket-server/src/WsServerBean.php
@@ -0,0 +1,27 @@
+assertSame($conn, $conn1);
- Session::destroy($sid);
-
+ $this->rmConnection($sid);
$this->assertFalse(Session::has($sid));
}
}
diff --git a/src/websocket-server/test/unit/Message/ResponseTest.php b/src/websocket-server/test/unit/Message/ResponseTest.php
index 895aa7d60..9f5147cb0 100644
--- a/src/websocket-server/test/unit/Message/ResponseTest.php
+++ b/src/websocket-server/test/unit/Message/ResponseTest.php
@@ -16,6 +16,7 @@ public function testBasic(): void
$this->assertSame(22, $w->getFd());
$this->assertSame(22, $w->getSender());
+ $this->assertSame(1, $w->getFinish());
$w
->setFd(33)
@@ -28,6 +29,7 @@ public function testBasic(): void
$this->assertSame(7, $w->getOpcode());
$this->assertFalse($w->isSent());
$this->assertFalse($w->isFinish());
+ $this->assertSame(0, $w->getFinish());
$this->assertFalse($w->isSendToAll());
$w->toAll();
diff --git a/src/websocket-server/test/unit/WsDispatcherTest.php b/src/websocket-server/test/unit/WsDispatcherTest.php
index 2da22bdb1..fd9a10799 100644
--- a/src/websocket-server/test/unit/WsDispatcherTest.php
+++ b/src/websocket-server/test/unit/WsDispatcherTest.php
@@ -63,7 +63,7 @@ public function testHandshake(): string
public function testModuleInfo(string $sid): void
{
$this->assertTrue(Session::has($sid));
- $conn = Session::mustGet();
+ $conn = Session::current();
$this->assertSame($conn, Session::mustGet($sid));
$info = $conn->getModuleInfo();
diff --git a/src/websocket-server/test/unit/WsServerTestCase.php b/src/websocket-server/test/unit/WsServerTestCase.php
index f8bcca743..fbc1791ce 100644
--- a/src/websocket-server/test/unit/WsServerTestCase.php
+++ b/src/websocket-server/test/unit/WsServerTestCase.php
@@ -50,9 +50,10 @@ public static function tearDownAfterClass(): void
*/
protected function mockHttpRequest(int $fd = 1, string $path = '/'): Request
{
- $req = MockHttpRequest::new([
+ $req = MockHttpRequest::new([
'request_uri' => $path,
]);
+
$req->fd = $fd;
return Request::new($req);
diff --git a/test/bin/bootstrap.php b/test/bin/bootstrap.php
new file mode 100644
index 000000000..bd8c79bb4
--- /dev/null
+++ b/test/bin/bootstrap.php
@@ -0,0 +1,16 @@
+addPsr4("Swoft\\Cache\\", 'vendor/swoft/cache/src/');
+$loader->addPsr4("Swoft\\Swlib\\", 'vendor/swoft/swlib/src/');
+$loader->addPsr4("Swoft\\Serialize\\", 'vendor/swoft/serialize/src/');
diff --git a/test/bin/swoft b/test/bin/swoft
new file mode 100644
index 000000000..a99e04b24
--- /dev/null
+++ b/test/bin/swoft
@@ -0,0 +1,15 @@
+#!/usr/bin/env php
+ 300000,
+]);
+
+// Run application
+(new \App\Application())->run();
diff --git a/test/bootstrap.php b/test/bootstrap.php
index a202591c6..76d96b076 100644
--- a/test/bootstrap.php
+++ b/test/bootstrap.php
@@ -21,6 +21,10 @@
exit('Please run "composer install" to install the dependencies' . PHP_EOL);
}
+if (defined('RUN_TEST_APP') && !RUN_TEST_APP) {
+ return;
+}
+
$application = new TestApplication();
$application->setBeanFile(__DIR__ . '/testing/bean.php');
$application->run();
diff --git a/test/testing/AutoLoader.php b/test/testing/AutoLoader.php
index 57c102a8a..96fe53d8c 100644
--- a/test/testing/AutoLoader.php
+++ b/test/testing/AutoLoader.php
@@ -1,9 +1,7 @@